/// Remap the 8259 PIC to an interrupt base of 0x32 const arch = @import("../root.zig"); const std = @import("std"); const log = std.log.scoped(.pic); const out = arch.port.out; const in = arch.port.in; const PIC_ONE_CMD_PORT = 0x20; const PIC_ONE_DATA_PORT = 0x21; const PIC_ONE_IDT_BASE = 32; const PIC_TWO_CMD_PORT = 0xA0; const PIC_TWO_DATA_PORT = 0xA1; const PIC_TWO_IDT_BASE = 40; const CMD_INIT = 0x11; const CMD_EOI = 0x20; // Remap the sixteen 8259 interrupts out of the way to // base interrupt number 32, and mask all interrupts // except the 8254 PIT pub fn init() void { // Init the 8259's out(u8, PIC_ONE_CMD_PORT, CMD_INIT); wait(); out(u8, PIC_TWO_CMD_PORT, CMD_INIT); wait(); // Write the interrupt base numbers for both out(u8, PIC_ONE_DATA_PORT, PIC_ONE_IDT_BASE); wait(); out(u8, PIC_TWO_DATA_PORT, PIC_TWO_IDT_BASE); wait(); // Tell first 8259 that there's a second 8259 at IRQ 2, and tell // the second 8259 that it is at that position. out(u8, PIC_ONE_DATA_PORT, 1 << 2); wait(); out(u8, PIC_TWO_DATA_PORT, 2); wait(); // Tell the PICs to use 8086 mode out(u8, PIC_ONE_DATA_PORT, 1); wait(); out(u8, PIC_ONE_DATA_PORT, 1); wait(); // Unmask only the 8254 out(u8, PIC_ONE_DATA_PORT, 0b1111_1111); wait(); out(u8, PIC_TWO_DATA_PORT, 0b1111_1111); wait(); // Set up a spurious IRQ7 handler arch.interrupts.idt.add_handler(.{ .interrupt = 32 + 7 }, spurious_handler, 3, 0); } inline fn wait() void { out(u8, 0x80, 0); } // Notify the first 8259 that we're done with the timer interrupt pub fn end_of_timer_interrupt() void { out(u8, PIC_ONE_CMD_PORT, CMD_EOI); } pub fn spurious_handler(_: *arch.interrupts.idt.InterruptFrame(u64)) callconv(.{ .x86_64_sysv = .{} }) void { std.log.warn("Got a spurious IRQ7 (8259)", .{}); }