* Added an emergency key mechanism to the kernel, inspired by Jan Klötzke's

patch from about a year ago (I couldn't use any code of his yet, though,
  but there are a few things left). The emergency keys are triggered by
  pressing Alt-SysReq + key.
* By default, only Alt-SysReq+'d' is used as a means to deliberately enter
  the kernel debugger. F12 belongs to userland again, now :-)
* Debugger add-ons now have another optional method to implement their own
  emergency keys - 'd' for the debugger cannot be overridden, though.
* The mechanism can be turned off via a new kernel setting, so it's not that
  easy anymore to "crash" Haiku if you don't want to.
* Right now, the PS/2 driver, and the pre-input_server in-kernel debugger
  keyboard mini-driver support this, USB not yet.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31660 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-07-20 20:39:37 +00:00
parent 8ef9253a59
commit c755ecfe96
6 changed files with 151 additions and 53 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 <string.h>
#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];

View File

@ -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 <string.h>
#include <debug.h>
#include <debugger_keymaps.h>
#include "ps2_service.h"
#include "kb_mouse_driver.h"
#include "packet_buffer.h"
#include <string.h>
#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,

View File

@ -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 <judd@ob-wan.com>
* Copyright 2002, Marcus Overhagen <marcus@overhagen.de>
* 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;
}

View File

@ -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