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.
7 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8 * Distributed under the terms of the NewOS License.
10 #include "debugger_keymaps.h"
13 #include <KernelExport.h>
14 #include <driver_settings.h>
18 #include <arch/debug_console.h>
19 #include <boot/stage2.h>
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,
62 static uint32 sSerialBaudRate
= 115200;
63 static uint16 sSerialBasePort
= 0x3f8;
64 // COM1 is the default debug output port
66 static bool sKeyboardHandlerInstalled
= false;
68 static spinlock sSerialOutputSpinlock
= B_SPINLOCK_INITIALIZER
;
72 init_serial_port(uint16 basePort
, uint32 baudRate
)
74 sSerialBasePort
= basePort
;
75 sSerialBaudRate
= baudRate
;
77 uint16 divisor
= (uint16
)(115200 / baudRate
);
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 */
87 put_char(const char c
)
89 // wait until the transmitter empty bit is set
90 while ((in8(sSerialBasePort
+ SERIAL_LINE_STATUS
) & 0x20) == 0)
91 asm volatile ("pause;");
93 out8(c
, sSerialBasePort
+ SERIAL_TRANSMIT_BUFFER
);
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.
104 debug_keyboard_interrupt(void *data
)
106 static bool controlPressed
= false;
107 static bool altPressed
= false;
108 static bool sysReqPressed
= false;
111 key
= in8(PS2_PORT_DATA
);
112 //dprintf("debug_keyboard_interrupt: key = 0x%x\n", key);
115 if (key
== LEFT_CONTROL
)
116 controlPressed
= false;
117 else if (key
== LEFT_ALT
)
119 else if (key
== SYS_REQ
)
120 sysReqPressed
= false;
122 return B_HANDLED_INTERRUPT
;
127 controlPressed
= true;
136 sysReqPressed
= true;
140 if (controlPressed
&& altPressed
)
141 arch_cpu_shutdown(true);
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;
156 return B_HANDLED_INTERRUPT
;
164 arch_debug_remove_interrupt_handler(uint32 line
)
166 if (line
!= INT_PS2_KEYBOARD
|| !sKeyboardHandlerInstalled
)
169 remove_io_interrupt_handler(INT_PS2_KEYBOARD
, &debug_keyboard_interrupt
,
171 sKeyboardHandlerInstalled
= false;
176 arch_debug_install_interrupt_handlers(void)
178 install_io_interrupt_handler(INT_PS2_KEYBOARD
, &debug_keyboard_interrupt
,
180 sKeyboardHandlerInstalled
= true;
185 arch_debug_blue_screen_try_getchar(void)
187 /* polling the keyboard, similar to code in keyboard
188 * driver, but without using an interrupt
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;
197 if (special
& 0x80) {
212 uint8 status
= in8(PS2_PORT_CTRL
);
214 if ((status
& PS2_STATUS_OUTPUT_BUFFER_FULL
) == 0) {
215 // no data in keyboard buffer
219 key
= in8(PS2_PORT_DATA
);
221 if (status
& PS2_STATUS_AUX_DATA
) {
222 // we read mouse data, ignore it
228 switch (key
& ~0x80) {
231 shiftPressed
= false;
234 controlPressed
= false;
249 controlPressed
= true;
256 // start escape sequence for cursor movement
258 special
= 0x80 | 'A';
261 special
= 0x80 | 'B';
264 special
= 0x80 | 'C';
267 special
= 0x80 | 'D';
270 special
= 0x80 | 'H';
273 special
= 0x80 | 'F';
276 special
= 0x80 | '5';
280 special
= 0x80 | '6';
286 if (controlPressed
&& altPressed
)
287 arch_cpu_shutdown(true);
289 special
= 0x80 | '3';
294 if (controlPressed
) {
295 char c
= kShiftedKeymap
[key
];
296 if (c
>= 'A' && c
<= 'Z')
301 return kAltedKeymap
[key
];
304 ? kShiftedKeymap
[key
] : kUnshiftedKeymap
[key
];
313 arch_debug_blue_screen_getchar(void)
316 int c
= arch_debug_blue_screen_try_getchar();
326 arch_debug_serial_try_getchar(void)
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.
335 if ((lineStatus
& 0x1) == 0)
338 return in8(sSerialBasePort
+ SERIAL_RECEIVE_BUFFER
);
343 arch_debug_serial_getchar(void)
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.
353 if ((lineStatus
& 0x1) != 0)
359 return in8(sSerialBasePort
+ SERIAL_RECEIVE_BUFFER
);
364 _arch_debug_serial_putchar(const char c
)
369 } else if (c
!= '\r')
374 arch_debug_serial_putchar(const char c
)
376 cpu_status state
= 0;
377 if (!debug_debugger_running()) {
378 state
= disable_interrupts();
379 acquire_spinlock(&sSerialOutputSpinlock
);
382 _arch_debug_serial_putchar(c
);
384 if (!debug_debugger_running()) {
385 release_spinlock(&sSerialOutputSpinlock
);
386 restore_interrupts(state
);
392 arch_debug_serial_puts(const char *s
)
394 cpu_status state
= 0;
395 if (!debug_debugger_running()) {
396 state
= disable_interrupts();
397 acquire_spinlock(&sSerialOutputSpinlock
);
401 _arch_debug_serial_putchar(*s
);
405 if (!debug_debugger_running()) {
406 release_spinlock(&sSerialOutputSpinlock
);
407 restore_interrupts(state
);
413 arch_debug_serial_early_boot_message(const char *string
)
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
);
423 arch_debug_console_init(kernel_args
*args
)
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];
429 init_serial_port(sSerialBasePort
, sSerialBaudRate
);
436 arch_debug_console_init_settings(kernel_args
*args
)
438 uint32 baudRate
= sSerialBaudRate
;
439 uint16 basePort
= sSerialBasePort
;
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",
448 int32 number
= strtol(value
, NULL
, 0);
449 if (number
>= MAX_SERIAL_PORTS
) {
450 // use as port number directly
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
];
457 // ignore value and use default
461 value
= get_driver_parameter(handle
, "serial_debug_speed", NULL
, NULL
);
463 int32 number
= strtol(value
, NULL
, 0);
475 unload_driver_settings(handle
);
478 if (sSerialBasePort
== basePort
&& baudRate
== sSerialBaudRate
)
481 init_serial_port(basePort
, baudRate
);