Kernel: Guard against recursive panics
Previously, when we panicked (page-fault for example) while dumping a kernel panic, it would just loop over and over again. Now, we check if we were already in a panic, and limit the dump: - No stack trace. - Only a few registers. - Only serial (since we can page fault while writing to the framebuffer) This should make recursive panics much more difficult to achieve. If we page-fault while writing to console, we don't even see a panic (not even in serial) and eventually triple-fault. So this patch is actually more user-friendly.
This commit is contained in:
parent
59506b8852
commit
bb00e3c112
@ -13,6 +13,26 @@
|
||||
#include "thread/Scheduler.h"
|
||||
#include "trace/StackTracer.h"
|
||||
|
||||
static bool g_is_in_panic = false;
|
||||
static bool g_is_in_double_panic = false;
|
||||
|
||||
static void panic_prepare_keyboard_triple_fault()
|
||||
{
|
||||
PIC::enable_master(0b11111101); // enable keyboard only
|
||||
PIC::enable_slave(0b11111111);
|
||||
|
||||
IDTR idtr;
|
||||
idtr.limit = 0x0000;
|
||||
idtr.offset = 0x0000;
|
||||
asm volatile(
|
||||
"lidt %0"
|
||||
:
|
||||
: "m"(
|
||||
idtr)); // when an interrupt arrives, triple-fault (the only interrupt that should come is the keyboard one)
|
||||
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void dump_registers(Context* context)
|
||||
{
|
||||
kinfoln("-- Registers:");
|
||||
@ -25,6 +45,32 @@ void dump_registers(Context* context)
|
||||
kinfoln("ia32_efer: %lx", MSR::read_from(IA32_EFER_MSR));
|
||||
}
|
||||
|
||||
void fatal_dump_registers(Context* context)
|
||||
{
|
||||
printf("-- Possibly Relevant Registers:\n");
|
||||
printf("rbp: %lx, rsp: %lx, rip: %lx, cs: %lx, ss: %lx, rflags: %lx, cr2: %lx\n", context->rbp, context->rsp,
|
||||
context->rip, context->cs, context->ss, context->rflags, context->cr2);
|
||||
}
|
||||
|
||||
[[noreturn]] void __panic_fatal_stub(Context* context)
|
||||
{
|
||||
if (context) fatal_dump_registers(context);
|
||||
printf("-- No stack trace available\n");
|
||||
|
||||
KernelLog::enable_log_backend(Backend::Console);
|
||||
KernelLog::toggle_log_backend(
|
||||
Backend::Console); // disable console logging, as we can page fault while writing to the framebuffer.
|
||||
|
||||
Scheduler::current_task()->id = 0; // we're panicking, we don't even care anymore. This is so KernelLog shows
|
||||
// (kernel) instead of (taskname: PID) in the log.
|
||||
|
||||
panic_prepare_keyboard_triple_fault();
|
||||
|
||||
printf("Press any key to restart.\n");
|
||||
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
|
||||
[[noreturn]] void __panic_stub(Context* context)
|
||||
{
|
||||
VMM::switch_back_to_kernel_address_space();
|
||||
@ -50,21 +96,7 @@ void dump_registers(Context* context)
|
||||
}
|
||||
else { kinfoln("-- No stack trace available"); }
|
||||
|
||||
PIC::enable_master(0b11111101); // enable keyboard only
|
||||
PIC::enable_slave(0b11111111);
|
||||
|
||||
IDTR idtr;
|
||||
idtr.limit = 0x0000;
|
||||
idtr.offset = 0x0000;
|
||||
asm volatile(
|
||||
"lidt %0"
|
||||
:
|
||||
: "m"(
|
||||
idtr)); // when an interrupt arrives, triple-fault (the only interrupt that should come is the keyboard one)
|
||||
|
||||
asm volatile("sti");
|
||||
|
||||
kinfoln("Press any key to restart.");
|
||||
panic_prepare_keyboard_triple_fault();
|
||||
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
@ -73,6 +105,22 @@ extern "C" [[noreturn]] bool __do_int_panic(Context* context, const char* file,
|
||||
{
|
||||
asm volatile("cli");
|
||||
|
||||
if (g_is_in_double_panic)
|
||||
{
|
||||
panic_prepare_keyboard_triple_fault();
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
|
||||
if (g_is_in_panic)
|
||||
{
|
||||
g_is_in_double_panic = true;
|
||||
printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line,
|
||||
message);
|
||||
__panic_fatal_stub(context);
|
||||
}
|
||||
|
||||
g_is_in_panic = true;
|
||||
|
||||
KernelLog::enable_log_backend(Backend::Console);
|
||||
|
||||
TextRenderer::reset();
|
||||
@ -95,6 +143,22 @@ extern "C" [[noreturn]] bool __do_panic(const char* file, int line, const char*
|
||||
{
|
||||
asm volatile("cli");
|
||||
|
||||
if (g_is_in_double_panic)
|
||||
{
|
||||
panic_prepare_keyboard_triple_fault();
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
|
||||
if (g_is_in_panic)
|
||||
{
|
||||
g_is_in_double_panic = true;
|
||||
printf("Kernel panic while panicking (showing vital information only) at %s, line %d: %s\n", file, line,
|
||||
message);
|
||||
__panic_fatal_stub(nullptr);
|
||||
}
|
||||
|
||||
g_is_in_panic = true;
|
||||
|
||||
KernelLog::enable_log_backend(Backend::Console);
|
||||
|
||||
TextRenderer::reset();
|
||||
|
Loading…
Reference in New Issue
Block a user