diff --git a/kernel/idt.c b/kernel/idt.c new file mode 100644 index 0000000..5ff5be5 --- /dev/null +++ b/kernel/idt.c @@ -0,0 +1,58 @@ +#include +#include + +#define IDT_MAX_DESCRIPTORS 256 + +#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110) + +#define SEGMENT_KERN 0x08 + +extern void load_idt(void); +extern void enable_int(void); + +extern void isr0(); +extern void isr1(); +extern void isr8(); +extern void isr13(); +extern void isr14(); +extern void isr32(); +extern void isr33(); + +void* isr_stub_table[256] = { + [0] = isr0, + [1] = isr1, + [8] = isr8, + [13] = isr13, + [14] = isr14, + [32] = isr32, + [33] = isr33, +}; + +idt_entry idt[IDT_MAX_DESCRIPTORS]; +idt_ptr idtr; + +void set_idtr(uint8_t vector, void* isr, uint8_t attributes) { + idt_entry* desc = &idt[vector]; + + desc->isr_low = (uint32_t)isr & 0xFFFF; + desc->kernel_cs = SEGMENT_KERN; + desc->reserved = 0; + desc->attributes = attributes; + desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF; +} + +void init_idt() { + idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1; + idtr.base = (uint32_t)&idt; + + for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) { + if (isr_stub_table[i] != 0) { + set_idtr(i, isr_stub_table[i], ATTR_KERN_32); + } else { + set_idtr(i, 0, 0); + } + } + + load_idt(); + enable_int(); +} \ No newline at end of file diff --git a/kernel/idt.h b/kernel/idt.h new file mode 100644 index 0000000..3869750 --- /dev/null +++ b/kernel/idt.h @@ -0,0 +1,19 @@ +#ifndef KIDT_H +#define KIDT_H + +#include + +typedef struct { + uint16_t isr_low; // The lower 16 bits of the ISR's address + uint16_t kernel_cs; // The GDT segment selector the CPU will load into CS + uint8_t reserved; // Set to 0 + uint8_t attributes;// Type and attributes flags + uint16_t isr_high; // The higher 16 bits of the ISR's address +} idt_entry __attribute__((packed)); + +typedef struct { + uint16_t limit; + uint32_t base; +} idt_ptr __attribute__((packed)); + +#endif \ No newline at end of file diff --git a/kernel/idt_stubs.s b/kernel/idt_stubs.s new file mode 100644 index 0000000..e097fdc --- /dev/null +++ b/kernel/idt_stubs.s @@ -0,0 +1,54 @@ +.code32 + +.macro ISR_NOERRCODE num +.global isr\num +isr\num: + pushl $0 + pushl $\num + jmp isr_common_stub +.endm + +.macro ISR_ERRCODE num +.global isr\num +isr\num: + pushl $\num + jmp isr_common_stub +.endm + +.extern common_interrupt_handler +isr_common_stub: + pushal + + pushl %esp + call common_interrupt_handler + addl $4, %esp + + popal + addl $8, %esp + iret + +.global master_eoi +master_eoi: + movb $0x20, %al + outb %al, $0x20 + ret + +.extern idtr +.global load_idt +load_idt: + lidt idtr + ret + +.global enable_int +enable_int: + sti + ret + +ISR_NOERRCODE 0 # Divide by Zero +ISR_NOERRCODE 1 # Debug +ISR_ERRCODE 8 # Double Fault (Has Error Code!) +ISR_ERRCODE 13 # General Protection Fault (Has Error Code!) +ISR_ERRCODE 14 # Page Fault (Has Error Code!) + +ISR_NOERRCODE 32 # IRQ0 - Timer +ISR_NOERRCODE 33 # IRQ1 - Keyboard \ No newline at end of file diff --git a/kernel/interrupts.c b/kernel/interrupts.c new file mode 100644 index 0000000..5f8ade5 --- /dev/null +++ b/kernel/interrupts.c @@ -0,0 +1,46 @@ +#include "lib/print.h" +#include + +extern void master_eoi(void); + +struct registers { + uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax; + + uint32_t int_no; + uint32_t error_code; + + uint32_t eip, cs, eflags, useresp, ss; +}; + +const char* err_messages[32] = { + [0] = "Divide by 0", + [1] = "", + [8] = "", + [13] = "General Protection Fault", + [14] = "Page Fault", +}; + +void common_interrupt_handler(struct registers *regs) { + switch (regs->int_no) { + case 0: + case 1: + case 8: + case 13: + case 14: + kprint("CPU Error: "); + kprint(err_messages[regs->int_no]); + kprint("\n"); + break; + case 32: + // wake the PIC timer driver + master_eoi(); + break; + case 33: + // wake the keyboard driver + master_eoi(); + break; + default: + kprint("Received unhandled interrupt\n"); + return; + } +} \ No newline at end of file diff --git a/kernel/kmain.c b/kernel/kmain.c index d6caee1..16de644 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,6 +1,13 @@ #include #include +#include + +#include + +extern void init_idt(); +extern idt_entry create_idt_entry(uint32_t addr, uint16_t segment, uint8_t attributes); + void kernel_main(void) { extern print_stream_t vga_print_stream; @@ -9,4 +16,6 @@ void kernel_main(void) kout->trunc(); kprint("RockOS booting..."); + + init_idt(); }