summaryrefslogtreecommitdiff
path: root/stage3/pic.c
diff options
context:
space:
mode:
Diffstat (limited to 'stage3/pic.c')
-rw-r--r--stage3/pic.c92
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();
+}