diff --git a/kernel/include/assert.h b/kernel/include/assert.h index daec8784..62b12681 100644 --- a/kernel/include/assert.h +++ b/kernel/include/assert.h @@ -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 \ No newline at end of file diff --git a/kernel/include/panic/Panic.h b/kernel/include/panic/Panic.h new file mode 100644 index 00000000..182a2e46 --- /dev/null +++ b/kernel/include/panic/Panic.h @@ -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) \ No newline at end of file diff --git a/kernel/src/interrupts/Entry.cpp b/kernel/src/interrupts/Entry.cpp index d3ad1133..30d5a6e8 100644 --- a/kernel/src/interrupts/Entry.cpp +++ b/kernel/src/interrupts/Entry.cpp @@ -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,22 +16,24 @@ 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) { - 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); - kinfoln("Stack trace:"); + Interrupts::disable(); - StackTracer tracer(context->rbp); - tracer.trace_with_ip(context->rip); - if (context->cs == 0x8) { PANIC("Fatal: GPF in kernel task"); } + 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); + kinfoln("Stack trace:"); + + StackTracer tracer(context->rbp); + tracer.trace_with_ip(context->rip); 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); - kinfoln("Stack trace:"); - StackTracer tracer(context->rbp); - tracer.trace_with_ip(context->rip); - - if (context->cs == 0x8) { PANIC("Fatal: Page fault in kernel task"); } + 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); + 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(); diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 8dbde7f6..7222d079 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -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" diff --git a/kernel/src/misc/stack.cpp b/kernel/src/misc/stack.cpp index 9b803320..90b8e55f 100644 --- a/kernel/src/misc/stack.cpp +++ b/kernel/src/misc/stack.cpp @@ -1,9 +1,9 @@ #define MODULE "stack" -#include "assert.h" +#include "panic/Panic.h" #include extern "C" void __stack_chk_fail() { - PANIC("Stack smashing detected"); + panic("Stack smashing detected"); } \ No newline at end of file diff --git a/kernel/src/panic/Panic.asm b/kernel/src/panic/Panic.asm new file mode 100644 index 00000000..c3d1e70f --- /dev/null +++ b/kernel/src/panic/Panic.asm @@ -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 \ No newline at end of file diff --git a/kernel/src/panic/Panic.cpp b/kernel/src/panic/Panic.cpp new file mode 100644 index 00000000..8c3e9c54 --- /dev/null +++ b/kernel/src/panic/Panic.cpp @@ -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); +} \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index d3a046c4..3eb5f7a3 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -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)