diff options
Diffstat (limited to 'src/interrupt.c')
-rw-r--r-- | src/interrupt.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/interrupt.c b/src/interrupt.c new file mode 100644 index 0000000..e588353 --- /dev/null +++ b/src/interrupt.c @@ -0,0 +1,92 @@ + +#include "interrupt.h" +#include "string.h" +#include "vga.h" +#include "bees.h" +#include "printf.h" +#include "keyboard.h" + +struct port pic_master_command = {0x20, port8bit_slow}; +struct port pic_master_data = {0x21, port8bit_slow}; +struct port pic_slave_command = {0xA0, port8bit_slow}; +struct port pic_slave_data = {0xA1, port8bit_slow}; + +struct port ps2_port = {0x60, port8bit}; + +struct gate_desc idt[256] = {0}; + +#define PIC_EOI 0x20 + +void irq_end(uint8_t int_number) { + if (int_number >= 0x28) + port_write(pic_slave_command, PIC_EOI); + port_write(pic_master_command, PIC_EOI); +} + +uint32_t handle_int(uint8_t int_number, uint32_t idk, uint32_t esp) { + switch (int_number) { + case 0x0D: + // bye + bees("general protection fault"); + break; + case 0x21: + process_scancode(port_read(ps2_port)); + irq_end(int_number); + break; + } + + return esp; +} + +void set_int_desc_entry(uint8_t int_number, uint16_t gdt_code_seg, + void (*handler)(), uint8_t privilege_level, + uint8_t desc_type) { + const uint8_t IDT_DESC_PRESENT = 0x80; + + idt[int_number].handler_low = ((uint32_t) handler) & 0xFFFF; + idt[int_number].handler_high = ((uint32_t) handler >> 16) & 0xFFFF; + idt[int_number].gdt_code_seg = gdt_code_seg; + idt[int_number].access = IDT_DESC_PRESENT | desc_type | ((privilege_level&3) << 5); + idt[int_number].reserved = 0; +} + +void interrupt_init() { + uint16_t code_seg = 0x08; + const uint8_t IDT_INTERRUPT_GATE = 0xE; + + for (uint16_t i = 0; i < 256; i++) + set_int_desc_entry(i, code_seg, &int_ignore, 0, IDT_INTERRUPT_GATE); + + // Put the interrupt handlers in the IDT + set_int_desc_entry(0x20, code_seg, &handle_irq0x00, 0, IDT_INTERRUPT_GATE); + set_int_desc_entry(0x21, code_seg, &handle_irq0x01, 0, IDT_INTERRUPT_GATE); + set_int_desc_entry(0x0D, code_seg, &handle_irq0x0D, 0, IDT_INTERRUPT_GATE); + + port_write(pic_master_command, 0x11); + port_write(pic_slave_command, 0x11); + + // (I actually don't understand how this works) + // Remap the PIC + port_write(pic_master_data, 0x20); // Interrupt vector offsets + port_write(pic_slave_data, 0x28); + + port_write(pic_master_data, 0x04); // There is a slave PIC at IRQ2 + port_write(pic_slave_data, 0x02); // Slave PIC cascade identity + + port_write(pic_master_data, 0x01); + port_write(pic_slave_data, 0x01); + + port_write(pic_master_data, 0xFD); + port_write(pic_slave_data, 0xFF); + + // Load the IDT + struct idt_pointer i; + i.size = 256 * sizeof(struct gate_desc) - 1; + i.base = (uint32_t) idt; + + asm volatile("lidt %0" : : "m" (i)); +} + +void start_interrupts() { + asm("sti"); +} |