Pass argv to processes on a SysV entry stack; grow the user stack to 32 KiB
Processes now start with C-compatible arguments: the kernel builds the System V AMD64 entry block (argc, argv, empty envp, auxiliary vector) at the top of the stack, argv[0] is the path or initial-ramdisk name the process was spawned as, and system_spawn carries an optional NUL-separated blob that becomes argv[1..]. The runtime parses the block (runtime.argumentCount/argument) and its spawn wrappers pass arguments through. The name is also recorded on the task, so a fault report says which binary died, not just its id. The user stack grows from one page to eight (32 KiB, parameters.user_stack_pages), with the page below left unmapped as a guard so an overflow faults into a clean process kill rather than corrupting the image. Task.name_buffer is zero-initialised, not undefined: an undefined default is materialised as a 0xAA fill that moved the static task pool out of .bss and made the whole kernel ~7x slower under QEMU TCG (caught by the affinity test). Proven end to end by the new args test: args-echo respawns itself with arguments via the syscall blob, burns more stack than one page could hold, and echoes its argv intact. Full suite: 44/44.
This commit is contained in:
@@ -5,25 +5,52 @@
|
||||
const std = @import("std");
|
||||
const system = @import("system.zig");
|
||||
|
||||
/// The kernel enters at `_start` with rsp 16-aligned, but a SystemV function expects
|
||||
/// rsp ≡ 8 (mod 16) on entry (as if reached by `call`). The `call` below pushes
|
||||
/// the 8-byte return address, satisfying the ABI before any Zig frame runs; the
|
||||
/// `ud2` is a safety net if `rt_start` ever returns.
|
||||
/// The kernel enters at `_start` with rsp 16-aligned, pointing at the System V
|
||||
/// process-entry block it built: argc, argv pointers, NULL, envp terminator, the
|
||||
/// auxiliary vector, then the strings (see system/kernel/process.zig,
|
||||
/// `buildEntryStack`). Capture that address in rdi — the first SysV argument —
|
||||
/// before `call` disturbs the stack; the call's pushed return address also puts
|
||||
/// rsp ≡ 8 (mod 16), satisfying the ABI before any Zig frame runs. The `ud2` is a
|
||||
/// safety net if `rt_start` ever returns.
|
||||
pub export fn _start() callconv(.naked) noreturn {
|
||||
asm volatile (
|
||||
\\mov %%rsp, %%rdi
|
||||
\\call rt_start
|
||||
\\ud2
|
||||
);
|
||||
}
|
||||
|
||||
/// The first Zig frame. The heap is lazy (first alloc grows it), so there is no
|
||||
/// runtime init to order here — just hand control to the program's `main`.
|
||||
export fn rt_start() callconv(.c) noreturn {
|
||||
// The process-entry block, recorded by `rt_start` for the accessors below.
|
||||
var argument_count: usize = 0;
|
||||
var argument_vector: [*]const u64 = undefined;
|
||||
|
||||
/// The first Zig frame, entered with `stack` pointing at the kernel-built entry
|
||||
/// block. Record argc/argv for the accessors, then hand control to the program's
|
||||
/// `main`. The heap is lazy (first alloc grows it), so there is no other runtime
|
||||
/// init to order here.
|
||||
export fn rt_start(stack: [*]const u64) callconv(.c) noreturn {
|
||||
argument_count = stack[0];
|
||||
argument_vector = stack + 1;
|
||||
const root = @import("root"); // the user binary's root source file
|
||||
root.main();
|
||||
system.exit(0);
|
||||
}
|
||||
|
||||
/// Number of process arguments (argc). At least 1: argument 0 is the path or
|
||||
/// name this binary was spawned as.
|
||||
pub fn argumentCount() usize {
|
||||
return argument_count;
|
||||
}
|
||||
|
||||
/// Process argument `index` (0 = the program's own path/name), or an empty slice
|
||||
/// if out of range. The bytes live in the entry block at the top of the stack
|
||||
/// page, NUL-terminated, valid for the process's lifetime.
|
||||
pub fn argument(index: usize) []const u8 {
|
||||
if (index >= argument_count) return "";
|
||||
const string: [*:0]const u8 = @ptrFromInt(argument_vector[index]);
|
||||
return std.mem.span(string);
|
||||
}
|
||||
|
||||
/// No runtime to unwind into — report a panic as a nonzero exit code.
|
||||
pub const panic = std.debug.FullPanic(struct {
|
||||
fn panic(_: []const u8, _: ?usize) noreturn {
|
||||
|
||||
Reference in New Issue
Block a user