1 /* 2 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de 3 * Copyright 2001, Rob Judd <judd@ob-wan.com> 4 * Copyright 2002, Marcus Overhagen <marcus@overhagen.de> 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 #include "debugger_keymaps.h" 11 #include "ps2_defs.h" 12 13 #include <KernelExport.h> 14 #include <driver_settings.h> 15 #include <int.h> 16 17 #include <arch/cpu.h> 18 #include <arch/debug_console.h> 19 #include <boot/stage2.h> 20 #include <debug.h> 21 22 #include <string.h> 23 #include <stdlib.h> 24 25 26 enum serial_register_offsets { 27 SERIAL_TRANSMIT_BUFFER = 0, 28 SERIAL_RECEIVE_BUFFER = 0, 29 SERIAL_DIVISOR_LATCH_LOW = 0, 30 SERIAL_DIVISOR_LATCH_HIGH = 1, 31 SERIAL_FIFO_CONTROL = 2, 32 SERIAL_LINE_CONTROL = 3, 33 SERIAL_MODEM_CONTROL = 4, 34 SERIAL_LINE_STATUS = 5, 35 SERIAL_MODEM_STATUS = 6, 36 }; 37 38 enum keycodes { 39 LEFT_SHIFT = 42, 40 RIGHT_SHIFT = 54, 41 42 LEFT_CONTROL = 29, 43 44 LEFT_ALT = 56, 45 RIGHT_ALT = 58, 46 47 CURSOR_LEFT = 75, 48 CURSOR_RIGHT = 77, 49 CURSOR_UP = 72, 50 CURSOR_DOWN = 80, 51 CURSOR_HOME = 71, 52 CURSOR_END = 79, 53 PAGE_UP = 73, 54 PAGE_DOWN = 81, 55 56 DELETE = 83, 57 SYS_REQ = 84, 58 F12 = 88, 59 }; 60 61 62 static const uint32 kSerialBaudRate = 115200; 63 static uint16 sSerialBasePort = 0x3f8; 64 // COM1 is the default debug output port 65 66 static bool sKeyboardHandlerInstalled = false; 67 68 static spinlock sSerialOutputSpinlock = B_SPINLOCK_INITIALIZER; 69 70 71 static void 72 init_serial_port(uint16 basePort, uint32 baudRate) 73 { 74 sSerialBasePort = basePort; 75 76 uint16 divisor = (uint16)(115200 / baudRate); 77 78 out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL); /* set divisor latch access bit */ 79 out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW); 80 out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH); 81 out8(3, sSerialBasePort + SERIAL_LINE_CONTROL); /* 8N1 */ 82 } 83 84 85 static void 86 put_char(const char c) 87 { 88 // wait until the transmitter empty bit is set 89 while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0) 90 asm volatile ("pause;"); 91 92 out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER); 93 } 94 95 96 /** Minimal keyboard handler to be able to get into the debugger and 97 * reboot the machine before the input_server is up and running. 98 * It is added as soon as interrupts become available, and removed 99 * again if anything else requests the interrupt 1. 100 */ 101 102 static int32 103 debug_keyboard_interrupt(void *data) 104 { 105 static bool controlPressed = false; 106 static bool altPressed = false; 107 static bool sysReqPressed = false; 108 uint8 key; 109 110 key = in8(PS2_PORT_DATA); 111 //dprintf("debug_keyboard_interrupt: key = 0x%x\n", key); 112 113 if (key & 0x80) { 114 if (key == LEFT_CONTROL) 115 controlPressed = false; 116 else if (key == LEFT_ALT) 117 altPressed = false; 118 else if (key == SYS_REQ) 119 sysReqPressed = false; 120 121 return B_HANDLED_INTERRUPT; 122 } 123 124 switch (key) { 125 case LEFT_CONTROL: 126 controlPressed = true; 127 break; 128 129 case LEFT_ALT: 130 case RIGHT_ALT: 131 altPressed = true; 132 break; 133 134 case SYS_REQ: 135 sysReqPressed = true; 136 break; 137 138 case DELETE: 139 if (controlPressed && altPressed) 140 arch_cpu_shutdown(true); 141 break; 142 143 default: 144 if (altPressed && sysReqPressed) { 145 if (debug_emergency_key_pressed(kUnshiftedKeymap[key])) { 146 // we probably have lost some keys, so reset our key states 147 controlPressed = false; 148 sysReqPressed = false; 149 altPressed = false; 150 } 151 } 152 break; 153 } 154 155 return B_HANDLED_INTERRUPT; 156 } 157 158 159 // #pragma mark - 160 161 162 void 163 arch_debug_remove_interrupt_handler(uint32 line) 164 { 165 if (line != INT_PS2_KEYBOARD || !sKeyboardHandlerInstalled) 166 return; 167 168 remove_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt, 169 NULL); 170 sKeyboardHandlerInstalled = false; 171 } 172 173 174 void 175 arch_debug_install_interrupt_handlers(void) 176 { 177 install_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt, 178 NULL, 0); 179 sKeyboardHandlerInstalled = true; 180 } 181 182 183 int 184 arch_debug_blue_screen_try_getchar(void) 185 { 186 /* polling the keyboard, similar to code in keyboard 187 * driver, but without using an interrupt 188 */ 189 static bool shiftPressed = false; 190 static bool controlPressed = false; 191 static bool altPressed = false; 192 static uint8 special = 0; 193 static uint8 special2 = 0; 194 uint8 key = 0; 195 196 if (special & 0x80) { 197 special &= ~0x80; 198 return '['; 199 } 200 if (special != 0) { 201 key = special; 202 special = 0; 203 return key; 204 } 205 if (special2 != 0) { 206 key = special2; 207 special2 = 0; 208 return key; 209 } 210 211 uint8 status = in8(PS2_PORT_CTRL); 212 213 if ((status & PS2_STATUS_OUTPUT_BUFFER_FULL) == 0) { 214 // no data in keyboard buffer 215 return -1; 216 } 217 218 key = in8(PS2_PORT_DATA); 219 220 if (status & PS2_STATUS_AUX_DATA) { 221 // we read mouse data, ignore it 222 return -1; 223 } 224 225 if (key & 0x80) { 226 // key up 227 switch (key & ~0x80) { 228 case LEFT_SHIFT: 229 case RIGHT_SHIFT: 230 shiftPressed = false; 231 return -1; 232 case LEFT_CONTROL: 233 controlPressed = false; 234 return -1; 235 case LEFT_ALT: 236 altPressed = false; 237 return -1; 238 } 239 } else { 240 // key down 241 switch (key) { 242 case LEFT_SHIFT: 243 case RIGHT_SHIFT: 244 shiftPressed = true; 245 return -1; 246 247 case LEFT_CONTROL: 248 controlPressed = true; 249 return -1; 250 251 case LEFT_ALT: 252 altPressed = true; 253 return -1; 254 255 // start escape sequence for cursor movement 256 case CURSOR_UP: 257 special = 0x80 | 'A'; 258 return '\x1b'; 259 case CURSOR_DOWN: 260 special = 0x80 | 'B'; 261 return '\x1b'; 262 case CURSOR_RIGHT: 263 special = 0x80 | 'C'; 264 return '\x1b'; 265 case CURSOR_LEFT: 266 special = 0x80 | 'D'; 267 return '\x1b'; 268 case CURSOR_HOME: 269 special = 0x80 | 'H'; 270 return '\x1b'; 271 case CURSOR_END: 272 special = 0x80 | 'F'; 273 return '\x1b'; 274 case PAGE_UP: 275 special = 0x80 | '5'; 276 special2 = '~'; 277 return '\x1b'; 278 case PAGE_DOWN: 279 special = 0x80 | '6'; 280 special2 = '~'; 281 return '\x1b'; 282 283 284 case DELETE: 285 if (controlPressed && altPressed) 286 arch_cpu_shutdown(true); 287 288 special = 0x80 | '3'; 289 special2 = '~'; 290 return '\x1b'; 291 292 default: 293 if (controlPressed) { 294 char c = kShiftedKeymap[key]; 295 if (c >= 'A' && c <= 'Z') 296 return 0x1f & c; 297 } 298 299 if (altPressed) 300 return kAltedKeymap[key]; 301 302 return shiftPressed 303 ? kShiftedKeymap[key] : kUnshiftedKeymap[key]; 304 } 305 } 306 307 return -1; 308 } 309 310 311 char 312 arch_debug_blue_screen_getchar(void) 313 { 314 while (true) { 315 int c = arch_debug_blue_screen_try_getchar(); 316 if (c >= 0) 317 return (char)c; 318 319 PAUSE(); 320 } 321 } 322 323 324 int 325 arch_debug_serial_try_getchar(void) 326 { 327 uint8 lineStatus = in8(sSerialBasePort + SERIAL_LINE_STATUS); 328 if (lineStatus == 0xff) { 329 // The "data available" bit is set, but also all error bits. Likely we 330 // don't have a valid I/O port. 331 return -1; 332 } 333 334 if ((lineStatus & 0x1) == 0) 335 return -1; 336 337 return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER); 338 } 339 340 341 char 342 arch_debug_serial_getchar(void) 343 { 344 while (true) { 345 uint8 lineStatus = in8(sSerialBasePort + SERIAL_LINE_STATUS); 346 if (lineStatus == 0xff) { 347 // The "data available" bit is set, but also all error bits. Likely 348 // we don't have a valid I/O port. 349 return 0; 350 } 351 352 if ((lineStatus & 0x1) != 0) 353 break; 354 355 PAUSE(); 356 } 357 358 return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER); 359 } 360 361 362 static void 363 _arch_debug_serial_putchar(const char c) 364 { 365 if (c == '\n') { 366 put_char('\r'); 367 put_char('\n'); 368 } else if (c != '\r') 369 put_char(c); 370 } 371 372 void 373 arch_debug_serial_putchar(const char c) 374 { 375 cpu_status state = 0; 376 if (!debug_debugger_running()) { 377 state = disable_interrupts(); 378 acquire_spinlock(&sSerialOutputSpinlock); 379 } 380 381 _arch_debug_serial_putchar(c); 382 383 if (!debug_debugger_running()) { 384 release_spinlock(&sSerialOutputSpinlock); 385 restore_interrupts(state); 386 } 387 } 388 389 390 void 391 arch_debug_serial_puts(const char *s) 392 { 393 cpu_status state = 0; 394 if (!debug_debugger_running()) { 395 state = disable_interrupts(); 396 acquire_spinlock(&sSerialOutputSpinlock); 397 } 398 399 while (*s != '\0') { 400 _arch_debug_serial_putchar(*s); 401 s++; 402 } 403 404 if (!debug_debugger_running()) { 405 release_spinlock(&sSerialOutputSpinlock); 406 restore_interrupts(state); 407 } 408 } 409 410 411 void 412 arch_debug_serial_early_boot_message(const char *string) 413 { 414 // this function will only be called in fatal situations 415 // ToDo: also enable output via text console?! 416 arch_debug_console_init(NULL); 417 arch_debug_serial_puts(string); 418 } 419 420 421 status_t 422 arch_debug_console_init(kernel_args *args) 423 { 424 // only use the port if we could find one, else use the standard port 425 if (args != NULL && args->platform_args.serial_base_ports[0] != 0) 426 sSerialBasePort = args->platform_args.serial_base_ports[0]; 427 428 init_serial_port(sSerialBasePort, kSerialBaudRate); 429 430 return B_OK; 431 } 432 433 434 status_t 435 arch_debug_console_init_settings(kernel_args *args) 436 { 437 uint32 baudRate = kSerialBaudRate; 438 uint16 basePort = sSerialBasePort; 439 void *handle; 440 441 // get debug settings 442 handle = load_driver_settings("kernel"); 443 if (handle != NULL) { 444 const char *value = get_driver_parameter(handle, "serial_debug_port", 445 NULL, NULL); 446 if (value != NULL) { 447 int32 number = strtol(value, NULL, 0); 448 if (number >= MAX_SERIAL_PORTS) { 449 // use as port number directly 450 basePort = number; 451 } else if (number >= 0) { 452 // use as index into port array 453 if (args->platform_args.serial_base_ports[number] != 0) 454 basePort = args->platform_args.serial_base_ports[number]; 455 } else { 456 // ignore value and use default 457 } 458 } 459 460 value = get_driver_parameter(handle, "serial_debug_speed", NULL, NULL); 461 if (value != NULL) { 462 int32 number = strtol(value, NULL, 0); 463 switch (number) { 464 case 9600: 465 case 19200: 466 case 38400: 467 case 57600: 468 case 115200: 469 //case 230400: 470 baudRate = number; 471 } 472 } 473 474 unload_driver_settings(handle); 475 } 476 477 if (sSerialBasePort == basePort && baudRate == kSerialBaudRate) 478 return B_OK; 479 480 init_serial_port(sSerialBasePort, kSerialBaudRate); 481 482 return B_OK; 483 } 484