Interrupts!

alentours-dev
Sergiusz Bazanski 2011-02-22 18:09:58 +01:00
parent 236f28e1c7
commit 619ce7bda1
15 changed files with 520 additions and 21 deletions

44
include/Tier0/acpi.h Normal file
View File

@ -0,0 +1,44 @@
#include "types.h"
#ifndef __ACPI_H__
#define __ACPI_H__
#define ACPI_VERSION_UNK 0
#define ACPI_VERSION_10 1
#define ACPI_VERSION_20 2
#define ACPI_10_RSDP_SIZE 20
#define ACPI_20_RSDP_SIZE 16
struct S_ACPI_RSDP {
s8 Magic[8];
u8 Checksum;
s8 OEMID[6];
u8 Revision;
u32 RSDTAddress;
// Additional ACPI 2.0 fields
u32 Length;
u32 RSDTAddressExLow;
u32 RSDTAddressExHigh;
u8 ChecksumEx;
u8 Reserved[3];
} __attribute__((packed));
typedef struct S_ACPI_RSDP T_ACPI_RSDP;
struct S_ACPI_SDT_HEADER {
s8 Signature[4];
u32 Length;
u8 Revision;
u8 Checksum;
s8 OEMID[6];
s8 OEMTableID[8];
u32 OEMRevision;
u32 CreatorID;
u32 CreatorRevision;
} __attribute__ ((packed));
typedef struct S_ACPI_SDT_HEADER T_ACPI_SDT_HEADER;
u32 acpi_find_rsdp(void);
#endif

View File

@ -0,0 +1,52 @@
#include "types.h"
struct S_IDT_PTR {
u16 Limit;
u32 Base;
} __attribute__ ((packed));
typedef struct S_IDT_PTR T_IDT_PTR;
struct S_IDT_ENTRY {
u16 OffsetLow;
u16 Selector;
u8 Zero;
u8 Type;
u16 OffsetHigh;
} __attribute__ ((packed));
typedef struct S_IDT_ENTRY T_IDT_ENTRY;
enum E_INTERRUPTS_RING {
E_INTERRUPTS_RING0 = 0,
E_INTERRUPTS_RING1,
E_INTERRUPTS_RING2,
E_INTERRUPTS_RING3
};
typedef enum E_INTERRUPTS_RING T_INTERRUPTS_RING;
enum E_INTERRUPTS_CHIP {
E_INTERRUPTS_CHIP_UNK,
E_INTERRUPTS_CHIP_PIC,
E_INTERRUPTS_CHIP_APIC
};
typedef enum E_INTERRUPTS_CHIP T_INTERRUPTS_CHIP;
// This is a structure that allows easy access to a 12-byte ASM stub which
// calls a stdcall handler. Not the best way and not the shortest stub,
// but hey, it works.
struct S_ISR_STUB {
u16 Code1;
u8 Code2;
u32 Handler;
u32 Code3;
u8 Code4;
} __attribute__ ((packed));
typedef struct S_ISR_STUB T_ISR_STUB;
u8 interrupts_init_idt(void);
void interrupts_setup_irq(u8 IRQ, void *Handler);
void interrupts_setup_isr(u8 Interrupt, void *Handler, T_INTERRUPTS_RING Ring);
void interrupts_init_simple(void);
void interrupts_interrupt_finish(u8 IRQ);
void interrupts_lidt(void);
void interrupts_dump_idt_entry(u8 Interrupt);
void interrupts_dump_idt_ptr(void);

View File

@ -4,6 +4,8 @@
#include "types.h"
void koutb(u16 Port, u8 Data);
u8 kinb(u16 Port);
void kio_wait(void);
u32 kstrlen(s8 *szString);
void kmove_cursor(u8 X, u8 Y);
void kputs(s8 *szString);
@ -14,5 +16,6 @@ void kputi(s32 Number);
void kprintf(s8 *Format, ...);
void kdump(u8 *bData, u32 Length);
void kprint_hex(u32 Number);
s32 kmemcmp(u8 *MemA, u8 *MemB, u32 Length);
#endif

View File

@ -1,6 +1,8 @@
#ifndef __PAGING_H__
#define __PAGING_H__
void paging_init_simple(void);
#include "types.h"
void paging_init_simple(void);
u8 paging_get_physical(u32 Virtual, u32 *Physical);
#endif

