add a proper kernel panic
This commit is contained in:
parent
6fc7608c35
commit
aee4e55fdd
@ -34,16 +34,6 @@
|
||||
else { __call_assert_fail("TODO at %s, line %d: %s", __FILE__, __LINE__, message); } \
|
||||
} while (0)
|
||||
|
||||
#define PANIC(message) \
|
||||
do { \
|
||||
Task* cur_task = Scheduler::current_task(); \
|
||||
if (cur_task) \
|
||||
{ \
|
||||
__call_assert_fail("PANIC in task %ld at %s, line %d: %s", cur_task->id, __FILE__, __LINE__, message); \
|
||||
} \
|
||||
else { __call_assert_fail("PANIC at %s, line %d: %s", __FILE__, __LINE__, message); } \
|
||||
} while (0)
|
||||
|
||||
#ifdef ___weird_hack_to_put_something_at_end_of_file
|
||||
#undef ___weird_hack_to_put_something_at_end_of_file
|
||||
#endif
|
17
kernel/include/panic/Panic.h
Normal file
17
kernel/include/panic/Panic.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "interrupts/Context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
[[noreturn]] void __do_int_panic(Context* context, const char* file, int line, const char* message);
|
||||
[[noreturn]] void __do_panic(Context* context, const char* message);
|
||||
|
||||
[[noreturn]] void __panic(const char* message);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define panic(message) asm volatile("cli\npush $16\npushq %%rsp\npushfq\npush $8\ncall __panic" : : "D"(message))
|
||||
#define int_panic(context, message) __do_int_panic(context, __FILE__, __LINE__, message)
|
@ -6,6 +6,7 @@
|
||||
#include "interrupts/Interrupts.h"
|
||||
#include "log/Log.h"
|
||||
#include "misc/hang.h"
|
||||
#include "panic/Panic.h"
|
||||
#include "std/stdio.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include "trace/StackTracer.h"
|
||||
@ -15,12 +16,17 @@ extern "C" void common_handler(Context* context)
|
||||
ASSERT(Interrupts::is_in_handler());
|
||||
if (context->number >= 0x20 && context->number < 0x30)
|
||||
{
|
||||
Interrupts::ensure_handler(); // restore the "in interrupt flag" if an interrupt happened in the middle of this
|
||||
Interrupts::ensure_handler(); // restore the "in-interrupt flag" if an interrupt happened in the middle of this
|
||||
// one
|
||||
IRQ::interrupt_handler(context);
|
||||
return;
|
||||
}
|
||||
if (context->number == 13)
|
||||
{
|
||||
Interrupts::disable();
|
||||
|
||||
if (context->cs == 0x8) { int_panic(context, "GPF in kernel task"); }
|
||||
else
|
||||
{
|
||||
kerrorln("General protection fault at RIP %lx, cs %ld, ss %ld, RSP %lx, error code %ld", context->rip,
|
||||
context->cs, context->ss, context->rsp, context->error_code);
|
||||
@ -28,9 +34,6 @@ extern "C" void common_handler(Context* context)
|
||||
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
if (context->cs == 0x8) { PANIC("Fatal: GPF in kernel task"); }
|
||||
else
|
||||
{
|
||||
Interrupts::ensure_handler();
|
||||
Scheduler::task_misbehave(context);
|
||||
}
|
||||
@ -38,30 +41,22 @@ extern "C" void common_handler(Context* context)
|
||||
if (context->number == 14)
|
||||
{
|
||||
Interrupts::disable();
|
||||
kerrorln("Page fault in %s (RIP %lx), while trying to access %lx, error code %ld",
|
||||
context->cs == 8 ? "ring 0" : "ring 3", context->rip, context->cr2, context->error_code);
|
||||
|
||||
if (context->cs == 0x8) { int_panic(context, "Page fault in kernel task"); }
|
||||
else
|
||||
{
|
||||
kerrorln("Page fault in ring 3 (RIP %lx), while trying to access %lx, error code %ld", context->rip,
|
||||
context->cr2, context->error_code);
|
||||
kinfoln("Stack trace:");
|
||||
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
|
||||
if (context->cs == 0x8) { PANIC("Fatal: Page fault in kernel task"); }
|
||||
else
|
||||
{
|
||||
Interrupts::ensure_handler();
|
||||
Scheduler::task_misbehave(context);
|
||||
}
|
||||
}
|
||||
if (context->number == 8)
|
||||
{
|
||||
kerrorln("Double fault, halting");
|
||||
kinfoln("Stack trace:");
|
||||
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
|
||||
hang();
|
||||
}
|
||||
if (context->number == 8) { int_panic(context, "Double fault, halting"); }
|
||||
if (context->number == 48)
|
||||
{
|
||||
Interrupts::ensure_handler();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "memory/VMM.h"
|
||||
#include "misc/PCITypes.h"
|
||||
#include "misc/reboot.h"
|
||||
#include "panic/Panic.h"
|
||||
#include "rand/Mersenne.h"
|
||||
#include "render/Framebuffer.h"
|
||||
#include "render/TextRenderer.h"
|
||||
|
@ -1,9 +1,9 @@
|
||||
#define MODULE "stack"
|
||||
|
||||
#include "assert.h"
|
||||
#include "panic/Panic.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" void __stack_chk_fail()
|
||||
{
|
||||
PANIC("Stack smashing detected");
|
||||
panic("Stack smashing detected");
|
||||
}
|
34
kernel/src/panic/Panic.asm
Normal file
34
kernel/src/panic/Panic.asm
Normal file
@ -0,0 +1,34 @@
|
||||
extern __do_panic
|
||||
global __panic
|
||||
|
||||
__panic:
|
||||
push BYTE 0 ; interrupt number
|
||||
push BYTE 0 ; error code
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rbp
|
||||
push rdi
|
||||
push rsi
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov r8, cr2
|
||||
push r8
|
||||
|
||||
mov rsi, rdi
|
||||
mov rdi, rsp
|
||||
|
||||
call __do_panic
|
||||
|
||||
cli
|
||||
loop:
|
||||
hlt
|
||||
jmp loop
|
75
kernel/src/panic/Panic.cpp
Normal file
75
kernel/src/panic/Panic.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#define MODULE "panic"
|
||||
|
||||
#include "panic/Panic.h"
|
||||
#include "interrupts/IDT.h"
|
||||
#include "io/PIC.h"
|
||||
#include "log/Log.h"
|
||||
#include "misc/MSR.h"
|
||||
#include "std/stdio.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include "trace/StackTracer.h"
|
||||
|
||||
static void dump_registers(Context* context)
|
||||
{
|
||||
printf("-- Registers: \n");
|
||||
printf("rax: %lx, rbx: %lx, rcx: %lx, rdx: %lx\n", context->rax, context->rbx, context->rcx, context->rdx);
|
||||
printf("rsi: %lx, rdi: %lx, rsp: %lx, rbp: %lx\n", context->rsi, context->rdi, context->rsp, context->rbp);
|
||||
printf("r8: %lx, r9: %lx, r10: %lx, r11: %lx\n", context->r8, context->r9, context->r10, context->r11);
|
||||
printf("r12: %lx, r13: %lx, r14: %lx, r15: %lx\n", context->r12, context->r13, context->r14, context->r15);
|
||||
printf("rip: %lx, cs: %lx, ss: %lx\n", context->rip, context->cs, context->ss);
|
||||
printf("rflags: %lx, cr2: %lx\n", context->rflags, context->cr2);
|
||||
printf("ia32_efer: %lx\n", MSR::read_from(IA32_EFER_MSR));
|
||||
}
|
||||
|
||||
[[noreturn]] static void __panic_stub(Context* context)
|
||||
{
|
||||
dump_registers(context);
|
||||
|
||||
printf("-- Stack trace:\n");
|
||||
|
||||
StackTracer tracer(context->rbp);
|
||||
tracer.trace_with_ip(context->rip);
|
||||
|
||||
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.");
|
||||
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
|
||||
extern "C" [[noreturn]] void __do_int_panic(Context* context, const char* file, int line, const char* message)
|
||||
{
|
||||
asm volatile("cli");
|
||||
|
||||
if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi(context->irq_number); }
|
||||
|
||||
Task* task;
|
||||
if ((task = Scheduler::current_task()))
|
||||
{
|
||||
kerrorln("Kernel panic in task %ld, at %s, line %d: %s", task->id, file, line, message);
|
||||
}
|
||||
else { kerrorln("Kernel panic at %s, line %d: %s", file, line, message); }
|
||||
|
||||
__panic_stub(context);
|
||||
}
|
||||
|
||||
extern "C" [[noreturn]] void __do_panic(Context* context, const char* message)
|
||||
{
|
||||
Task* task;
|
||||
if ((task = Scheduler::current_task())) { kerrorln("Kernel panic in task %ld: %s", task->id, message); }
|
||||
else { kerrorln("Kernel panic: %s", message); }
|
||||
|
||||
__panic_stub(context);
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "memory/VMM.h"
|
||||
#include "misc/hang.h"
|
||||
#include "panic/Panic.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
#include "thread/PIT.h"
|
||||
@ -147,7 +148,7 @@ void Scheduler::reap_tasks()
|
||||
do {
|
||||
if (task->state == task->Exited)
|
||||
{
|
||||
if (task == base_task && task == end_task) { PANIC("Last task exited"); }
|
||||
if (task == base_task && task == end_task) { panic("Last task exited"); }
|
||||
else if (task == base_task) { base_task = task->next_task; }
|
||||
else if (task == end_task) { end_task = task->prev_task; }
|
||||
if (!reap_base)
|
||||
|
Loading…
Reference in New Issue
Block a user