diff --git a/data/settings/kernel/drivers/kernel b/data/settings/kernel/drivers/kernel index df1e9b9a7b..9fa14bc27b 100644 --- a/data/settings/kernel/drivers/kernel +++ b/data/settings/kernel/drivers/kernel @@ -50,5 +50,8 @@ # (system shutdown, battery info, ...) # default is off +#emergency_keys false + # Disables emergency keys (ie. Alt-SysReq+*), enabled by default + #acpi true # ACPI support, off by default diff --git a/headers/private/kernel/debug.h b/headers/private/kernel/debug.h index cd92ffa28f..c0e959c751 100644 --- a/headers/private/kernel/debug.h +++ b/headers/private/kernel/debug.h @@ -28,7 +28,11 @@ #endif #define ASSERT_ALWAYS(x) \ - do { if (!(x)) { panic("ASSERT FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0) + do { \ + if (!(x)) { \ + panic("ASSERT FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); \ + } \ + } while (0) #define ASSERT_ALWAYS_PRINT(x, format...) \ do { \ @@ -66,10 +70,13 @@ struct debugger_module_info { void (*enter_debugger)(void); void (*exit_debugger)(void); - // io hooks + // I/O hooks int (*debugger_puts)(const char *str, int32 length); int (*debugger_getchar)(void); // TODO: add hooks for tunnelling gdb ? + + // Misc. hooks + bool (*emergency_key_pressed)(char key); }; struct debugger_demangle_module_info { @@ -113,7 +120,8 @@ extern void debug_stop_screen_debug_output(void); extern void debug_set_page_fault_info(addr_t faultAddress, addr_t pc, uint32 flags); extern debug_page_fault_info* debug_get_page_fault_info(); -extern void debug_trap_cpu_in_kdl(bool returnIfHandedOver); +extern void debug_trap_cpu_in_kdl(bool returnIfHandedOver); +extern bool debug_emergency_key_pressed(char key); extern char kgetc(void); extern void kputs(const char *string); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c index 6199aa581a..442561a34e 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Haiku, Inc. + * Copyright 2004-2009 Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors (in chronological order): @@ -10,6 +10,7 @@ /*! PS/2 bus manager */ + #include #include "ps2_common.h" @@ -277,32 +278,33 @@ ps2_interrupt(void* cookie) return B_UNHANDLED_INTERRUPT; if (atomic_get(&sIgnoreInterrupts)) { - TRACE("ps2: ps2_interrupt ignoring, ctrl 0x%02x (%s)\n", ctrl, (ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb"); + TRACE("ps2: ps2_interrupt ignoring, ctrl 0x%02x (%s)\n", ctrl, + (ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb"); return B_HANDLED_INTERRUPT; } data = ps2_read_data(); - if (ctrl & PS2_STATUS_AUX_DATA) { + if ((ctrl & PS2_STATUS_AUX_DATA) != 0) { uint8 idx; if (gActiveMultiplexingEnabled) { idx = ctrl >> 6; error = (ctrl & 0x04) != 0; - TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (mouse %d)\n", ctrl, data, idx); + TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (mouse %d)\n", + ctrl, data, idx); } else { idx = 0; error = (ctrl & 0xC0) != 0; - TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (aux)\n", ctrl, data); + TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (aux)\n", ctrl, + data); } dev = &ps2_device[PS2_DEVICE_MOUSE + idx]; } else { - TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (keyb)\n", ctrl, data); + TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (keyb)\n", ctrl, + data); + dev = &ps2_device[PS2_DEVICE_KEYB]; error = (ctrl & 0xC0) != 0; - - // TODO: remove me again; let us drop into the kernel debugger with F12 - if (data == 88) - panic("keyboard requested halt.\n"); } dev->history[1] = dev->history[0]; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c index dd249e43d3..b6932c449c 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Haiku, Inc. + * Copyright 2004-2009 Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors (in chronological order): @@ -10,11 +10,16 @@ /*! PS/2 keyboard device driver */ + +#include + +#include +#include + #include "ps2_service.h" #include "kb_mouse_driver.h" #include "packet_buffer.h" -#include #define KEY_BUFFER_SIZE 100 // we will buffer 100 key strokes before we start dropping them @@ -26,7 +31,11 @@ enum { } leds_status; enum { - EXTENDED_KEY = 0xe0, + EXTENDED_KEY = 0xe0, + + LEFT_ALT_KEY = 0x38, + RIGHT_ALT_KEY = 0xb8, + SYS_REQ_KEY = 0x54 }; @@ -35,8 +44,9 @@ static sem_id sKeyboardSem; static struct packet_buffer *sKeyBuffer; static bool sIsExtended = false; -static int32 sKeyboardRepeatRate; -static bigtime_t sKeyboardRepeatDelay; +static int32 sKeyboardRepeatRate; +static bigtime_t sKeyboardRepeatDelay; + static status_t set_leds(led_info *ledInfo) @@ -52,7 +62,8 @@ set_leds(led_info *ledInfo) if (ledInfo->caps_lock) leds |= LED_CAPS; - return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0); + return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], + PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0); } @@ -84,13 +95,20 @@ set_typematic(int32 rate, bigtime_t delay) else value |= 0 << 5; - return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_TYPEMATIC, &value, 1, NULL, 0); + return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], + PS2_CMD_KEYBOARD_SET_TYPEMATIC, &value, 1, NULL, 0); } static int32 keyboard_handle_int(ps2_dev *dev) { + enum emergency_keys { + EMERGENCY_LEFT_ALT = 0x01, + EMERGENCY_RIGHT_ALT = 0x02, + EMERGENCY_SYS_REQ = 0x04, + }; + static int emergencyKeyStatus = 0; at_kbd_io keyInfo; uint8 scancode = dev->history[0].data; @@ -107,7 +125,7 @@ keyboard_handle_int(ps2_dev *dev) // TRACE("scancode: %x\n", scancode); - if (scancode & 0x80) { + if ((scancode & 0x80) != 0) { keyInfo.is_keydown = false; scancode &= 0x7f; } else @@ -118,12 +136,33 @@ keyboard_handle_int(ps2_dev *dev) sIsExtended = false; } + // Handle emergency keys + if (scancode == LEFT_ALT_KEY || scancode == RIGHT_ALT_KEY) { + // left or right alt-key pressed + if (keyInfo.is_keydown) { + emergencyKeyStatus |= scancode == LEFT_ALT_KEY + ? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT; + } else { + emergencyKeyStatus &= ~(scancode == LEFT_ALT_KEY + ? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT); + } + } else if (scancode == SYS_REQ_KEY) { + if (keyInfo.is_keydown) + emergencyKeyStatus |= EMERGENCY_SYS_REQ; + else + emergencyKeyStatus &= EMERGENCY_SYS_REQ; + } else if (emergencyKeyStatus > EMERGENCY_SYS_REQ + && debug_emergency_key_pressed(kUnshiftedKeymap[scancode])) + return B_HANDLED_INTERRUPT; + keyInfo.timestamp = dev->history[0].time; keyInfo.scancode = scancode; - if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, sizeof(keyInfo)) == 0) { - // If there is no space left in the buffer, we drop this key stroke. We avoid - // dropping old key strokes, to not destroy what already was typed. + if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, + sizeof(keyInfo)) == 0) { + // If there is no space left in the buffer, we drop this key stroke. We + // avoid dropping old key strokes, to not destroy what already was + // typed. return B_HANDLED_INTERRUPT; } @@ -150,11 +189,14 @@ read_keyboard_packet(at_kbd_io *packet) } if (packet_buffer_read(sKeyBuffer, (uint8 *)packet, sizeof(*packet)) == 0) { - TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n", strerror(status)); + TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n", + strerror(status)); return B_ERROR; } - TRACE("ps2: read_keyboard_packet: scancode: %x, keydown: %s\n", packet->scancode, packet->is_keydown ? "true" : "false"); + TRACE("ps2: read_keyboard_packet: scancode: %x, keydown: %s\n", + packet->scancode, packet->is_keydown ? "true" : "false"); + return B_OK; } @@ -184,13 +226,16 @@ probe_keyboard(void) // return B_ERROR; // } - status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, 0, &data, 1); + status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, + 0, &data, 1); if (status != B_OK || data != 0xaa) { - INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", status, data); + INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", + status, data); return B_ERROR; } - // default settings after keyboard reset: delay = 0x01 (500 ms), rate = 0x0b (10.9 chr/sec) + // default settings after keyboard reset: delay = 0x01 (500 ms), + // rate = 0x0b (10.9 chr/sec) sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20; sKeyboardRepeatDelay = 500000; @@ -328,24 +373,29 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length) case KB_SET_KEY_REPEATING: { TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n"); - // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds with "ack" (0xFA). - return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, NULL, 0); + // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds + // with "ack" (0xFA). + return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, + NULL, 0); } case KB_SET_KEY_NONREPEATING: { TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n"); - // 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack" (0xFA). - return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0, NULL, 0); + // 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack" + // (0xFA). + return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0, + NULL, 0); } case KB_SET_KEY_REPEAT_RATE: { int32 key_repeat_rate; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n"); - if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate)) < B_OK) + if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate)) + != B_OK) return B_BAD_ADDRESS; - if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) < B_OK) + if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK) return B_ERROR; sKeyboardRepeatRate = key_repeat_rate; return B_OK; @@ -354,16 +404,18 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length) case KB_GET_KEY_REPEAT_RATE: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n"); - return user_memcpy(buffer, &sKeyboardRepeatRate, sizeof(sKeyboardRepeatRate)); + return user_memcpy(buffer, &sKeyboardRepeatRate, + sizeof(sKeyboardRepeatRate)); } case KB_SET_KEY_REPEAT_DELAY: { bigtime_t key_repeat_delay; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n"); - if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay)) < B_OK) + if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay)) + != B_OK) return B_BAD_ADDRESS; - if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) < B_OK) + if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK) return B_ERROR; sKeyboardRepeatDelay = key_repeat_delay; return B_OK; @@ -373,7 +425,8 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length) case KB_GET_KEY_REPEAT_DELAY: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n"); - return user_memcpy(buffer, &sKeyboardRepeatDelay, sizeof(sKeyboardRepeatDelay)); + return user_memcpy(buffer, &sKeyboardRepeatDelay, + sizeof(sKeyboardRepeatDelay)); } case KB_GET_KEYBOARD_ID: @@ -389,6 +442,7 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length) } } + device_hooks gKeyboardDeviceHooks = { keyboard_open, keyboard_close, diff --git a/src/system/kernel/arch/x86/arch_debug_console.c b/src/system/kernel/arch/x86/arch_debug_console.c index e89653f064..779bc2fa47 100644 --- a/src/system/kernel/arch/x86/arch_debug_console.c +++ b/src/system/kernel/arch/x86/arch_debug_console.c @@ -1,8 +1,8 @@ /* - * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de * Copyright 2001, Rob Judd * Copyright 2002, Marcus Overhagen - * Distributed under the terms of the Haiku License. + * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. @@ -52,6 +52,7 @@ enum keycodes { LEFT_CONTROL = 29, LEFT_ALT = 56, + RIGHT_ALT = 58, CURSOR_LEFT = 75, CURSOR_RIGHT = 77, @@ -62,8 +63,8 @@ enum keycodes { PAGE_UP = 73, PAGE_DOWN = 81, - BREAK = 198, // TODO: >= 128 can't be valid DELETE = 83, + SYS_REQ = 84, F12 = 88, }; @@ -108,7 +109,8 @@ static int32 debug_keyboard_interrupt(void *data) { static bool controlPressed = false; - static bool altPressed; + static bool altPressed = false; + static bool sysReqPressed = false; uint8 key; key = in8(PS2_PORT_DATA); @@ -117,8 +119,10 @@ debug_keyboard_interrupt(void *data) if (key & 0x80) { if (key == LEFT_CONTROL) controlPressed = false; - if (key == LEFT_ALT) + else if (key == LEFT_ALT) altPressed = false; + else if (key == SYS_REQ) + sysReqPressed = false; return B_HANDLED_INTERRUPT; } @@ -129,22 +133,22 @@ debug_keyboard_interrupt(void *data) break; case LEFT_ALT: + case RIGHT_ALT: altPressed = true; break; + case SYS_REQ: + sysReqPressed = true; + break; + case DELETE: if (controlPressed && altPressed) arch_cpu_shutdown(true); break; - /* the following code has two possibilities because of issues - * with BeBochs & BeOS (all special keys don't map to anything - * useful, and SYS_REQ does a screen dump in BeOS). - * ToDo: remove these key functions some day... - */ - case F12: - case BREAK: - panic("Keyboard Requested Halt\n"); + default: + if (altPressed && sysReqPressed) + debug_emergency_key_pressed(kUnshiftedKeymap[key]); break; } diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index aa3dca682f..59966bb270 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -1,6 +1,6 @@ /* * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -63,6 +63,7 @@ static bool sBlueScreenEnabled = false; // must always be false on startup static bool sDebugScreenEnabled = false; static bool sBlueScreenOutput = true; +static bool sEmergencyKeysEnabled = true; static spinlock sSpinlock = B_SPINLOCK_INITIALIZER; static int32 sDebuggerOnCPU = -1; @@ -1239,6 +1240,8 @@ debug_init_post_vm(kernel_args* args) "syslog_debug_output", sSyslogOutputEnabled, sSyslogOutputEnabled); sBlueScreenOutput = get_driver_boolean_parameter(handle, "bluescreen", true, true); + sEmergencyKeysEnabled = get_driver_boolean_parameter(handle, + "emergency_keys", sEmergencyKeysEnabled, sEmergencyKeysEnabled); unload_driver_settings(handle); } @@ -1350,6 +1353,30 @@ debug_trap_cpu_in_kdl(bool returnIfHandedOver) } +bool +debug_emergency_key_pressed(char key) +{ + if (!sEmergencyKeysEnabled) + return false; + + if (key == 'd') { + kernel_debugger("Keyboard Requested Halt."); + return true; + } + + // Broadcast to the kernel debugger modules + + for (uint32 i = 0; i < kMaxDebuggerModules; i++) { + if (sDebuggerModules[i] && sDebuggerModules[i]->emergency_key_pressed) { + if (sDebuggerModules[i]->emergency_key_pressed(key)) + return true; + } + } + + return false; +} + + // #pragma mark - public API