20
include/Tier0/pic.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __PIC_H__
#define __PIC_H__
#include "types.h"
#define PIC_1_ADDR 0x20
#define PIC_1_DATA 0x21
#define PIC_1_START 0xF0
#define PIC_2_ADDR 0xA0
#define PIC_2_DATA 0xA1
#define PIC_2_START 0xF8
#define PIC_IRQ_START 0xF0
void pic_init(u8 *OldMask1, u8 *OldMask2);
void pic_eoi(u8 IRQ);
void pic_unmask_irq(u8 IRQ);
#endif

View File

@ -45,7 +45,6 @@ higherhalf:
mov esp, kstack + STACKSIZE
push eax
push ebx
call kmain

66
src/Tier0/acpi.c Normal file
View File

@ -0,0 +1,66 @@
#include "Tier0/acpi.h"
#include "Tier0/kstdio.h"
u8 g_acpi_version = 0;
u32 g_acpi_rsdt_address = 0;
u32 acpi_find_rsdp(void)
{
s8 *szMagic = "RSD PTR ";
// Try to find the pointer... apparently it's 16byte-aligned...
kprintf("[i] Looking for the RSDP...\n");
u32 Address = 0;
for (u32 Search = 0x000E0000; Search <= 0x000FFFFF; Search += 4)
{
if (kmemcmp((u8 *)Search, (u8 *)szMagic, 8) == 0)
{
Address = Search;
break;
}
}
if (Address == 0)
return 0;
T_ACPI_RSDP *RSDP = (T_ACPI_RSDP *)Address;
u8 ChecksumVerify = 0;
for (u8 i = 0; i < ACPI_10_RSDP_SIZE; i++)
ChecksumVerify += ((u8*)Address)[i];
if (ChecksumVerify != 0)
{
kprintf("[e] ACPI checksum failed. Memory failure? Weird PC? We may never " \
"know ...\n");
return 0;
}
if (RSDP->Revision == 1)
{
// ACPI 2.0...
ChecksumVerify = 0;
for (u8 i = ACPI_10_RSDP_SIZE; i < ACPI_20_RSDP_SIZE; i++)
ChecksumVerify += ((u8*)Address)[i];
if (ChecksumVerify != 0)
{
kprintf("[e] ACPI 2.0 checksum failed. Yet 1.0 succeeded? WTF.\n");
return 0;
}
}
g_acpi_version = RSDP->Revision + 1;
kprintf("[i] Detected ACPI version %i.0.\n", RSDP->Revision + 1);
if (*RSDP->OEMID != 0)
kprintf("[i] OEMID %s.\n", RSDP->OEMID);
if (g_acpi_version == ACPI_VERSION_10)
g_acpi_rsdt_address = Address;
else
g_acpi_rsdt_address = RSDP->RSDTAddressExLow;
return Address;
}

1
src/Tier0/cpp.c Normal file
View File

@ -0,0 +1 @@
// Basically stuff that is needed to go into C++ Land

9
src/Tier0/interrupts.asm Normal file
View File

@ -0,0 +1,9 @@
BITS 32
section .text
global interrupts_lidt
extern g_idt_ptr
interrupts_lidt:
lidt [g_idt_ptr]
ret

139
src/Tier0/interrupts.c Normal file
View File

