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