From 2a09642f4d75b2ea6afdc4752b2d790fe5abd512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gr=C3=A9goire?= Date: Wed, 5 Aug 2026 16:10:37 -0400 Subject: [PATCH] ke: rework kernel initialization --- src/ex/init.zig | 13 ++++--------- src/ex/root.zig | 2 ++ src/kern/amd64/impl.zig | 6 +++++- src/kern/amd64/init.zig | 9 +++++---- src/kern/amd64/locore.s | 13 +++++++++++++ src/kern/init.zig | 35 +++++++++++++++++++++-------------- src/loader/info.zig | 3 +++ src/loader/main.zig | 3 +++ src/loader/pmap.zig | 2 +- src/platform/pc/smp.zig | 1 - src/root.zig | 2 +- 11 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/ex/init.zig b/src/ex/init.zig index 1ce987d..29d519f 100644 --- a/src/ex/init.zig +++ b/src/ex/init.zig @@ -11,8 +11,7 @@ const rtl = @import("rtl"); // XXX const fbconsole = @import("../dev/fbconsole.zig"); -export fn kmain(boot_info: *r.BootInfo) callconv(.c) void { - ke.init(boot_info); +pub fn init() void { mm.init(); ps.init(); @@ -23,11 +22,11 @@ export fn kmain(boot_info: *r.BootInfo) callconv(.c) void { exp.console.init(); exp.string.init(); - if (boot_info.cmdline) |cline| { + if (r.boot_info.cmdline) |cline| { if (rtl.cmdline.get_string(cline, "test")) |tst| { // Run a test if specified. if (r.tests.tests.get(tst)) |func| { - const t = ps.thread.create_kernel(ke.Thread.Priority.default, func, boot_info) catch @panic("oom"); + const t = ps.thread.create_kernel(ke.Thread.Priority.default, func, r.boot_info) catch @panic("oom"); ke.sched.enqueue(&t.kern); } else { std.log.info("invalid test: \"{s}\"", .{tst}); @@ -35,11 +34,7 @@ export fn kmain(boot_info: *r.BootInfo) callconv(.c) void { } } - if (boot_info.framebuffer != null) { + if (r.boot_info.framebuffer != null) { // fbconsole.init(boot_info); } - - while (true) { - std.atomic.spinLoopHint(); - } } diff --git a/src/ex/root.zig b/src/ex/root.zig index fe85b8d..e109902 100644 --- a/src/ex/root.zig +++ b/src/ex/root.zig @@ -7,6 +7,8 @@ pub const DelayedWorkItem = p.work.DelayedWorkItem; pub const Console = p.console.Console; pub const InternedString = p.string.InternedString; +pub const init = p.init; + pub const work = struct { pub const enqueue = p.work.enqueue; pub const enqueue_in = p.work.enqueue_in; diff --git a/src/kern/amd64/impl.zig b/src/kern/amd64/impl.zig index 7bd812c..ea61cbe 100644 --- a/src/kern/amd64/impl.zig +++ b/src/kern/amd64/impl.zig @@ -26,6 +26,7 @@ const ThreadFrame = extern struct { extern fn asm_thread_entry() void; extern fn do_context_switch(old: *ThreadContext, new: *ThreadContext, lock: *u8, switching: *bool) callconv(.c) void; +extern fn do_context_load(td: *ThreadContext) callconv(.c) void; pub const ThreadContext = extern struct { rsp: u64 align(1), @@ -35,7 +36,6 @@ pub const ThreadContext = extern struct { const entry_fn: *const fn (?*anyopaque) void = @ptrFromInt(entry); ke.ipl.lower(.Passive); entry_fn(@ptrFromInt(arg)); - // TODO: This shouldn't be reached!!! } pub fn init(stack: r.VAddr, stack_size: usize, entry: *const fn (?*anyopaque) void, arg: ?*anyopaque) @This() { @@ -62,6 +62,10 @@ pub const ThreadContext = extern struct { const thread: *ke.Thread = @alignCast(@fieldParentPtr("context", self)); do_context_switch(self, new, &thread.lock.inner.locked.raw, &thread.switching.raw); } + + pub fn load(self: *ThreadContext) callconv(.c) void { + do_context_load(self); + } }; inline fn percpu_ptr_for(variable: anytype, cpu: u32) @TypeOf(variable) { diff --git a/src/kern/amd64/init.zig b/src/kern/amd64/init.zig index c1b0ad3..7d6d9ca 100644 --- a/src/kern/amd64/init.zig +++ b/src/kern/amd64/init.zig @@ -91,16 +91,17 @@ pub fn ap_entry(cpu_id: u32, booted: *std.atomic.Value(usize)) noreturn { ki.cpu.init_cpu(cpu_id); pl.impl.init_ap(); - ki.sched.percpu.local().current_thread = pl.impl.smp.start_thread.local().*; + const sched = ki.sched.percpu.local(); + + sched.current_thread = pl.impl.smp.start_thread.local().*; + sched.idle_thread = sched.current_thread; amd64.sti(); _ = booted.fetchAdd(1, .monotonic); ke.ipl.lower(.Passive); - while (true) { - std.atomic.spinLoopHint(); - } + ki.sched.idle(null); } var initial_offsets: [1]usize = .{0}; diff --git a/src/kern/amd64/locore.s b/src/kern/amd64/locore.s index a9181c4..5e75ade 100644 --- a/src/kern/amd64/locore.s +++ b/src/kern/amd64/locore.s @@ -166,6 +166,19 @@ do_context_switch: pop %r15 ret +.global do_context_load +do_context_load: + /* Load new stack pointer. */ + mov (%rdi), %rsp + + /* Restore callee-saved registers. */ + pop %rbp + pop %rbx + pop %r12 + pop %r13 + pop %r14 + pop %r15 + ret .extern thread_entry .global asm_thread_entry diff --git a/src/kern/init.zig b/src/kern/init.zig index 6968bc9..000f26e 100644 --- a/src/kern/init.zig +++ b/src/kern/init.zig @@ -7,10 +7,24 @@ const ki = ke.private; const ex = r.ex; var thread0: ke.Thread = undefined; -var stack: [r.kib(16)]u8 align(16) = undefined; -pub fn init(boot_info: *r.BootInfo) linksection(r.init) void { +export fn kmain(boot_info: *r.BootInfo) callconv(.c) void { r.boot_info = boot_info; + + thread0.init( + boot_info.kernel_stack, + boot_info.kernel_stack_size, + ke.Thread.Priority.idle_low, + init, + null, + ); + thread0.pinned = true; + + // Jump into the thread. + thread0.context.load(); +} + +pub fn init(_: ?*anyopaque) linksection(r.init) void { ke.ncpus = 1; ki.impl.early_init(); ki.tunable.init(); @@ -20,18 +34,11 @@ pub fn init(boot_info: *r.BootInfo) linksection(r.init) void { ki.cpu.init_cpu(0); ki.turnstile.init_turnstiles(); - thread0.init( - @intFromPtr(&stack), - r.kib(16), - ke.Thread.Priority.idle_low, - ki.sched.idle, - null, - ); - thread0.priority = 0; - thread0.base_priority = 0; - thread0.pinned = true; - ki.sched.percpu.local().current_thread = &thread0; + ki.sched.percpu.local().idle_thread = &thread0; - std.log.info("Zag for {s} ({s}), cmdline is \"{?s}\"", .{ pl.name, arch.name, boot_info.cmdline }); + std.log.info("Zag for {s} ({s}), cmdline is \"{?s}\"", .{ pl.name, arch.name, r.boot_info.cmdline }); + + ex.init(); + ki.sched.idle(null); } diff --git a/src/loader/info.zig b/src/loader/info.zig index 6be089e..fcd87c2 100644 --- a/src/loader/info.zig +++ b/src/loader/info.zig @@ -34,6 +34,9 @@ pub const Framebuffer = struct { // Kept in sync with the kernel pub const page_struct_size = 16; +kernel_stack: usize, +kernel_stack_size: usize, + /// RSDP on ACPI machines rsdp: ?usize, diff --git a/src/loader/main.zig b/src/loader/main.zig index 35f1e14..f2fa824 100644 --- a/src/loader/main.zig +++ b/src/loader/main.zig @@ -93,6 +93,9 @@ pub fn loader_main(kernel: *anyopaque) void { const memmap = &r.loader_info.memory_map; + r.loader_info.kernel_stack = stack; + r.loader_info.kernel_stack_size = stack_size; + // Finally, sort the memory map once we're done allocating everything. std.mem.sort(Entry, memmap.entries[0..memmap.entry_count], {}, cmp_entries); diff --git a/src/loader/pmap.zig b/src/loader/pmap.zig index 1603224..9078449 100644 --- a/src/loader/pmap.zig +++ b/src/loader/pmap.zig @@ -172,7 +172,7 @@ pub const PMap = struct { /// Choose the largest page size that satisfies the alignment and /// size constraints of the current VA, PA, and remaining byte count. - /// Tries large pages first; falls back to 4K. + /// Tries large pages first, falls back to 4K. fn choose_target_level(self: *Cursor, pa: usize, remain: usize) usize { var level: usize = num_levels; while (level > 0) { diff --git a/src/platform/pc/smp.zig b/src/platform/pc/smp.zig index 30ccb0c..37ee63f 100644 --- a/src/platform/pc/smp.zig +++ b/src/platform/pc/smp.zig @@ -110,7 +110,6 @@ pub fn init() linksection(r.init) void { const stack_top = @intFromPtr(mm.heap.alloc(r.kib(32), .DontWaitForMemory) catch @panic("Failed to allocate AP stack")) + r.kib(32); start_stack.remote(@intCast(cpu_id)).* = stack_top & ~@as(usize, 15); - start_thread.remote(@intCast(cpu_id)).* = make_thread(@ptrCast(&ap_entry), stack_top - r.kib(32)); rtl.barrier.fence(.release); diff --git a/src/root.zig b/src/root.zig index a0268dd..96a067d 100644 --- a/src/root.zig +++ b/src/root.zig @@ -67,5 +67,5 @@ pub const panic = std.debug.FullPanic(ke.panic); comptime { // Ensure the entry point is linked in. - _ = @import("ex/init.zig"); + _ = @import("kern/init.zig"); }