#include "interrupt.h" #include "string.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 gate_desc idt[256] = {0}; 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(irqh_t *int_handler, uint8_t int_number, uint32_t esp) { // we want exceptions but no other interrupts port_write(pic_master_data, 0xFF); // mask all IRQs start_interrupts(); // reenable interrupts if (int_handler != NULL) (*int_handler)(); irq_end(int_number); // call event loop here clear_interrupts(); port_write(pic_master_data, INT_MASK); // restore normal interrupt mask 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); #define IRQH(IRQ) \ set_int_desc_entry( \ IRQ + 0x20, code_seg, &handle_irq ## IRQ, 0, IDT_INTERRUPT_GATE) #define EXCH(IRQ) \ set_int_desc_entry( \ IRQ, code_seg, &handle_exception ## IRQ, 0, IDT_INTERRUPT_GATE) IRQH(0x00); IRQH(0x01); EXCH(0x00); EXCH(0x01); EXCH(0x02); EXCH(0x03); EXCH(0x06); EXCH(0x07); EXCH(0x08); EXCH(0x0D); port_write(pic_master_command, 0x11); port_write(pic_slave_command, 0x11); // 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, INT_MASK); 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 volatile("sti"); } void clear_interrupts() { asm volatile("cli"); }