mirror of
https://github.com/rdmsr/zag.git
synced 2026-11-02 08:08:21 +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);
|
return percpu_ptr_for(variable, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn halt() void {
|
||||||
|
asm volatile ("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn percpu_ptr(variable: anytype) @TypeOf(variable) {
|
pub inline fn percpu_ptr(variable: anytype) @TypeOf(variable) {
|
||||||
const offset = asm volatile ("mov %%gs:(%[self]), %[out]"
|
const offset = asm volatile ("mov %%gs:(%[self]), %[out]"
|
||||||
: [out] "=r" (-> u64),
|
: [out] "=r" (-> u64),
|
||||||
|
|||||||
+38
-1
@@ -4,7 +4,7 @@ const r = @import("root");
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const ke = r.ke;
|
const ke = r.ke;
|
||||||
const ki = r.ki;
|
const ki = ke.private;
|
||||||
const pl = r.pl;
|
const pl = r.pl;
|
||||||
|
|
||||||
const State = enum(u8) {
|
const State = enum(u8) {
|
||||||
@@ -31,6 +31,8 @@ const PerCpu = struct {
|
|||||||
|
|
||||||
const percpu = ke.CpuLocal(PerCpu, undefined);
|
const percpu = ke.CpuLocal(PerCpu, undefined);
|
||||||
|
|
||||||
|
var frozen_cpus: std.atomic.Value(u32) = .init(0);
|
||||||
|
|
||||||
/// Call a function on another CPU.
|
/// Call a function on another CPU.
|
||||||
/// The function will be executed synchronously, i.e this will block until
|
/// The function will be executed synchronously, i.e this will block until
|
||||||
/// the function finishes running. The callback is called with the sender cpu
|
/// the function finishes running. The callback is called with the sender cpu
|
||||||
@@ -63,6 +65,10 @@ pub fn unicast(
|
|||||||
ke.ipl.lower(ipl);
|
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 {
|
pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void {
|
||||||
const ipl = ke.ipl.raise(.Dispatch);
|
const ipl = ke.ipl.raise(.Dispatch);
|
||||||
const curcpu = percpu.local();
|
const curcpu = percpu.local();
|
||||||
@@ -91,6 +97,28 @@ pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void
|
|||||||
ke.ipl.lower(ipl);
|
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 {
|
pub fn ipi_handler() void {
|
||||||
const curcpu = percpu.local();
|
const curcpu = percpu.local();
|
||||||
|
|
||||||
@@ -105,6 +133,15 @@ pub fn ipi_handler() void {
|
|||||||
.monotonic,
|
.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) {
|
if (val != null) {
|
||||||
// CAS failed.
|
// CAS failed.
|
||||||
return;
|
return;
|
||||||
|
|||||||
+31
-5
@@ -71,24 +71,50 @@ fn walk_stack_frame(base: usize) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub var panic_lock: ke.SpinLock = .init();
|
pub var panic_lock: ke.SpinLock = .init();
|
||||||
|
var crash_count: std.atomic.Value(u8) = .init(0);
|
||||||
|
|
||||||
pub fn panic_with_frame(
|
pub fn panic_with_frame(
|
||||||
msg: []const u8,
|
msg: []const u8,
|
||||||
frame: usize,
|
frame: usize,
|
||||||
) noreturn {
|
) 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:", .{});
|
std.log.err("Stack trace:", .{});
|
||||||
|
|
||||||
walk_stack_frame(frame);
|
walk_stack_frame(frame);
|
||||||
|
|
||||||
panic_lock.release_no_ipl();
|
while (true) {
|
||||||
|
ki.impl.halt();
|
||||||
while (true) {}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic(
|
pub fn panic(
|
||||||
msg: []const u8,
|
msg: []const u8,
|
||||||
_: ?usize,
|
_: ?usize,
|
||||||
) noreturn {
|
) noreturn {
|
||||||
panic_lock.acquire_no_ipl();
|
|
||||||
panic_with_frame(msg, @frameAddress());
|
panic_with_frame(msg, @frameAddress());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ const ImplSchema = struct {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Halt the CPU. This is called on crashes.
|
||||||
|
pub fn halt() void {}
|
||||||
|
|
||||||
/// Restore the state of interrupts.
|
/// Restore the state of interrupts.
|
||||||
pub fn restore_interrupts(state: bool) void {
|
pub fn restore_interrupts(state: bool) void {
|
||||||
_ = state;
|
_ = state;
|
||||||
|
|||||||
Reference in New Issue
Block a user