Microkernel thing OS experiment (Zig ⚡)
1/// Remap the 8259 PIC to an interrupt base of 0x32
2const arch = @import("../root.zig");
3const idt = arch.interrupts.idt;
4const std = @import("std");
5const log = std.log.scoped(.pic);
6const out = arch.port.out;
7const in = arch.port.in;
8
9const PIC_ONE_CMD_PORT = 0x20;
10const PIC_ONE_DATA_PORT = 0x21;
11const PIC_ONE_IDT_BASE = 32;
12
13const PIC_TWO_CMD_PORT = 0xA0;
14const PIC_TWO_DATA_PORT = 0xA1;
15const PIC_TWO_IDT_BASE = 40;
16
17const CMD_INIT = 0x11;
18const CMD_EOI = 0x20;
19
20// Remap the sixteen 8259 interrupts out of the way to
21// base interrupt number 32, and mask all interrupts
22// except the 8254 PIT
23pub fn init() void {
24 // Init the 8259's
25 out(u8, PIC_ONE_CMD_PORT, CMD_INIT);
26 wait();
27 out(u8, PIC_TWO_CMD_PORT, CMD_INIT);
28 wait();
29
30 // Write the interrupt base numbers for both
31 out(u8, PIC_ONE_DATA_PORT, PIC_ONE_IDT_BASE);
32 wait();
33 out(u8, PIC_TWO_DATA_PORT, PIC_TWO_IDT_BASE);
34 wait();
35
36 // Tell first 8259 that there's a second 8259 at IRQ 2, and tell
37 // the second 8259 that it is at that position.
38 out(u8, PIC_ONE_DATA_PORT, 1 << 2);
39 wait();
40 out(u8, PIC_TWO_DATA_PORT, 2);
41 wait();
42
43 // Tell the PICs to use 8086 mode
44 out(u8, PIC_ONE_DATA_PORT, 1);
45 wait();
46 out(u8, PIC_ONE_DATA_PORT, 1);
47 wait();
48
49 // Unmask only the 8254
50 out(u8, PIC_ONE_DATA_PORT, 0b1111_1111);
51 wait();
52 out(u8, PIC_TWO_DATA_PORT, 0b1111_1111);
53 wait();
54
55 // Set up a spurious IRQ7 handler
56 arch.interrupts.idt.add_handler(.{ .interrupt = 32 + 7 }, u64, spurious_handler, 0, 0);
57}
58
59inline fn wait() void {
60 out(u8, 0x80, 0);
61}
62
63// Notify the first 8259 that we're done with the timer interrupt
64pub fn end_of_timer_interrupt() void {
65 out(u8, PIC_ONE_CMD_PORT, CMD_EOI);
66}
67
68pub fn spurious_handler(_: *idt.InterruptFrame(u64)) callconv(idt.CallConv) void {
69 std.log.warn("Got a spurious IRQ7 (8259)", .{});
70}