kernel: Provide more meaningful panic messages for critical failures
This commit is contained in:
parent
e79d4297ea
commit
7cace9a0d7
@ -136,6 +136,11 @@ bool log_text_console_enabled()
|
|||||||
return g_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;
|
static bool g_check_already_failed = false;
|
||||||
|
|
||||||
[[noreturn]] bool __check_failed(SourceLocation location, const char* expr)
|
[[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)
|
if (!g_check_already_failed)
|
||||||
{ // Avoid endlessly failing when trying to report a failed check.
|
{ // Avoid endlessly failing when trying to report a failed check.
|
||||||
g_check_already_failed = true;
|
g_check_already_failed = true;
|
||||||
kerrorln("ERROR: Check failed at %s:%d, in %s: %s", location.file(), location.line(), location.function(),
|
kerrorln("KERNEL PANIC: Check failed at %s:%d, in %s: %s", location.file(), location.line(),
|
||||||
expr);
|
location.function(), expr);
|
||||||
CPU::print_stack_trace();
|
CPU::print_stack_trace();
|
||||||
}
|
}
|
||||||
CPU::efficient_halt();
|
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();
|
||||||
|
}
|
||||||
|
@ -19,7 +19,23 @@ bool log_debug_enabled();
|
|||||||
bool log_serial_enabled();
|
bool log_serial_enabled();
|
||||||
bool log_text_console_enabled();
|
bool log_text_console_enabled();
|
||||||
|
|
||||||
|
void set_text_console_initialized();
|
||||||
|
|
||||||
#define kdbgln(...) log(LogLevel::Debug, __VA_ARGS__)
|
#define kdbgln(...) log(LogLevel::Debug, __VA_ARGS__)
|
||||||
#define kinfoln(...) log(LogLevel::Info, __VA_ARGS__)
|
#define kinfoln(...) log(LogLevel::Info, __VA_ARGS__)
|
||||||
#define kwarnln(...) log(LogLevel::Warn, __VA_ARGS__)
|
#define kwarnln(...) log(LogLevel::Warn, __VA_ARGS__)
|
||||||
#define kerrorln(...) log(LogLevel::Error, __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<T> 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(); \
|
||||||
|
})
|
||||||
|
@ -265,8 +265,8 @@ namespace CPU
|
|||||||
|
|
||||||
void platform_finish_init()
|
void platform_finish_init()
|
||||||
{
|
{
|
||||||
g_io_thread = Scheduler::new_kernel_thread(io_thread, "[x86_64-io]")
|
g_io_thread = mark_critical(Scheduler::new_kernel_thread(io_thread, "[x86_64-io]"),
|
||||||
.expect_value("Could not create the IO background thread!");
|
"Could not create the IO background thread!");
|
||||||
|
|
||||||
remap_pic();
|
remap_pic();
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ void Init::early_init()
|
|||||||
CPU::disable_interrupts();
|
CPU::disable_interrupts();
|
||||||
|
|
||||||
Framebuffer::init();
|
Framebuffer::init();
|
||||||
|
set_text_console_initialized();
|
||||||
|
|
||||||
#ifdef DEBUG_MODE
|
#ifdef DEBUG_MODE
|
||||||
constexpr bool should_log_console = true;
|
constexpr bool should_log_console = true;
|
||||||
@ -40,6 +41,6 @@ void Init::early_init()
|
|||||||
MemoryManager::init();
|
MemoryManager::init();
|
||||||
InitRD::initialize();
|
InitRD::initialize();
|
||||||
|
|
||||||
MemoryManager::protect_kernel_sections().expect_release_value(
|
mark_critical(MemoryManager::protect_kernel_sections(),
|
||||||
"Failed to remap kernel data sections as non-executable / read-only");
|
"Could not remap kernel data sections as non-executable / read-only");
|
||||||
}
|
}
|
||||||
|
@ -89,11 +89,11 @@ void ConsoleDevice::did_press_key(char key)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_temp_input.try_append((u8)key).value();
|
g_temp_input.try_append((u8)key);
|
||||||
|
|
||||||
if (key == '\n')
|
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();
|
g_temp_input.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ void reap_thread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> init()
|
[[noreturn]] void init()
|
||||||
{
|
{
|
||||||
kinfoln("Starting Moon %s, built on %s at %s", MOON_VERSION, __DATE__, __TIME__);
|
kinfoln("Starting Moon %s, built on %s at %s", MOON_VERSION, __DATE__, __TIME__);
|
||||||
|
|
||||||
@ -45,15 +45,17 @@ Result<void> init()
|
|||||||
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
||||||
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
||||||
|
|
||||||
auto root = TRY(TmpFS::FileSystem::create());
|
auto root = mark_critical(TmpFS::FileSystem::create(), "Failed to create initial ramfs");
|
||||||
TRY(VFS::mount_root(root));
|
mark_critical(VFS::mount_root(root), "Failed to mount the initial ramfs as the root filesystem");
|
||||||
TRY(InitRD::populate_vfs());
|
mark_critical(InitRD::populate_vfs(), "Failed to load files from the initial ramdisk");
|
||||||
TRY(DeviceRegistry::init());
|
mark_critical(DeviceRegistry::init(), "Failed to register initial devices");
|
||||||
|
|
||||||
auto init = TRY(VFS::resolve_path("/bin/init", Credentials {}));
|
auto init = mark_critical(VFS::resolve_path("/bin/init", Credentials {}), "Can't find init in the initial ramfs!");
|
||||||
auto init_thread = TRY(Scheduler::new_userspace_thread(init, "/bin/init"));
|
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);
|
Scheduler::set_reap_thread(reap);
|
||||||
|
|
||||||
#ifdef ARCH_X86_64
|
#ifdef ARCH_X86_64
|
||||||
@ -68,13 +70,6 @@ Result<void> init()
|
|||||||
kernel_exit();
|
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()
|
extern "C" [[noreturn]] void _start()
|
||||||
{
|
{
|
||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
@ -85,7 +80,7 @@ extern "C" [[noreturn]] void _start()
|
|||||||
Thread::init();
|
Thread::init();
|
||||||
Scheduler::init();
|
Scheduler::init();
|
||||||
|
|
||||||
Scheduler::new_kernel_thread(init_wrapper, "[kinit]");
|
Scheduler::new_kernel_thread(init, "[kinit]");
|
||||||
|
|
||||||
CPU::platform_finish_init();
|
CPU::platform_finish_init();
|
||||||
|
|
||||||
|
@ -267,8 +267,9 @@ namespace MemoryManager
|
|||||||
|
|
||||||
memset((void*)address, 0, count * ARCH_PAGE_SIZE);
|
memset((void*)address, 0, count * ARCH_PAGE_SIZE);
|
||||||
|
|
||||||
remap(address, count, flags)
|
// This should never fail (we just mapped memory at that address) but we don't want to crash the kernel if it
|
||||||
.expect_value("Wait... we just mapped something but it doesn't exist anymore? Confused.");
|
// does.
|
||||||
|
TRY(remap(address, count, flags));
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ namespace Scheduler
|
|||||||
g_idle.ticks_left = 1;
|
g_idle.ticks_left = 1;
|
||||||
|
|
||||||
// Map some stack for the idle task
|
// Map some stack for the idle task
|
||||||
u64 idle_stack_vm = MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite)
|
u64 idle_stack_vm = mark_critical(MemoryManager::alloc_for_kernel(1, MMU::NoExecute | MMU::ReadWrite),
|
||||||
.expect_value("Error while setting up the idle task, cannot continue");
|
"Failed to allocate stack memory for the CPU idle thread");
|
||||||
|
|
||||||
Stack idle_stack { idle_stack_vm, ARCH_PAGE_SIZE };
|
Stack idle_stack { idle_stack_vm, ARCH_PAGE_SIZE };
|
||||||
g_idle.set_sp(idle_stack.top());
|
g_idle.set_sp(idle_stack.top());
|
||||||
|
Loading…
Reference in New Issue
Block a user