"Axel Dörfler" <axeld@xxxxxxxxxxxxxxxx> wrote: > Jan Klötzke <jan.kloetzke@xxxxxxxxxx> wrote: > > "Axel Dörfler" <axeld@xxxxxxxxxxxxxxxx> wrote: > > Good point. That's certainly a problem with the chosen approach. > > There is a light at the end of the tunnel, though. We do have a minimal > keyboard interrupt handler in arch_debug_console.c - you could change > int.c in such a way that it will install that handler again after the > PS/2 interrupt is unused again. > This way, it would work even without a running input_server (but then > not for USB keyboards). I would think that's acceptable, though. I looked into it but I don't have a good idea yet on how to use and integrate it with the emergency module. At least not at the moment. I'll leave it for the moment as it is... > > While I do agree in general I made the halting optional only for the > > "show > > backtraces on all CPU's" feature. I thought it would lock up on SMP > > systems > > because the "sc" KDL command is broadcasted to all CPU's via ICI > > (call_all_cpus()) and would then again try to lock all CPU's also via > > ICI's. > > So all CPU's try to lock each other. But quite frankly I'm not sure > > anymore > > that there is really a problem after digging in the code. > > Unfortunately I > > have no SMP system to test... > > I'd be glad to check it out for you :-) > But if all CPUs are in the kernel debugger, anyway, maybe it isn't that > bad after all. At least I wouldn't mind applying your patch now as is > if you like. Great. :-) I removed the optional locking and fixed a bug which caused a deadlock when a page fault happened while executing the KDL command. I attached the revised patches #1 and #2. Patches #3 and #4 are not affected. /Jan
From 06230c8023c48853bc6df8b2d1356319e96877a3 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Jan=20Kl=C3=B6tzke?= <jan.kloetzke@xxxxxxxxxx> Date: Sun, 22 Jun 2008 12:44:20 +0200 Subject: [PATCH 1/4] Allow non-interactive execution of KDL commands * Add kernel_debugger_exec() which allows to execute a single command * Route the output of the non-interactive command to syslog too --- headers/os/drivers/KernelExport.h | 1 + src/system/kernel/debug/debug.cpp | 138 ++++++++++++++++++------- src/system/kernel/debug/debug_commands.cpp | 2 +- src/system/kernel/debug/debug_output_filter.h | 7 +- 4 files changed, 110 insertions(+), 38 deletions(-) diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 3a88928..8b76534 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -164,6 +164,7 @@ extern bool set_dprintf_enabled(bool new_state); extern void panic(const char *format, ...) _PRINTFLIKE(1, 2); extern void kernel_debugger(const char *message); +extern void kernel_debugger_exec(const char *command); extern uint64 parse_expression(const char *string); extern int add_debugger_command(char *name, debugger_command_hook hook, char *help); diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index 08ee466..82e25b7 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -70,7 +70,10 @@ static const char* sCurrentKernelDebuggerMessage; static char sOutputBuffer[OUTPUT_BUFFER_SIZE]; static char sLastOutputBuffer[OUTPUT_BUFFER_SIZE]; static DebugOutputFilter* sDebugOutputFilter = NULL; +DebugOutputFilter *gCurrentDebugOutputFilter = NULL; DefaultDebugOutputFilter gDefaultDebugOutputFilter; +ExecDebugOutputFilter gExecDebugOutputFilter; +static vint32 sInDebugger = 0; static void flush_pending_repeats(void); static void check_pending_repeats(void *data, int iter); @@ -92,6 +95,7 @@ static int32 sCurrentLine = 0; #define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) +static void syslog_write(const char *text, int32 length); // #pragma mark - DebugOutputFilter @@ -142,6 +146,18 @@ DefaultDebugOutputFilter::Print(const char* format, va_list args) } +void +ExecDebugOutputFilter::PrintString(const char* string) +{ + if (sSerialDebugEnabled) + arch_debug_serial_puts(string); + if (sBlueScreenEnabled || sDebugScreenEnabled) + blue_screen_puts(string); + if (sSyslogOutputEnabled) + syslog_write(string, strlen(string)); +} + + // #pragma mark - @@ -178,7 +194,8 @@ kputs(const char *s) void kputs_unfiltered(const char *s) { - gDefaultDebugOutputFilter.PrintString(s); + if (gCurrentDebugOutputFilter) + gCurrentDebugOutputFilter->PrintString(s); } @@ -646,9 +663,6 @@ kgets(char *buffer, int length) static void kernel_debugger_loop(void) { - int32 previousCPU = sDebuggerOnCPU; - sDebuggerOnCPU = smp_get_current_cpu(); - // set a few temporary debug variables if (struct thread* thread = thread_get_current_thread()) { set_debug_variable("_thread", (uint64)(addr_t)thread); @@ -700,8 +714,6 @@ kernel_debugger_loop(void) if (++sCurrentLine >= HISTORY_SIZE) sCurrentLine = 0; } - - sDebuggerOnCPU = previousCPU; } @@ -907,6 +919,50 @@ call_modules_hook(bool enter) } +static cpu_status +debugger_halt_cpus(void) +{ + cpu_status state; + + state = disable_interrupts(); + while (atomic_add(&sInDebugger, 1) > 0) { + // The debugger is already running, find out where... + if (sDebuggerOnCPU != smp_get_current_cpu()) { + // Some other CPU must have entered the debugger and tried to halt + // us. Process ICIs to ensure we get the halt request. Then we are + // blocking there until everyone leaves the debugger and we can + // try to enter it again. + atomic_add(&sInDebugger, -1); + smp_intercpu_int_handler(); + } else { + // We are re-entering the debugger on the same CPU. + break; + } + } + + if (sDebuggerOnCPU != smp_get_current_cpu() && smp_get_num_cpus() > 1) { + // First entry on a MP system, send a halt request to all of the other + // CPUs. Should they try to enter the debugger they will be cought in + // the loop above. + smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, + (void *)&sInDebugger, SMP_MSG_FLAG_SYNC); + } + + sDebuggerOnCPU = smp_get_current_cpu(); + + return state; +} + + +static void +debugger_resume_cpus(cpu_status state) +{ + if (atomic_add(&sInDebugger, -1) == 1) + sDebuggerOnCPU = -1; + restore_interrupts(state); +} + + // #pragma mark - private kernel API @@ -927,7 +983,7 @@ debug_stop_screen_debug_output(void) bool debug_debugger_running(void) { - return sDebuggerOnCPU != -1; + return sInDebugger > 0; } @@ -980,6 +1036,7 @@ status_t debug_init(kernel_args *args) { new(&gDefaultDebugOutputFilter) DefaultDebugOutputFilter; + new(&gExecDebugOutputFilter) ExecDebugOutputFilter; debug_paranoia_init(); return arch_debug_console_init(args); @@ -1095,43 +1152,21 @@ panic(const char *format, ...) void kernel_debugger(const char *message) { - static vint32 inDebugger = 0; cpu_status state; bool dprintfState; - state = disable_interrupts(); - while (atomic_add(&inDebugger, 1) > 0) { - // The debugger is already running, find out where... - if (sDebuggerOnCPU != smp_get_current_cpu()) { - // Some other CPU must have entered the debugger and tried to halt - // us. Process ICIs to ensure we get the halt request. Then we are - // blocking there until everyone leaves the debugger and we can - // try to enter it again. - atomic_add(&inDebugger, -1); - smp_intercpu_int_handler(); - } else { - // We are re-entering the debugger on the same CPU. - break; - } - } + state = debugger_halt_cpus(); arch_debug_save_registers(&dbg_register_file[smp_get_current_cpu()][0]); dprintfState = set_dprintf_enabled(true); - if (sDebuggerOnCPU != smp_get_current_cpu() && smp_get_num_cpus() > 1) { - // First entry on a MP system, send a halt request to all of the other - // CPUs. Should they try to enter the debugger they will be cought in - // the loop above. - smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, - (void *)&inDebugger, SMP_MSG_FLAG_SYNC); - } - if (sBlueScreenOutput) { if (blue_screen_enter(false) == B_OK) sBlueScreenEnabled = true; } sDebugOutputFilter = &gDefaultDebugOutputFilter; + gCurrentDebugOutputFilter = sDebugOutputFilter; if (message) kprintf("PANIC: %s\n", message); @@ -1149,15 +1184,43 @@ kernel_debugger(const char *message) set_dprintf_enabled(dprintfState); sDebugOutputFilter = NULL; + gCurrentDebugOutputFilter = NULL; sBlueScreenEnabled = false; - atomic_add(&inDebugger, -1); - restore_interrupts(state); + + debugger_resume_cpus(state); // ToDo: in case we change dbg_register_file - don't we want to restore it? } +void +kernel_debugger_exec(const char *command) +{ + cpu_status state; + bool dprintfState; + + state = debugger_halt_cpus(); + + dprintfState = set_dprintf_enabled(true); + arch_debug_save_registers(&dbg_register_file[smp_get_current_cpu()][0]); + sDebugOutputFilter = &gExecDebugOutputFilter; + gCurrentDebugOutputFilter = sDebugOutputFilter; + sCurrentKernelDebuggerMessage = NULL; + + // sort the commands + sort_debugger_commands(); + + evaluate_debug_command(command); + + set_dprintf_enabled(dprintfState); + sDebugOutputFilter = NULL; + gCurrentDebugOutputFilter = NULL; + + debugger_resume_cpus(state); +} + + bool set_dprintf_enabled(bool newState) { @@ -1321,9 +1384,12 @@ void kprintf_unfiltered(const char *format, ...) { va_list args; - va_start(args, format); - gDefaultDebugOutputFilter.Print(format, args); - va_end(args); + + if (gCurrentDebugOutputFilter) { + va_start(args, format); + gCurrentDebugOutputFilter->Print(format, args); + va_end(args); + } } diff --git a/src/system/kernel/debug/debug_commands.cpp b/src/system/kernel/debug/debug_commands.cpp index ea42af7..111a5a5 100644 --- a/src/system/kernel/debug/debug_commands.cpp +++ b/src/system/kernel/debug/debug_commands.cpp @@ -155,7 +155,7 @@ invoke_pipe_segment(debugger_command_pipe* pipe, int32 index, char* argument) // set debug output DebugOutputFilter* oldFilter = set_debug_output_filter( index == pipe->segment_count - 1 - ? &gDefaultDebugOutputFilter + ? gCurrentDebugOutputFilter : (DebugOutputFilter*)&sPipeOutputFilters[index]); // set last command argument diff --git a/src/system/kernel/debug/debug_output_filter.h b/src/system/kernel/debug/debug_output_filter.h index 7a7ede2..e0dbc39 100644 --- a/src/system/kernel/debug/debug_output_filter.h +++ b/src/system/kernel/debug/debug_output_filter.h @@ -25,8 +25,13 @@ public: virtual void Print(const char* format, va_list args); }; +class ExecDebugOutputFilter : public DefaultDebugOutputFilter { +public: + virtual void PrintString(const char* string); +}; + -extern DefaultDebugOutputFilter gDefaultDebugOutputFilter; +extern DebugOutputFilter *gCurrentDebugOutputFilter; DebugOutputFilter* set_debug_output_filter(DebugOutputFilter* filter); -- 1.5.4.2
From 27f2f83f2ad3ed84fd737e8bb6b8a32ae64b0c20 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Jan=20Kl=C3=B6tzke?= <jan.kloetzke@xxxxxxxxxx> Date: Wed, 18 Jun 2008 22:33:01 +0200 Subject: [PATCH 2/4] Emergency functions module Simple module which provides a "emergency_key" method. This method should be called with the last pressed character of a combination by keyboard drivers, such as "Shift+F12+s". Depending on the passed character the following functions are available * s = Sync disks * b = reBoot * o = Off (shutdown) * t = dump Threads * l = dump Locks * f = print stack Frames from all CPU's --- build/jam/HaikuImage | 2 +- headers/os/drivers/emergency.h | 28 +++++++ src/add-ons/kernel/generic/Jamfile | 1 + src/add-ons/kernel/generic/emergency/Jamfile | 6 ++ src/add-ons/kernel/generic/emergency/emergency.c | 93 ++++++++++++++++++++++ 5 files changed, 129 insertions(+), 1 deletions(-) create mode 100644 headers/os/drivers/emergency.h create mode 100644 src/add-ons/kernel/generic/emergency/Jamfile create mode 100644 src/add-ons/kernel/generic/emergency/emergency.c diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index e59f113..aea4299 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -156,7 +156,7 @@ AddFilesToHaikuImage beos system add-ons kernel debugger AddFilesToHaikuImage beos system add-ons kernel file_systems : $(BEOS_ADD_ONS_FILE_SYSTEMS) ; AddFilesToHaikuImage beos system add-ons kernel generic - : block_io dpc ide_adapter locked_pool mpu401 scsi_periph ; + : block_io dpc emergency ide_adapter locked_pool mpu401 scsi_periph ; AddFilesToHaikuImage beos system add-ons kernel partitioning_systems : intel session ; AddFilesToHaikuImage beos system add-ons kernel interrupt_controllers diff --git a/headers/os/drivers/emergency.h b/headers/os/drivers/emergency.h new file mode 100644 index 0000000..0c42f49 --- /dev/null +++ b/headers/os/drivers/emergency.h @@ -0,0 +1,28 @@ +/* + * Copyright 2008, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _EMERGENCY_H_ +#define _EMERGENCY_H_ + +#include <OS.h> +#include <module.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define B_EMERGENCY_MODULE_NAME "generic/emergency/v1" + +typedef struct emergency_module_info { + module_info info; + + void (*emergency_key)(char key); +} emergency_module_info; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/add-ons/kernel/generic/Jamfile b/src/add-ons/kernel/generic/Jamfile index 617d177..6200f0b 100644 --- a/src/add-ons/kernel/generic/Jamfile +++ b/src/add-ons/kernel/generic/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel generic ; SubInclude HAIKU_TOP src add-ons kernel generic atomizer ; SubInclude HAIKU_TOP src add-ons kernel generic block_io ; SubInclude HAIKU_TOP src add-ons kernel generic dpc ; +SubInclude HAIKU_TOP src add-ons kernel generic emergency ; SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ; SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ; SubInclude HAIKU_TOP src add-ons kernel generic mpu401 ; diff --git a/src/add-ons/kernel/generic/emergency/Jamfile b/src/add-ons/kernel/generic/emergency/Jamfile new file mode 100644 index 0000000..abf115c --- /dev/null +++ b/src/add-ons/kernel/generic/emergency/Jamfile @@ -0,0 +1,6 @@ +SubDir HAIKU_TOP src add-ons kernel generic emergency ; + +KernelAddon emergency : + emergency.c +; + diff --git a/src/add-ons/kernel/generic/emergency/emergency.c b/src/add-ons/kernel/generic/emergency/emergency.c new file mode 100644 index 0000000..81a8bb4 --- /dev/null +++ b/src/add-ons/kernel/generic/emergency/emergency.c @@ -0,0 +1,93 @@ +/* + * Copyright 2008, Jan Kloetzke. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include <KernelExport.h> +#include <dpc.h> +#include <stdlib.h> + +#include <emergency.h> + +static void *sQueue; +static dpc_module_info *sDpc; + + +static void +em_sync(void *arg) +{ + sync(); + dprintf("Emergency sync completed\n"); +} + + +static void +em_stack_frames(void *cookie, int cpu) +{ + kernel_debugger_exec("sc"); +} + + +static void +emergency_key(char key) +{ + switch (key) { + case 's': /* Sync */ + sDpc->queue_dpc(sQueue, em_sync, NULL); + break; + case 'b': /* reBoot */ + kernel_debugger_exec("reboot"); + break; + case 'o': /* Off */ + kernel_debugger_exec("shutdown"); + break; + case 't': /* Threads */ + kernel_debugger_exec("threads"); + break; + case 'l': /* Locks */ + kernel_debugger_exec("sems"); + break; + case 'f': /* stack Frames */ + call_all_cpus(em_stack_frames, NULL); + break; + } +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return sDpc->new_dpc_queue(&sQueue, "emergency", B_MAX_PRIORITY); + case B_MODULE_UNINIT: + return sDpc->delete_dpc_queue(sQueue); + + default: + return B_ERROR; + } +} + + +static emergency_module_info sEmergencyModule = { + { + B_EMERGENCY_MODULE_NAME, + 0, + std_ops + }, + + emergency_key +}; + + +module_dependency module_dependencies[] = { + { B_DPC_MODULE_NAME, (module_info **)&sDpc }, + {} +}; + + +module_info *modules[] = { + (module_info *) &sEmergencyModule, + NULL +}; + -- 1.5.4.2