@ -0,0 +1,139 @@
#include "Tier0/interrupts.h"
#include "Tier0/paging.h"
#include "Tier0/kstdio.h"
#include "Tier0/pic.h"
T_IDT_PTR g_idt_ptr;
T_IDT_ENTRY g_idt_entries[256];
T_ISR_STUB g_isr_stubs[256];
T_INTERRUPTS_CHIP g_interrupts_chip = E_INTERRUPTS_CHIP_UNK;
void interrupts_set_chip(T_INTERRUPTS_CHIP Chip)
{
g_interrupts_chip = Chip;
if (Chip == E_INTERRUPTS_CHIP_UNK)
kprintf("[i] Interrupts: Turning off.\n");
else if (Chip == E_INTERRUPTS_CHIP_PIC)
kprintf("[i] Interrupts: Switching to 8259 based interrupts.\n");
else if (Chip == E_INTERRUPTS_CHIP_APIC)
kprintf("[i] Interrupts: Switching to intel I/O APIC based "
"interrupts.\n");
}
u8 interrupts_init_idt(void)
{
g_idt_ptr.Limit = 256 * 8;
u32 Physical = 0;
u8 Result = paging_get_physical((u32)g_idt_entries, &Physical);
if (!Result)
return 0;
kprintf("[i] Setting up IDT at 0x%x (0x%x Virtual).\n", Physical, g_idt_entries);
g_idt_ptr.Base = Physical;
// Null those entries!
for (u16 i = 0; i < 256; i++)
{
// Maybe I should access the struct's members...
// Or i can just cast that to to u32's and null them.
// This will set the Present flag to 0 either way
*((u32 *)(&g_idt_entries[i])) = 0;
*(((u32 *)(&g_idt_entries[i]) + 1)) = 0;
}
return 1;
}
// This creates a 12-byte ASM stub for a handler
void interrupts_create_stub(T_ISR_STUB *Destination, u32 Address)
{
// The ASM code is as follows:
// cli
// pushad
// mov eax, Handler
// call eax
// popad
// sti
// iret
Destination->Code1 = 0x60FA; // pishad, cli
Destination->Code2 = 0xB8; // mov eax,
Destination->Handler = Address; // Address
Destination->Code3 = 0xFB61D0FF; // sti, popad, call eax
Destination->Code4 = 0xCF; // iret
}
void interrupts_setup_irq(u8 IRQ, void *Handler)
{
if (g_interrupts_chip != E_INTERRUPTS_CHIP_PIC)
{
kprintf("[e] Sorry, but I only do PIC-based interrupts for now :(.\n");
return;
}
u8 Interrupt = IRQ + PIC_IRQ_START;
interrupts_setup_isr(Interrupt, Handler, E_INTERRUPTS_RING0);
// We also need to set the IRQ mask
pic_unmask_irq(IRQ);
}
void interrupts_dump_idt_ptr(void)
{
kprintf("[i] IDT Pointer structure:\n");
kprintf(" Base: 0x%x.\n", g_idt_ptr.Base);
kprintf(" Limit: 0x%x.\n", g_idt_ptr.Limit);
}
void interrupts_dump_idt_entry(u8 Interrupt)
{
u32 *dwEntry = (u32 *)&g_idt_entries[Interrupt];
kprintf("[i] IDT Entry for interrupt %x:\n", Interrupt);
kprintf(" DW Low : 0x%x.\n", *dwEntry);
kprintf(" DW High: 0x%x.\n", *(dwEntry + 1));
T_IDT_ENTRY Entry = g_idt_entries[Interrupt];
kprintf(" Offset: 0x%x.\n", (Entry.OffsetHigh << 16) + Entry.OffsetLow);
kprintf(" Selector: %u.\n", Entry.Selector);
kprintf(" Zero: %u.\n", Entry.Zero);
kprintf(" P: %u.\n", (Entry.Type >> 7) & 0b1);
kprintf(" DPL: %u.\n", (Entry.Type >> 5) & 0b11);
kprintf(" S: %u.\n", (Entry.Type >> 4) & 0b1);
kprintf(" Gate type: %u.\n", Entry.Type & 0b1111);
}
void interrupts_setup_isr(u8 Interrupt, void *Handler, T_INTERRUPTS_RING Ring)
{
interrupts_create_stub(&g_isr_stubs[Interrupt], (u32)Handler);
u32 ASMHandler = (u32)&g_isr_stubs[Interrupt];
g_idt_entries[Interrupt].OffsetLow = ASMHandler & 0xFFFF;
g_idt_entries[Interrupt].OffsetHigh = (ASMHandler >> 16) & 0xFFFF;
g_idt_entries[Interrupt].Selector = 0x08; // Second segment, code.
g_idt_entries[Interrupt].Zero = 0;
u8 Type = 0;
Type |= (1 << 7); // Present = 1
Type |= (Ring << 5); // DPL = Ring
Type |= (0 << 4); // Storage = 0
Type |= 0xE; // Type = 0xE (32-bit interrupt gate)
g_idt_entries[Interrupt].Type = Type;
}
void interrupts_init_simple(void)
{
interrupts_set_chip(E_INTERRUPTS_CHIP_PIC);
interrupts_init_idt();
interrupts_lidt();
pic_init(0, 0);
}
void interrupts_interrupt_finish(u8 IRQ)
{
if (g_interrupts_chip == E_INTERRUPTS_CHIP_PIC)
pic_eoi(IRQ);
}

