hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/boot/idt.zig
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-25 21:21:09 +0200
committerhachem <im@hachem.wtf>2026-09-25 21:21:09 +0200
commit09982d80c45805715984cc1cae96c37e4fc148c3 (patch)
treef711d6e7f4d4cb2d4dcb555d6a139aae343d7334 /boot/idt.zig
parentfd3f51eecaecc12806a573c38263df1de43ee8c2 (diff)
feat: scheduler + cleanup
Diffstat (limited to 'boot/idt.zig')
-rw-r--r--boot/idt.zig177
1 files changed, 53 insertions, 124 deletions
diff --git a/boot/idt.zig b/boot/idt.zig
index 19afa6b..0ffd116 100644
--- a/boot/idt.zig
+++ b/boot/idt.zig
@@ -1,5 +1,5 @@
// the idt is for the 32 cpu excpetion vectors, if i dont implement this,
-// any fault triple-falts and the machine just fucking dies for some reason
+// any fault triple falts and the machine just fucking dies for some reason
// this just maps interupts and halts ig
//
// see: https://wiki.osdev.org/Interrupt_Descriptor_Table
@@ -9,13 +9,16 @@ const serial = @import("serial.zig");
const pic = @import("pic.zig");
const keyboard = @import("keyboard.zig");
const timer = @import("timer.zig");
+const sched = @import("sched.zig");
+const regs = @import("regs.zig");
+const Frame = regs.Frame;
// 64bit interrupt gate
const Gate = packed struct {
offset_low: u16,
selector: u16,
ist: u8,
- type_attr: u8, // 0x8E = present, ring 0, 64-bit interrupt gate
+ type_attr: u8, // 0x8e = present, ring 0, 64 bit interrupt gate
offset_mid: u16,
offset_high: u32,
reserved: u32,
@@ -29,34 +32,6 @@ const Idtr = packed struct {
var idt = [_]Gate{@bitCast(@as(u128, 0))} ** 256;
var idtr: Idtr = undefined;
-// what the common stub leaves on the stack, low address -> high.
-// `mov rdi, rsp` hands the handler a pointer to this
-const Frame = extern struct {
- r15: u64,
- r14: u64,
- r13: u64,
- r12: u64,
- r11: u64,
- r10: u64,
- r9: u64,
- r8: u64,
- rbp: u64,
- rdi: u64,
- rsi: u64,
- rdx: u64,
- rcx: u64,
- rbx: u64,
- rax: u64,
- vector: u64,
- error_code: u64,
- // pushed by the CPU on the exception:
- rip: u64,
- cs: u64,
- rflags: u64,
- rsp: u64,
- ss: u64,
-};
-
const names = [_][]const u8{
"divide by zero", "debug",
"non-maskable interrupt", "breakpoint",
@@ -98,77 +73,50 @@ fn stub(comptime vector: u8) fn () callconv(.naked) void {
}.entry;
}
-// Save the GP registers into a Frame, hand its address to the Zig handler
+// save the gp registers into a frame, hand its address to the zig handler
export fn isrCommon() callconv(.naked) void {
- asm volatile (
- \\ push %rax
- \\ push %rbx
- \\ push %rcx
- \\ push %rdx
- \\ push %rsi
- \\ push %rdi
- \\ push %rbp
- \\ push %r8
- \\ push %r9
- \\ push %r10
- \\ push %r11
- \\ push %r12
- \\ push %r13
- \\ push %r14
- \\ push %r15
- \\ mov %rsp, %rdi
- \\ call exceptionHandler
+ asm volatile (regs.PUSH_GPRS ++
+ \\
+ \\ mov %rsp, %rdi
+ \\ call exceptionHandler
);
}
-fn writeHex(value: u64) void {
- const digits = "0123456789abcdef";
- var buf: [18]u8 = undefined;
- buf[0] = '0';
- buf[1] = 'x';
- var i: usize = 0;
- while (i < 16) : (i += 1) {
- const shift: u6 = @intCast((15 - i) * 4);
- buf[2 + i] = digits[(value >> shift) & 0xF];
- }
- serial.write(&buf);
-}
-
export fn exceptionHandler(frame: *Frame) callconv(.c) noreturn {
serial.write("\r\n!!! CPU DID AN OOPSIE: ");
serial.write(name(frame.vector));
serial.write("\r\n vector=");
- writeHex(frame.vector);
+ serial.writeHex(frame.vector);
serial.write(" err=");
- writeHex(frame.error_code);
+ serial.writeHex(frame.error_code);
serial.write("\r\n rip=");
- writeHex(frame.rip);
+ serial.writeHex(frame.rip);
serial.write(" cs=");
- writeHex(frame.cs);
+ serial.writeHex(frame.cs);
serial.write("\r\n rflags=");
- writeHex(frame.rflags);
+ serial.writeHex(frame.rflags);
serial.write(" rsp=");
- writeHex(frame.rsp);
- // page faults stash the offending address in CR2
+ serial.writeHex(frame.rsp);
+ // page faults stash the offending address in cr2
if (frame.vector == 14) {
const cr2 = asm volatile ("mov %%cr2, %[out]"
: [out] "=r" (-> u64),
);
serial.write("\r\n cr2=");
- writeHex(cr2);
+ serial.writeHex(cr2);
}
serial.write("\r\n");
while (true) asm volatile ("hlt");
}
-// hardware IRQ
-// unlike exceptions these must return so we acknowledge the PIC and iretq
+// hardware irq
+// unlike exceptions these must return so we acknowledge the pic and iretq
// back to whatever we interrupted. the stub mirrors the exception one (dummy
-// error code + vector for a uniform Frame) but jumps to the returning path.
+// error code + vector for a uniform frame) but jumps to the returning path
fn irqStub(comptime vector: u8) fn () callconv(.naked) void {
return struct {
fn entry() callconv(.naked) void {
- asm volatile ("pushq $0"); // dummy error code, keeps Frame uniform
+ asm volatile ("pushq $0"); // dummy error code, keeps frame uniform
asm volatile ("pushq %[v]\n jmp irqCommon"
:
: [v] "i" (@as(u32, vector)),
@@ -177,63 +125,41 @@ fn irqStub(comptime vector: u8) fn () callconv(.naked) void {
}.entry;
}
-// same register save as isrCommon, but afterwards we restore everything, drop
-// the pushed vector + error code, and iretq instead of halting.
+// same register save as isrcommon, but afterwards we restore everything, drop
+// the pushed vector + error code, and iretq instead of halting
export fn irqCommon() callconv(.naked) void {
- asm volatile (
- \\ push %rax
- \\ push %rbx
- \\ push %rcx
- \\ push %rdx
- \\ push %rsi
- \\ push %rdi
- \\ push %rbp
- \\ push %r8
- \\ push %r9
- \\ push %r10
- \\ push %r11
- \\ push %r12
- \\ push %r13
- \\ push %r14
- \\ push %r15
- \\ mov %rsp, %rdi
- \\ call irqDispatch
- \\ pop %r15
- \\ pop %r14
- \\ pop %r13
- \\ pop %r12
- \\ pop %r11
- \\ pop %r10
- \\ pop %r9
- \\ pop %r8
- \\ pop %rbp
- \\ pop %rdi
- \\ pop %rsi
- \\ pop %rdx
- \\ pop %rcx
- \\ pop %rbx
- \\ pop %rax
- \\ add $16, %rsp
- \\ iretq
+ asm volatile (regs.PUSH_GPRS ++
+ \\
+ \\ mov %rsp, %rdi
+ \\ call irqDispatch
+ \\
+ ++ regs.POP_GPRS ++
+ \\
+ \\ add $16, %rsp
+ \\ iretq
);
}
export fn irqDispatch(frame: *Frame) callconv(.c) void {
switch (frame.vector) {
- pic.MASTER_OFFSET + 0 => timer.onIrq(), // IRQ0: PIT
- pic.MASTER_OFFSET + 1 => keyboard.onIrq(), // IRQ1: keyboard
+ pic.MASTER_OFFSET + 0 => timer.onIrq(), // irq0: pit (tick count)
+ pic.MASTER_OFFSET + 1 => keyboard.onIrq(), // irq1: keyboard
else => {},
}
+ // eoi before we possibly switch tasks (the switch never returns here)
pic.eoi(@intCast(frame.vector - pic.MASTER_OFFSET));
+ // maybe swap `frame` to another task
+ if (frame.vector == pic.MASTER_OFFSET + 0) sched.tick(frame);
}
-// dpl 0 = only ring 0 can invoke via `int`
-// dpl 3 = ring 3 may (for syscalls)
-pub fn setGate(vector: u8, handler: u64, dpl: u2) void {
+// dpl 0 = only ring 0 can invoke via `int`, dpl 3 = ring 3 may (for syscalls)
+// ist 0 = use the stack the cpu would pick (rsp0 on a ring switch), ist 1..7 =
+// force tss.istn, for handlers that need a known good/big stack
+pub fn setGate(vector: u8, handler: u64, dpl: u2, ist: u3) void {
idt[vector] = .{
.offset_low = @truncate(handler),
.selector = gdt.KERNEL_CODE,
- .ist = 0,
+ .ist = ist,
.type_attr = 0x8E | (@as(u8, dpl) << 5),
.offset_mid = @truncate(handler >> 16),
.offset_high = @truncate(handler >> 32),
@@ -241,14 +167,17 @@ pub fn setGate(vector: u8, handler: u64, dpl: u2) void {
};
}
-// fill the exception vectors and load the IDT
+// fill the exception vectors and load the idt
pub fn init() void {
- inline for (0..32) |v| setGate(v, @intFromPtr(&stub(v)), 0);
- // IRQ0 (PIT) -> vector 0x20
- // IRQ1 (keyboard) -> vector 0x21
- // the PIC is remapped separately in boot
- setGate(pic.MASTER_OFFSET + 0, @intFromPtr(&irqStub(pic.MASTER_OFFSET + 0)), 0);
- setGate(pic.MASTER_OFFSET + 1, @intFromPtr(&irqStub(pic.MASTER_OFFSET + 1)), 0);
+ inline for (0..32) |v| setGate(v, @intFromPtr(&stub(v)), 0, 0);
+ // #df (8) and #pf (14) land on ist2s fault stack, so a kernel stack overflow
+ // produces a real exception dump instead of a silent triple fault
+ setGate(8, @intFromPtr(&stub(8)), 0, 2);
+ setGate(14, @intFromPtr(&stub(14)), 0, 2);
+ // irq0 (pit) -> vector 0x20, irq1 (keyboard) -> vector 0x21
+ // the pic is remapped separately in boot
+ setGate(pic.MASTER_OFFSET + 0, @intFromPtr(&irqStub(pic.MASTER_OFFSET + 0)), 0, 0);
+ setGate(pic.MASTER_OFFSET + 1, @intFromPtr(&irqStub(pic.MASTER_OFFSET + 1)), 0, 0);
idtr = .{ .limit = @sizeOf(@TypeOf(idt)) - 1, .base = @intFromPtr(&idt) };
asm volatile ("lidt (%[idtr])"
: