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
init_serial_port(uint16 basePort,uint32 baudRate)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
put_char(const char c)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
debug_keyboard_interrupt(void * data)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
arch_debug_remove_interrupt_handler(uint32 line)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
arch_debug_install_interrupt_handlers(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
arch_debug_blue_screen_try_getchar(void)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
arch_debug_blue_screen_getchar(void)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
arch_debug_serial_try_getchar(void)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
arch_debug_serial_getchar(void)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
_arch_debug_serial_putchar(const char c)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
arch_debug_serial_putchar(const char c)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
arch_debug_serial_puts_locked(const char * string)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
arch_debug_serial_puts(const char * s)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
arch_debug_serial_early_boot_message(const char * string)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
arch_debug_console_init(kernel_args * args)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
arch_debug_console_init_settings(kernel_args * args)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