mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-31 07:18:22 +00:00
feat(pc): add AP startup
This commit is contained in:
+5
-10
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ===
|
||||
|
||||
Reference in New Issue
Block a user