diff options
author | Tyler Murphy <=> | 2023-07-16 02:54:32 -0400 |
---|---|---|
committer | Tyler Murphy <=> | 2023-07-16 02:54:32 -0400 |
commit | fbf131b5c043b27e0b1543374bb144e3e426f723 (patch) | |
tree | 07f0ab2fc107b36621d5ae95480e6a91e332548b /kernel/src/interrupt | |
download | finix-fbf131b5c043b27e0b1543374bb144e3e426f723.tar.gz finix-fbf131b5c043b27e0b1543374bb144e3e426f723.tar.bz2 finix-fbf131b5c043b27e0b1543374bb144e3e426f723.zip |
initial
Diffstat (limited to 'kernel/src/interrupt')
-rw-r--r-- | kernel/src/interrupt/idt.c | 108 | ||||
-rw-r--r-- | kernel/src/interrupt/idt.h | 36 | ||||
-rw-r--r-- | kernel/src/interrupt/isr.asm | 99 | ||||
-rw-r--r-- | kernel/src/interrupt/pic.c | 85 | ||||
-rw-r--r-- | kernel/src/interrupt/pic.h | 11 |
5 files changed, 339 insertions, 0 deletions
diff --git a/kernel/src/interrupt/idt.c b/kernel/src/interrupt/idt.c new file mode 100644 index 0000000..6df3793 --- /dev/null +++ b/kernel/src/interrupt/idt.c @@ -0,0 +1,108 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <sys.h> +#include <print.h> +#include <panic.h> + +#include "acpi/acpi.h" +#include "drivers/ps2kb.h" +#include "drivers/ps2mouse.h" +#include "tty/color.h" +#include "idt.h" +#include "pic.h" +#include "tty/term.h" + +static int timer = 0; + +void idt_pic_eoi(uint8_t exception) { + pic_eoi(exception - PIC_REMAP_OFFSET); +} + +void idt_pic_timer(void) { + uint32_t state = term_save(); + term_setfg(VGA_LIGHT_GREEN); + term_setpos(60, 0); + puts(" "); + term_setpos(60, 0); + printk("%d", timer); + timer += 1; + term_load(state); +} + +void idt_pic_keyboard(void) { + ps2kb_recv(); +} + +void idt_pic_mouse(void) { + ps2mouse_recv(); +} + +void idt_exception_handler(uint8_t exception) { + char* msg; + switch(exception) { + case 0x00: + msg = "Division by zero"; + break; + case 0x02: + msg = "NMI"; + break; + case 0x04: + msg = "Overflow"; + break; + case 0x06: + msg = "invalid opcode"; + break; + case 0x08: + msg = "double fault"; + break; + case 0x0A: + msg = "invalid task state segment"; + break; + case 0x0C: + msg = "stack segment fault"; + break; + case 0x0D: + msg = "general protection fault"; + break; + case 0x0E: + msg = "page fault"; + break; + default: + msg = "unknown exception"; + break; + } + panic("E%u: %s", exception, msg); +} + +__attribute__((aligned(0x10))) +static struct IdtEntry idt[256]; +static struct Idtr idtr; +extern void* isr_stub_table[]; + +static void set_descriptor(uint8_t vector, void* isr, uint8_t flags) { + struct IdtEntry* entry = &idt[vector]; + entry->isr_low = (size_t)isr & 0xffff; + entry->kernel_cs = 0x08; + entry->attributes = flags; + entry->isr_high = (size_t)isr >> 16; + entry->_reserved = 0; +} + +void idt_init(void) { + + debugk("Loading IDT"); + + idtr.base = (uintptr_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1; + + for(int i = 0; i < IDT_INTERRUPTS; i++) { + set_descriptor(i, isr_stub_table[i], 0x8e); + } + + __asm__ volatile ("lidt %0" : : "m"(idtr)); + + succek("IDT has been loaded"); +} + diff --git a/kernel/src/interrupt/idt.h b/kernel/src/interrupt/idt.h new file mode 100644 index 0000000..86a685f --- /dev/null +++ b/kernel/src/interrupt/idt.h @@ -0,0 +1,36 @@ +#pragma once + +#include <stdint.h> + +#define IDT_SIZE 256 +#define IDT_INTERRUPTS 256 + +struct IdtEntry { + uint16_t isr_low; + uint16_t kernel_cs; + uint8_t _reserved; + uint8_t attributes; + uint16_t isr_high; +} __attribute__((packed)); + +struct Idtr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +enum IDTFlags { + IDT_FLAG_GATE_TASK = 0x5, + IDT_FLAG_GATE_16BIT_INT = 0x6, + IDT_FLAG_GATE_16BIT_TRAP = 0x7, + IDT_FLAG_GATE_32BIT_INT = 0xE, + IDT_FLAG_GATE_32BIT_TRAP = 0xF, + + IDT_FLAG_RING0 = (0 << 5), + IDT_FLAG_RING1 = (1 << 5), + IDT_FLAG_RING2 = (2 << 5), + IDT_FLAG_RING3 = (3 << 5), + + IDT_FLAG_PRESENT = 0x80, +}; + +void idt_init(void); diff --git a/kernel/src/interrupt/isr.asm b/kernel/src/interrupt/isr.asm new file mode 100644 index 0000000..6cccdc6 --- /dev/null +++ b/kernel/src/interrupt/isr.asm @@ -0,0 +1,99 @@ +extern idt_exception_handler +extern idt_pic_timer +extern idt_pic_keyboard +extern idt_pic_mouse +extern idt_pic_eoi +global isr_stub_table + +%macro ISRErrorStub 1 +isr_stub_%+%1: + push dword %1 + call idt_exception_handler + pop eax + iret +%endmacro + +%macro PICGeneric 1 +isr_stub_%+%1: + push dword %1 + call idt_pic_eoi + pop eax + iret +%endmacro + +%macro PICTimer 1 +isr_stub_%+%1: + call idt_pic_timer + push dword %1 + call idt_pic_eoi + pop eax + iret +%endmacro + +%macro PICKeyboard 1 +isr_stub_%+%1: + call idt_pic_keyboard + push dword %1 + call idt_pic_eoi + pop eax + iret +%endmacro + +%macro PICMouse 1 +isr_stub_%+%1: + call idt_pic_mouse + push dword %1 + call idt_pic_eoi + pop eax + iret +%endmacro + +%macro ISRSyscall 1 +isr_stub_%+%1: + push eax + push ebx + push ecx + push edx + call idt_syscall + add esp, 16 + pop eax + iret +%endmacro + +section .text +align 8 +%assign i 0 +%rep 32 + ISRErrorStub i +%assign i i+1 +%endrep +PICTimer 32 ; 0 +PICKeyboard 33 ; 1 +PICGeneric 34 ; 2 +PICGeneric 35 ; 3 +PICGeneric 36 ; 4 +PICGeneric 37 ; 5 +PICGeneric 38 ; 6 +PICGeneric 39 ; 7 +PICGeneric 40 ; 8 +PICGeneric 41 ; 9 +PICGeneric 42 ; 10 +PICGeneric 43 ; 11 +PICMouse 44 ; 12 +PICGeneric 45 ; 13 +PICGeneric 46 ; 14 +PICGeneric 47 ; 15 +%assign i 48 +%rep 256 - 48 + ISRErrorStub i +%assign i i+1 +%endrep + +section .rodata +align 8 +isr_stub_table: +%assign i 0x00 +%rep 256 + dd isr_stub_%+i +%assign i i+0x01 +%endrep diff --git a/kernel/src/interrupt/pic.c b/kernel/src/interrupt/pic.c new file mode 100644 index 0000000..86056a1 --- /dev/null +++ b/kernel/src/interrupt/pic.c @@ -0,0 +1,85 @@ +#include <sys.h> +#include <print.h> + +#include "pic.h" + +#define PIC1_COMMAND_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_COMMAND_PORT 0xA0 +#define PIC2_DATA_PORT 0xA1 + +void pic_remap(uint8_t offset) { + + debugk("Remapping PIC"); + + char a1 = inb(PIC1_DATA_PORT); + char a2 = inb(PIC2_DATA_PORT); + // control word 1 + // 0x11: initialize, enable ICW4 + outb(PIC1_COMMAND_PORT, 0x11); + io_wait(); + outb(PIC2_COMMAND_PORT, 0x11); + io_wait(); + // control word 2 + // interrupt offset + outb(PIC1_DATA_PORT, offset); + io_wait(); + outb(PIC2_DATA_PORT, offset + 8); + io_wait(); + // control word 3 + // primary pic: set which pin secondary is connected to + // (pin 2) + outb(PIC1_DATA_PORT, 0x04); + io_wait(); + outb(PIC2_DATA_PORT, 2); + io_wait(); + // control word 3 + // 0x01: enable 8086 mode + outb(PIC1_DATA_PORT, 0x01); + io_wait(); + outb(PIC2_DATA_PORT, 0x01); + io_wait(); + // clear data registers + outb(PIC1_DATA_PORT, a1); + outb(PIC2_DATA_PORT, a2); + + succek("PIC has been remapped to offset 0x%X", offset); +} + +void pic_mask(int irq) { + uint8_t port; + if(irq < 8) { + port = PIC1_DATA_PORT; + } else { + irq -= 8; + port = PIC2_DATA_PORT; + } + uint8_t mask = inb(port); + outb(port, mask | (1 << irq)); +} + +void pic_unmask(int irq) { + uint8_t port; + if(irq < 8) { + port = PIC1_DATA_PORT; + } else { + irq -= 8; + port = PIC2_DATA_PORT; + } + uint8_t mask = inb(port); + outb(port, mask & ~(1 << irq)); +} + +void pic_disable(void) { + outb(PIC1_DATA_PORT, 0xff); + io_wait(); + outb(PIC2_DATA_PORT, 0xff); + io_wait(); +} + +void pic_eoi(int irq) { + if(irq >= 8) { + outb(PIC2_COMMAND_PORT, 0x20); + } + outb(PIC1_COMMAND_PORT, 0x20); +} diff --git a/kernel/src/interrupt/pic.h b/kernel/src/interrupt/pic.h new file mode 100644 index 0000000..a87420d --- /dev/null +++ b/kernel/src/interrupt/pic.h @@ -0,0 +1,11 @@ +#pragma once + +#include <stdint.h> + +#define PIC_REMAP_OFFSET 0x20 + +void pic_remap(uint8_t offset); +void pic_mask(int irq); +void pic_unmask(int irq); +void pic_disable(void); +void pic_eoi(int irq); |