M8: initrd handoff + multi-binary shipping
Ship more than one user binary: the bootloader now ferries an initrd bundle
(the VFS server + future drivers) alongside sbin/init, and the kernel unpacks
and spawns each program.
- src/user/proto/initrd.zig: the container format (Header{magic,count} +
Entry{name[32],offset,len} + blobs) with a validating Reader, shared by the
kernel and the packer.
- tools/mkinitrd.py: host-side packer (Python — trivial format, and sidesteps
the reworked Zig 0.16 std fs/args API). build.zig runs it on the built user
binaries via addSystemCommand and installs initrd.img to zig-out/bin + the
ESP root.
- BootInfo gains initrd_base/initrd_len; efi.zig loadInit refactored into a
shared loadFile, and loadInitrd ferries \initrd.img into surviving
LoaderData like init.
- main.zig startInitrdBinaries(): parse the image, spawn every entry (kernel-
spawns-all for now; init takes over via sys_spawn later).
- sbin/vfs.zig: a heartbeat stub (the real VFS server is M9), packed into the
initrd to prove the pipeline.
- New `initrd` test: parse + spawn + confirm the vfs stub reaches ring 3 and
heartbeats. Harness ships initrd.img on the ESP. Suite 30/30.
This commit is contained in:
@@ -147,6 +147,12 @@ pub fn build(b: *std.Build) void {
|
||||
},
|
||||
});
|
||||
|
||||
// The initrd container format, shared by the kernel (unpacks it) and the
|
||||
// build-time packer tools/mkinitrd.zig (produces it). No dependencies.
|
||||
const initrd_mod = b.addModule("initrd", .{
|
||||
.root_source_file = b.path("src/user/proto/initrd.zig"),
|
||||
});
|
||||
|
||||
// Compile-time config the kernel reads as `@import("build_options")`. The
|
||||
// QEMU test harness sets -Dtest-case=<name> to run one self-test at boot.
|
||||
const test_case = b.option([]const u8, "test-case", "Kernel self-test case to run at boot (see src/kernel/tests.zig)");
|
||||
@@ -182,6 +188,7 @@ pub fn build(b: *std.Build) void {
|
||||
.{ .name = "platform", .module = platform_mod },
|
||||
.{ .name = "config", .module = config_mod },
|
||||
.{ .name = "build_options", .module = build_options_mod },
|
||||
.{ .name = "initrd", .module = initrd_mod },
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -206,6 +213,26 @@ pub fn build(b: *std.Build) void {
|
||||
const init_exe = addUserBinary(b, kernel_target, rt_mod, "init", "sbin/init.zig");
|
||||
b.installArtifact(init_exe);
|
||||
|
||||
// --- initrd: a bundle of extra user binaries (VFS server + drivers) ---
|
||||
// Each is built by the same user-binary recipe, then packed into one image by
|
||||
// the host-side mkinitrd tool. The bootloader ferries the image to the kernel,
|
||||
// which unpacks it and spawns each program (src/user/proto/initrd.zig).
|
||||
const vfs_exe = addUserBinary(b, kernel_target, rt_mod, "vfs", "sbin/vfs.zig");
|
||||
|
||||
// Pack the user binaries into the initrd image with the host-side Python tool
|
||||
// (the container format is trivial, and Python sidesteps std API churn). Args:
|
||||
// mkinitrd.py <out> [<name> <file>]... — one name/file pair per binary.
|
||||
const mk_run = b.addSystemCommand(&.{"python3"});
|
||||
mk_run.addFileArg(b.path("tools/mkinitrd.py"));
|
||||
const initrd_img = mk_run.addOutputFileArg("initrd.img");
|
||||
mk_run.addArg("vfs");
|
||||
mk_run.addFileArg(vfs_exe.getEmittedBin());
|
||||
|
||||
// Install the image to zig-out/bin (so the QEMU test harness picks it up like
|
||||
// the other binaries). The run-x86-64 ESP install is added below.
|
||||
const initrd_install = b.addInstallFile(initrd_img, "bin/initrd.img");
|
||||
b.getInstallStep().dependOn(&initrd_install.step);
|
||||
|
||||
// Boot methods live in src/boot/, one per way of getting the kernel running.
|
||||
// Each is its own binary/entry (a loader is built for its own target); today
|
||||
// that's UEFI for x86-64, with room for e.g. a device-tree path for the Pis.
|
||||
@@ -268,6 +295,8 @@ pub fn build(b: *std.Build) void {
|
||||
const init_install = b.addInstallArtifact(init_exe, .{
|
||||
.dest_dir = .{ .override = .{ .custom = "esp/sbin" } },
|
||||
});
|
||||
// ...and the initrd (VFS server + drivers) from the volume root.
|
||||
const initrd_esp_install = b.addInstallFile(initrd_img, "esp/initrd.img");
|
||||
|
||||
// The firmware needs to write NVRAM, so give it a writable copy of the vars.
|
||||
const vars_copy = b.addSystemCommand(&.{ "cp", "-f", ovmf_vars });
|
||||
@@ -305,6 +334,7 @@ pub fn build(b: *std.Build) void {
|
||||
run_efi.step.dependOn(&efi_install.step);
|
||||
run_efi.step.dependOn(&kernel_install.step);
|
||||
run_efi.step.dependOn(&init_install.step);
|
||||
run_efi.step.dependOn(&initrd_esp_install.step);
|
||||
|
||||
const run_efi_step = b.step("run-x86-64", "Boot the x86-64 kernel in QEMU (UEFI/OVMF); serial0 is logged to zig-out/run-x86-64-serial0-<timestamp>.log");
|
||||
run_efi_step.dependOn(&run_efi.step);
|
||||
|
||||
Reference in New Issue
Block a user