diff --git a/src/arch/amd64/boot.S b/src/arch/amd64/boot.S index 6482d79..483f0f0 100644 --- a/src/arch/amd64/boot.S +++ b/src/arch/amd64/boot.S @@ -117,7 +117,6 @@ start: ;push ebx ; Call our function to set up basic paging ;call amd64_shim - mov eax, cr4 ; Enable the PAE bit or eax, 1 << 5 mov cr4, eax @@ -139,6 +138,7 @@ code64: pop rdi call amd64_shim mov rdi, rax + sti call kmain cli halt: diff --git a/src/arch/amd64/idt.S b/src/arch/amd64/idt.S new file mode 100644 index 0000000..43f4fd2 --- /dev/null +++ b/src/arch/amd64/idt.S @@ -0,0 +1,92 @@ +extern idt_exception_handler +global isr_stub_table + +; call the exception handler with the interrupt number +; args: interrupt number +%macro ISRException 1 +align 8 +isr_stub_%+%1: + cld + mov rdi, %1 + mov rsi, 0 + call idt_exception_handler + iretq +%endmacro + +; call the exception handler with the interrupt number +; these exceptions also put an error code on the stack +; args: interrupt number +%macro ISRExceptionCode 1 +align 8 +isr_stub_%+%1: + cld + mov rdi, %1 + pop rsi + call idt_exception_handler + iretq +%endmacro + +; do nothing +; args: interrupt number +%macro ISRIgnore 1 +align 8 +isr_stub_%+%1: + iretq +%endmacro + +; isr stubs +section .text +bits 64 + +ISRException 0 +ISRException 1 +ISRException 2 +ISRException 3 +ISRException 4 +ISRException 5 +ISRException 6 +ISRException 7 +ISRExceptionCode 8 +ISRException 9 +ISRExceptionCode 10 +ISRExceptionCode 11 +ISRExceptionCode 12 +ISRExceptionCode 13 +ISRExceptionCode 14 +ISRException 15 +ISRException 16 +ISRExceptionCode 17 +ISRException 18 +ISRException 19 +ISRException 20 +ISRExceptionCode 21 +ISRException 22 +ISRException 23 +ISRException 24 +ISRException 25 +ISRException 26 +ISRException 27 +ISRException 28 +ISRExceptionCode 29 +ISRExceptionCode 30 +ISRException 31 + +%assign i 32 + +; ignore other interrupts +%rep 0x100 - i + ISRIgnore i + %assign i i+1 +%endrep + +; isr stub table +section .rodata +bits 64 +align 16 + +isr_stub_table: +%assign i 0 +%rep 256 + dq isr_stub_%+i +%assign i i+1 +%endrep diff --git a/src/arch/amd64/idt.c b/src/arch/amd64/idt.c new file mode 100644 index 0000000..5445560 --- /dev/null +++ b/src/arch/amd64/idt.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include + +#include "idt.h" + +#define IDT_SIZE 256 + +struct idt_entry { + uint16_t isr_low; // low 16 bits of isr + uint16_t kernel_cs; // kernel segment selector + uint8_t ist; // interrupt stack table + uint8_t flags; // gate type, privilege level, present bit + uint16_t isr_mid; // middle 16 bits of isr + uint32_t isr_high; // high 32 bits of isr + uint32_t reserved; +} __attribute__((packed)); + +struct idtr { + uint16_t size; + void *address; +} __attribute__((packed)); + +// interrupt gate +#define GATE_64BIT_INT 0x0E +// trap gate +#define GATE_64BIT_TRAP 0x0F + +// privilege ring allowed to call interrupt +#define RING0 0x00 +#define RING1 0x20 +#define RING2 0x40 +#define RING3 0x60 + +// interrupt is present in IDT +#define PRESENT 0x80 + +__attribute__((aligned(0x10))) +static struct idt_entry idt[256]; + +static struct idtr idtr; +// from idt.S +extern void *isr_stub_table[]; + +// initialize and load the IDT +void idt_init(void) { + // initialize idtr + idtr.address = &idt; + idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1; + + // initialize idt + for(size_t vector = 0; vector < IDT_SIZE; vector++) { + struct idt_entry* entry = &idt[vector]; + + uint64_t isr = (uint64_t)isr_stub_table[vector]; + // interrupts before 0x20 are for cpu exceptions + uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT; + + entry->kernel_cs = 0x08; // offset of 1 into GDT + entry->ist = 0; + entry->flags = PRESENT | RING0 | gate_type; + entry->isr_low = isr & 0xffff; + entry->isr_mid = (isr >> 16) & 0xffff; + entry->isr_high = isr >> 32; + entry->reserved = 0; + } + + __asm__ volatile ("lidt %0" : : "m"(idtr)); +} + + +// Intel manual vol 3 ch 6.3.1 +char *EXCEPTIONS[] = { + "Exception 0x00 Divide Error", + "Exception 0x01 Debug Exception", + "Exception 0x02 NMI Interrupt", + "Exception 0x03 Breakpoint", + "Exception 0x04 Overflow", + "Exception 0x05 BOUND Range Exceeded", + "Exception 0x06 Invalid Opcode", + "Exception 0x07 Device Not Available", + "Exception 0x08 Double Fault", + "Exception 0x09 Coprocessor Segment Overrun", + "Exception 0x0A Invalid TSS", + "Exception 0x0B Segment Not Present", + "Exception 0x0C Stack-Segment Fault", + "Exception 0x0D General Protection", + "Exception 0x0E Page Fault", + "Exception 0x0F Reserved", + "Exception 0x10 x87 FPU Floating-Point Error", + "Exception 0x11 Alignment Check", + "Exception 0x12 Machine Check", + "Exception 0x13 SIMD Floaing-Point Exception", + "Exception 0x14 Virtualization Exception", + "Exception 0x15 Control Protection Exception", + "Exception 0x16 Reserved", + "Exception 0x17 Reserved", + "Exception 0x18 Reserved", + "Exception 0x19 Reserved", + "Exception 0x1A Reserved", + "Exception 0x1B Reserved", + "Exception 0x1C Reserved", + "Exception 0x1D Reserved", + "Exception 0x1E Reserved", + "Exception 0x1F Reserved", +}; + +void idt_exception_handler(uint64_t exception, uint64_t code) { + // TODO don't just panic + char buf[80]; + char *end = strcpy(buf, EXCEPTIONS[exception]); + end = strcpy(end, "\nError code 0x"); + ltoa(code, end, 16); + panic(buf); +} + diff --git a/src/arch/amd64/idt.h b/src/arch/amd64/idt.h new file mode 100644 index 0000000..5627657 --- /dev/null +++ b/src/arch/amd64/idt.h @@ -0,0 +1,3 @@ +#pragma once + +void idt_init(); diff --git a/src/arch/amd64/shim.c b/src/arch/amd64/shim.c index 4afa6d2..5639aab 100644 --- a/src/arch/amd64/shim.c +++ b/src/arch/amd64/shim.c @@ -6,13 +6,13 @@ #include "paging.h" #include "mboot.h" - +#include "idt.h" static struct boot_info boot_info; -// entry point for amd64 void* amd64_shim(void *mboot_data_ptr) { serial_init(); paging_init(); + idt_init(); kmap_page(mboot_data_ptr, mboot_data_ptr, F_WRITEABLE);