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