diff options
Diffstat (limited to 'stage3/pic.c')
-rw-r--r-- | stage3/pic.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/stage3/pic.c b/stage3/pic.c new file mode 100644 index 0000000..726a6da --- /dev/null +++ b/stage3/pic.c @@ -0,0 +1,92 @@ +#include "pic.h" +#include "io.h" + +void disable_irqs() +{ + asm volatile("cli"); +} + +void enable_irqs() +{ + asm volatile("sti"); +} + +void ack_irq(u8 lane) +{ + if (lane >= 8) + outb(IO_PIC2_CTRL, 1 << 5); + + outb(IO_PIC1_CTRL, 1 << 5); +} + +void unmask_irq(u8 lane) +{ + u8 port = IO_PIC1_DATA; + + if (lane >= 8) { + port = IO_PIC2_DATA; + lane -= 8; + } + + outb(port, inb(port) & ~(1 << lane)); +} + +void pic_init() +{ + typedef struct { + bool ic4 : 1; + bool single : 1; + bool addr_interval : 1; + bool level_triggered : 1; + bool init : 1; + unsigned int zeros : 3; + } __attribute__((packed)) pic_icw1; + + u8 icw1 = BITCAST(((pic_icw1) { + .ic4 = true, + .single = false, + .addr_interval = false, + .level_triggered = false, + .init = true, + .zeros = 0, + }), pic_icw1, u8); + + outb(IO_PIC1_CTRL, icw1); + outb(IO_PIC2_CTRL, icw1); + + // map IRQs 0-15 to 0x20-0x2F + // 0x1F is the highest reserved interrupt + outb(IO_PIC1_DATA, 0x20); + outb(IO_PIC2_DATA, 0x28); + + // pic2 is connected to IRQ2 + outb(IO_PIC1_DATA, 1 << 2); + outb(IO_PIC2_DATA, 2); + + typedef struct { + bool x86 : 1; + bool auto_eoi : 1; + bool primary_buffered : 1; + bool buffered : 1; + bool fully_nested : 1; + unsigned int zeros : 3; + } __attribute__((packed)) pic_icw4; + + u8 icw4 = BITCAST(((pic_icw4) { + .x86 = true, + .auto_eoi = false, + .primary_buffered = false, + .buffered = false, + .fully_nested = false, + .zeros = 0, + }), pic_icw4, u8); + + outb(IO_PIC1_DATA, icw4); + outb(IO_PIC2_DATA, icw4); + + // mask all interrupts + outb(IO_PIC1_DATA, 0xff); + outb(IO_PIC2_DATA, 0xff); + + disable_irqs(); +} |