feat(pl/pc): add APIC timer support

This commit is contained in:
Loïc Grégoire
2026-04-18 11:18:33 -04:00
parent 1aa6743f43
commit a1db75746a
13 changed files with 175 additions and 48 deletions
+8 -5
View File
@@ -81,30 +81,33 @@ fn early_cpu_init() linksection(r.init) void {
efer.nxe = true;
amd64.write_msr(.Efer, @bitCast(efer));
amd64.sti();
}
pub fn ap_entry(cpu_id: u32) noreturn {
pub fn ap_entry(cpu_id: u32, booted: *std.atomic.Value(usize)) noreturn {
early_cpu_init();
ki.cpu.init_cpu(cpu_id);
pl.impl.init_ap();
_ = booted.fetchAdd(1, .monotonic);
while (true) {
std.atomic.spinLoopHint();
}
}
var initial_offsets: [1]usize = undefined;
var initial_offsets: [1]usize = .{0};
extern var __percpu_start: u8;
pub fn early_init() linksection(r.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
amd64.write_msr(.GsBase, 0);
int.init();
}
+17
View File
@@ -3,6 +3,7 @@ const std = @import("std");
const r = @import("root");
const ke = r.ke;
const ki = ke.private;
const pl = r.pl;
extern const __interrupt_vectors: [256]usize;
@@ -44,6 +45,8 @@ const exception_msg = [32][]const u8{
};
export fn isr_handler_main(frame: *const amd64.IrqFrame) callconv(.{ .x86_64_sysv = .{} }) void {
const ipl = ke.ipl.set_hardware(.Device);
if (frame.intno < 32) {
std.log.err("Unhandled exception: 0x{x} ({s}), err=0x{x}, pc=0x{x}", .{ frame.intno, exception_msg[frame.intno], frame.errcode, frame.rip });
std.log.err("RAX=0x{x:0>16} RBX=0x{x:0>16} RCX=0x{x:0>16} RDX=0x{x:0>16}", .{ frame.rax, frame.rbx, frame.rcx, frame.rdx });
@@ -75,6 +78,20 @@ export fn isr_handler_main(frame: *const amd64.IrqFrame) callconv(.{ .x86_64_sys
ki.panic.panic_with_frame("Unhandled exception", frame.rbp);
}
if (frame.intno == 32) {
ki.timer.clock();
}
if (frame.intno >= 32) {
pl.impl.apic.eoi();
}
ki.impl.set_hardware_ipl(ipl);
if (@intFromEnum(ipl) < @intFromEnum(ke.Ipl.get_max_software()) and ki.ipl.is_softint_pending(.Dispatch)) {
ki.dpc.dispatch(ke.cpu.current());
}
}
extern fn idt_load(idt_ptr: *const amd64.Idtr) callconv(.{ .x86_64_sysv = .{} }) void;
+1 -2
View File
@@ -100,7 +100,7 @@ const balance_interval = @as(u64, config.CONFIG_BALANCE_INTERVAL);
const steal_threshold = 1;
var balance_timer: ke.Timer = undefined;
var balance_dpc: ke.Dpc = undefined;
var balance_dpc: ke.Dpc = .init(balance);
// LCG values taken from FreeBSD.
var lcg = std.Random.lcg.Wrapping(u32).init(0, 69069, 5);
@@ -313,7 +313,6 @@ fn init_cpu() linksection(r.init) callconv(.c) void {
/// Called on CPU 0 to initialize load balancing mechanisms.
pub fn late_init() linksection(r.init) void {
balance_dpc = ke.Dpc.init(balance);
balance_timer.init();
ke.timer.set(&balance_timer, balance_interval * std.time.ns_per_ms, &balance_dpc);
}
+11 -9
View File
@@ -8,7 +8,10 @@ fn set_signals(enabled: bool) bool {
var newmask: c.sigset_t = undefined;
var oldmask: c.sigset_t = undefined;
_ = c.sigfillset(&newmask);
_ = c.sigemptyset(&newmask);
_ = c.sigaddset(&newmask, c.SIGUSR1);
_ = c.sigaddset(&newmask, c.SIGUSR2);
_ = c.sigaddset(&newmask, c.SIGALRM);
const how = if (enabled) c.SIG_UNBLOCK else c.SIG_BLOCK;
@@ -19,12 +22,13 @@ fn set_signals(enabled: bool) bool {
return c.sigismember(&oldmask, c.SIGUSR1) == 0;
}
threadlocal var hard_ipl: ke.Ipl = .Passive;
/// Set the hardware IPL.
pub fn set_hardware_ipl(ipl: ke.Ipl) void {
// This is a no-op since we handle this in enable_interrupts().
hard_ipl = ipl;
if (@intFromEnum(ipl) > @intFromEnum(ke.Ipl.get_max_software())) {
_ = disable_interrupts();
} else {
_ = enable_interrupts();
}
}
/// Disable interrupts and return the previous state.
@@ -34,14 +38,12 @@ pub fn disable_interrupts() bool {
/// Enable interrupts and return the previous state.
pub fn enable_interrupts() bool {
const ipl_allows_ints = @intFromEnum(hard_ipl) <= @intFromEnum(ke.Ipl.get_max_software());
return set_signals(ipl_allows_ints);
return set_signals(true);
}
/// Restore an interrupt state.
pub fn restore_interrupts(val: bool) void {
const ipl_allows_ints = @intFromEnum(hard_ipl) <= @intFromEnum(ke.Ipl.get_max_software());
_ = set_signals(val and ipl_allows_ints);
_ = set_signals(val);
}
pub fn send_resched_ipi(cpu: u32) void {