diff --git a/headers/private/kernel/boot/kernel_args.h b/headers/private/kernel/boot/kernel_args.h index 1ebd5c1ef4..6f608641b3 100644 --- a/headers/private/kernel/boot/kernel_args.h +++ b/headers/private/kernel/boot/kernel_args.h @@ -82,8 +82,21 @@ typedef struct kernel_args { FixedWidthPointer edid_info; FixedWidthPointer debug_output; + // If keep_debug_output_buffer, points to a ring_buffer, else to a + // simple flat buffer. In either case it stores the debug output from + // the boot loader. + FixedWidthPointer previous_debug_output; + // A flat pointer to a buffer containing the debug output from the + // previous session. May be NULL. uint32 debug_size; + // If keep_debug_output_buffer, the size of the ring buffer, otherwise + // the size of the flat buffer debug_output points to. + uint32 previous_debug_size; + // The size of the buffer previous_debug_output points to. Used as a + // boolean indicator whether to save the previous session's debug output + // until initialized for the kernel. bool keep_debug_output_buffer; + // If true, debug_output is a ring buffer, otherwise a flat buffer. platform_kernel_args platform_args; arch_kernel_args arch_args; diff --git a/src/system/boot/loader/main.cpp b/src/system/boot/loader/main.cpp index c0b8f31490..e0555dcdc4 100644 --- a/src/system/boot/loader/main.cpp +++ b/src/system/boot/loader/main.cpp @@ -39,6 +39,8 @@ main(stage2_args *args) // set debug syslog default #if KDEBUG_ENABLE_DEBUG_SYSLOG gKernelArgs.keep_debug_output_buffer = true; + gKernelArgs.previous_debug_size = true; + // used as a boolean indicator until initialized for the kernel #endif add_stage2_driver_settings(args); diff --git a/src/system/boot/loader/menu.cpp b/src/system/boot/loader/menu.cpp index 8f35f19ce6..9f91397f73 100644 --- a/src/system/boot/loader/menu.cpp +++ b/src/system/boot/loader/menu.cpp @@ -1026,6 +1026,14 @@ debug_menu_toggle_debug_syslog(Menu* menu, MenuItem* item) } +static bool +debug_menu_toggle_previous_debug_syslog(Menu* menu, MenuItem* item) +{ + gKernelArgs.previous_debug_size = item->IsMarked(); + return true; +} + + static bool debug_menu_save_previous_syslog(Menu* menu, MenuItem* item) { @@ -1280,6 +1288,20 @@ add_debug_menu() item->SetHelpText("Enables a special in-memory syslog buffer for this " "session that the boot loader will be able to access after rebooting."); + ring_buffer* syslogBuffer + = (ring_buffer*)gKernelArgs.debug_output.Pointer(); + bool hasPreviousSyslog + = syslogBuffer != NULL && ring_buffer_readable(syslogBuffer) > 0; + if (hasPreviousSyslog) { + menu->AddItem(item = new(nothrow) MenuItem( + "Save syslog from previous session during boot")); + item->SetType(MENU_ITEM_MARKABLE); + item->SetMarked(gKernelArgs.previous_debug_size); + item->SetTarget(&debug_menu_toggle_previous_debug_syslog); + item->SetHelpText("Saves the syslog from the previous Haiku session to " + "/var/log/previous_syslog when booting."); + } + bool currentLogItemVisible = platform_debug_get_log_buffer(NULL) != NULL; if (currentLogItemVisible) { menu->AddSeparatorItem(); @@ -1291,9 +1313,7 @@ add_debug_menu() "Displays the debug info the boot loader has logged."); } - ring_buffer* syslogBuffer - = (ring_buffer*)gKernelArgs.debug_output.Pointer(); - if (syslogBuffer != NULL && ring_buffer_readable(syslogBuffer) > 0) { + if (hasPreviousSyslog) { if (!currentLogItemVisible) menu->AddSeparatorItem(); diff --git a/src/system/boot/platform/bios_ia32/debug.cpp b/src/system/boot/platform/bios_ia32/debug.cpp index 39cfc1f94b..9bbc6dc708 100644 --- a/src/system/boot/platform/bios_ia32/debug.cpp +++ b/src/system/boot/platform/bios_ia32/debug.cpp @@ -172,6 +172,23 @@ void debug_cleanup(void) { if (sDebugSyslogBuffer != NULL) { + // If desired, store the debug syslog data from the previous session for + // the kernel. + size_t bytesReadable = 0; + if (gKernelArgs.previous_debug_size != 0) { + bytesReadable = ring_buffer_readable(sDebugSyslogBuffer); + gKernelArgs.previous_debug_size = bytesReadable; + } + + if (bytesReadable != 0) { + if (uint8* buffer = (uint8*)kernel_args_malloc(bytesReadable)) { + ring_buffer_read(sDebugSyslogBuffer, buffer, bytesReadable); + gKernelArgs.previous_debug_output = buffer; + } else + gKernelArgs.previous_debug_size = 0; + } + + // Prepare the debug syslog buffer for this session. size_t signatureLength = strlen(kDebugSyslogSignature); void* buffer = (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE); diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index da74437805..7e9266dd39 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -13,8 +13,17 @@ #include "blue_screen.h" +#include +#include +#include +#include +#include +#include +#include + #include +#include #include #include #include @@ -39,13 +48,6 @@ #include -#include -#include -#include -#include -#include -#include - #include "debug_builtin_commands.h" #include "debug_commands.h" #include "debug_output_filter.h" @@ -106,6 +108,9 @@ static size_t sSyslogDebuggerOffset = 0; // (relative) buffer offset of the kernel debugger messages of the current // KDL session +static void* sPreviousSessionSyslogBuffer = NULL; +static size_t sPreviousSessionSyslogBufferSize = 0; + static const char* sCurrentKernelDebuggerMessagePrefix; static const char* sCurrentKernelDebuggerMessage; static va_list sCurrentKernelDebuggerMessageArgs; @@ -1406,6 +1411,17 @@ syslog_init_post_vm(struct kernel_args* args) args->debug_size, false); } + // Allocate memory for the previous session's debug syslog output. In + // syslog_init_post_modules() we'll write it back to disk and free it. + if (args->previous_debug_output != NULL) { + sPreviousSessionSyslogBuffer = malloc(args->previous_debug_size); + if (sPreviousSessionSyslogBuffer != NULL) { + sPreviousSessionSyslogBufferSize = args->previous_debug_size; + memcpy(sPreviousSessionSyslogBuffer, args->previous_debug_output, + sPreviousSessionSyslogBufferSize); + } + } + char revisionBuffer[64]; length = snprintf(revisionBuffer, sizeof(revisionBuffer), "Welcome to syslog debug output!\nHaiku revision: %s\n", @@ -1429,6 +1445,28 @@ err1: return status; } +static void +syslog_init_post_modules() +{ + if (sPreviousSessionSyslogBuffer == NULL) + return; + + void* buffer = sPreviousSessionSyslogBuffer; + size_t bufferSize = sPreviousSessionSyslogBufferSize; + sPreviousSessionSyslogBuffer = NULL; + sPreviousSessionSyslogBufferSize = 0; + MemoryDeleter bufferDeleter(buffer); + + int fd = open("/var/log/previous_syslog", O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + dprintf("Failed to open previous syslog file: %s\n", strerror(errno)); + return; + } + + write(fd, buffer, bufferSize); + close(fd); +} static status_t syslog_init(struct kernel_args* args) @@ -1713,7 +1751,7 @@ debug_init_post_settings(struct kernel_args* args) void debug_init_post_modules(struct kernel_args* args) { - void* cookie; + syslog_init_post_modules(); // check for dupped lines every 10/10 second register_kernel_daemon(check_pending_repeats, NULL, 10); @@ -1724,7 +1762,7 @@ debug_init_post_modules(struct kernel_args* args) static const char* kDemanglePrefix = "debugger/demangle/"; - cookie = open_module_list("debugger"); + void* cookie = open_module_list("debugger"); uint32 count = 0; while (count < kMaxDebuggerModules) { char name[B_FILE_NAME_LENGTH];