View File

@ -2,15 +2,28 @@
#include "Tier0/kstdio.h"
#include "Tier0/gdt.h"
#include "Tier0/paging.h"
#include "Tier0/acpi.h"
#include "Tier0/interrupts.h"
// Just to see whether this stuff actually works
void sample_interrupt_0x2A(void)
{
kprintf("[i] Hello from ISR for interrupt 0x2A!\n");
return;
}
// Real kernel entry point, called from _start.asm
void kmain(void *mbd, u32 magic)
void kmain(u32 Magic)
{
kclear();
kprintf(" _ \n"
" ___ _ _ ___ _ _ _____| |_ ___ ___ \n"
" | _| | | _| | | | . | -_| _|\n"
" |___|___|___|___|_|_|_|___|___|_| \n\n");
kprintf("[i] Welcome to Cucumber!\n\n");
kprintf("[i] Magic from bootloader: 0x%x.\n", magic);
if (magic != 0x2BADB002)
if (Magic != 0x2BADB002)
{
kprintf("[e] Fatal! Boot via incompatible bootloader.\n");
return;
@ -18,5 +31,28 @@ void kmain(void *mbd, u32 magic)
paging_init_simple();
gdt_create_flat();
}
kprintf("[i] Paging and GDT set up correctly.\n");
u32 RSDPAddress = acpi_find_rsdp();
if (RSDPAddress == 0)
{
kprintf("[e] Fatal! ACPI not found.\n");
return;
}
kprintf("[i] RSDP found at 0x%X.\n", RSDPAddress);
u32 PhysicalTest;
u8 Result = paging_get_physical(0xC00B8000, &PhysicalTest);
if (!Result || PhysicalTest != 0xB8000)
{
kprintf("[e] Paging self-test failed!\n");
return;
}
interrupts_init_simple();
interrupts_setup_isr(0x2A, sample_interrupt_0x2A, E_INTERRUPTS_RING0);
__asm__ volatile("int $0x2a");
}

View File

@ -14,7 +14,19 @@ u8 g_kstdio_cur_x = 0, g_kstdio_cur_y = 0;
void koutb(u16 Port, u8 Data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (Port), "a" (Data));
__asm__ volatile("outb %1, %0" :: "dN" (Port), "a" (Data));
}
u8 kinb(u16 Port)
{
u8 Return;
__asm__ volatile("inb %1, %0" :"=a"(Return):"Nd"(Port));
return Return;
}
void kio_wait(void)
{
__asm__ volatile("jmp 1f;1:jmp 1f;1:");
}
void kputi(s32 Number)
@ -216,3 +228,17 @@ void kclear(void)
}
kmove_cursor(0, 0);
}
s32 kmemcmp(u8 *MemA, u8 *MemB, u32 Length)
{
u32 Result = -1;
for (u32 Search = 0; Search < Length; Search++)
{
if (MemA[Search] != MemB[Search])
{
Result = Search;
break;
}
}
return Result;
}

View File

