xref: /haiku/src/system/kernel/debug/blue_screen.cpp (revision e7d7b1e232d4bf96e2f01a32c9a6897053ac6cf1)
1f33c8020SAxel Dörfler /*
246af4e77SAxel Dörfler  * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
3f33c8020SAxel Dörfler  * Distributed under the terms of the MIT License.
446af4e77SAxel Dörfler  *
546af4e77SAxel Dörfler  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
646af4e77SAxel Dörfler  * Distributed under the terms of the NewOS License.
7f33c8020SAxel Dörfler  */
8f33c8020SAxel Dörfler 
9f33c8020SAxel Dörfler 
10f33c8020SAxel Dörfler #include "blue_screen.h"
11f33c8020SAxel Dörfler 
1267f20716SAxel Dörfler #include <KernelExport.h>
13f33c8020SAxel Dörfler #include <frame_buffer_console.h>
14f33c8020SAxel Dörfler #include <console.h>
156eba0636SMichael Lotz #include <debug.h>
16f33c8020SAxel Dörfler #include <arch/debug_console.h>
17*e7d7b1e2SRene Gollent #include <safemode.h>
18f33c8020SAxel Dörfler 
19f33c8020SAxel Dörfler #include <string.h>
20f33c8020SAxel Dörfler #include <stdio.h>
21f33c8020SAxel Dörfler 
22855ab2b3SAxel Dörfler #include "debug_commands.h"
23855ab2b3SAxel Dörfler 
24f33c8020SAxel Dörfler 
25f33c8020SAxel Dörfler #define USE_SCROLLING 0
26f33c8020SAxel Dörfler #define NO_CLEAR 1
27f33c8020SAxel Dörfler 
2867f20716SAxel Dörfler #define MAX_ARGS 8
2967f20716SAxel Dörfler 
3067f20716SAxel Dörfler #define FMASK 0x0f
3167f20716SAxel Dörfler #define BMASK 0x70
3267f20716SAxel Dörfler 
3367f20716SAxel Dörfler typedef enum {
3467f20716SAxel Dörfler 	CONSOLE_STATE_NORMAL = 0,
3567f20716SAxel Dörfler 	CONSOLE_STATE_GOT_ESCAPE,
3667f20716SAxel Dörfler 	CONSOLE_STATE_SEEN_BRACKET,
3767f20716SAxel Dörfler 	CONSOLE_STATE_NEW_ARG,
3867f20716SAxel Dörfler 	CONSOLE_STATE_PARSING_ARG,
3967f20716SAxel Dörfler } console_state;
4067f20716SAxel Dörfler 
4170c3e1a4SAxel Dörfler typedef enum {
4270c3e1a4SAxel Dörfler 	LINE_ERASE_WHOLE,
4370c3e1a4SAxel Dörfler 	LINE_ERASE_LEFT,
4470c3e1a4SAxel Dörfler 	LINE_ERASE_RIGHT
4570c3e1a4SAxel Dörfler } erase_line_mode;
4670c3e1a4SAxel Dörfler 
47f33c8020SAxel Dörfler struct screen_info {
48f33c8020SAxel Dörfler 	int32	columns;
49f33c8020SAxel Dörfler 	int32	rows;
50f33c8020SAxel Dörfler 	int32	x, y;
51f33c8020SAxel Dörfler 	uint8	attr;
5267f20716SAxel Dörfler 	bool	bright_attr;
5367f20716SAxel Dörfler 	bool	reverse_attr;
54855ab2b3SAxel Dörfler 	int32	in_command_rows;
55855ab2b3SAxel Dörfler 	bool	paging;
56fec23a53SMichael Lotz 	bool	paging_timeout;
5733965e02SAxel Dörfler 	bool	boot_debug_output;
58855ab2b3SAxel Dörfler 	bool	ignore_output;
5967f20716SAxel Dörfler 
6067f20716SAxel Dörfler 	// state machine
6167f20716SAxel Dörfler 	console_state state;
6267f20716SAxel Dörfler 	int32	arg_count;
6367f20716SAxel Dörfler 	int32	args[MAX_ARGS];
64f33c8020SAxel Dörfler } sScreen;
65f33c8020SAxel Dörfler 
66f33c8020SAxel Dörfler console_module_info *sModule;
67f33c8020SAxel Dörfler 
68f33c8020SAxel Dörfler 
69f33c8020SAxel Dörfler static inline void
70f33c8020SAxel Dörfler hide_cursor(void)
71f33c8020SAxel Dörfler {
72f33c8020SAxel Dörfler 	sModule->move_cursor(-1, -1);
73f33c8020SAxel Dörfler }
74f33c8020SAxel Dörfler 
75f33c8020SAxel Dörfler 
76f33c8020SAxel Dörfler static inline void
77f33c8020SAxel Dörfler update_cursor(int32 x, int32 y)
78f33c8020SAxel Dörfler {
79f33c8020SAxel Dörfler 	sModule->move_cursor(x, y);
80f33c8020SAxel Dörfler }
81f33c8020SAxel Dörfler 
82f33c8020SAxel Dörfler 
8367f20716SAxel Dörfler static inline void
8467f20716SAxel Dörfler move_cursor(int32 x, int32 y)
8567f20716SAxel Dörfler {
8667f20716SAxel Dörfler 	sScreen.x = x;
8767f20716SAxel Dörfler 	sScreen.y = y;
8867f20716SAxel Dörfler 	update_cursor(x, y);
8967f20716SAxel Dörfler }
9067f20716SAxel Dörfler 
9167f20716SAxel Dörfler 
92f33c8020SAxel Dörfler #if USE_SCROLLING
93f33c8020SAxel Dörfler 
94855ab2b3SAxel Dörfler /*!	Scroll from the cursor line up to the top of the scroll region up one
95855ab2b3SAxel Dörfler 	line.
96855ab2b3SAxel Dörfler */
97f33c8020SAxel Dörfler static void
98f33c8020SAxel Dörfler scroll_up(void)
99f33c8020SAxel Dörfler {
100f33c8020SAxel Dörfler 	// move the screen up one
101f33c8020SAxel Dörfler 	sModule->blit(0, 1, sScreen.columns, sScreen.rows - 1, 0, 0);
102f33c8020SAxel Dörfler 
103f33c8020SAxel Dörfler 	// clear the bottom line
104f33c8020SAxel Dörfler 	sModule->fill_glyph(0, 0, sScreen.columns, 1, ' ', sScreen.attr);
105f33c8020SAxel Dörfler }
106f33c8020SAxel Dörfler #endif
107f33c8020SAxel Dörfler 
108f33c8020SAxel Dörfler 
109f33c8020SAxel Dörfler static void
110f33c8020SAxel Dörfler next_line(void)
111f33c8020SAxel Dörfler {
112f937627dSIngo Weinhold 	bool abortCommand = false;
113f937627dSIngo Weinhold 
114a39bfc19SAxel Dörfler #if USE_SCROLLING
115a39bfc19SAxel Dörfler 	// TODO: scrolling is usually too slow; we could probably just remove it
116a39bfc19SAxel Dörfler 	if (sScreen.y == sScreen.rows - 1)
117a39bfc19SAxel Dörfler  		scroll_up();
118a39bfc19SAxel Dörfler  	else
119a39bfc19SAxel Dörfler  		sScreen.y++;
120a39bfc19SAxel Dörfler #else
121855ab2b3SAxel Dörfler 	if (in_command_invocation())
122855ab2b3SAxel Dörfler 		sScreen.in_command_rows++;
123855ab2b3SAxel Dörfler 	else
124855ab2b3SAxel Dörfler 		sScreen.in_command_rows = 0;
125855ab2b3SAxel Dörfler 
126a39bfc19SAxel Dörfler 	if (sScreen.paging && ((sScreen.in_command_rows > 0
127a39bfc19SAxel Dörfler 			&& ((sScreen.in_command_rows + 3) % sScreen.rows) == 0)
128a39bfc19SAxel Dörfler 		|| (sScreen.boot_debug_output && sScreen.y == sScreen.rows - 1))) {
129fec23a53SMichael Lotz 		if (sScreen.paging_timeout)
130fec23a53SMichael Lotz 			spin(1000 * 1000 * 3);
131fec23a53SMichael Lotz 		else {
132a39bfc19SAxel Dörfler 			// Use the paging mechanism: either, we're in the debugger, and a
133a39bfc19SAxel Dörfler 			// command is being executed, or we're currently showing boot debug
134a39bfc19SAxel Dörfler 			// output
135f937627dSIngo Weinhold 			const char *text = in_command_invocation()
136f937627dSIngo Weinhold 				? "Press key to continue, Q to quit, S to skip output"
137bc2836bbSMichael Lotz 				: "Press key to continue, S to skip output, P to disable paging";
138855ab2b3SAxel Dörfler 			int32 length = strlen(text);
139855ab2b3SAxel Dörfler 			if (sScreen.x + length > sScreen.columns) {
140855ab2b3SAxel Dörfler 				// make sure we don't overwrite too much
141855ab2b3SAxel Dörfler 				text = "P";
142855ab2b3SAxel Dörfler 				length = 1;
143855ab2b3SAxel Dörfler 			}
144855ab2b3SAxel Dörfler 
145855ab2b3SAxel Dörfler 			for (int32 i = 0; i < length; i++) {
146a39bfc19SAxel Dörfler 				// yellow on black (or reverse, during boot)
147855ab2b3SAxel Dörfler 				sModule->put_glyph(sScreen.columns - length + i, sScreen.y,
148a39bfc19SAxel Dörfler 					text[i], sScreen.boot_debug_output ? 0x6f : 0xf6);
149855ab2b3SAxel Dörfler 			}
150855ab2b3SAxel Dörfler 
1516eba0636SMichael Lotz 			char c = kgetc();
152f937627dSIngo Weinhold 			if (c == 's') {
153855ab2b3SAxel Dörfler 				sScreen.ignore_output = true;
154bc2836bbSMichael Lotz 			} else if (c == 'q' && in_command_invocation()) {
155bc2836bbSMichael Lotz 				abortCommand = true;
15673aa393dSIngo Weinhold 				sScreen.ignore_output = true;
157bc2836bbSMichael Lotz 			} else if (c == 'p' && !in_command_invocation())
158bc2836bbSMichael Lotz 				sScreen.paging = false;
159fec23a53SMichael Lotz 			else if (c == 't' && !in_command_invocation())
160fec23a53SMichael Lotz 				sScreen.paging_timeout = true;
161855ab2b3SAxel Dörfler 
162855ab2b3SAxel Dörfler 			// remove on screen text again
163855ab2b3SAxel Dörfler 			sModule->fill_glyph(sScreen.columns - length, sScreen.y, length,
164855ab2b3SAxel Dörfler 				1, ' ', sScreen.attr);
165855ab2b3SAxel Dörfler 		}
166ab542128SMichael Lotz 
167ab542128SMichael Lotz 		if (sScreen.in_command_rows > 0)
168ab542128SMichael Lotz 			sScreen.in_command_rows += 2;
169fec23a53SMichael Lotz 	}
170a39bfc19SAxel Dörfler 	if (sScreen.y == sScreen.rows - 1) {
171f33c8020SAxel Dörfler 		sScreen.y = 0;
172855ab2b3SAxel Dörfler 		sModule->fill_glyph(0, 0, sScreen.columns, 2, ' ', sScreen.attr);
173a39bfc19SAxel Dörfler 	} else
174f33c8020SAxel Dörfler 		sScreen.y++;
175a39bfc19SAxel Dörfler #endif
176f33c8020SAxel Dörfler 
177f33c8020SAxel Dörfler #if NO_CLEAR
178855ab2b3SAxel Dörfler 	if (sScreen.y + 2 < sScreen.rows) {
179855ab2b3SAxel Dörfler 		sModule->fill_glyph(0, (sScreen.y + 2) % sScreen.rows, sScreen.columns,
180855ab2b3SAxel Dörfler 			1, ' ', sScreen.attr);
181855ab2b3SAxel Dörfler 	}
182f33c8020SAxel Dörfler #endif
183f33c8020SAxel Dörfler 	sScreen.x = 0;
184f937627dSIngo Weinhold 
185f937627dSIngo Weinhold 	if (abortCommand) {
186f937627dSIngo Weinhold 		abort_debugger_command();
187f937627dSIngo Weinhold 			// should not return
188f937627dSIngo Weinhold 	}
189f33c8020SAxel Dörfler }
190f33c8020SAxel Dörfler 
191f33c8020SAxel Dörfler 
192f33c8020SAxel Dörfler static void
19370c3e1a4SAxel Dörfler erase_line(erase_line_mode mode)
19470c3e1a4SAxel Dörfler {
19570c3e1a4SAxel Dörfler 	switch (mode) {
19670c3e1a4SAxel Dörfler 		case LINE_ERASE_WHOLE:
197855ab2b3SAxel Dörfler 			sModule->fill_glyph(0, sScreen.y, sScreen.columns, 1, ' ',
198855ab2b3SAxel Dörfler 				sScreen.attr);
19970c3e1a4SAxel Dörfler 			break;
20070c3e1a4SAxel Dörfler 		case LINE_ERASE_LEFT:
201855ab2b3SAxel Dörfler 			sModule->fill_glyph(0, sScreen.y, sScreen.x + 1, 1, ' ',
202855ab2b3SAxel Dörfler 				sScreen.attr);
20370c3e1a4SAxel Dörfler 			break;
20470c3e1a4SAxel Dörfler 		case LINE_ERASE_RIGHT:
205855ab2b3SAxel Dörfler 			sModule->fill_glyph(sScreen.x, sScreen.y, sScreen.columns
206855ab2b3SAxel Dörfler 				- sScreen.x, 1, ' ', sScreen.attr);
20770c3e1a4SAxel Dörfler 			break;
20870c3e1a4SAxel Dörfler 	}
20970c3e1a4SAxel Dörfler }
21070c3e1a4SAxel Dörfler 
21170c3e1a4SAxel Dörfler 
21270c3e1a4SAxel Dörfler static void
213f33c8020SAxel Dörfler back_space(void)
214f33c8020SAxel Dörfler {
215f33c8020SAxel Dörfler 	if (sScreen.x <= 0)
216f33c8020SAxel Dörfler 		return;
217f33c8020SAxel Dörfler 
218f33c8020SAxel Dörfler 	sScreen.x--;
219f33c8020SAxel Dörfler 	sModule->put_glyph(sScreen.x, sScreen.y, ' ', sScreen.attr);
220f33c8020SAxel Dörfler }
221f33c8020SAxel Dörfler 
222f33c8020SAxel Dörfler 
223f33c8020SAxel Dörfler static void
224f33c8020SAxel Dörfler put_character(char c)
225f33c8020SAxel Dörfler {
226f33c8020SAxel Dörfler 	if (++sScreen.x >= sScreen.columns) {
227f33c8020SAxel Dörfler 		next_line();
228f33c8020SAxel Dörfler 		sScreen.x++;
229f33c8020SAxel Dörfler 	}
230f33c8020SAxel Dörfler 
231f33c8020SAxel Dörfler 	sModule->put_glyph(sScreen.x - 1, sScreen.y, c, sScreen.attr);
232f33c8020SAxel Dörfler }
233f33c8020SAxel Dörfler 
234f33c8020SAxel Dörfler 
235f33c8020SAxel Dörfler static void
23667f20716SAxel Dörfler set_vt100_attributes(int32 *args, int32 argCount)
23767f20716SAxel Dörfler {
23867f20716SAxel Dörfler 	if (argCount == 0) {
23967f20716SAxel Dörfler 		// that's the default (attributes off)
24067f20716SAxel Dörfler 		argCount++;
24167f20716SAxel Dörfler 		args[0] = 0;
24267f20716SAxel Dörfler 	}
24367f20716SAxel Dörfler 
24467f20716SAxel Dörfler 	for (int32 i = 0; i < argCount; i++) {
24567f20716SAxel Dörfler 		switch (args[i]) {
24667f20716SAxel Dörfler 			case 0: // reset
24733965e02SAxel Dörfler 				sScreen.attr = sScreen.boot_debug_output ? 0xf0 : 0x0f;
24867f20716SAxel Dörfler 				sScreen.bright_attr = true;
24967f20716SAxel Dörfler 				sScreen.reverse_attr = false;
25067f20716SAxel Dörfler 				break;
25167f20716SAxel Dörfler 			case 1: // bright
25267f20716SAxel Dörfler 				sScreen.bright_attr = true;
25367f20716SAxel Dörfler 				sScreen.attr |= 0x08; // set the bright bit
25467f20716SAxel Dörfler 				break;
25567f20716SAxel Dörfler 			case 2: // dim
25667f20716SAxel Dörfler 				sScreen.bright_attr = false;
25767f20716SAxel Dörfler 				sScreen.attr &= ~0x08; // unset the bright bit
25867f20716SAxel Dörfler 				break;
25967f20716SAxel Dörfler 			case 4: // underscore we can't do
26067f20716SAxel Dörfler 				break;
26167f20716SAxel Dörfler 			case 5: // blink
26267f20716SAxel Dörfler 				sScreen.attr |= 0x80; // set the blink bit
26367f20716SAxel Dörfler 				break;
26467f20716SAxel Dörfler 			case 7: // reverse
26567f20716SAxel Dörfler 				sScreen.reverse_attr = true;
266855ab2b3SAxel Dörfler 				sScreen.attr = ((sScreen.attr & BMASK) >> 4)
267855ab2b3SAxel Dörfler 					| ((sScreen.attr & FMASK) << 4);
26867f20716SAxel Dörfler 				if (sScreen.bright_attr)
26967f20716SAxel Dörfler 					sScreen.attr |= 0x08;
27067f20716SAxel Dörfler 				break;
27167f20716SAxel Dörfler 			case 8: // hidden?
27267f20716SAxel Dörfler 				break;
27367f20716SAxel Dörfler 
27467f20716SAxel Dörfler 			/* foreground colors */
275855ab2b3SAxel Dörfler 			case 30: // black
276855ab2b3SAxel Dörfler 			case 31: // red
277855ab2b3SAxel Dörfler 			case 32: // green
278855ab2b3SAxel Dörfler 			case 33: // yellow
279855ab2b3SAxel Dörfler 			case 34: // blue
280855ab2b3SAxel Dörfler 			case 35: // magenta
281855ab2b3SAxel Dörfler 			case 36: // cyan
282855ab2b3SAxel Dörfler 			case 37: // white
283855ab2b3SAxel Dörfler 			{
284855ab2b3SAxel Dörfler 				const uint8 colors[] = {0, 4, 2, 6, 1, 5, 3, 7};
285855ab2b3SAxel Dörfler 				sScreen.attr = (sScreen.attr & ~FMASK) | colors[args[i] - 30]
286855ab2b3SAxel Dörfler 					| (sScreen.bright_attr ? 0x08 : 0);
287855ab2b3SAxel Dörfler 				break;
288855ab2b3SAxel Dörfler 			}
28967f20716SAxel Dörfler 
29067f20716SAxel Dörfler 			/* background colors */
29167f20716SAxel Dörfler 			case 40: sScreen.attr = (sScreen.attr & ~BMASK) | (0 << 4); break; // black
29267f20716SAxel Dörfler 			case 41: sScreen.attr = (sScreen.attr & ~BMASK) | (4 << 4); break; // red
29367f20716SAxel Dörfler 			case 42: sScreen.attr = (sScreen.attr & ~BMASK) | (2 << 4); break; // green
29467f20716SAxel Dörfler 			case 43: sScreen.attr = (sScreen.attr & ~BMASK) | (6 << 4); break; // yellow
29567f20716SAxel Dörfler 			case 44: sScreen.attr = (sScreen.attr & ~BMASK) | (1 << 4); break; // blue
29667f20716SAxel Dörfler 			case 45: sScreen.attr = (sScreen.attr & ~BMASK) | (5 << 4); break; // magenta
29767f20716SAxel Dörfler 			case 46: sScreen.attr = (sScreen.attr & ~BMASK) | (3 << 4); break; // cyan
29867f20716SAxel Dörfler 			case 47: sScreen.attr = (sScreen.attr & ~BMASK) | (7 << 4); break; // white
29967f20716SAxel Dörfler 		}
30067f20716SAxel Dörfler 	}
30167f20716SAxel Dörfler }
30267f20716SAxel Dörfler 
30367f20716SAxel Dörfler 
30467f20716SAxel Dörfler static bool
30546af4e77SAxel Dörfler process_vt100_command(const char c, bool seenBracket, int32 *args,
30646af4e77SAxel Dörfler 	int32 argCount)
30767f20716SAxel Dörfler {
30867f20716SAxel Dörfler 	bool ret = true;
30967f20716SAxel Dörfler 
31067f20716SAxel Dörfler //	kprintf("process_vt100_command: c '%c', argCount %ld, arg[0] %ld, arg[1] %ld, seenBracket %d\n",
31167f20716SAxel Dörfler //		c, argCount, args[0], args[1], seenBracket);
31267f20716SAxel Dörfler 
31367f20716SAxel Dörfler 	if (seenBracket) {
31467f20716SAxel Dörfler 		switch (c) {
31546af4e77SAxel Dörfler 			case 'H':	// set cursor position
31646af4e77SAxel Dörfler 			case 'f':
31746af4e77SAxel Dörfler 			{
31867f20716SAxel Dörfler 				int32 row = argCount > 0 ? args[0] : 1;
31967f20716SAxel Dörfler 				int32 col = argCount > 1 ? args[1] : 1;
32067f20716SAxel Dörfler 				if (row > 0)
32167f20716SAxel Dörfler 					row--;
32267f20716SAxel Dörfler 				if (col > 0)
32367f20716SAxel Dörfler 					col--;
32467f20716SAxel Dörfler 				move_cursor(col, row);
32567f20716SAxel Dörfler 				break;
32667f20716SAxel Dörfler 			}
32746af4e77SAxel Dörfler 			case 'A':	// move up
32846af4e77SAxel Dörfler 			{
32946af4e77SAxel Dörfler 				int32 deltaY = argCount > 0 ? -args[0] : -1;
33046af4e77SAxel Dörfler 				if (deltaY == 0)
33146af4e77SAxel Dörfler 					deltaY = -1;
33246af4e77SAxel Dörfler 				move_cursor(sScreen.x, sScreen.y + deltaY);
33367f20716SAxel Dörfler 				break;
33467f20716SAxel Dörfler 			}
33567f20716SAxel Dörfler 			case 'e':
33646af4e77SAxel Dörfler 			case 'B':	// move down
33746af4e77SAxel Dörfler 			{
33846af4e77SAxel Dörfler 				int32 deltaY = argCount > 0 ? args[0] : 1;
33946af4e77SAxel Dörfler 				if (deltaY == 0)
34046af4e77SAxel Dörfler 					deltaY = 1;
34146af4e77SAxel Dörfler 				move_cursor(sScreen.x, sScreen.y + deltaY);
34267f20716SAxel Dörfler 				break;
34367f20716SAxel Dörfler 			}
34446af4e77SAxel Dörfler 			case 'D':	// move left
34546af4e77SAxel Dörfler 			{
34646af4e77SAxel Dörfler 				int32 deltaX = argCount > 0 ? -args[0] : -1;
34746af4e77SAxel Dörfler 				if (deltaX == 0)
34846af4e77SAxel Dörfler 					deltaX = -1;
34946af4e77SAxel Dörfler 				move_cursor(sScreen.x + deltaX, sScreen.y);
35067f20716SAxel Dörfler 				break;
35167f20716SAxel Dörfler 			}
35267f20716SAxel Dörfler 			case 'a':
35346af4e77SAxel Dörfler 			case 'C':	// move right
35446af4e77SAxel Dörfler 			{
35546af4e77SAxel Dörfler 				int32 deltaX = argCount > 0 ? args[0] : 1;
35646af4e77SAxel Dörfler 				if (deltaX == 0)
35746af4e77SAxel Dörfler 					deltaX = 1;
35846af4e77SAxel Dörfler 				move_cursor(sScreen.x + deltaX, sScreen.y);
35967f20716SAxel Dörfler 				break;
36067f20716SAxel Dörfler 			}
36167f20716SAxel Dörfler 			case '`':
36246af4e77SAxel Dörfler 			case 'G':	// set X position
36346af4e77SAxel Dörfler 			{
36446af4e77SAxel Dörfler 				int32 newX = argCount > 0 ? args[0] : 1;
36546af4e77SAxel Dörfler 				if (newX > 0)
36646af4e77SAxel Dörfler 					newX--;
36746af4e77SAxel Dörfler 				move_cursor(newX, sScreen.y);
36867f20716SAxel Dörfler 				break;
36967f20716SAxel Dörfler 			}
37046af4e77SAxel Dörfler 			case 'd':	// set y position
37146af4e77SAxel Dörfler 			{
37246af4e77SAxel Dörfler 				int32 newY = argCount > 0 ? args[0] : 1;
37346af4e77SAxel Dörfler 				if (newY > 0)
37446af4e77SAxel Dörfler 					newY--;
37546af4e77SAxel Dörfler 				move_cursor(sScreen.x, newY);
37667f20716SAxel Dörfler 				break;
37767f20716SAxel Dörfler 			}
37867f20716SAxel Dörfler #if 0
37946af4e77SAxel Dörfler 			case 's':	// save current cursor
38067f20716SAxel Dörfler 				save_cur(console, false);
38167f20716SAxel Dörfler 				break;
38246af4e77SAxel Dörfler 			case 'u':	// restore cursor
38367f20716SAxel Dörfler 				restore_cur(console, false);
38467f20716SAxel Dörfler 				break;
38546af4e77SAxel Dörfler 			case 'r':	// set scroll region
38646af4e77SAxel Dörfler 			{
38767f20716SAxel Dörfler 				int32 low = argCount > 0 ? args[0] : 1;
38867f20716SAxel Dörfler 				int32 high = argCount > 1 ? args[1] : sScreen.lines;
38967f20716SAxel Dörfler 				if (low <= high)
39067f20716SAxel Dörfler 					set_scroll_region(console, low - 1, high - 1);
39167f20716SAxel Dörfler 				break;
39267f20716SAxel Dörfler 			}
39346af4e77SAxel Dörfler 			case 'L':	// scroll virtual down at cursor
39446af4e77SAxel Dörfler 			{
39567f20716SAxel Dörfler 				int32 lines = argCount > 0 ? args[0] : 1;
39667f20716SAxel Dörfler 				while (lines > 0) {
39767f20716SAxel Dörfler 					scrdown(console);
39867f20716SAxel Dörfler 					lines--;
39967f20716SAxel Dörfler 				}
40067f20716SAxel Dörfler 				break;
40167f20716SAxel Dörfler 			}
40246af4e77SAxel Dörfler 			case 'M':	// scroll virtual up at cursor
40346af4e77SAxel Dörfler 			{
40467f20716SAxel Dörfler 				int32 lines = argCount > 0 ? args[0] : 1;
40567f20716SAxel Dörfler 				while (lines > 0) {
40667f20716SAxel Dörfler 					scrup(console);
40767f20716SAxel Dörfler 					lines--;
40867f20716SAxel Dörfler 				}
40967f20716SAxel Dörfler 				break;
41067f20716SAxel Dörfler 			}
41170c3e1a4SAxel Dörfler #endif
41267f20716SAxel Dörfler 			case 'K':
41367f20716SAxel Dörfler 				if (argCount == 0 || args[0] == 0) {
41467f20716SAxel Dörfler 					// erase to end of line
41570c3e1a4SAxel Dörfler 					erase_line(LINE_ERASE_RIGHT);
41667f20716SAxel Dörfler 				} else if (argCount > 0) {
41767f20716SAxel Dörfler 					if (args[0] == 1)
41870c3e1a4SAxel Dörfler 						erase_line(LINE_ERASE_LEFT);
41967f20716SAxel Dörfler 					else if (args[0] == 2)
42070c3e1a4SAxel Dörfler 						erase_line(LINE_ERASE_WHOLE);
42167f20716SAxel Dörfler 				}
42267f20716SAxel Dörfler 				break;
42370c3e1a4SAxel Dörfler #if 0
42467f20716SAxel Dörfler 			case 'J':
42567f20716SAxel Dörfler 				if (argCount == 0 || args[0] == 0) {
42667f20716SAxel Dörfler 					// erase to end of screen
42767f20716SAxel Dörfler 					erase_screen(console, SCREEN_ERASE_DOWN);
42867f20716SAxel Dörfler 				} else {
42967f20716SAxel Dörfler 					if (args[0] == 1)
43067f20716SAxel Dörfler 						erase_screen(console, SCREEN_ERASE_UP);
43167f20716SAxel Dörfler 					else if (args[0] == 2)
43267f20716SAxel Dörfler 						erase_screen(console, SCREEN_ERASE_WHOLE);
43367f20716SAxel Dörfler 				}
43467f20716SAxel Dörfler 				break;
43567f20716SAxel Dörfler #endif
43667f20716SAxel Dörfler 			case 'm':
43767f20716SAxel Dörfler 				if (argCount >= 0)
43867f20716SAxel Dörfler 					set_vt100_attributes(args, argCount);
43967f20716SAxel Dörfler 				break;
44067f20716SAxel Dörfler 			default:
44167f20716SAxel Dörfler 				ret = false;
44267f20716SAxel Dörfler 		}
44367f20716SAxel Dörfler 	} else {
44467f20716SAxel Dörfler 		switch (c) {
44567f20716SAxel Dörfler #if 0
44667f20716SAxel Dörfler 			case 'c':
44767f20716SAxel Dörfler 				reset_console(console);
44867f20716SAxel Dörfler 				break;
44967f20716SAxel Dörfler 			case 'D':
45067f20716SAxel Dörfler 				rlf(console);
45167f20716SAxel Dörfler 				break;
45267f20716SAxel Dörfler 			case 'M':
45367f20716SAxel Dörfler 				lf(console);
45467f20716SAxel Dörfler 				break;
45567f20716SAxel Dörfler 			case '7':
45667f20716SAxel Dörfler 				save_cur(console, true);
45767f20716SAxel Dörfler 				break;
45867f20716SAxel Dörfler 			case '8':
45967f20716SAxel Dörfler 				restore_cur(console, true);
46067f20716SAxel Dörfler 				break;
46167f20716SAxel Dörfler #endif
46267f20716SAxel Dörfler 			default:
46367f20716SAxel Dörfler 				ret = false;
46467f20716SAxel Dörfler 		}
46567f20716SAxel Dörfler 	}
46667f20716SAxel Dörfler 
46767f20716SAxel Dörfler 	return ret;
46867f20716SAxel Dörfler }
46967f20716SAxel Dörfler 
47067f20716SAxel Dörfler 
47167f20716SAxel Dörfler static void
472f33c8020SAxel Dörfler parse_character(char c)
473f33c8020SAxel Dörfler {
47467f20716SAxel Dörfler 	switch (sScreen.state) {
47567f20716SAxel Dörfler 		case CONSOLE_STATE_NORMAL:
476f33c8020SAxel Dörfler 			// just output the stuff
477f33c8020SAxel Dörfler 			switch (c) {
478f33c8020SAxel Dörfler 				case '\n':
479f33c8020SAxel Dörfler 					next_line();
480f33c8020SAxel Dörfler 					break;
481f33c8020SAxel Dörfler 				case 0x8:
482f33c8020SAxel Dörfler 					back_space();
483f33c8020SAxel Dörfler 					break;
484f33c8020SAxel Dörfler 				case '\t':
48546af4e77SAxel Dörfler 					// TODO: real tab...
486f31dc4ddSAxel Dörfler 					sScreen.x = (sScreen.x + 8) & ~7;
487f31dc4ddSAxel Dörfler 					if (sScreen.x >= sScreen.columns)
488f31dc4ddSAxel Dörfler 						next_line();
489f33c8020SAxel Dörfler 					break;
490f33c8020SAxel Dörfler 
491f33c8020SAxel Dörfler 				case '\r':
492f33c8020SAxel Dörfler 				case '\0':
49367f20716SAxel Dörfler 				case '\a': // beep
494f33c8020SAxel Dörfler 					break;
495f33c8020SAxel Dörfler 
49667f20716SAxel Dörfler 				case 0x1b:
49767f20716SAxel Dörfler 					// escape character
49846af4e77SAxel Dörfler 					sScreen.arg_count = 0;
49967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_GOT_ESCAPE;
50067f20716SAxel Dörfler 					break;
501f33c8020SAxel Dörfler 				default:
502f33c8020SAxel Dörfler 					put_character(c);
503f33c8020SAxel Dörfler 			}
50467f20716SAxel Dörfler 			break;
50567f20716SAxel Dörfler 		case CONSOLE_STATE_GOT_ESCAPE:
50667f20716SAxel Dörfler 			// look for either commands with no argument, or the '[' character
50767f20716SAxel Dörfler 			switch (c) {
50867f20716SAxel Dörfler 				case '[':
50967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_SEEN_BRACKET;
51067f20716SAxel Dörfler 					break;
51167f20716SAxel Dörfler 				default:
51246af4e77SAxel Dörfler 					sScreen.args[0] = 0;
51346af4e77SAxel Dörfler 					process_vt100_command(c, false, sScreen.args, 0);
51467f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
51567f20716SAxel Dörfler 			}
51667f20716SAxel Dörfler 			break;
51767f20716SAxel Dörfler 		case CONSOLE_STATE_SEEN_BRACKET:
51867f20716SAxel Dörfler 			switch (c) {
51967f20716SAxel Dörfler 				case '0'...'9':
52067f20716SAxel Dörfler 					sScreen.arg_count = 0;
52146af4e77SAxel Dörfler 					sScreen.args[0] = c - '0';
52267f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_PARSING_ARG;
52367f20716SAxel Dörfler 					break;
52467f20716SAxel Dörfler 				case '?':
525855ab2b3SAxel Dörfler 					// private DEC mode parameter follows - we ignore those
526855ab2b3SAxel Dörfler 					// anyway
52767f20716SAxel Dörfler 					break;
52867f20716SAxel Dörfler 				default:
52938eb09a3SIngo Weinhold 					process_vt100_command(c, true, sScreen.args, 0);
53067f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
53146af4e77SAxel Dörfler 					break;
53267f20716SAxel Dörfler 			}
53367f20716SAxel Dörfler 			break;
53467f20716SAxel Dörfler 		case CONSOLE_STATE_NEW_ARG:
53567f20716SAxel Dörfler 			switch (c) {
53667f20716SAxel Dörfler 				case '0'...'9':
53746af4e77SAxel Dörfler 					if (++sScreen.arg_count == MAX_ARGS) {
53867f20716SAxel Dörfler 						sScreen.state = CONSOLE_STATE_NORMAL;
53967f20716SAxel Dörfler 						break;
54067f20716SAxel Dörfler 					}
54167f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] = c - '0';
54267f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_PARSING_ARG;
54367f20716SAxel Dörfler 					break;
54467f20716SAxel Dörfler 				default:
545855ab2b3SAxel Dörfler 					process_vt100_command(c, true, sScreen.args,
546855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
54767f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
54846af4e77SAxel Dörfler 					break;
54967f20716SAxel Dörfler 			}
55067f20716SAxel Dörfler 			break;
55167f20716SAxel Dörfler 		case CONSOLE_STATE_PARSING_ARG:
55267f20716SAxel Dörfler 			// parse args
55367f20716SAxel Dörfler 			switch (c) {
55467f20716SAxel Dörfler 				case '0'...'9':
55567f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] *= 10;
55667f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] += c - '0';
55767f20716SAxel Dörfler 					break;
55867f20716SAxel Dörfler 				case ';':
55967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NEW_ARG;
56067f20716SAxel Dörfler 					break;
56167f20716SAxel Dörfler 				default:
562855ab2b3SAxel Dörfler 					process_vt100_command(c, true, sScreen.args,
563855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
56467f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
56546af4e77SAxel Dörfler 					break;
56667f20716SAxel Dörfler 			}
56767f20716SAxel Dörfler 	}
568f33c8020SAxel Dörfler }
569f33c8020SAxel Dörfler 
570f33c8020SAxel Dörfler 
571855ab2b3SAxel Dörfler static int
572855ab2b3SAxel Dörfler set_paging(int argc, char **argv)
573855ab2b3SAxel Dörfler {
574855ab2b3SAxel Dörfler 	if (argc > 1 && !strcmp(argv[1], "--help")) {
575855ab2b3SAxel Dörfler 		kprintf("usage: %s [on|off]\n", argv[0]);
576855ab2b3SAxel Dörfler 		return 0;
577855ab2b3SAxel Dörfler 	}
578855ab2b3SAxel Dörfler 
579855ab2b3SAxel Dörfler 	if (argc == 1)
580855ab2b3SAxel Dörfler 		sScreen.paging = !sScreen.paging;
581855ab2b3SAxel Dörfler 	else if (!strcmp(argv[1], "on"))
582855ab2b3SAxel Dörfler 		sScreen.paging = true;
583855ab2b3SAxel Dörfler 	else if (!strcmp(argv[1], "off"))
584855ab2b3SAxel Dörfler 		sScreen.paging = false;
585855ab2b3SAxel Dörfler 	else
586855ab2b3SAxel Dörfler 		sScreen.paging = parse_expression(argv[1]) != 0;
587855ab2b3SAxel Dörfler 
588855ab2b3SAxel Dörfler 	kprintf("paging is turned %s now.\n", sScreen.paging ? "on" : "off");
589855ab2b3SAxel Dörfler 	return 0;
590855ab2b3SAxel Dörfler }
591855ab2b3SAxel Dörfler 
592855ab2b3SAxel Dörfler 
593f33c8020SAxel Dörfler //	#pragma mark -
594f33c8020SAxel Dörfler 
595f33c8020SAxel Dörfler 
596f33c8020SAxel Dörfler status_t
597f33c8020SAxel Dörfler blue_screen_init(void)
598f33c8020SAxel Dörfler {
599f33c8020SAxel Dörfler 	extern console_module_info gFrameBufferConsoleModule;
600f33c8020SAxel Dörfler 
601f33c8020SAxel Dörfler 	// we can't use get_module() here, since it's too early in the boot process
602f33c8020SAxel Dörfler 
603f33c8020SAxel Dörfler 	if (!frame_buffer_console_available())
604f33c8020SAxel Dörfler 		return B_ERROR;
605f33c8020SAxel Dörfler 
606f33c8020SAxel Dörfler 	sModule = &gFrameBufferConsoleModule;
607*e7d7b1e2SRene Gollent 	sScreen.paging = !get_safemode_boolean(
608*e7d7b1e2SRene Gollent 		"disable_onscreen_paging", false);
609fec23a53SMichael Lotz 	sScreen.paging_timeout = false;
610855ab2b3SAxel Dörfler 
611855ab2b3SAxel Dörfler 	add_debugger_command("paging", set_paging, "Enable or disable paging");
612f33c8020SAxel Dörfler 	return B_OK;
613f33c8020SAxel Dörfler }
614f33c8020SAxel Dörfler 
615f33c8020SAxel Dörfler 
616173d0b2fSAxel Dörfler status_t
61792447917SAxel Dörfler blue_screen_enter(bool debugOutput)
618f33c8020SAxel Dörfler {
61992447917SAxel Dörfler 	sScreen.attr = debugOutput ? 0xf0 : 0x0f;
62092447917SAxel Dörfler 		// black on white for KDL, white on black for debug output
62133965e02SAxel Dörfler 	sScreen.boot_debug_output = debugOutput;
62233965e02SAxel Dörfler 	sScreen.ignore_output = false;
62333965e02SAxel Dörfler 
624f33c8020SAxel Dörfler 	sScreen.x = sScreen.y = 0;
62567f20716SAxel Dörfler 	sScreen.state = CONSOLE_STATE_NORMAL;
626f33c8020SAxel Dörfler 
627173d0b2fSAxel Dörfler 	if (sModule == NULL)
628173d0b2fSAxel Dörfler 		return B_NO_INIT;
629173d0b2fSAxel Dörfler 
630f33c8020SAxel Dörfler 	sModule->get_size(&sScreen.columns, &sScreen.rows);
631f33c8020SAxel Dörfler #if !NO_CLEAR
632f33c8020SAxel Dörfler 	sModule->clear(sScreen.attr);
633f33c8020SAxel Dörfler #else
634f33c8020SAxel Dörfler 	sModule->fill_glyph(0, sScreen.y, sScreen.columns, 3, ' ', sScreen.attr);
635f33c8020SAxel Dörfler #endif
636173d0b2fSAxel Dörfler 	return B_OK;
637f33c8020SAxel Dörfler }
638f33c8020SAxel Dörfler 
639f33c8020SAxel Dörfler 
640976e5259SIngo Weinhold bool
641976e5259SIngo Weinhold blue_screen_paging_enabled(void)
642976e5259SIngo Weinhold {
643976e5259SIngo Weinhold 	return sScreen.paging;
644976e5259SIngo Weinhold }
645976e5259SIngo Weinhold 
646976e5259SIngo Weinhold 
647976e5259SIngo Weinhold void
648976e5259SIngo Weinhold blue_screen_set_paging(bool enabled)
649976e5259SIngo Weinhold {
650976e5259SIngo Weinhold 	sScreen.paging = enabled;
651976e5259SIngo Weinhold }
652976e5259SIngo Weinhold 
653976e5259SIngo Weinhold 
654a1587d16SIngo Weinhold void
655a1587d16SIngo Weinhold blue_screen_clear_screen(void)
656a1587d16SIngo Weinhold {
657a1587d16SIngo Weinhold 	sModule->clear(sScreen.attr);
658a1587d16SIngo Weinhold 	move_cursor(0, 0);
659a1587d16SIngo Weinhold }
660a1587d16SIngo Weinhold 
661a1587d16SIngo Weinhold 
662f33c8020SAxel Dörfler char
663f33c8020SAxel Dörfler blue_screen_getchar(void)
664f33c8020SAxel Dörfler {
665f33c8020SAxel Dörfler 	return arch_debug_blue_screen_getchar();
666f33c8020SAxel Dörfler }
667f33c8020SAxel Dörfler 
668f33c8020SAxel Dörfler 
669f33c8020SAxel Dörfler void
670f33c8020SAxel Dörfler blue_screen_putchar(char c)
671f33c8020SAxel Dörfler {
67233965e02SAxel Dörfler 	if (sScreen.ignore_output
67333965e02SAxel Dörfler 		&& (in_command_invocation() || sScreen.boot_debug_output))
674855ab2b3SAxel Dörfler 		return;
675855ab2b3SAxel Dörfler 
676855ab2b3SAxel Dörfler 	sScreen.ignore_output = false;
677f33c8020SAxel Dörfler 	hide_cursor();
678f33c8020SAxel Dörfler 
679f33c8020SAxel Dörfler 	parse_character(c);
680f33c8020SAxel Dörfler 
681f33c8020SAxel Dörfler 	update_cursor(sScreen.x, sScreen.y);
682f33c8020SAxel Dörfler }
683f33c8020SAxel Dörfler 
684f33c8020SAxel Dörfler 
685f33c8020SAxel Dörfler void
686f33c8020SAxel Dörfler blue_screen_puts(const char *text)
687f33c8020SAxel Dörfler {
68833965e02SAxel Dörfler 	if (sScreen.ignore_output
68933965e02SAxel Dörfler 		&& (in_command_invocation() || sScreen.boot_debug_output))
690855ab2b3SAxel Dörfler 		return;
691855ab2b3SAxel Dörfler 
692855ab2b3SAxel Dörfler 	sScreen.ignore_output = false;
693f33c8020SAxel Dörfler 	hide_cursor();
694f33c8020SAxel Dörfler 
695f33c8020SAxel Dörfler 	while (text[0] != '\0') {
696f33c8020SAxel Dörfler 		parse_character(text[0]);
697f33c8020SAxel Dörfler 		text++;
698f33c8020SAxel Dörfler 	}
699f33c8020SAxel Dörfler 
700f33c8020SAxel Dörfler 	update_cursor(sScreen.x, sScreen.y);
701f33c8020SAxel Dörfler }
702