From c3f8d7d8f2b0a0eeab8c7f22cd141364cdc8f051 Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 21 Mar 2025 14:09:15 +0100 Subject: [PATCH] Got IDT & ISRs working! --- kernel/include/idt.h | 27 +++++++++ kernel/include/isr.h | 26 +++++++++ kernel/include/syscall.h | 8 +++ kernel/include/system.h | 3 +- kernel/src/idt.c | 28 +++++++++ kernel/src/isr.c | 105 ++++++++++++++++++++++++++++++++++ kernel/src/isr.s | 119 +++++++++++++++++++++++++++++++++++++++ kernel/src/kernel.c | 3 +- kernel/src/system.c | 5 ++ 9 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 kernel/include/idt.h create mode 100644 kernel/include/isr.h create mode 100644 kernel/include/syscall.h create mode 100644 kernel/src/idt.c create mode 100644 kernel/src/isr.c create mode 100644 kernel/src/isr.s diff --git a/kernel/include/idt.h b/kernel/include/idt.h new file mode 100644 index 0000000..7c8b7e7 --- /dev/null +++ b/kernel/include/idt.h @@ -0,0 +1,27 @@ +#ifndef _IDT_H +#define _IDT_H + +#include + +#define IDT_ENTRIES 256 +#define IDT_FLAG_TRAP 0x8f // P = 1, Priv = 00, S = 0, Type = 1111 (32-bit trap) +#define IDT_FLAG_INT 0x8e // P = 1, Priv = 00, S = 0, Type = 1110 (32-bit int) +#define IDT_FLAG_USER 0xee // P = 1, Priv = 11, S = 0, Type = 1110 (32-bit int) + +struct idt_entry { + uint16_t offsetLow; + uint16_t selector; + uint8_t __unused; + uint8_t flags; + uint16_t offsetHigh; +} __packed; + +struct idt_pointer { + uint16_t limit; + uint32_t base; +} __packed; + +int idt_init(void); +void idt_setGate(uint8_t i, void* handler, uint8_t flags); + +#endif diff --git a/kernel/include/isr.h b/kernel/include/isr.h new file mode 100644 index 0000000..73e24c1 --- /dev/null +++ b/kernel/include/isr.h @@ -0,0 +1,26 @@ +#ifndef _ISR_H +#define _ISR_H + +#include + +// Interrupt frame (ie. what's on the stack on interrupt) +struct isr_intFrame { + // Pushed by OS + uint32_t esp, ebx, ecx, edx, esi, edi, ebp; + uint32_t ds, es, fs, gs, eax; + uint32_t interrupt, error; + + // Pushed by CPU + uint32_t eip, cs, eflags, user_esp, user_ss; +}; +typedef void (*isr_handlerPtr)(struct isr_intFrame* iframe); + +int isr_init(void); +void isr_registerIRQ(uint8_t i, isr_handlerPtr handler); +int isr_handleInterrupt(struct isr_intFrame iframe); + +// Assembly definitions (isr.s) +extern void* isr_redirectTable[48]; // ISR Table +extern void isr128(); // int 0x80 - syscall + +#endif diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h new file mode 100644 index 0000000..2debd8e --- /dev/null +++ b/kernel/include/syscall.h @@ -0,0 +1,8 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#include + +int syscallHandler(struct isr_intFrame* iframe) { return 1; } + +#endif diff --git a/kernel/include/system.h b/kernel/include/system.h index eb314b8..6cbd43d 100644 --- a/kernel/include/system.h +++ b/kernel/include/system.h @@ -6,7 +6,8 @@ void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx); // Ports -uint8_t inb(uint16_t port); +void iowait(void); +uint8_t inb(uint16_t port); void outb(uint16_t port, uint8_t data); uint16_t inw(uint16_t port); void outw(uint16_t port, uint16_t data); diff --git a/kernel/src/idt.c b/kernel/src/idt.c new file mode 100644 index 0000000..2c5b204 --- /dev/null +++ b/kernel/src/idt.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +__align(16) // performace :fire: +static struct idt_entry idt[IDT_ENTRIES]; +static struct idt_pointer idtp; + +void idt_setGate(uint8_t i, void* handler, uint8_t flags) { + uint32_t offset = (uint32_t)handler; + struct idt_entry* entry = &idt[i]; + + entry->offsetLow = (uint16_t)offset; + entry->selector = GDT_KERNEL_CODE; + entry->flags = flags; + entry->offsetHigh = (uint16_t)(offset >> 16); +} + +int idt_init(void) { + memset(&idt, 0, sizeof(idt)); + idtp.limit = sizeof(idt); + idtp.base = (uint32_t)&idt; + + __asm__ volatile ("lidt %0" : : "m"(idtp)); + return 0; +} + diff --git a/kernel/src/isr.c b/kernel/src/isr.c new file mode 100644 index 0000000..2089a57 --- /dev/null +++ b/kernel/src/isr.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include + +isr_handlerPtr irqHandlers[16]; + +const char* exceptions[] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +// I have no clue how this works or what it does, but it doesn't work without it +void isr_remapPIC(void) { + outb(0x20, 0x11); iowait(); + outb(0xa0, 0x11); iowait(); + outb(0x21, 0x20); iowait(); + outb(0xa1, 0x28); iowait(); + outb(0x21, 0x04); iowait(); + outb(0xa1, 0x02); iowait(); + outb(0x21, 0x01); iowait(); + outb(0xa1, 0x01); iowait(); + outb(0x21, 0x00); iowait(); + outb(0xa1, 0x00); iowait(); +} + +int isr_init(void) { + idt_init(); + isr_remapPIC(); + + for (int i = 0; i < 48; i++) { + // First 32 IRSs are exceptions (traps) and the next 16 are hardware interrupts + idt_setGate(i, isr_redirectTable[i], (i < 32) ? IDT_FLAG_TRAP : IDT_FLAG_INT); + } + + // System call (should be callable from userspace) + idt_setGate(0x80, (void*)(uint32_t)isr128, IDT_FLAG_USER); + + // Let interrupts interrupt + __asm__ volatile ("sti"); + return 0; +} + +void isr_registerIRQ(uint8_t i, isr_handlerPtr handler) { + irqHandlers[i] = handler; +} + +void isr_sendEOI(uint8_t irq) { + if (irq >= 8) { + outb(0xa0, 0x20); + } + outb(0x20, 0x20); +} + +int isr_handleInterrupt(struct isr_intFrame iframe) { + if (iframe.interrupt < 32) { + // ISRs 0-31 - Exceptions + panic(exceptions[iframe.interrupt]); + } else if (iframe.interrupt >= 32 && iframe.interrupt < 48) { + // ISRs 32-47 - Hardware interrupts + uint8_t irq = iframe.interrupt - 32; + if (irqHandlers[irq]) { + irqHandlers[irq](&iframe); + isr_sendEOI(irq); + } + } else if (iframe.interrupt == 128) { + // ISR 128 - System call + return syscallHandler(&iframe); + } + + return 0; +} + diff --git a/kernel/src/isr.s b/kernel/src/isr.s new file mode 100644 index 0000000..bed40bd --- /dev/null +++ b/kernel/src/isr.s @@ -0,0 +1,119 @@ +; ISR Assembly +[bits 32] + +isr_common: + ;; Push registers to the intFrame_t struct + push eax + push gs + push fs + push es + push ds + push ebp + push edi + push esi + push edx + push ecx + push ebx + push esp + + [extern isr_handleInterrupt] + call isr_handleInterrupt +isr_return: + add esp, 4 ; Keep ESP + pop ebx + pop ecx + pop edx + pop esi + pop edi + pop ebp + pop ds + pop es + pop fs + pop gs + add esp, 4 ; Keep EAX + add esp, 8 ; Pop interupt number and error code + + iretd ; Pop CS, EIP & EFLAGS (Also SS & ESP if it's from userspace) + +%macro ISR_WITH_ERRNO 1 +isr%1: + push dword %1 + jmp isr_common +%endmacro + +%macro ISR_WITHOUT_ERRNO 1 +isr%1: + push dword 0 ; Instead of error code + push dword %1 + jmp isr_common +%endmacro + +;; Exceptions +ISR_WITHOUT_ERRNO 0 +ISR_WITHOUT_ERRNO 1 +ISR_WITHOUT_ERRNO 2 +ISR_WITHOUT_ERRNO 3 +ISR_WITHOUT_ERRNO 4 +ISR_WITHOUT_ERRNO 5 +ISR_WITHOUT_ERRNO 6 +ISR_WITHOUT_ERRNO 7 +ISR_WITH_ERRNO 8 +ISR_WITHOUT_ERRNO 9 +ISR_WITH_ERRNO 10 +ISR_WITH_ERRNO 11 +ISR_WITH_ERRNO 12 +ISR_WITH_ERRNO 13 +ISR_WITH_ERRNO 14 +ISR_WITHOUT_ERRNO 15 +ISR_WITHOUT_ERRNO 16 +ISR_WITHOUT_ERRNO 17 +ISR_WITHOUT_ERRNO 18 +ISR_WITHOUT_ERRNO 19 +ISR_WITHOUT_ERRNO 20 +ISR_WITHOUT_ERRNO 21 +ISR_WITHOUT_ERRNO 22 +ISR_WITHOUT_ERRNO 23 +ISR_WITHOUT_ERRNO 24 +ISR_WITHOUT_ERRNO 25 +ISR_WITHOUT_ERRNO 26 +ISR_WITHOUT_ERRNO 27 +ISR_WITHOUT_ERRNO 28 +ISR_WITHOUT_ERRNO 29 +ISR_WITHOUT_ERRNO 30 +ISR_WITHOUT_ERRNO 31 + +;; IRQs 0-15 (mapped 32-47) +ISR_WITHOUT_ERRNO 32 +ISR_WITHOUT_ERRNO 33 +ISR_WITHOUT_ERRNO 34 +ISR_WITHOUT_ERRNO 35 +ISR_WITHOUT_ERRNO 36 +ISR_WITHOUT_ERRNO 37 +ISR_WITHOUT_ERRNO 38 +ISR_WITHOUT_ERRNO 39 +ISR_WITHOUT_ERRNO 40 +ISR_WITHOUT_ERRNO 41 +ISR_WITHOUT_ERRNO 42 +ISR_WITHOUT_ERRNO 43 +ISR_WITHOUT_ERRNO 44 +ISR_WITHOUT_ERRNO 45 +ISR_WITHOUT_ERRNO 46 +ISR_WITHOUT_ERRNO 47 + +;; Syscall ISR128 +[global isr128] +isr128: + cli ; Prevent race condition & other issues + push dword 0 + push dword 128 + jmp isr_common + +;; Create table of ISRs +[global isr_redirectTable] +isr_redirectTable: +%assign i 0 +%rep 48 + dd isr%+i +%assign i i+1 +%endrep + diff --git a/kernel/src/kernel.c b/kernel/src/kernel.c index b7f5c6a..bf00c10 100644 --- a/kernel/src/kernel.c +++ b/kernel/src/kernel.c @@ -2,6 +2,7 @@ #include #include #include +#include #include // TODO: Commented out stuff @@ -25,7 +26,7 @@ void kmain(void* ptr, uint32_t magic) { // vmm_init(); gdt_init(); - // isr_init(); + isr_init(); // pag_init(); debugf("Basic initialization complete!\n"); diff --git a/kernel/src/system.c b/kernel/src/system.c index f44c378..69b6ffd 100644 --- a/kernel/src/system.c +++ b/kernel/src/system.c @@ -1,4 +1,5 @@ #include +#include void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { __asm__ volatile ("cpuid" @@ -7,6 +8,10 @@ void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { : "memory"); } +void iowait(void) { + outb(0x80, 0); +} + uint8_t inb(uint16_t port) { uint8_t r; __asm__ volatile ("inb %1, %0" : "=a"(r) : "dN"(port));