ia64/xen-unstable

view xen/drivers/char/console.c @ 4146:f2d61710e4d9

bitkeeper revision 1.1236.25.24 (42366e9aQ71LQ8uCB-Y1IwVNqx5eqA)

Merge djm@kirby.fc.hp.com://home/djm/src/xen/xeno-unstable-ia64.bk
into sportsman.spdomain:/home/djm/xeno-unstable-ia64.bk
author djm@sportsman.spdomain
date Tue Mar 15 05:11:54 2005 +0000 (2005-03-15)
parents 00e4db805624 0c846e77cca4
children 48ddf32dad5b
line source
1 /******************************************************************************
2 * console.c
3 *
4 * Emergency console I/O for Xen and the domain-0 guest OS.
5 *
6 * Copyright (c) 2002-2004, K A Fraser.
7 */
9 #include <stdarg.h>
10 #include <xen/config.h>
11 #include <xen/compile.h>
12 #include <xen/init.h>
13 #include <xen/lib.h>
14 #include <xen/errno.h>
15 #include <xen/event.h>
16 #include <xen/spinlock.h>
17 #include <xen/console.h>
18 #include <xen/serial.h>
19 #include <xen/keyhandler.h>
20 #include <asm/uaccess.h>
21 #include <asm/mm.h>
22 #include <asm/debugger.h>
24 /* opt_console: comma-separated list of console outputs. */
25 static 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;
53 /*
54 * *******************************************************
55 * *************** OUTPUT TO VGA CONSOLE *****************
56 * *******************************************************
57 */
59 /* VGA text (mode 3) definitions. */
60 #define COLUMNS 80
61 #define LINES 25
62 #define ATTRIBUTE 7
64 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
65 static void cls(void)
66 {
67 memset(video, 0, COLUMNS * LINES * 2);
68 xpos = ypos = 0;
69 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
70 }
72 static int detect_video(void *video_base)
73 {
74 volatile u16 *p = (volatile u16 *)video_base;
75 u16 saved1 = p[0], saved2 = p[1];
76 int video_found = 1;
78 p[0] = 0xAA55;
79 p[1] = 0x55AA;
80 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
81 video_found = 0;
83 p[0] = 0x55AA;
84 p[1] = 0xAA55;
85 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
86 video_found = 0;
88 p[0] = saved1;
89 p[1] = saved2;
91 return video_found;
92 }
94 static int detect_vga(void)
95 {
96 /*
97 * Look at a number of well-known locations. Even if video is not at
98 * 0xB8000 right now, it will appear there when we set up text mode 3.
99 *
100 * We assume if there is any sign of a video adaptor then it is at least
101 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
102 *
103 * These checks are basically to detect headless server boxes.
104 */
105 return (detect_video(__va(0xA0000)) ||
106 detect_video(__va(0xB0000)) ||
107 detect_video(__va(0xB8000)));
108 }
110 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
111 static void init_vga(void)
112 {
113 /* The following VGA state was saved from a chip in text mode 3. */
114 static unsigned char regs[] = {
115 /* Sequencer registers */
116 0x03, 0x00, 0x03, 0x00, 0x02,
117 /* CRTC registers */
118 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
119 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
120 0xb9, 0xa3, 0xff,
121 /* Graphic registers */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
123 /* Attribute registers */
124 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
125 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
126 };
128 int i, j = 0;
129 volatile unsigned char tmp;
131 if ( !vgacon_enabled )
132 return;
134 if ( !detect_vga() )
135 {
136 printk("No VGA adaptor detected!\n");
137 vgacon_enabled = 0;
138 return;
139 }
141 video = __va(0xB8000);
143 tmp = inb(0x3da);
144 outb(0x00, 0x3c0);
146 for ( i = 0; i < 5; i++ )
147 outw((regs[j++] << 8) | i, 0x3c4);
149 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
150 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
152 for ( i = 0; i < 25; i++ )
153 outw((regs[j++] << 8) | i, 0x3d4);
155 for ( i = 0; i < 9; i++ )
156 outw((regs[j++] << 8) | i, 0x3ce);
158 for ( i = 0; i < 21; i++ )
159 {
160 tmp = inb(0x3da);
161 outb(i, 0x3c0);
162 outb(regs[j++], 0x3c0);
163 }
165 tmp = inb(0x3da);
166 outb(0x20, 0x3c0);
168 cls();
169 }
171 static void put_newline(void)
172 {
173 xpos = 0;
174 ypos++;
176 if (ypos >= LINES)
177 {
178 static char zeroarr[2*COLUMNS] = { 0 };
179 ypos = LINES-1;
180 memcpy((char*)video,
181 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
182 memcpy((char*)video + (LINES-1)*2*COLUMNS,
183 zeroarr, 2*COLUMNS);
184 }
185 }
187 static void putchar_console(int c)
188 {
189 if ( !vgacon_enabled )
190 return;
192 if ( c == '\n' )
193 {
194 put_newline();
195 }
196 else
197 {
198 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
199 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
200 if ( ++xpos >= COLUMNS )
201 put_newline();
202 }
203 }
206 /*
207 * ********************************************************
208 * *************** ACCESS TO CONSOLE RING *****************
209 * ********************************************************
210 */
212 static void putchar_console_ring(int c)
213 {
214 if ( console_ring.len < CONSOLE_RING_SIZE )
215 console_ring.buf[console_ring.len++] = (char)c;
216 }
218 long read_console_ring(unsigned long str, unsigned int count, unsigned cmd)
219 {
220 unsigned int len;
222 len = (console_ring.len < count) ? console_ring.len : count;
224 if ( copy_to_user((char *)str, console_ring.buf, len) )
225 return -EFAULT;
227 if ( cmd & CONSOLE_RING_CLEAR )
228 console_ring.len = 0;
230 return len;
231 }
234 /*
235 * *******************************************************
236 * *************** ACCESS TO SERIAL LINE *****************
237 * *******************************************************
238 */
240 /* Characters received over the serial line are buffered for domain 0. */
241 #define SERIAL_RX_SIZE 128
242 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
243 static char serial_rx_ring[SERIAL_RX_SIZE];
244 static unsigned int serial_rx_cons, serial_rx_prod;
246 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
247 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
248 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
250 static void switch_serial_input(void)
251 {
252 static char *input_str[2] = { "DOM0", "Xen" };
253 xen_rx = !xen_rx;
254 if ( SWITCH_CODE != 0 )
255 {
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 }
260 }
262 static void __serial_rx(unsigned char c, struct xen_regs *regs)
263 {
264 if ( xen_rx )
265 {
266 handle_keypress(c, regs);
267 }
268 else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
269 {
270 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
271 if ( serial_rx_prod++ == serial_rx_cons )
272 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
273 }
274 }
276 static void serial_rx(unsigned char c, struct xen_regs *regs)
277 {
278 static int switch_code_count = 0;
280 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
281 {
282 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
283 if ( ++switch_code_count == 3 )
284 {
285 switch_serial_input();
286 switch_code_count = 0;
287 }
288 }
289 else
290 {
291 switch_code_count = 0;
292 }
294 /* Finally process the just-received character. */
295 __serial_rx(c, regs);
296 }
298 long do_console_io(int cmd, int count, char *buffer)
299 {
300 char *kbuf;
301 long rc;
303 #ifndef VERBOSE
304 /* Only domain-0 may access the emergency console. */
305 if ( current->domain->id != 0 )
306 return -EPERM;
307 #endif
309 switch ( cmd )
310 {
311 case CONSOLEIO_write:
312 if ( count > (PAGE_SIZE-1) )
313 count = PAGE_SIZE-1;
314 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
315 return -ENOMEM;
316 kbuf[count] = '\0';
317 rc = count;
318 if ( copy_from_user(kbuf, buffer, count) )
319 rc = -EFAULT;
320 else
321 serial_puts(sercon_handle, kbuf);
322 free_xenheap_page((unsigned long)kbuf);
323 break;
324 case CONSOLEIO_read:
325 rc = 0;
326 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
327 {
328 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
329 &buffer[rc]) )
330 {
331 rc = -EFAULT;
332 break;
333 }
334 rc++;
335 serial_rx_cons++;
336 }
337 break;
338 default:
339 rc = -ENOSYS;
340 break;
341 }
343 return rc;
344 }
347 /*
348 * *****************************************************
349 * *************** GENERIC CONSOLE I/O *****************
350 * *****************************************************
351 */
353 static inline void __putstr(const char *str)
354 {
355 int c;
357 serial_puts(sercon_handle, str);
359 while ( (c = *str++) != '\0' )
360 {
361 putchar_console(c);
362 putchar_console_ring(c);
363 }
364 }
366 void printf(const char *fmt, ...)
367 {
368 static char buf[1024];
369 static int start_of_line = 1;
371 va_list args;
372 char *p, *q;
373 unsigned long flags;
375 spin_lock_irqsave(&console_lock, flags);
377 va_start(args, fmt);
378 (void)vsnprintf(buf, sizeof(buf), fmt, args);
379 va_end(args);
381 p = buf;
382 while ( (q = strchr(p, '\n')) != NULL )
383 {
384 *q = '\0';
385 if ( start_of_line )
386 __putstr(printk_prefix);
387 __putstr(p);
388 __putstr("\n");
389 start_of_line = 1;
390 p = q + 1;
391 }
393 if ( *p != '\0' )
394 {
395 if ( start_of_line )
396 __putstr(printk_prefix);
397 __putstr(p);
398 start_of_line = 0;
399 }
401 spin_unlock_irqrestore(&console_lock, flags);
402 }
404 void set_printk_prefix(const char *prefix)
405 {
406 strcpy(printk_prefix, prefix);
407 }
409 void init_console(void)
410 {
411 char *p;
413 /* Where should console output go? */
414 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
415 {
416 if ( *p == ',' )
417 p++;
418 if ( strncmp(p, "com", 3) == 0 )
419 sercon_handle = parse_serial_handle(p);
420 else if ( strncmp(p, "vga", 3) == 0 )
421 vgacon_enabled = 1;
422 }
424 init_vga();
426 serial_set_rx_handler(sercon_handle, serial_rx);
428 /* HELLO WORLD --- start-of-day banner text. */
429 printk(XEN_BANNER);
430 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
431 printk(" University of Cambridge Computer Laboratory\n\n");
432 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
433 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
434 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
435 XEN_COMPILER, XEN_COMPILE_DATE);
436 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
437 set_printk_prefix("(XEN) ");
438 }
440 void console_endboot(int disable_vga)
441 {
442 if ( disable_vga )
443 vgacon_enabled = 0;
445 /*
446 * If user specifies so, we fool the switch routine to redirect input
447 * straight back to Xen. I use this convoluted method so we still print
448 * a useful 'how to switch' message.
449 */
450 if ( opt_conswitch[1] == 'x' )
451 xen_rx = !xen_rx;
453 /* Serial input is directed to DOM0 by default. */
454 switch_serial_input();
455 }
457 void console_force_unlock(void)
458 {
459 console_lock = SPIN_LOCK_UNLOCKED;
460 serial_force_unlock(sercon_handle);
461 }
463 void console_force_lock(void)
464 {
465 spin_lock(&console_lock);
466 }
468 void console_putc(char c)
469 {
470 serial_putc(sercon_handle, c);
471 }
473 int console_getc(void)
474 {
475 return serial_getc(sercon_handle);
476 }
478 int irq_console_getc(void)
479 {
480 return irq_serial_getc(sercon_handle);
481 }
484 /*
485 * **************************************************************
486 * *************** Serial console ring buffer *******************
487 * **************************************************************
488 */
490 #ifndef NDEBUG
492 /* Send output direct to console, or buffer it? */
493 int debugtrace_send_to_console;
495 static unsigned char *debugtrace_buf; /* Debug-trace buffer */
496 static unsigned int debugtrace_prd; /* Producer index */
497 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
498 static spinlock_t debugtrace_lock = SPIN_LOCK_UNLOCKED;
499 integer_param("debugtrace", debugtrace_kilobytes);
501 void debugtrace_dump(void)
502 {
503 int _watchdog_on = watchdog_on;
504 unsigned long flags;
506 if ( debugtrace_bytes == 0 )
507 return;
509 /* Watchdog can trigger if we print a really large buffer. */
510 watchdog_on = 0;
512 spin_lock_irqsave(&debugtrace_lock, flags);
514 /* Print oldest portion of the ring. */
515 serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
517 /* Print youngest portion of the ring. */
518 debugtrace_buf[debugtrace_prd] = '\0';
519 serial_puts(sercon_handle, &debugtrace_buf[0]);
521 memset(debugtrace_buf, '\0', debugtrace_bytes);
523 spin_unlock_irqrestore(&debugtrace_lock, flags);
525 watchdog_on = _watchdog_on;
526 }
528 void debugtrace_printk(const char *fmt, ...)
529 {
530 static char buf[1024];
532 va_list args;
533 unsigned char *p;
534 unsigned long flags;
536 if ( debugtrace_bytes == 0 )
537 return;
539 spin_lock_irqsave(&debugtrace_lock, flags);
541 va_start(args, fmt);
542 (void)vsnprintf(buf, sizeof(buf), fmt, args);
543 va_end(args);
545 if ( debugtrace_send_to_console )
546 {
547 serial_puts(sercon_handle, buf);
548 }
549 else
550 {
551 for ( p = buf; *p != '\0'; p++ )
552 {
553 debugtrace_buf[debugtrace_prd++] = *p;
554 /* Always leave a nul byte at the end of the buffer. */
555 if ( debugtrace_prd == (debugtrace_bytes - 1) )
556 debugtrace_prd = 0;
557 }
558 }
560 spin_unlock_irqrestore(&debugtrace_lock, flags);
561 }
563 static int __init debugtrace_init(void)
564 {
565 int order;
566 unsigned int kbytes;
568 /* Round size down to next power of two. */
569 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
570 debugtrace_kilobytes = kbytes;
572 debugtrace_bytes = debugtrace_kilobytes << 10;
573 if ( debugtrace_bytes == 0 )
574 return 0;
576 order = get_order(debugtrace_bytes);
577 debugtrace_buf = (unsigned char *)alloc_xenheap_pages(order);
578 ASSERT(debugtrace_buf != NULL);
580 memset(debugtrace_buf, '\0', debugtrace_bytes);
582 return 0;
583 }
584 __initcall(debugtrace_init);
586 #endif /* !NDEBUG */
590 /*
591 * **************************************************************
592 * *************** Debugging/tracing/error-report ***************
593 * **************************************************************
594 */
596 extern void trap_to_xendbg(void);
598 void panic(const char *fmt, ...)
599 {
600 va_list args;
601 char buf[128];
602 unsigned long flags;
603 extern void machine_restart(char *);
605 debugtrace_dump();
607 va_start(args, fmt);
608 (void)vsnprintf(buf, sizeof(buf), fmt, args);
609 va_end(args);
611 debugger_trap_immediate();
613 /* Spit out multiline message in one go. */
614 spin_lock_irqsave(&console_lock, flags);
615 __putstr("\n****************************************\n");
616 __putstr(buf);
617 __putstr("Aieee! CPU");
618 sprintf(buf, "%d", smp_processor_id());
619 __putstr(buf);
620 __putstr(" is toast...\n");
621 __putstr("****************************************\n\n");
622 __putstr("Reboot in five seconds...\n");
623 spin_unlock_irqrestore(&console_lock, flags);
625 watchdog_on = 0;
626 mdelay(5000);
627 machine_restart(0);
628 }
631 void __out_of_line_bug(int line)
632 {
633 printk("kernel BUG in header file at line %d\n", line);
634 BUG();
635 for ( ; ; ) ;
636 }
638 /*
639 * Local variables:
640 * mode: C
641 * c-set-style: "BSD"
642 * c-basic-offset: 4
643 * tab-width: 4
644 * indent-tabs-mode: nil
645 * End:
646 */