Add lib/ — the shared user-space runtime every user binary links against (init now, servers/drivers later): syscall wrappers, the heap, IPC stub, and the process start shim. - lib/heap.zig: the kernel first-fit free-list ported to user space, grown via the mmap syscall instead of pmm+mapPage. Dual API over one global free list: extern "C" malloc/free/calloc/realloc (C ABI for future C code) and a std.mem.Allocator adapter (with in-place resize) for Zig std containers. - lib/syscall.zig + sys.zig: raw syscall0..5 (arg3 in r10) and typed yield/write/sleep/exit/mmap/munmap over danos.Syscall. - lib/start.zig: naked _start -> rt_start -> root.main() (SysV realign via call), panic -> exit(127). - lib/user.ld: the user link script, moved from sbin/linker.ld (shared by all user binaries). - build.zig: register the `rt` module; add an addUserBinary() helper that is the one recipe for every user binary (freestanding, .large, use_lld, user.ld, image_base), replacing the bespoke init block. - sbin/init.zig: migrated onto rt; drops its hand-rolled syscall2/shims. Now proves the heap (alloc -> write from a heap pointer -> free) before the heartbeat loop. Serial shows "init: heap ok". Suite 28/28.
40 lines
1.7 KiB
Zig
40 lines
1.7 KiB
Zig
//! /sbin/init — the first user-space program, PID 1. Built as its own
|
|
//! freestanding binary (see build.zig), shipped on the boot volume at sbin/init,
|
|
//! loaded by the bootloader, and started in ring 3 as a scheduled process by the
|
|
//! kernel (src/kernel/process.zig). It links against the shared user runtime
|
|
//! library `rt` and talks to the kernel only through `rt`'s syscall wrappers.
|
|
//!
|
|
//! Today it proves the C-convention heap works, then settles into a heartbeat:
|
|
//! it prints a line and sleeps, forever — enough to show the system reaches user
|
|
//! space and stays alive with a real process scheduled alongside the kernel's
|
|
//! idle loop. It grows into the real init (service supervision) once there are
|
|
//! other user programs to supervise.
|
|
|
|
const rt = @import("rt");
|
|
|
|
pub fn main() void {
|
|
// Prove the heap end to end: allocate through the runtime allocator (which
|
|
// mmaps pages from the kernel and carves them with the free list), write into
|
|
// that heap buffer (exercising the widened debug_write bounds check), and
|
|
// free it. A fault here would kill init before it heartbeats — so the init
|
|
// test doubles as the heap regression test. (C code links the same heap via
|
|
// the extern malloc/free symbols; Zig code uses this allocator.)
|
|
const gpa = rt.allocator();
|
|
if (gpa.alloc(u8, 64)) |buf| {
|
|
const msg = "init: heap ok\n";
|
|
@memcpy(buf[0..msg.len], msg);
|
|
_ = rt.sys.write(buf[0..msg.len]);
|
|
gpa.free(buf);
|
|
} else |_| {}
|
|
|
|
while (true) {
|
|
_ = rt.sys.write("init: heartbeat\n");
|
|
rt.sys.sleep(1000);
|
|
}
|
|
}
|
|
|
|
pub const panic = rt.panic;
|
|
comptime {
|
|
_ = &rt.start._start; // pull the runtime entry shim into the image
|
|
}
|