debuggers.hg

view xen/drivers/char/console.c @ 10989:16aa4b417c6b

[XEN] Clean up shutdown handling and ignore opt_noreboot if dom0
shuts down cleanly. The option is intended only to retain information
on the local console in case of a crash.

Based on a patch from Muli Ben-Yehuda <muli@il.ibm.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Aug 07 15:35:06 2006 +0100 (2006-08-07)
parents b786bfb058eb
children 600da8225858
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/version.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/softirq.h>
20 #include <xen/keyhandler.h>
21 #include <xen/mm.h>
22 #include <xen/delay.h>
23 #include <xen/guest_access.h>
24 #include <xen/shutdown.h>
25 #include <asm/current.h>
26 #include <asm/debugger.h>
27 #include <asm/io.h>
29 /* console: comma-separated list of console outputs. */
30 static char opt_console[30] = OPT_CONSOLE_STR;
31 string_param("console", opt_console);
33 /* conswitch: a character pair controlling console switching. */
34 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
35 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
36 /* boots. Any other value, or omitting the char, enables auto-switch */
37 static unsigned char opt_conswitch[5] = "a";
38 string_param("conswitch", opt_conswitch);
40 /* sync_console: force synchronous console output (useful for debugging). */
41 static int opt_sync_console;
42 boolean_param("sync_console", opt_sync_console);
44 static int xpos, ypos;
45 static unsigned char *video;
47 #define CONRING_SIZE 16384
48 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
49 static char conring[CONRING_SIZE];
50 static unsigned int conringc, conringp;
52 static char printk_prefix[16] = "";
54 static int sercon_handle = -1;
55 static int vgacon_enabled = 0;
57 static DEFINE_SPINLOCK(console_lock);
59 /*
60 * *******************************************************
61 * *************** OUTPUT TO VGA CONSOLE *****************
62 * *******************************************************
63 */
65 /* VGA text (mode 3) definitions. */
66 #define COLUMNS 80
67 #define LINES 25
68 #define ATTRIBUTE 7
69 #define VIDEO_SIZE (COLUMNS * LINES * 2)
71 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
72 static void cls(void)
73 {
74 memset(video, 0, VIDEO_SIZE);
75 xpos = ypos = 0;
76 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
77 }
79 static int detect_video(void *video_base)
80 {
81 volatile u16 *p = (volatile u16 *)video_base;
82 u16 saved1 = p[0], saved2 = p[1];
83 int video_found = 1;
85 p[0] = 0xAA55;
86 p[1] = 0x55AA;
87 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
88 video_found = 0;
90 p[0] = 0x55AA;
91 p[1] = 0xAA55;
92 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
93 video_found = 0;
95 p[0] = saved1;
96 p[1] = saved2;
98 return video_found;
99 }
101 static int detect_vga(void)
102 {
103 /*
104 * Look at a number of well-known locations. Even if video is not at
105 * 0xB8000 right now, it will appear there when we set up text mode 3.
106 *
107 * We assume if there is any sign of a video adaptor then it is at least
108 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
109 *
110 * These checks are basically to detect headless server boxes.
111 */
112 return (detect_video(ioremap(0xA0000, VIDEO_SIZE)) ||
113 detect_video(ioremap(0xB0000, VIDEO_SIZE)) ||
114 detect_video(ioremap(0xB8000, VIDEO_SIZE)));
115 }
117 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
118 static void init_vga(void)
119 {
120 /* The following VGA state was saved from a chip in text mode 3. */
121 static unsigned char regs[] = {
122 /* Sequencer registers */
123 0x03, 0x00, 0x03, 0x00, 0x02,
124 /* CRTC registers */
125 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
126 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
127 0xb9, 0xa3, 0xff,
128 /* Graphic registers */
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
130 /* Attribute registers */
131 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
132 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
133 };
135 int i, j = 0;
136 volatile unsigned char tmp;
138 if ( !vgacon_enabled )
139 return;
141 if ( !detect_vga() )
142 {
143 printk("No VGA adaptor detected!\n");
144 vgacon_enabled = 0;
145 return;
146 }
148 video = ioremap(0xB8000, VIDEO_SIZE);
150 tmp = inb(0x3da);
151 outb(0x00, 0x3c0);
153 for ( i = 0; i < 5; i++ )
154 outw((regs[j++] << 8) | i, 0x3c4);
156 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
157 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
159 for ( i = 0; i < 25; i++ )
160 outw((regs[j++] << 8) | i, 0x3d4);
162 for ( i = 0; i < 9; i++ )
163 outw((regs[j++] << 8) | i, 0x3ce);
165 for ( i = 0; i < 21; i++ )
166 {
167 tmp = inb(0x3da);
168 outb(i, 0x3c0);
169 outb(regs[j++], 0x3c0);
170 }
172 tmp = inb(0x3da);
173 outb(0x20, 0x3c0);
175 cls();
176 }
178 static void put_newline(void)
179 {
180 xpos = 0;
181 ypos++;
183 if (ypos >= LINES)
184 {
185 ypos = LINES-1;
186 memmove((char*)video,
187 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
188 memset((char*)video + (LINES-1)*2*COLUMNS, 0, 2*COLUMNS);
189 }
190 }
192 static void putchar_console(int c)
193 {
194 if ( !vgacon_enabled )
195 return;
197 if ( c == '\n' )
198 {
199 put_newline();
200 }
201 else
202 {
203 if ( xpos >= COLUMNS )
204 put_newline();
205 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
206 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
207 ++xpos;
208 }
209 }
212 /*
213 * ********************************************************
214 * *************** ACCESS TO CONSOLE RING *****************
215 * ********************************************************
216 */
218 static void putchar_console_ring(int c)
219 {
220 conring[CONRING_IDX_MASK(conringp++)] = c;
221 if ( (conringp - conringc) > CONRING_SIZE )
222 conringc = conringp - CONRING_SIZE;
223 }
225 long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
226 {
227 unsigned int idx, len, max, sofar, c;
228 unsigned long flags;
230 max = *pcount;
231 sofar = 0;
233 c = conringc;
234 while ( (c != conringp) && (sofar < max) )
235 {
236 idx = CONRING_IDX_MASK(c);
237 len = conringp - c;
238 if ( (idx + len) > CONRING_SIZE )
239 len = CONRING_SIZE - idx;
240 if ( (sofar + len) > max )
241 len = max - sofar;
242 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
243 return -EFAULT;
244 sofar += len;
245 c += len;
246 }
248 if ( clear )
249 {
250 spin_lock_irqsave(&console_lock, flags);
251 if ( (conringp - c) > CONRING_SIZE )
252 conringc = conringp - CONRING_SIZE;
253 else
254 conringc = c;
255 spin_unlock_irqrestore(&console_lock, flags);
256 }
258 *pcount = sofar;
259 return 0;
260 }
263 /*
264 * *******************************************************
265 * *************** ACCESS TO SERIAL LINE *****************
266 * *******************************************************
267 */
269 /* Characters received over the serial line are buffered for domain 0. */
270 #define SERIAL_RX_SIZE 128
271 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
272 static char serial_rx_ring[SERIAL_RX_SIZE];
273 static unsigned int serial_rx_cons, serial_rx_prod;
275 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
276 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
277 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
279 static void switch_serial_input(void)
280 {
281 static char *input_str[2] = { "DOM0", "Xen" };
282 xen_rx = !xen_rx;
283 if ( (SWITCH_CODE != 0) && (dom0 != NULL) )
284 {
285 printk("*** Serial input -> %s "
286 "(type 'CTRL-%c' three times to switch input to %s).\n",
287 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
288 }
289 }
291 static void __serial_rx(char c, struct cpu_user_regs *regs)
292 {
293 if ( xen_rx )
294 return handle_keypress(c, regs);
296 /* Deliver input to guest buffer, unless it is already full. */
297 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
298 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
299 /* Always notify the guest: prevents receive path from getting stuck. */
300 send_guest_global_virq(dom0, VIRQ_CONSOLE);
301 }
303 static void serial_rx(char c, struct cpu_user_regs *regs)
304 {
305 static int switch_code_count = 0;
307 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
308 {
309 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
310 if ( ++switch_code_count == 3 )
311 {
312 switch_serial_input();
313 switch_code_count = 0;
314 return;
315 }
316 }
317 else
318 {
319 switch_code_count = 0;
320 }
322 /* Finally process the just-received character. */
323 __serial_rx(c, regs);
324 }
326 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
327 {
328 char kbuf[128], *kptr;
329 int kcount;
331 while ( count > 0 )
332 {
333 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
334 {
335 if ( hypercall_preempt_check() )
336 break;
337 cpu_relax();
338 }
340 if ( hypercall_preempt_check() )
341 return hypercall_create_continuation(
342 __HYPERVISOR_console_io, "iih",
343 CONSOLEIO_write, count, buffer);
345 kcount = min_t(int, count, sizeof(kbuf)-1);
346 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
347 return -EFAULT;
348 kbuf[kcount] = '\0';
350 serial_puts(sercon_handle, kbuf);
352 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
353 putchar_console(*kptr);
355 guest_handle_add_offset(buffer, kcount);
356 count -= kcount;
357 }
359 return 0;
360 }
362 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
363 {
364 long rc;
365 unsigned int idx, len;
367 #ifndef VERBOSE
368 /* Only domain 0 may access the emergency console. */
369 if ( current->domain->domain_id != 0 )
370 return -EPERM;
371 #endif
373 switch ( cmd )
374 {
375 case CONSOLEIO_write:
376 rc = guest_console_write(buffer, count);
377 break;
378 case CONSOLEIO_read:
379 rc = 0;
380 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
381 {
382 idx = SERIAL_RX_MASK(serial_rx_cons);
383 len = serial_rx_prod - serial_rx_cons;
384 if ( (idx + len) > SERIAL_RX_SIZE )
385 len = SERIAL_RX_SIZE - idx;
386 if ( (rc + len) > count )
387 len = count - rc;
388 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
389 {
390 rc = -EFAULT;
391 break;
392 }
393 rc += len;
394 serial_rx_cons += len;
395 }
396 break;
397 default:
398 rc = -ENOSYS;
399 break;
400 }
402 return rc;
403 }
406 /*
407 * *****************************************************
408 * *************** GENERIC CONSOLE I/O *****************
409 * *****************************************************
410 */
412 static inline void __putstr(const char *str)
413 {
414 int c;
416 serial_puts(sercon_handle, str);
418 while ( (c = *str++) != '\0' )
419 {
420 putchar_console(c);
421 putchar_console_ring(c);
422 }
423 }
425 void printf(const char *fmt, ...)
426 {
427 static char buf[1024];
428 static int start_of_line = 1;
430 va_list args;
431 char *p, *q;
432 unsigned long flags;
434 spin_lock_irqsave(&console_lock, flags);
436 va_start(args, fmt);
437 (void)vsnprintf(buf, sizeof(buf), fmt, args);
438 va_end(args);
440 p = buf;
441 while ( (q = strchr(p, '\n')) != NULL )
442 {
443 *q = '\0';
444 if ( start_of_line )
445 __putstr(printk_prefix);
446 __putstr(p);
447 __putstr("\n");
448 start_of_line = 1;
449 p = q + 1;
450 }
452 if ( *p != '\0' )
453 {
454 if ( start_of_line )
455 __putstr(printk_prefix);
456 __putstr(p);
457 start_of_line = 0;
458 }
460 spin_unlock_irqrestore(&console_lock, flags);
461 }
463 void set_printk_prefix(const char *prefix)
464 {
465 strcpy(printk_prefix, prefix);
466 }
468 void init_console(void)
469 {
470 char *p;
472 /* Where should console output go? */
473 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
474 {
475 if ( *p == ',' )
476 p++;
477 if ( strncmp(p, "com", 3) == 0 )
478 sercon_handle = serial_parse_handle(p);
479 else if ( strncmp(p, "vga", 3) == 0 )
480 {
481 vgacon_enabled = 1;
482 if ( strncmp(p+3, "[keep]", 6) == 0 )
483 vgacon_enabled++;
484 }
485 }
487 init_vga();
489 serial_set_rx_handler(sercon_handle, serial_rx);
491 /* HELLO WORLD --- start-of-day banner text. */
492 printk(xen_banner());
493 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
494 printk(" University of Cambridge Computer Laboratory\n\n");
495 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
496 xen_major_version(), xen_minor_version(), xen_extra_version(),
497 xen_compile_by(), xen_compile_domain(),
498 xen_compiler(), xen_compile_date());
499 printk(" Latest ChangeSet: %s\n\n", xen_changeset());
500 set_printk_prefix("(XEN) ");
502 if ( opt_sync_console )
503 {
504 serial_start_sync(sercon_handle);
505 add_taint(TAINT_SYNC_CONSOLE);
506 printk("Console output is synchronous.\n");
507 }
508 }
510 void console_endboot(void)
511 {
512 int i, j;
514 if ( opt_sync_console )
515 {
516 printk("**********************************************\n");
517 printk("******* WARNING: CONSOLE OUTPUT IS SYCHRONOUS\n");
518 printk("******* This option is intended to aid debugging "
519 "of Xen by ensuring\n");
520 printk("******* that all output is synchronously delivered "
521 "on the serial line.\n");
522 printk("******* However it can introduce SIGNIFICANT latencies "
523 "and affect\n");
524 printk("******* timekeeping. It is NOT recommended for "
525 "production use!\n");
526 printk("**********************************************\n");
527 for ( i = 0; i < 3; i++ )
528 {
529 printk("%d... ", 3-i);
530 for ( j = 0; j < 100; j++ )
531 {
532 process_pending_timers();
533 mdelay(10);
534 }
535 }
536 printk("\n");
537 }
539 if ( vgacon_enabled )
540 {
541 vgacon_enabled--;
542 printk("Xen is %s VGA console.\n",
543 vgacon_enabled ? "keeping" : "relinquishing");
544 }
546 /*
547 * If user specifies so, we fool the switch routine to redirect input
548 * straight back to Xen. I use this convoluted method so we still print
549 * a useful 'how to switch' message.
550 */
551 if ( opt_conswitch[1] == 'x' )
552 xen_rx = !xen_rx;
554 /* Serial input is directed to DOM0 by default. */
555 switch_serial_input();
556 }
558 void console_force_unlock(void)
559 {
560 console_lock = SPIN_LOCK_UNLOCKED;
561 serial_force_unlock(sercon_handle);
562 console_start_sync();
563 }
565 void console_force_lock(void)
566 {
567 spin_lock(&console_lock);
568 }
570 void console_start_sync(void)
571 {
572 serial_start_sync(sercon_handle);
573 }
575 void console_end_sync(void)
576 {
577 serial_end_sync(sercon_handle);
578 }
580 void console_putc(char c)
581 {
582 serial_putc(sercon_handle, c);
583 }
585 int console_getc(void)
586 {
587 return serial_getc(sercon_handle);
588 }
591 /*
592 * **************************************************************
593 * *************** Serial console ring buffer *******************
594 * **************************************************************
595 */
597 #ifndef NDEBUG
599 /* Send output direct to console, or buffer it? */
600 int debugtrace_send_to_console;
602 static char *debugtrace_buf; /* Debug-trace buffer */
603 static unsigned int debugtrace_prd; /* Producer index */
604 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
605 static unsigned int debugtrace_used;
606 static DEFINE_SPINLOCK(debugtrace_lock);
607 integer_param("debugtrace", debugtrace_kilobytes);
609 void debugtrace_dump(void)
610 {
611 unsigned long flags;
613 if ( (debugtrace_bytes == 0) || !debugtrace_used )
614 return;
616 watchdog_disable();
618 spin_lock_irqsave(&debugtrace_lock, flags);
620 printk("debugtrace_dump() starting\n");
622 /* Print oldest portion of the ring. */
623 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
624 serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
626 /* Print youngest portion of the ring. */
627 debugtrace_buf[debugtrace_prd] = '\0';
628 serial_puts(sercon_handle, &debugtrace_buf[0]);
630 memset(debugtrace_buf, '\0', debugtrace_bytes);
632 printk("debugtrace_dump() finished\n");
634 spin_unlock_irqrestore(&debugtrace_lock, flags);
636 watchdog_enable();
637 }
639 void debugtrace_printk(const char *fmt, ...)
640 {
641 static char buf[1024];
643 va_list args;
644 char *p;
645 unsigned long flags;
647 if ( debugtrace_bytes == 0 )
648 return;
650 debugtrace_used = 1;
652 spin_lock_irqsave(&debugtrace_lock, flags);
654 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
656 va_start(args, fmt);
657 (void)vsnprintf(buf, sizeof(buf), fmt, args);
658 va_end(args);
660 if ( debugtrace_send_to_console )
661 {
662 serial_puts(sercon_handle, buf);
663 }
664 else
665 {
666 for ( p = buf; *p != '\0'; p++ )
667 {
668 debugtrace_buf[debugtrace_prd++] = *p;
669 /* Always leave a nul byte at the end of the buffer. */
670 if ( debugtrace_prd == (debugtrace_bytes - 1) )
671 debugtrace_prd = 0;
672 }
673 }
675 spin_unlock_irqrestore(&debugtrace_lock, flags);
676 }
678 static int __init debugtrace_init(void)
679 {
680 int order;
681 unsigned int kbytes, bytes;
683 /* Round size down to next power of two. */
684 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
685 debugtrace_kilobytes = kbytes;
687 bytes = debugtrace_kilobytes << 10;
688 if ( bytes == 0 )
689 return 0;
691 order = get_order_from_bytes(bytes);
692 debugtrace_buf = alloc_xenheap_pages(order);
693 ASSERT(debugtrace_buf != NULL);
695 memset(debugtrace_buf, '\0', bytes);
697 debugtrace_bytes = bytes;
699 return 0;
700 }
701 __initcall(debugtrace_init);
703 #endif /* !NDEBUG */
707 /*
708 * **************************************************************
709 * *************** Debugging/tracing/error-report ***************
710 * **************************************************************
711 */
713 void panic(const char *fmt, ...)
714 {
715 va_list args;
716 char buf[128];
717 unsigned long flags;
718 static DEFINE_SPINLOCK(lock);
719 extern void machine_restart(char *);
721 debugtrace_dump();
723 va_start(args, fmt);
724 (void)vsnprintf(buf, sizeof(buf), fmt, args);
725 va_end(args);
727 /* Spit out multiline message in one go. */
728 console_start_sync();
729 spin_lock_irqsave(&lock, flags);
730 printk("\n****************************************\n");
731 printk("Panic on CPU %d:\n", smp_processor_id());
732 printk(buf);
733 printk("****************************************\n\n");
734 if ( opt_noreboot )
735 printk("Manual reset required ('noreboot' specified)\n");
736 else
737 printk("Reboot in five seconds...\n");
738 spin_unlock_irqrestore(&lock, flags);
740 debugger_trap_immediate();
742 if ( opt_noreboot )
743 {
744 machine_halt();
745 }
746 else
747 {
748 watchdog_disable();
749 mdelay(5000);
750 machine_restart(NULL);
751 }
752 }
754 void __bug(char *file, int line)
755 {
756 console_start_sync();
757 debugtrace_dump();
758 printk("BUG at %s:%d\n", file, line);
759 FORCE_CRASH();
760 for ( ; ; ) ;
761 }
763 /*
764 * Local variables:
765 * mode: C
766 * c-set-style: "BSD"
767 * c-basic-offset: 4
768 * tab-width: 4
769 * indent-tabs-mode: nil
770 * End:
771 */