From 7cace9a0d74126b6b94b5ab7f6bafaefe2c66a49 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 17 Jun 2023 19:43:25 +0200 Subject: [PATCH] kernel: Provide more meaningful panic messages for critical failures --- kernel/src/Log.cpp | 25 +++++++++++++++++++++-- kernel/src/Log.h | 16 +++++++++++++++ kernel/src/arch/x86_64/CPU.cpp | 4 ++-- kernel/src/boot/Init.cpp | 5 +++-- kernel/src/fs/devices/ConsoleDevice.cpp | 4 ++-- kernel/src/main.cpp | 27 ++++++++++--------------- kernel/src/memory/MemoryManager.cpp | 5 +++-- kernel/src/thread/Scheduler.cpp | 4 ++-- 8 files changed, 62 insertions(+), 28 deletions(-) diff --git a/kernel/src/Log.cpp b/kernel/src/Log.cpp index 5ea34f29..b2dbdab1 100644 --- a/kernel/src/Log.cpp +++ b/kernel/src/Log.cpp @@ -136,6 +136,11 @@ bool log_text_console_enabled() return g_text_console_enabled; } +void set_text_console_initialized() +{ + g_text_console_initialized = true; +} + static bool g_check_already_failed = false; [[noreturn]] bool __check_failed(SourceLocation location, const char* expr) @@ -145,9 +150,25 @@ static bool g_check_already_failed = false; if (!g_check_already_failed) { // Avoid endlessly failing when trying to report a failed check. g_check_already_failed = true; - kerrorln("ERROR: Check failed at %s:%d, in %s: %s", location.file(), location.line(), location.function(), - expr); + kerrorln("KERNEL PANIC: Check failed at %s:%d, in %s: %s", location.file(), location.line(), + location.function(), expr); CPU::print_stack_trace(); } CPU::efficient_halt(); } + +[[noreturn]] void __critical_error_handler(SourceLocation location, const char* expr, const char* failmsg, + const char* errmsg) +{ + CPU::disable_interrupts(); + if (g_text_console_initialized) g_text_console_enabled = true; + if (!g_check_already_failed) + { // Avoid endlessly failing when trying to report a failed check. + g_check_already_failed = true; + kerrorln("-- KERNEL PANIC: Critical routine \"%s\" failed in %s: %s (%s) --", expr, location.file(), failmsg, + errmsg); + CPU::print_stack_trace(); + kerrorln("-- END KERNEL PANIC --"); + } + CPU::efficient_halt(); +} diff --git a/kernel/src/Log.h b/kernel/src/Log.h index 97f2155d..ac92b64b 100644 --- a/kernel/src/Log.h +++ b/kernel/src/Log.h @@ -19,7 +19,23 @@ bool log_debug_enabled(); bool log_serial_enabled(); bool log_text_console_enabled(); +void set_text_console_initialized(); + #define kdbgln(...) log(LogLevel::Debug, __VA_ARGS__) #define kinfoln(...) log(LogLevel::Info, __VA_ARGS__) #define kwarnln(...) log(LogLevel::Warn, __VA_ARGS__) #define kerrorln(...) log(LogLevel::Error, __VA_ARGS__) + +[[noreturn]] extern void __critical_error_handler(SourceLocation location, const char* expr, const char* failmsg, + const char* errmsg); + +// Mark an expression that returns a Result as critical. If the operation is successful, the Result will be +// unwrapped. If the operation throws an error, however, the kernel will panic, showing the expression, the file in +// which mark_critical() was called, failmsg and the error code. +#define mark_critical(expr, failmsg) \ + ({ \ + auto _expr_rc = (expr); \ + if (!_expr_rc.has_value()) \ + __critical_error_handler(SourceLocation::current(), #expr, failmsg, _expr_rc.error_string()); \ + _expr_rc.release_value(); \ + }) diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp index 4c4e519c..1da8ee53 100644 --- a/kernel/src/arch/x86_64/CPU.cpp +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -265,8 +265,8 @@ namespace CPU void platform_finish_init() { - g_io_thread = Scheduler::new_kernel_thread(io_thread, "[x86_64-io]") - .expect_value("Could not create the IO background thread!"); + g_io_thread = mark_critical(Scheduler::new_kernel_thread(io_thread, "[x86_64-io]"), + "Could not create the IO background thread!"); remap_pic(); diff --git a/kernel/src/boot/Init.cpp b/kernel/src/boot/Init.cpp index 4f291585..f279366e 100644 --- a/kernel/src/boot/Init.cpp +++ b/kernel/src/boot/Init.cpp @@ -27,6 +27,7 @@ void Init::early_init() CPU::disable_interrupts(); Framebuffer::init(); + set_text_console_initialized(); #ifdef DEBUG_MODE constexpr bool should_log_console = true; @@ -40,6 +41,6 @@ void Init::early_init() MemoryManager::init(); InitRD::initialize(); - MemoryManager::protect_kernel_sections().expect_release_value( - "Failed to remap kernel data sections as non-executable / read-only"); + mark_critical(MemoryManager::protect_kernel_sections(), + "Could not remap kernel data sections as non-executable / read-only"); } diff --git a/kernel/src/fs/devices/ConsoleDevice.cpp b/kernel/src/fs/devices/ConsoleDevice.cpp index 594261c2..c9aad225 100644 --- a/kernel/src/fs/devices/ConsoleDevice.cpp +++ b/kernel/src/fs/devices/ConsoleDevice.cpp @@ -89,11 +89,11 @@ void ConsoleDevice::did_press_key(char key) return; } - g_temp_input.try_append((u8)key).value(); + g_temp_input.try_append((u8)key); if (key == '\n') { - g_console_input.append_data(g_temp_input.data(), g_temp_input.size()).value(); + g_console_input.append_data(g_temp_input.data(), g_temp_input.size()); g_temp_input.clear(); } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index fc56ed17..8673fbcd 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -30,7 +30,7 @@ void reap_thread() } } -Result init() +[[noreturn]] void init() { kinfoln("Starting Moon %s, built on %s at %s", MOON_VERSION, __DATE__, __TIME__); @@ -45,15 +45,17 @@ Result init() kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars()); kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars()); - auto root = TRY(TmpFS::FileSystem::create()); - TRY(VFS::mount_root(root)); - TRY(InitRD::populate_vfs()); - TRY(DeviceRegistry::init()); + auto root = mark_critical(TmpFS::FileSystem::create(), "Failed to create initial ramfs"); + mark_critical(VFS::mount_root(root), "Failed to mount the initial ramfs as the root filesystem"); + mark_critical(InitRD::populate_vfs(), "Failed to load files from the initial ramdisk"); + mark_critical(DeviceRegistry::init(), "Failed to register initial devices"); - auto init = TRY(VFS::resolve_path("/bin/init", Credentials {})); - auto init_thread = TRY(Scheduler::new_userspace_thread(init, "/bin/init")); + auto init = mark_critical(VFS::resolve_path("/bin/init", Credentials {}), "Can't find init in the initial ramfs!"); + auto init_thread = + mark_critical(Scheduler::new_userspace_thread(init, "/bin/init"), "Failed to create PID 1 process for init"); - auto reap = Scheduler::new_kernel_thread(reap_thread, "[reap]").release_value(); + auto reap = mark_critical(Scheduler::new_kernel_thread(reap_thread, "[reap]"), + "Failed to create the process reaper kernel thread"); Scheduler::set_reap_thread(reap); #ifdef ARCH_X86_64 @@ -68,13 +70,6 @@ Result init() kernel_exit(); } -[[noreturn]] void init_wrapper() -{ - auto rc = init(); - if (rc.has_error()) kerrorln("Runtime error: %s", rc.error_string()); - kernel_exit(); -} - extern "C" [[noreturn]] void _start() { Init::check_magic(); @@ -85,7 +80,7 @@ extern "C" [[noreturn]] void _start() Thread::init(); Scheduler::init(); - Scheduler::new_kernel_thread(init_wrapper, "[kinit]"); + Scheduler::new_kernel_thread(init, "[kinit]"); CPU::platform_finish_init(); diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index aaddf064..26b75e63 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -267,8 +267,9 @@ namespace MemoryManager memset((void*)address, 0, count * ARCH_PAGE_SIZE); - remap(address, count, flags) - .expect_value("Wait... we just mapped something but it doesn't exist anymore? Confused."); + // This should never fail (we just mapped memory at that address) but we don't want to crash the kernel if it + // does. + TRY(remap(address, count, flags)); return address; } diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 5edb1cd6..de0ba2f6 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -31,8 +31,8 @@ namespace Scheduler g_idle.ticks_left = 1; // Map some stack for the idle task - u64 idle_stack_vm = MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite) - .expect_value("Error while setting up the idle task, cannot continue"); + u64 idle_stack_vm = mark_critical(MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite), + "Failed to allocate stack memory for the CPU idle thread"); Stack idle_stack { idle_stack_vm, ARCH_PAGE_SIZE }; g_idle.set_sp(idle_stack.top());