@ -5,30 +5,40 @@
u32 g_kernel_page_directory[1024] __attribute__ ((aligned (4096)));
u32 g_low_page_table[1024] __attribute__ ((aligned (4096)));
/*u8 paging_get_physical(u32 Virtual, u32 *Physical)
u8 paging_get_physical(u32 Virtual, u32 *Physical)
{
u16 Index =
u32 DirectoryEntry = g_kernel_page_directory[Index];
u16 DirectoryIndex = (Virtual >> 22) & 0x3FF;
u32 DirectoryEntry = g_kernel_page_directory[DirectoryIndex];
u8 TablePresent = DirectoryEntry & 0b1;
if (!TablePresent)
return 0;
u32 TableAddress = 0;
TableAddress |= (DirectoryEntry & 0xFFFFF000);
u32 *Table = (u32 *)TableAddress;
u32 Table = *((u32 *) &TableAddress);
u8 PagePresent = DirectoryEntry &
}*/
u16 TableIndex = (Virtual >> 12) & 0x3FF;
u32 TableEntry = Table[TableIndex];
u8 PagePresent = TableEntry &0b1;
if (!PagePresent)
return 0;
*Physical = 0;
*Physical |= (TableEntry & 0xFFFFF000);
*Physical |= (Virtual & 0xFFF);
return 1;
}
void paging_dump_directory(void)
{
for (u32 i = 0; i < 10; i++)
{
kprintf("[i] Virtual 0x%X - 0x%X, Entry 0x%X.\n", i * 4096 * 1024, (i + 1) * 4096 * 1024, g_kernel_page_directory[i] & 0xFFFFF000);
kprintf("[i] Virtual 0x%X - 0x%X, Entry 0x%X.\n", i * 4096 * 1024, \
(i + 1) * 4096 * 1024, g_kernel_page_directory[i] & 0xFFFFF000);
}
}
@ -43,15 +53,14 @@ void paging_init_simple(void)
g_kernel_page_directory[i] = 0;
}
kprintf("[i] Page Directory Physical: 0x%X, Virtual: 0x%X.\n", RealKernelPageDir, g_kernel_page_directory);
kprintf("[i] Low Page Table Physical: 0x%X, Virtual: 0x%X.\n", RealLowPageTable, g_low_page_table);
kprintf("[i] Page Directory Physical: 0x%X, Virtual: 0x%X.\n", \
RealKernelPageDir, g_kernel_page_directory);
kprintf("[i] Low Page Table Physical: 0x%X, Virtual: 0x%X.\n", \
RealLowPageTable, g_low_page_table);
g_kernel_page_directory[0] = (u32)RealLowPageTable | 0x03;
g_kernel_page_directory[768] = (u32)RealLowPageTable | 0x03;
paging_dump_directory();
__asm volatile ( "mov %0, %%eax\n"
"mov %%eax, %%cr3\n"
"mov %%cr0, %%eax\n"

93
src/Tier0/pic.c Normal file
View File

@ -0,0 +1,93 @@
// 8259 Programmable interrupt controller routines...
// The usual computer will switch to IOAPIC later on, once ACPI is fully
// initialized and the driver/module system is active.
// I could probably try to do without interrupts until I get in C++-land but
// you never know - also, paging without interrupts is pointless, especiallly
// if I want a good heap implementation, which is more-or-less indispensable
// if I want to ever reach Tier1 in a sane way.
// tl;dr - This code isn't going to be running all the time
#include "types.h"
#include "Tier0/kstdio.h"
#include "Tier0/pic.h"
#define PIC_COMMAND_EOI 0x20
// Initialisation "words".
#define PIC_ICW1_INIT 0x10
#define PIC_ICW1_ICW4 0x01
#define PIC_ICW4_8086 0x01
void pic_init(u8 *OldMask1, u8 *OldMask2)
{
if (OldMask1 != 0)
*OldMask1 = kinb(PIC_1_DATA);
if (OldMask2 != 0)
*OldMask2 = kinb(PIC_2_DATA);
koutb(PIC_1_ADDR, PIC_ICW1_INIT | PIC_ICW1_ICW4);
kio_wait();
koutb(PIC_2_ADDR, PIC_ICW1_INIT | PIC_ICW1_ICW4);
kio_wait();
// ICW2
koutb(PIC_1_DATA, PIC_1_START);
kio_wait();
koutb(PIC_2_DATA, PIC_2_START);
kio_wait();
// ICW3
koutb(PIC_1_DATA, 4);
kio_wait();
koutb(PIC_2_DATA, 2);
kio_wait();
// ICW4
koutb(PIC_1_DATA, PIC_ICW4_8086);
kio_wait();
koutb(PIC_2_DATA, PIC_ICW4_8086);
kio_wait();
//We don't support ANYTHING
koutb(PIC_1_DATA, 0xFF);
koutb(PIC_2_DATA, 0xFF);
}
void pic_eoi(u8 IRQ)
{
if (IRQ > 7)
koutb(PIC_2_ADDR, PIC_COMMAND_EOI);
koutb(PIC_1_ADDR, PIC_COMMAND_EOI);
}
void pic_unmask_irq(u8 IRQ)
{
if (IRQ > 7)
{
u8 Bit = 0;
Bit |= 1 << (IRQ - 8);
u8 CurrentMask = kinb(PIC_2_DATA);
u8 NewMask = ~((~CurrentMask) | Bit);
koutb(PIC_2_DATA, NewMask);
}
else
{
u8 Bit = 0;
Bit |= 1 << (IRQ);
u8 CurrentMask = kinb(PIC_1_DATA);
u8 NewMask = ~((~CurrentMask) | Bit);
koutb(PIC_1_DATA, NewMask);
}
}