feat(pc): add AP startup

This commit is contained in:
Loïc Grégoire
2026-04-15 19:38:00 -04:00
parent a7cdfeb57a
commit a09c78474d
13 changed files with 636 additions and 35 deletions
+5 -10
View File
@@ -5,14 +5,11 @@ const amd64 = b.arch;
const std = @import("std");
pub const early_init = @import("init.zig").early_init;
pub const init = @import("init.zig");
pub const early_init = init.early_init;
pub const Cpu = struct {
self_ptr: *Cpu,
percpu_offset: usize,
};
pub var cpu_self_offset: usize linksection(b.percpu) = 0;
pub export var cpu_self_offset: usize linksection(b.percpu) = 0;
pub export var cpu_offsets: [*]usize = undefined;
pub const ThreadContext = struct {
rdi: u64,
@@ -104,9 +101,7 @@ pub const ThreadContext = struct {
};
inline fn percpu_ptr_for(variable: anytype, cpu: u32) @TypeOf(variable) {
_ = cpu; // TODO
@panic("TODO percpu_ptr_for");
// return @ptrFromInt(@intFromPtr(variable) +% cpu.impl.percpu_offset);
return @ptrFromInt(@intFromPtr(variable) +% cpu_offsets[cpu]);
}
pub inline fn percpu_ptr_other(variable: anytype, id: u32) @TypeOf(variable) {
+71 -1
View File
@@ -1,6 +1,10 @@
const amd64 = @import("arch");
const int = @import("int.zig");
const b = @import("base");
const std = @import("std");
const impl = @import("impl.zig");
const ke = b.ke;
const ki = b.ke.private;
var gdt = extern struct {
entries: [9]u64 align(1),
@@ -23,7 +27,7 @@ var gdt = extern struct {
extern fn gdt_load(gdtr: *const amd64.Gdtr) callconv(.{ .x86_64_sysv = .{} }) void;
pub fn early_init() linksection(b.init) void {
fn early_cpu_init() linksection(b.init) void {
const gdtr: amd64.Gdtr = .{
.limit = @sizeOf(@TypeOf(gdt)) - 1,
.base = @intFromPtr(&gdt),
@@ -31,6 +35,72 @@ pub fn early_init() linksection(b.init) void {
gdt_load(&gdtr);
var cr0: amd64.Cr0 = @bitCast(amd64.read_cr(0));
// Disable x87 emulation.
cr0.em = false;
// Monitor co-processor.
cr0.mp = true;
// Numeric error.
cr0.ne = true;
// Write-protection (cannot write to read-only pages).
cr0.wp = true;
amd64.write_cr(0, @bitCast(cr0));
// Enable CPU features we might want through cr4.
const f = amd64.cpu_features;
var cr4: amd64.Cr4 = @bitCast(amd64.read_cr(4));
// Allow userspace to read TSC.
cr4.tsd = false;
// Enable global pages.
cr4.pge = f.pge;
if (f.fxsave == true) {
// Enable FXSAVE/FXRSTOR and SSE.
cr4.osfxsr = true;
cr4.osxmmexcpt = true;
}
// Enable XSAVE.
cr4.osxsave = f.xsave;
// Enable UMIP.
cr4.umip = f.umip;
amd64.write_cr(4, @bitCast(cr4));
// Configure the EFER MSR.
var efer: amd64.Efer = @bitCast(amd64.read_msr(.Efer));
// Enable syscall if supported.
efer.sce = f.syscall;
// Enable NX.
efer.nxe = true;
amd64.write_msr(.Efer, @bitCast(efer));
}
pub fn ap_entry(cpu_id: u32) noreturn {
early_cpu_init();
ki.cpu.init_cpu(cpu_id);
while (true) {
std.atomic.spinLoopHint();
}
}
var initial_offsets: [1]usize = undefined;
extern var __percpu_start: u8;
pub fn early_init() linksection(b.init) void {
amd64.detect_cpu_features();
early_cpu_init();
initial_offsets[0] = @intFromPtr(&__percpu_start);
impl.cpu_offsets = &initial_offsets;
int.init();
// Enable Per-CPU data for this CPU
+18 -7
View File
@@ -9,20 +9,15 @@ extern var __init_array_percpu_start: u8;
extern var __init_array_percpu_end: u8;
const id = CpuLocal(u32, 0);
var curr_id: std.atomic.Value(u32) = .init(0);
/// Initialize a CPU. Must be called on all CPUs.
pub fn init_cpu() void {
pub fn init_cpu(cpu_id: u32) void {
const start = @intFromPtr(&__init_array_percpu_start);
const end = @intFromPtr(&__init_array_percpu_end);
const count = (end - start) / @sizeOf(*const fn () void);
const funcs: [*]const *const fn () callconv(.c) void = @ptrFromInt(start);
if (curr_id.load(.monotonic) >= config.CONFIG_NCPUS) {
std.debug.panic("cpu: Too many CPUs booted! Maximum supported is {}", .{config.CONFIG_NCPUS});
}
id.local().* = curr_id.fetchAdd(1, .monotonic);
id.local().* = cpu_id;
for (0..count) |i| {
funcs[i]();
@@ -55,6 +50,22 @@ pub fn CpuLocal(comptime T: type, comptime init: T) type {
};
}
/// Wraps around CPU-local data with a designated symbol name.
pub fn ExportedCpuLocal(comptime T: type, comptime init: T, comptime name: []const u8) type {
const S = struct {
var storage: T linksection(".data.percpu") = init;
pub fn local() @TypeOf(ki.impl.percpu_ptr(&storage)) {
return ki.impl.percpu_ptr(&storage);
}
pub fn remote(cpu: u32) *T {
return ki.impl.percpu_ptr_other(&storage, cpu);
}
};
@export(&S.storage, .{ .name = name, .linkage = .strong });
return S;
}
/// Bitmask of CPUs.
pub const CpuMask = struct {
const bits_per_word = @bitSizeOf(usize);
+1 -1
View File
@@ -13,7 +13,7 @@ pub fn init(boot_info: *pl.BootInfo) linksection(b.init) void {
std.log.info("hello, world", .{});
ki.impl.early_init();
pl.early_init(boot_info);
ki.cpu.init_cpu();
ki.cpu.init_cpu(0);
thread0.init(@intFromPtr(&stack), 8192, ki.sched.idle, null);
thread0.priority = 0;
+5 -2
View File
@@ -6,6 +6,8 @@ const ke = b.ke;
const ki = ke.private;
const config = @import("config");
var out_lock: ke.SpinLock = .init();
const DebugWriter = struct {
interface: std.Io.Writer,
@@ -45,7 +47,6 @@ pub fn log(
) void {
_ = level;
const scope_str = if (scope == .default) "" else @tagName(scope) ++ ": ";
// Calculate the length required.
@@ -57,7 +58,6 @@ pub fn log(
res.info.timestamp = ke.time.read_time_nano();
res.info.length = @truncate(required_len);
// Format the log message into the reserved buffer.
res.buf = std.fmt.bufPrint(res.buf, scope_str ++ fmt ++ "\n", args) catch return;
@@ -68,6 +68,9 @@ pub fn log(
// which would consume the ringbuffer from multiple consoles in a separate thread.
var writer = DebugWriter.init();
const ipl = out_lock.acquire();
defer out_lock.release(ipl);
writer.interface.print("[{:>5}.{:06}] ", .{ res.info.timestamp / std.time.ns_per_s, res.info.timestamp / std.time.ns_per_us }) catch return;
_ = writer.interface.writeAll(res.buf[0..res.info.length]) catch return;
}
+1
View File
@@ -14,6 +14,7 @@ pub const TimeCounter = p.time.TimeCounter;
pub const Timer = p.timer.Timer;
pub const Console = p.log.Console;
pub const CpuLocal = p.cpu.CpuLocal;
pub const ExportedCpuLocal = p.cpu.ExportedCpuLocal;
pub const CpuMask = p.cpu.CpuMask;
// === Exported Interfaces ===