//! /sbin/hpetd — a user-space HPET driver, the first real device driver. It //! proves IO passthrough end to end: enumerate the device table, find the HPET //! (a timer with an MMIO window), claim it, map its registers directly into this //! ring-3 address space (strong-uncacheable), then drive the hardware — enable //! the main counter and read it. If the counter advances, a user process is //! touching real hardware through a kernel-granted MMIO mapping. //! //! Register offsets (HPET spec): general config = 0x10 (bit 0 = ENABLE), //! main counter = 0xF0. const rt = @import("rt"); const dev = rt.dev; pub fn main() void { // Enumerate into a heap buffer (too big for the one-page user stack). const buf = rt.allocator().alloc(dev.DeviceDesc, 32) catch { _ = rt.sys.write("hpetd: out of memory\n"); return; }; const total = dev.enumerate(buf); const n = @min(total, buf.len); // Find a timer-class device with an MMIO resource (the HPET). var dev_id: u64 = 0; var res_idx: u64 = 0; var found = false; var i: usize = 0; outer: while (i < n) : (i += 1) { const d = buf[i]; if (d.class != @intFromEnum(dev.DeviceClass.timer)) continue; var j: usize = 0; while (j < d.resource_count) : (j += 1) { if (d.resources[j].kind == @intFromEnum(dev.ResourceKind.memory)) { dev_id = d.id; res_idx = j; found = true; break :outer; } } } if (!found) { _ = rt.sys.write("hpetd: no HPET found\n"); return; } if (!dev.claim(dev_id)) { _ = rt.sys.write("hpetd: claim failed\n"); return; } const base = dev.mmioMap(dev_id, res_idx) orelse { _ = rt.sys.write("hpetd: mmio_map failed\n"); return; }; // Drive the hardware: enable the counter (an MMIO write), then read it twice. const config: *volatile u64 = @ptrFromInt(base + 0x10); config.* |= 1; // ENABLE const counter: *volatile u64 = @ptrFromInt(base + 0xF0); const a = counter.*; rt.sys.sleep(50); const b = counter.*; if (b > a) { while (true) { _ = rt.sys.write("hpetd: ok\n"); rt.sys.sleep(1000); } } _ = rt.sys.write("hpetd: counter stuck\n"); } pub const panic = rt.panic; comptime { _ = &rt.start._start; }