2 * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
10 #include "blue_screen.h"
12 #include <KernelExport.h>
13 #include <frame_buffer_console.h>
16 #include <arch/debug_console.h>
22 #include "debug_commands.h"
25 #define USE_SCROLLING 0
34 CONSOLE_STATE_NORMAL
= 0,
35 CONSOLE_STATE_GOT_ESCAPE
,
36 CONSOLE_STATE_SEEN_BRACKET
,
37 CONSOLE_STATE_NEW_ARG
,
38 CONSOLE_STATE_PARSING_ARG
,
54 int32 in_command_rows
;
57 bool boot_debug_output
;
66 console_module_info
*sModule
;
72 sModule
->move_cursor(-1, -1);
77 update_cursor(int32 x
, int32 y
)
79 sModule
->move_cursor(x
, y
);
84 move_cursor(int32 x
, int32 y
)
94 /*! Scroll from the cursor line up to the top of the scroll region up one
100 // move the screen up one
101 sModule
->blit(0, 1, sScreen
.columns
, sScreen
.rows
- 1, 0, 0);
103 // clear the bottom line
104 sModule
->fill_glyph(0, 0, sScreen
.columns
, 1, ' ', sScreen
.attr
);
112 bool abortCommand
= false;
115 // TODO: scrolling is usually too slow; we could probably just remove it
116 if (sScreen
.y
== sScreen
.rows
- 1)
121 if (in_command_invocation())
122 sScreen
.in_command_rows
++;
124 sScreen
.in_command_rows
= 0;
126 if (sScreen
.paging
&& ((sScreen
.in_command_rows
> 0
127 && ((sScreen
.in_command_rows
+ 3) % sScreen
.rows
) == 0)
128 || (sScreen
.boot_debug_output
&& sScreen
.y
== sScreen
.rows
- 1))) {
129 if (sScreen
.paging_timeout
)
130 spin(1000 * 1000 * 3);
132 // Use the paging mechanism: either, we're in the debugger, and a
133 // command is being executed, or we're currently showing boot debug
135 const char *text
= in_command_invocation()
136 ? "Press key to continue, Q to quit, S to skip output"
137 : "Press key to continue, S to skip output, P to disable paging";
138 int32 length
= strlen(text
);
139 if (sScreen
.x
+ length
> sScreen
.columns
) {
140 // make sure we don't overwrite too much
145 for (int32 i
= 0; i
< length
; i
++) {
146 // yellow on black (or reverse, during boot)
147 sModule
->put_glyph(sScreen
.columns
- length
+ i
, sScreen
.y
,
148 text
[i
], sScreen
.boot_debug_output
? 0x6f : 0xf6);
153 sScreen
.ignore_output
= true;
154 } else if (c
== 'q' && in_command_invocation()) {
156 sScreen
.ignore_output
= true;
157 } else if (c
== 'p' && !in_command_invocation())
158 sScreen
.paging
= false;
159 else if (c
== 't' && !in_command_invocation())
160 sScreen
.paging_timeout
= true;
162 // remove on screen text again
163 sModule
->fill_glyph(sScreen
.columns
- length
, sScreen
.y
, length
,
164 1, ' ', sScreen
.attr
);
167 if (sScreen
.in_command_rows
> 0)
168 sScreen
.in_command_rows
+= 2;
170 if (sScreen
.y
== sScreen
.rows
- 1) {
172 sModule
->fill_glyph(0, 0, sScreen
.columns
, 2, ' ', sScreen
.attr
);
178 if (sScreen
.y
+ 2 < sScreen
.rows
) {
179 sModule
->fill_glyph(0, (sScreen
.y
+ 2) % sScreen
.rows
, sScreen
.columns
,
180 1, ' ', sScreen
.attr
);
186 abort_debugger_command();
193 erase_line(erase_line_mode mode
)
196 case LINE_ERASE_WHOLE
:
197 sModule
->fill_glyph(0, sScreen
.y
, sScreen
.columns
, 1, ' ',
200 case LINE_ERASE_LEFT
:
201 sModule
->fill_glyph(0, sScreen
.y
, sScreen
.x
+ 1, 1, ' ',
204 case LINE_ERASE_RIGHT
:
205 sModule
->fill_glyph(sScreen
.x
, sScreen
.y
, sScreen
.columns
206 - sScreen
.x
, 1, ' ', sScreen
.attr
);
219 sModule
->put_glyph(sScreen
.x
, sScreen
.y
, ' ', sScreen
.attr
);
224 put_character(char c
)
226 if (++sScreen
.x
>= sScreen
.columns
) {
231 sModule
->put_glyph(sScreen
.x
- 1, sScreen
.y
, c
, sScreen
.attr
);
236 set_vt100_attributes(int32
*args
, int32 argCount
)
239 // that's the default (attributes off)
244 for (int32 i
= 0; i
< argCount
; i
++) {
247 sScreen
.attr
= sScreen
.boot_debug_output
? 0xf0 : 0x0f;
248 sScreen
.bright_attr
= true;
249 sScreen
.reverse_attr
= false;
252 sScreen
.bright_attr
= true;
253 sScreen
.attr
|= 0x08; // set the bright bit
256 sScreen
.bright_attr
= false;
257 sScreen
.attr
&= ~0x08; // unset the bright bit
259 case 4: // underscore we can't do
262 sScreen
.attr
|= 0x80; // set the blink bit
265 sScreen
.reverse_attr
= true;
266 sScreen
.attr
= ((sScreen
.attr
& BMASK
) >> 4)
267 | ((sScreen
.attr
& FMASK
) << 4);
268 if (sScreen
.bright_attr
)
269 sScreen
.attr
|= 0x08;
274 /* foreground colors */
284 const uint8 colors
[] = {0, 4, 2, 6, 1, 5, 3, 7};
285 sScreen
.attr
= (sScreen
.attr
& ~FMASK
) | colors
[args
[i
] - 30]
286 | (sScreen
.bright_attr
? 0x08 : 0);
290 /* background colors */
291 case 40: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (0 << 4); break; // black
292 case 41: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (4 << 4); break; // red
293 case 42: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (2 << 4); break; // green
294 case 43: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (6 << 4); break; // yellow
295 case 44: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (1 << 4); break; // blue
296 case 45: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (5 << 4); break; // magenta
297 case 46: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (3 << 4); break; // cyan
298 case 47: sScreen
.attr
= (sScreen
.attr
& ~BMASK
) | (7 << 4); break; // white
305 process_vt100_command(const char c
, bool seenBracket
, int32
*args
,
310 // kprintf("process_vt100_command: c '%c', argCount %ld, arg[0] %ld, arg[1] %ld, seenBracket %d\n",
311 // c, argCount, args[0], args[1], seenBracket);
315 case 'H': // set cursor position
318 int32 row
= argCount
> 0 ? args
[0] : 1;
319 int32 col
= argCount
> 1 ? args
[1] : 1;
324 move_cursor(col
, row
);
329 int32 deltaY
= argCount
> 0 ? -args
[0] : -1;
332 move_cursor(sScreen
.x
, sScreen
.y
+ deltaY
);
336 case 'B': // move down
338 int32 deltaY
= argCount
> 0 ? args
[0] : 1;
341 move_cursor(sScreen
.x
, sScreen
.y
+ deltaY
);
344 case 'D': // move left
346 int32 deltaX
= argCount
> 0 ? -args
[0] : -1;
349 move_cursor(sScreen
.x
+ deltaX
, sScreen
.y
);
353 case 'C': // move right
355 int32 deltaX
= argCount
> 0 ? args
[0] : 1;
358 move_cursor(sScreen
.x
+ deltaX
, sScreen
.y
);
362 case 'G': // set X position
364 int32 newX
= argCount
> 0 ? args
[0] : 1;
367 move_cursor(newX
, sScreen
.y
);
370 case 'd': // set y position
372 int32 newY
= argCount
> 0 ? args
[0] : 1;
375 move_cursor(sScreen
.x
, newY
);
379 case 's': // save current cursor
380 save_cur(console
, false);
382 case 'u': // restore cursor
383 restore_cur(console
, false);
385 case 'r': // set scroll region
387 int32 low
= argCount
> 0 ? args
[0] : 1;
388 int32 high
= argCount
> 1 ? args
[1] : sScreen
.lines
;
390 set_scroll_region(console
, low
- 1, high
- 1);
393 case 'L': // scroll virtual down at cursor
395 int32 lines
= argCount
> 0 ? args
[0] : 1;
402 case 'M': // scroll virtual up at cursor
404 int32 lines
= argCount
> 0 ? args
[0] : 1;
413 if (argCount
== 0 || args
[0] == 0) {
414 // erase to end of line
415 erase_line(LINE_ERASE_RIGHT
);
416 } else if (argCount
> 0) {
418 erase_line(LINE_ERASE_LEFT
);
419 else if (args
[0] == 2)
420 erase_line(LINE_ERASE_WHOLE
);
425 if (argCount
== 0 || args
[0] == 0) {
426 // erase to end of screen
427 erase_screen(console
, SCREEN_ERASE_DOWN
);
430 erase_screen(console
, SCREEN_ERASE_UP
);
431 else if (args
[0] == 2)
432 erase_screen(console
, SCREEN_ERASE_WHOLE
);
438 set_vt100_attributes(args
, argCount
);
447 reset_console(console
);
456 save_cur(console
, true);
459 restore_cur(console
, true);
472 parse_character(char c
)
474 switch (sScreen
.state
) {
475 case CONSOLE_STATE_NORMAL
:
476 // just output the stuff
486 sScreen
.x
= (sScreen
.x
+ 8) & ~7;
487 if (sScreen
.x
>= sScreen
.columns
)
498 sScreen
.arg_count
= 0;
499 sScreen
.state
= CONSOLE_STATE_GOT_ESCAPE
;
505 case CONSOLE_STATE_GOT_ESCAPE
:
506 // look for either commands with no argument, or the '[' character
509 sScreen
.state
= CONSOLE_STATE_SEEN_BRACKET
;
513 process_vt100_command(c
, false, sScreen
.args
, 0);
514 sScreen
.state
= CONSOLE_STATE_NORMAL
;
517 case CONSOLE_STATE_SEEN_BRACKET
:
520 sScreen
.arg_count
= 0;
521 sScreen
.args
[0] = c
- '0';
522 sScreen
.state
= CONSOLE_STATE_PARSING_ARG
;
525 // private DEC mode parameter follows - we ignore those
529 process_vt100_command(c
, true, sScreen
.args
, 0);
530 sScreen
.state
= CONSOLE_STATE_NORMAL
;
534 case CONSOLE_STATE_NEW_ARG
:
537 if (++sScreen
.arg_count
== MAX_ARGS
) {
538 sScreen
.state
= CONSOLE_STATE_NORMAL
;
541 sScreen
.args
[sScreen
.arg_count
] = c
- '0';
542 sScreen
.state
= CONSOLE_STATE_PARSING_ARG
;
545 process_vt100_command(c
, true, sScreen
.args
,
546 sScreen
.arg_count
+ 1);
547 sScreen
.state
= CONSOLE_STATE_NORMAL
;
551 case CONSOLE_STATE_PARSING_ARG
:
555 sScreen
.args
[sScreen
.arg_count
] *= 10;
556 sScreen
.args
[sScreen
.arg_count
] += c
- '0';
559 sScreen
.state
= CONSOLE_STATE_NEW_ARG
;
562 process_vt100_command(c
, true, sScreen
.args
,
563 sScreen
.arg_count
+ 1);
564 sScreen
.state
= CONSOLE_STATE_NORMAL
;
573 set_paging(int argc
, char **argv
)
575 if (argc
> 1 && !strcmp(argv
[1], "--help")) {
576 kprintf("usage: %s [on|off]\n", argv
[0]);
581 sScreen
.paging
= !sScreen
.paging
;
582 else if (!strcmp(argv
[1], "on"))
583 sScreen
.paging
= true;
584 else if (!strcmp(argv
[1], "off"))
585 sScreen
.paging
= false;
587 sScreen
.paging
= parse_expression(argv
[1]) != 0;
589 kprintf("paging is turned %s now.\n", sScreen
.paging
? "on" : "off");
592 #endif // !_BOOT_MODE
599 blue_screen_init(void)
601 extern console_module_info gFrameBufferConsoleModule
;
603 // we can't use get_module() here, since it's too early in the boot process
605 if (!frame_buffer_console_available())
608 sModule
= &gFrameBufferConsoleModule
;
610 sScreen
.paging
= false;
612 sScreen
.paging
= !get_safemode_boolean(
613 "disable_onscreen_paging", false);
614 sScreen
.paging_timeout
= false;
616 add_debugger_command("paging", set_paging
, "Enable or disable paging");
623 blue_screen_enter(bool debugOutput
)
625 sScreen
.attr
= debugOutput
? 0xf0 : 0x0f;
626 // black on white for KDL, white on black for debug output
627 sScreen
.boot_debug_output
= debugOutput
;
628 sScreen
.ignore_output
= false;
630 sScreen
.x
= sScreen
.y
= 0;
631 sScreen
.state
= CONSOLE_STATE_NORMAL
;
636 sModule
->get_size(&sScreen
.columns
, &sScreen
.rows
);
638 sModule
->clear(sScreen
.attr
);
640 sModule
->fill_glyph(0, sScreen
.y
, sScreen
.columns
, 3, ' ', sScreen
.attr
);
647 blue_screen_paging_enabled(void)
649 return sScreen
.paging
;
654 blue_screen_set_paging(bool enabled
)
656 sScreen
.paging
= enabled
;
661 blue_screen_clear_screen(void)
663 sModule
->clear(sScreen
.attr
);
670 blue_screen_try_getchar(void)
672 return arch_debug_blue_screen_try_getchar();
677 blue_screen_getchar(void)
679 return arch_debug_blue_screen_getchar();
685 blue_screen_putchar(char c
)
687 if (sScreen
.ignore_output
688 && (in_command_invocation() || sScreen
.boot_debug_output
))
691 sScreen
.ignore_output
= false;
696 update_cursor(sScreen
.x
, sScreen
.y
);
701 blue_screen_puts(const char *text
)
703 if (sScreen
.ignore_output
704 && (in_command_invocation() || sScreen
.boot_debug_output
))
707 sScreen
.ignore_output
= false;
710 while (text
[0] != '\0') {
711 parse_character(text
[0]);
715 update_cursor(sScreen
.x
, sScreen
.y
);