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