From fd3f51eecaecc12806a573c38263df1de43ee8c2 Mon Sep 17 00:00:00 2001 From: hachem Date: Fri, 25 Sep 2026 18:08:17 +0200 Subject: feat: pit timer --- boot/boot.zig | 6 ++++++ boot/idt.zig | 6 +++++- boot/limine.zig | 6 +++--- boot/pmm.zig | 10 +++++----- boot/timer.zig | 17 +++++++++++++++++ 5 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 boot/timer.zig (limited to 'boot') diff --git a/boot/boot.zig b/boot/boot.zig index 108afc8..8f8c7fe 100644 --- a/boot/boot.zig +++ b/boot/boot.zig @@ -10,6 +10,7 @@ const vmm = @import("vmm.zig"); const user = @import("user.zig"); const elf = @import("elf.zig"); const keyboard = @import("keyboard.zig"); +const timer = @import("timer.zig"); const bridge = @import("bridge"); // We need a panic handler otherwise zig won't be happy, @@ -166,11 +167,16 @@ export fn _start() callconv(.c) noreturn { // the cli/pop/sti-hlt bullshit closes the lost-wakeup race (a key // arriving between "queue empty" and hlt would otherwise sit until // the next keypress) + var last_ticks: u64 = 0; while (true) { asm volatile ("cli"); if (keyboard.pop()) |sc| { asm volatile ("sti"); bridge.onKey(sc); + } else if (timer.now() != last_ticks) { + last_ticks = timer.now(); + asm volatile ("sti"); + bridge.onTick(last_ticks); } else { asm volatile ("sti; hlt"); } diff --git a/boot/idt.zig b/boot/idt.zig index fda5b9d..19afa6b 100644 --- a/boot/idt.zig +++ b/boot/idt.zig @@ -8,6 +8,7 @@ const gdt = @import("gdt.zig"); const serial = @import("serial.zig"); const pic = @import("pic.zig"); const keyboard = @import("keyboard.zig"); +const timer = @import("timer.zig"); // 64bit interrupt gate const Gate = packed struct { @@ -219,6 +220,7 @@ export fn irqCommon() callconv(.naked) void { 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 else => {}, } @@ -242,8 +244,10 @@ pub fn setGate(vector: u8, handler: u64, dpl: u2) void { // 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. + // 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); idtr = .{ .limit = @sizeOf(@TypeOf(idt)) - 1, .base = @intFromPtr(&idt) }; asm volatile ("lidt (%[idtr])" diff --git a/boot/limine.zig b/boot/limine.zig index f1ed158..3d18b31 100644 --- a/boot/limine.zig +++ b/boot/limine.zig @@ -1,5 +1,5 @@ -// Limine scans the loaded image for these magic numbers, BaseRevision is -// a handshake, essentially we ask limine for rev 3, and if it supports it, +// Limine scans the loaded image for these magic numbers, BaseRevision is +// a handshake, essentially we ask limine for rev 3, and if it supports it, // limine zeros it out pub const BaseRevision = extern struct { magic0: u64 = 0xf9562b2d5c95a6c8, @@ -11,7 +11,7 @@ pub const BaseRevision = extern struct { } }; -// bracketing markers, they are pretty optional but when we add proper +// bracketing markers, they are pretty optional but when we add proper // limine requests, having these here comes handy pub const RequestsStartMarker = extern struct { m0: u64 = 0xf6b8f4b39de7d1ae, diff --git a/boot/pmm.zig b/boot/pmm.zig index 71d132e..0c4bdda 100644 --- a/boot/pmm.zig +++ b/boot/pmm.zig @@ -20,10 +20,10 @@ var hhdm_offset: u64 = 0; // reached through the HHDM, so it's just a normal slice we write through. var bitmap: []u8 = &[_]u8{}; -var total_frames: usize = 0; // frames the bitmap can index (up to highest usable end) +var total_frames: usize = 0; // frames the bitmap can index (up to highest usable end) var usable_frames: usize = 0; // frames that started free -var free_frames: usize = 0; // frames currently free -var next_hint: usize = 0; // where to start the next alloc scan +var free_frames: usize = 0; // frames currently free +var next_hint: usize = 0; // where to start the next alloc scan pub fn physToVirt(phys: u64) u64 { return phys + hhdm_offset; @@ -95,7 +95,7 @@ pub fn init(hhdm: *const limine.HhdmResponse, memmap: *const limine.MemoryMapRes // // WARNING: never hand out a physical-null address // - // unlike marking a region free, here we round the END UP so a partial + // unlike marking a region free, here we round the END UP so a partial // last frame the bitmap spills into still gets reserved { const start = storage_base / PAGE_SIZE; @@ -136,7 +136,7 @@ pub fn alloc() ?u64 { // hand out n contiguous physical frames cause the heap needs one flat buffer, and a // single usable region is contiguous in physical space, so this just finds a -// run of n free bits. +// run of n free bits. // NOTE: returns the base physical address of the run pub fn allocContig(n: usize) ?u64 { if (n == 0) return null; diff --git a/boot/timer.zig b/boot/timer.zig new file mode 100644 index 0000000..4569d6a --- /dev/null +++ b/boot/timer.zig @@ -0,0 +1,17 @@ +// PIT channel 0 tick counter +// configuring the PIT itself (outb to 0x43/0x40) is done in revo (kernel +// `pit_init`), since it's just port writes the VM can drive + +var ticks: u64 = 0; + +// called from the IRQ0 handler +pub fn onIrq() void { + const t: *volatile u64 = &ticks; + t.* +%= 1; +} + +// called from the event loop +pub fn now() u64 { + const t: *volatile u64 = &ticks; + return t.*; +} -- cgit v1.3