isolation M1: ring 3 + a real /sbin/init, end to end
Ring 3 works: user GDT descriptors (sysret-ready layout), TSS.rsp0, U/S-bit user mappings (W^X preserved), an int 0x80 syscall gate with a mutable trap frame, and a setjmp-style enter/exit path. /sbin/init is a real freestanding Zig binary built from sbin/, shipped on the ESP, loaded by the bootloader (BootInfo.init_base/len), validated and mapped by an in-kernel user-ELF loader, and run at CPL 3 — syscalls: exit, ping, write. Tests: user, user-pf (U/S isolation proof, error code 0x5), init. Suite 27/27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7501bd1703
commit
546dd44a2a
@@ -0,0 +1,54 @@
|
||||
//! /sbin/init — the first user-space program. 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 by the kernel's user-ELF loader
|
||||
//! (src/kernel/usermode.zig). It talks to the kernel only through the
|
||||
//! `int $0x80` syscall gate.
|
||||
//!
|
||||
//! Today it just proves the path — say hello, exit — and grows into the real
|
||||
//! init (service supervision) once processes are schedulable (M3).
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// The M1 syscall numbers (usermode.zig): 0 = exit(code), 2 = write(ptr, len).
|
||||
const sys_exit = 0;
|
||||
const sys_write = 2;
|
||||
|
||||
fn syscall2(n: u64, a: u64, b: u64) u64 {
|
||||
return asm volatile ("int $0x80"
|
||||
: [ret] "={rax}" (-> u64),
|
||||
: [n] "{rax}" (n),
|
||||
[a] "{rdi}" (a),
|
||||
[b] "{rsi}" (b),
|
||||
: .{ .memory = true });
|
||||
}
|
||||
|
||||
fn write(msg: []const u8) void {
|
||||
_ = syscall2(sys_write, @intFromPtr(msg.ptr), msg.len);
|
||||
}
|
||||
|
||||
fn exit(code: u64) noreturn {
|
||||
_ = syscall2(sys_exit, code, 0);
|
||||
unreachable; // the kernel never returns from exit
|
||||
}
|
||||
|
||||
/// Entry. Naked: the kernel enters with rsp 16-aligned, but a SysV function
|
||||
/// expects rsp ≡ 8 (mod 16) on entry (as if reached by `call`) — so re-enter
|
||||
/// the ABI with an actual call. The trap after is unreachable.
|
||||
pub export fn _start() callconv(.naked) noreturn {
|
||||
asm volatile (
|
||||
\\call init_main
|
||||
\\ud2
|
||||
);
|
||||
}
|
||||
|
||||
export fn init_main() callconv(.c) noreturn {
|
||||
write("init: hello from user space\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/// No runtime to unwind into — report the panic as a nonzero exit code.
|
||||
pub const panic = std.debug.FullPanic(struct {
|
||||
fn panic(_: []const u8, _: ?usize) noreturn {
|
||||
exit(127);
|
||||
}
|
||||
}.panic);
|
||||
@@ -0,0 +1,45 @@
|
||||
/* /sbin/init link layout.
|
||||
*
|
||||
* Linked at a fixed user-space virtual base (set by `image_base` in build.zig,
|
||||
* inside the kernel's user region). Same discipline as the kernel's script:
|
||||
* one PT_LOAD per permission set, every section page-aligned, so the kernel's
|
||||
* user-ELF loader can map each segment with exact W^X permissions. Note the
|
||||
* linker also emits a read-only PT_LOAD covering the ELF headers at the image
|
||||
* base, so the entry point comes from e_entry, not the base address.
|
||||
*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
/* FLAGS bits: 1=X, 2=W, 4=R. */
|
||||
PHDRS {
|
||||
text PT_LOAD FLAGS(5); /* R + X */
|
||||
rodata PT_LOAD FLAGS(4); /* R */
|
||||
data PT_LOAD FLAGS(6); /* R + W */
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
.text ALIGN(4K) : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
.rodata ALIGN(4K) : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
.data ALIGN(4K) : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* .bss occupies memory but not file space; the loader zeroes the
|
||||
* filesz..memsz gap. */
|
||||
.bss ALIGN(4K) : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note .note.*)
|
||||
*(.eh_frame .eh_frame_hdr)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user