debuggers.hg

view xen/drivers/char/console.c @ 3705:4294cfa9fad3

bitkeeper revision 1.1159.212.95 (4204aa0ee0re5Xx1zWrJ9ejxzgRs3w)

Various cleanups. Remove PDB pending simpler GDB stub and/or NetBSD debugger.
Force emacs mode to appropriate tabbing in various files.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Sat Feb 05 11:12:14 2005 +0000 (2005-02-05)
parents 1c55bbe02576
children 88957a238191
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2 /******************************************************************************
3 * console.c
4 *
5 * Emergency console I/O for Xen and the domain-0 guest OS.
6 *
7 * Copyright (c) 2002-2004, K A Fraser.
8 */
10 #include <stdarg.h>
11 #include <xen/config.h>
12 #include <xen/compile.h>
13 #include <xen/init.h>
14 #include <xen/lib.h>
15 #include <xen/errno.h>
16 #include <xen/event.h>
17 #include <xen/spinlock.h>
18 #include <xen/console.h>
19 #include <xen/serial.h>
20 #include <xen/keyhandler.h>
21 #include <asm/uaccess.h>
22 #include <asm/mm.h>
24 /* opt_console: comma-separated list of console outputs. */
25 static unsigned char opt_console[30] = OPT_CONSOLE_STR;
26 string_param("console", opt_console);
28 /* opt_conswitch: a character pair controlling console switching. */
29 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
30 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
31 /* boots. Any other value, or omitting the char, enables auto-switch */
32 static unsigned char opt_conswitch[5] = "a";
33 string_param("conswitch", opt_conswitch);
35 static int xpos, ypos;
36 static unsigned char *video;
38 #define CONSOLE_RING_SIZE 16392
39 typedef struct console_ring_st
40 {
41 char buf[CONSOLE_RING_SIZE];
42 unsigned int len;
43 } console_ring_t;
44 static console_ring_t console_ring;
46 static char printk_prefix[16] = "";
48 static int sercon_handle = -1;
49 static int vgacon_enabled = 0;
51 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
54 /*
55 * *******************************************************
56 * *************** OUTPUT TO VGA CONSOLE *****************
57 * *******************************************************
58 */
60 /* VGA text (mode 3) definitions. */
61 #define COLUMNS 80
62 #define LINES 25
63 #define ATTRIBUTE 7
65 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
66 static void cls(void)
67 {
68 memset(video, 0, COLUMNS * LINES * 2);
69 xpos = ypos = 0;
70 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
71 }
73 static int detect_video(void *video_base)
74 {
75 volatile u16 *p = (volatile u16 *)video_base;
76 u16 saved1 = p[0], saved2 = p[1];
77 int video_found = 1;
79 p[0] = 0xAA55;
80 p[1] = 0x55AA;
81 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
82 video_found = 0;
84 p[0] = 0x55AA;
85 p[1] = 0xAA55;
86 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
87 video_found = 0;
89 p[0] = saved1;
90 p[1] = saved2;
92 return video_found;
93 }
95 static int detect_vga(void)
96 {
97 /*
98 * Look at a number of well-known locations. Even if video is not at
99 * 0xB8000 right now, it will appear there when we set up text mode 3.
100 *
101 * We assume if there is any sign of a video adaptor then it is at least
102 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
103 *
104 * These checks are basically to detect headless server boxes.
105 */
106 return (detect_video(__va(0xA0000)) ||
107 detect_video(__va(0xB0000)) ||
108 detect_video(__va(0xB8000)));
109 }
111 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
112 static void init_vga(void)
113 {
114 /* The following VGA state was saved from a chip in text mode 3. */
115 static unsigned char regs[] = {
116 /* Sequencer registers */
117 0x03, 0x00, 0x03, 0x00, 0x02,
118 /* CRTC registers */
119 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
120 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
121 0xb9, 0xa3, 0xff,
122 /* Graphic registers */
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
124 /* Attribute registers */
125 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
126 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
127 };
129 int i, j = 0;
130 volatile unsigned char tmp;
132 if ( !vgacon_enabled )
133 return;
135 if ( !detect_vga() )
136 {
137 printk("No VGA adaptor detected!\n");
138 vgacon_enabled = 0;
139 return;
140 }
142 video = __va(0xB8000);
144 tmp = inb(0x3da);
145 outb(0x00, 0x3c0);
147 for ( i = 0; i < 5; i++ )
148 outw((regs[j++] << 8) | i, 0x3c4);
150 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
151 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
153 for ( i = 0; i < 25; i++ )
154 outw((regs[j++] << 8) | i, 0x3d4);
156 for ( i = 0; i < 9; i++ )
157 outw((regs[j++] << 8) | i, 0x3ce);
159 for ( i = 0; i < 21; i++ )
160 {
161 tmp = inb(0x3da);
162 outb(i, 0x3c0);
163 outb(regs[j++], 0x3c0);
164 }
166 tmp = inb(0x3da);
167 outb(0x20, 0x3c0);
169 cls();
170 }
172 static void put_newline(void)
173 {
174 xpos = 0;
175 ypos++;
177 if (ypos >= LINES)
178 {
179 static char zeroarr[2*COLUMNS] = { 0 };
180 ypos = LINES-1;
181 memcpy((char*)video,
182 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
183 memcpy((char*)video + (LINES-1)*2*COLUMNS,
184 zeroarr, 2*COLUMNS);
185 }
186 }
188 static void putchar_console(int c)
189 {
190 if ( !vgacon_enabled )
191 return;
193 if ( c == '\n' )
194 {
195 put_newline();
196 }
197 else
198 {
199 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
200 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
201 if ( ++xpos >= COLUMNS )
202 put_newline();
203 }
204 }
207 /*
208 * ********************************************************
209 * *************** ACCESS TO CONSOLE RING *****************
210 * ********************************************************
211 */
213 static void putchar_console_ring(int c)
214 {
215 if ( console_ring.len < CONSOLE_RING_SIZE )
216 console_ring.buf[console_ring.len++] = (char)c;
217 }
219 long read_console_ring(unsigned long str, unsigned int count, unsigned cmd)
220 {
221 unsigned int len;
223 len = (console_ring.len < count) ? console_ring.len : count;
225 if ( copy_to_user((char *)str, console_ring.buf, len) )
226 return -EFAULT;
228 if ( cmd & CONSOLE_RING_CLEAR )
229 console_ring.len = 0;
231 return len;
232 }
235 /*
236 * *******************************************************
237 * *************** ACCESS TO SERIAL LINE *****************
238 * *******************************************************
239 */
241 /* Characters received over the serial line are buffered for domain 0. */
242 #define SERIAL_RX_SIZE 128
243 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
244 static char serial_rx_ring[SERIAL_RX_SIZE];
245 static unsigned int serial_rx_cons, serial_rx_prod;
247 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
248 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
249 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
251 static void switch_serial_input(void)
252 {
253 static char *input_str[2] = { "DOM0", "Xen" };
254 xen_rx = !xen_rx;
255 if ( SWITCH_CODE != 0 )
256 printk("*** Serial input -> %s "
257 "(type 'CTRL-%c' three times to switch input to %s).\n",
258 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
259 }
261 static void __serial_rx(unsigned char c, struct xen_regs *regs)
262 {
263 if ( xen_rx )
264 {
265 handle_keypress(c, regs);
266 }
267 else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
268 {
269 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
270 if ( serial_rx_prod++ == serial_rx_cons )
271 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
272 }
273 }
275 static void serial_rx(unsigned char c, struct xen_regs *regs)
276 {
277 static int switch_code_count = 0;
279 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
280 {
281 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
282 if ( ++switch_code_count == 3 )
283 {
284 switch_serial_input();
285 switch_code_count = 0;
286 }
287 }
288 else
289 {
290 switch_code_count = 0;
291 }
293 /* Finally process the just-received character. */
294 __serial_rx(c, regs);
295 }
297 long do_console_io(int cmd, int count, char *buffer)
298 {
299 char *kbuf;
300 long rc;
302 #ifndef VERBOSE
303 /* Only domain-0 may access the emergency console. */
304 if ( current->domain->id != 0 )
305 return -EPERM;
306 #endif
308 switch ( cmd )
309 {
310 case CONSOLEIO_write:
311 if ( count > (PAGE_SIZE-1) )
312 count = PAGE_SIZE-1;
313 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
314 return -ENOMEM;
315 kbuf[count] = '\0';
316 rc = count;
317 if ( copy_from_user(kbuf, buffer, count) )
318 rc = -EFAULT;
319 else
320 serial_puts(sercon_handle, kbuf);
321 free_xenheap_page((unsigned long)kbuf);
322 break;
323 case CONSOLEIO_read:
324 rc = 0;
325 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
326 {
327 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
328 &buffer[rc]) )
329 {
330 rc = -EFAULT;
331 break;
332 }
333 rc++;
334 serial_rx_cons++;
335 }
336 break;
337 default:
338 rc = -ENOSYS;
339 break;
340 }
342 return rc;
343 }
346 /*
347 * *****************************************************
348 * *************** GENERIC CONSOLE I/O *****************
349 * *****************************************************
350 */
352 static inline void __putstr(const char *str)
353 {
354 int c;
355 serial_puts(sercon_handle, str);
356 while ( (c = *str++) != '\0' )
357 {
358 putchar_console(c);
359 putchar_console_ring(c);
360 }
361 }
363 void printf(const char *fmt, ...)
364 {
365 static char buf[1024];
366 static int start_of_line = 1;
368 va_list args;
369 char *p, *q;
370 unsigned long flags;
372 spin_lock_irqsave(&console_lock, flags);
374 va_start(args, fmt);
375 (void)vsnprintf(buf, sizeof(buf), fmt, args);
376 va_end(args);
378 p = buf;
379 while ( (q = strchr(p, '\n')) != NULL )
380 {
381 *q = '\0';
382 if ( start_of_line )
383 __putstr(printk_prefix);
384 __putstr(p);
385 __putstr("\n");
386 start_of_line = 1;
387 p = q + 1;
388 }
390 if ( *p != '\0' )
391 {
392 if ( start_of_line )
393 __putstr(printk_prefix);
394 __putstr(p);
395 start_of_line = 0;
396 }
398 spin_unlock_irqrestore(&console_lock, flags);
399 }
401 void set_printk_prefix(const char *prefix)
402 {
403 strcpy(printk_prefix, prefix);
404 }
406 void init_console(void)
407 {
408 unsigned char *p;
410 /* Where should console output go? */
411 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
412 {
413 if ( *p == ',' )
414 p++;
415 if ( strncmp(p, "com", 3) == 0 )
416 sercon_handle = parse_serial_handle(p);
417 else if ( strncmp(p, "vga", 3) == 0 )
418 vgacon_enabled = 1;
419 }
421 init_vga();
423 serial_set_rx_handler(sercon_handle, serial_rx);
425 /* HELLO WORLD --- start-of-day banner text. */
426 printk(XEN_BANNER);
427 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
428 printk(" University of Cambridge Computer Laboratory\n\n");
429 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
430 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
431 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
432 XEN_COMPILER, XEN_COMPILE_DATE);
433 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
434 set_printk_prefix("(XEN) ");
435 }
437 void console_endboot(int disable_vga)
438 {
439 if ( disable_vga )
440 vgacon_enabled = 0;
442 /*
443 * If user specifies so, we fool the switch routine to redirect input
444 * straight back to Xen. I use this convoluted method so we still print
445 * a useful 'how to switch' message.
446 */
447 if ( opt_conswitch[1] == 'x' )
448 xen_rx = !xen_rx;
450 /* Serial input is directed to DOM0 by default. */
451 switch_serial_input();
452 }
454 void console_force_unlock(void)
455 {
456 console_lock = SPIN_LOCK_UNLOCKED;
457 serial_force_unlock(sercon_handle);
458 }
460 void console_force_lock(void)
461 {
462 spin_lock(&console_lock);
463 }
465 void console_putc(char c)
466 {
467 serial_putc(sercon_handle, c);
468 }
470 int console_getc(void)
471 {
472 return serial_getc(sercon_handle);
473 }
475 int irq_console_getc(void)
476 {
477 return irq_serial_getc(sercon_handle);
478 }
481 /*
482 * **************************************************************
483 * *************** Debugging/tracing/error-report ***************
484 * **************************************************************
485 */
487 void panic(const char *fmt, ...)
488 {
489 va_list args;
490 char buf[128];
491 unsigned long flags;
492 extern void machine_restart(char *);
494 va_start(args, fmt);
495 (void)vsnprintf(buf, sizeof(buf), fmt, args);
496 va_end(args);
498 /* Spit out multiline message in one go. */
499 spin_lock_irqsave(&console_lock, flags);
500 __putstr("\n****************************************\n");
501 __putstr(buf);
502 __putstr("Aieee! CPU");
503 sprintf(buf, "%d", smp_processor_id());
504 __putstr(buf);
505 __putstr(" is toast...\n");
506 __putstr("****************************************\n\n");
507 __putstr("Reboot in five seconds...\n");
508 spin_unlock_irqrestore(&console_lock, flags);
510 watchdog_on = 0;
511 mdelay(5000);
512 machine_restart(0);
513 }
516 void __out_of_line_bug(int line)
517 {
518 printk("kernel BUG in header file at line %d\n", line);
519 BUG();
520 for ( ; ; ) ;
521 }