mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-27 13:58:20 +00:00
ke: freeze CPUs on panic
This commit is contained in:
@@ -158,6 +158,10 @@ pub inline fn percpu_ptr_other(variable: anytype, id: u32) @TypeOf(variable) {
|
||||
return percpu_ptr_for(variable, id);
|
||||
}
|
||||
|
||||
pub inline fn halt() void {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
|
||||
pub inline fn percpu_ptr(variable: anytype) @TypeOf(variable) {
|
||||
const offset = asm volatile ("mov %%gs:(%[self]), %[out]"
|
||||
: [out] "=r" (-> u64),
|
||||
|
||||
+38
-1
@@ -4,7 +4,7 @@ const r = @import("root");
|
||||
const std = @import("std");
|
||||
|
||||
const ke = r.ke;
|
||||
const ki = r.ki;
|
||||
const ki = ke.private;
|
||||
const pl = r.pl;
|
||||
|
||||
const State = enum(u8) {
|
||||
@@ -31,6 +31,8 @@ const PerCpu = struct {
|
||||
|
||||
const percpu = ke.CpuLocal(PerCpu, undefined);
|
||||
|
||||
var frozen_cpus: std.atomic.Value(u32) = .init(0);
|
||||
|
||||
/// Call a function on another CPU.
|
||||
/// The function will be executed synchronously, i.e this will block until
|
||||
/// the function finishes running. The callback is called with the sender cpu
|
||||
@@ -63,6 +65,10 @@ pub fn unicast(
|
||||
ke.ipl.lower(ipl);
|
||||
}
|
||||
|
||||
/// Call a function on all other CPUs.
|
||||
/// The function will be executed synchronously, i.e this will block until
|
||||
/// the function finishes running. The callback is called with the sender cpu
|
||||
/// and provided argument as arguments.
|
||||
pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void {
|
||||
const ipl = ke.ipl.raise(.Dispatch);
|
||||
const curcpu = percpu.local();
|
||||
@@ -91,6 +97,28 @@ pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void
|
||||
ke.ipl.lower(ipl);
|
||||
}
|
||||
|
||||
/// Freeze all other CPUs.
|
||||
/// Called at IPL >= Dispatch.
|
||||
pub fn freeze_cpus() void {
|
||||
frozen_cpus.store(1, .monotonic);
|
||||
|
||||
for (0..ke.ncpus) |i| {
|
||||
if (i == ke.cpu.current()) continue;
|
||||
const remote = percpu.remote(@intCast(i));
|
||||
remote.pending.set(ke.cpu.current(), .monotonic);
|
||||
|
||||
const state = remote.state.swap(.Pending, .release);
|
||||
|
||||
if (state == .Idle) {
|
||||
pl.send_ipi(@intCast(i));
|
||||
}
|
||||
}
|
||||
|
||||
while (frozen_cpus.load(.monotonic) != ke.ncpus) {
|
||||
std.atomic.spinLoopHint();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipi_handler() void {
|
||||
const curcpu = percpu.local();
|
||||
|
||||
@@ -105,6 +133,15 @@ pub fn ipi_handler() void {
|
||||
.monotonic,
|
||||
);
|
||||
|
||||
if (frozen_cpus.load(.monotonic) != 0) {
|
||||
// We have been requested to freeze, ack and do it now.
|
||||
_ = frozen_cpus.fetchAdd(1, .monotonic);
|
||||
|
||||
while (true) {
|
||||
ki.impl.halt();
|
||||
}
|
||||
}
|
||||
|
||||
if (val != null) {
|
||||
// CAS failed.
|
||||
return;
|
||||
|
||||
+31
-5
@@ -71,24 +71,50 @@ fn walk_stack_frame(base: usize) void {
|
||||
}
|
||||
|
||||
pub var panic_lock: ke.SpinLock = .init();
|
||||
var crash_count: std.atomic.Value(u8) = .init(0);
|
||||
|
||||
pub fn panic_with_frame(
|
||||
msg: []const u8,
|
||||
frame: usize,
|
||||
) noreturn {
|
||||
std.log.err("KERNEL PANIC: {s} on CPU {}, curthread is {*}", .{ msg, ke.cpu.current(), ki.sched.percpu.local().current_thread.? });
|
||||
_ = ki.impl.disable_interrupts();
|
||||
|
||||
std.log.info("Crash count is {} on cpu {}", .{ crash_count.load(.monotonic), ke.cpu.current() });
|
||||
|
||||
if (crash_count.fetchAdd(1, .monotonic) != 0) {
|
||||
std.log.err("Recursive panic from CPU {}", .{ke.cpu.current()});
|
||||
// Another CPU has already crashed, just freeze manually right now.
|
||||
|
||||
while (true) {
|
||||
ki.impl.halt();
|
||||
}
|
||||
}
|
||||
|
||||
// We're the first one who actually crashed, that means we get to handle
|
||||
// things like dumping the system info and freezing other CPUs. Start by
|
||||
// doing the freeze.
|
||||
ki.ipi.freeze_cpus();
|
||||
|
||||
_ = ke.ipl.raise(.High);
|
||||
|
||||
std.log.err("KERNEL PANIC: {s} on CPU {}, curthread is {*}", .{
|
||||
msg,
|
||||
ke.cpu.current(),
|
||||
ki.sched.percpu.local().current_thread.?,
|
||||
});
|
||||
|
||||
std.log.err("Stack trace:", .{});
|
||||
|
||||
walk_stack_frame(frame);
|
||||
|
||||
panic_lock.release_no_ipl();
|
||||
|
||||
while (true) {}
|
||||
while (true) {
|
||||
ki.impl.halt();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panic(
|
||||
msg: []const u8,
|
||||
_: ?usize,
|
||||
) noreturn {
|
||||
panic_lock.acquire_no_ipl();
|
||||
panic_with_frame(msg, @frameAddress());
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ const ImplSchema = struct {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Halt the CPU. This is called on crashes.
|
||||
pub fn halt() void {}
|
||||
|
||||
/// Restore the state of interrupts.
|
||||
pub fn restore_interrupts(state: bool) void {
|
||||
_ = state;
|
||||
|
||||
Reference in New Issue
Block a user