ia64/xen-unstable

view xen/drivers/char/console.c @ 10502:411a3c01bb40

[XEN] Xen always relinquishes VGA console to domain0 when domain0
starts to boot (previous behaviour looked for console=tty0 on
dom0's command line). To prevent this 'console=vga[keep]' must
be specified.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Jun 20 18:51:46 2006 +0100 (2006-06-20)
parents 967d4c65659a
children 1d17ddd9e45d
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/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 <asm/current.h>
25 #include <asm/debugger.h>
26 #include <asm/io.h>
28 /* console: comma-separated list of console outputs. */
29 static char opt_console[30] = OPT_CONSOLE_STR;
30 string_param("console", opt_console);
32 /* conswitch: a character pair controlling console switching. */
33 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
34 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
35 /* boots. Any other value, or omitting the char, enables auto-switch */
36 static unsigned char opt_conswitch[5] = "a";
37 string_param("conswitch", opt_conswitch);
39 /* sync_console: force synchronous console output (useful for debugging). */
40 static int opt_sync_console;
41 boolean_param("sync_console", opt_sync_console);
43 static int xpos, ypos;
44 static unsigned char *video;
46 #define CONRING_SIZE 16384
47 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
48 static char conring[CONRING_SIZE];
49 static unsigned int conringc, conringp;
51 static char printk_prefix[16] = "";
53 static int sercon_handle = -1;
54 static int vgacon_enabled = 0;
56 static DEFINE_SPINLOCK(console_lock);
58 /*
59 * *******************************************************
60 * *************** OUTPUT TO VGA CONSOLE *****************
61 * *******************************************************
62 */
64 /* VGA text (mode 3) definitions. */
65 #define COLUMNS 80
66 #define LINES 25
67 #define ATTRIBUTE 7
68 #define VIDEO_SIZE (COLUMNS * LINES * 2)
70 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
71 static void cls(void)
72 {
73 memset(video, 0, VIDEO_SIZE);
74 xpos = ypos = 0;
75 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
76 }
78 static int detect_video(void *video_base)
79 {
80 volatile u16 *p = (volatile u16 *)video_base;
81 u16 saved1 = p[0], saved2 = p[1];
82 int video_found = 1;
84 p[0] = 0xAA55;
85 p[1] = 0x55AA;
86 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
87 video_found = 0;
89 p[0] = 0x55AA;
90 p[1] = 0xAA55;
91 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
92 video_found = 0;
94 p[0] = saved1;
95 p[1] = saved2;
97 return video_found;
98 }
100 static int detect_vga(void)
101 {
102 /*
103 * Look at a number of well-known locations. Even if video is not at
104 * 0xB8000 right now, it will appear there when we set up text mode 3.
105 *
106 * We assume if there is any sign of a video adaptor then it is at least
107 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
108 *
109 * These checks are basically to detect headless server boxes.
110 */
111 return (detect_video(ioremap(0xA0000, VIDEO_SIZE)) ||
112 detect_video(ioremap(0xB0000, VIDEO_SIZE)) ||
113 detect_video(ioremap(0xB8000, VIDEO_SIZE)));
114 }
116 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
117 static void init_vga(void)
118 {
119 /* The following VGA state was saved from a chip in text mode 3. */
120 static unsigned char regs[] = {
121 /* Sequencer registers */
122 0x03, 0x00, 0x03, 0x00, 0x02,
123 /* CRTC registers */
124 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
125 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
126 0xb9, 0xa3, 0xff,
127 /* Graphic registers */
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
129 /* Attribute registers */
130 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
131 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
132 };
134 int i, j = 0;
135 volatile unsigned char tmp;
137 if ( !vgacon_enabled )
138 return;
140 if ( !detect_vga() )
141 {
142 printk("No VGA adaptor detected!\n");
143 vgacon_enabled = 0;
144 return;
145 }
147 video = ioremap(0xB8000, VIDEO_SIZE);
149 tmp = inb(0x3da);
150 outb(0x00, 0x3c0);
152 for ( i = 0; i < 5; i++ )
153 outw((regs[j++] << 8) | i, 0x3c4);
155 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
156 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
158 for ( i = 0; i < 25; i++ )
159 outw((regs[j++] << 8) | i, 0x3d4);
161 for ( i = 0; i < 9; i++ )
162 outw((regs[j++] << 8) | i, 0x3ce);
164 for ( i = 0; i < 21; i++ )
165 {
166 tmp = inb(0x3da);
167 outb(i, 0x3c0);
168 outb(regs[j++], 0x3c0);
169 }
171 tmp = inb(0x3da);
172 outb(0x20, 0x3c0);
174 cls();
175 }
177 static void put_newline(void)
178 {
179 xpos = 0;
180 ypos++;
182 if (ypos >= LINES)
183 {
184 ypos = LINES-1;
185 memmove((char*)video,
186 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
187 memset((char*)video + (LINES-1)*2*COLUMNS, 0, 2*COLUMNS);
188 }
189 }
191 static void putchar_console(int c)
192 {
193 if ( !vgacon_enabled )
194 return;
196 if ( c == '\n' )
197 {
198 put_newline();
199 }
200 else
201 {
202 if ( xpos >= COLUMNS )
203 put_newline();
204 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
205 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
206 ++xpos;
207 }
208 }
211 /*
212 * ********************************************************
213 * *************** ACCESS TO CONSOLE RING *****************
214 * ********************************************************
215 */
217 static void putchar_console_ring(int c)
218 {
219 conring[CONRING_IDX_MASK(conringp++)] = c;
220 if ( (conringp - conringc) > CONRING_SIZE )
221 conringc = conringp - CONRING_SIZE;
222 }
224 long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
225 {
226 unsigned int idx, len, max, sofar, c;
227 unsigned long flags;
229 max = *pcount;
230 sofar = 0;
232 c = conringc;
233 while ( (c != conringp) && (sofar < max) )
234 {
235 idx = CONRING_IDX_MASK(c);
236 len = conringp - c;
237 if ( (idx + len) > CONRING_SIZE )
238 len = CONRING_SIZE - idx;
239 if ( (sofar + len) > max )
240 len = max - sofar;
241 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
242 return -EFAULT;
243 sofar += len;
244 c += len;
245 }
247 if ( clear )
248 {
249 spin_lock_irqsave(&console_lock, flags);
250 if ( (conringp - c) > CONRING_SIZE )
251 conringc = conringp - CONRING_SIZE;
252 else
253 conringc = c;
254 spin_unlock_irqrestore(&console_lock, flags);
255 }
257 *pcount = sofar;
258 return 0;
259 }
262 /*
263 * *******************************************************
264 * *************** ACCESS TO SERIAL LINE *****************
265 * *******************************************************
266 */
268 /* Characters received over the serial line are buffered for domain 0. */
269 #define SERIAL_RX_SIZE 128
270 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
271 static char serial_rx_ring[SERIAL_RX_SIZE];
272 static unsigned int serial_rx_cons, serial_rx_prod;
274 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
275 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
276 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
278 static void switch_serial_input(void)
279 {
280 static char *input_str[2] = { "DOM0", "Xen" };
281 xen_rx = !xen_rx;
282 if ( SWITCH_CODE != 0 )
283 {
284 printk("*** Serial input -> %s "
285 "(type 'CTRL-%c' three times to switch input to %s).\n",
286 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
287 }
288 }
290 static void __serial_rx(char c, struct cpu_user_regs *regs)
291 {
292 if ( xen_rx )
293 return handle_keypress(c, regs);
295 /* Deliver input to guest buffer, unless it is already full. */
296 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
297 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
298 /* Always notify the guest: prevents receive path from getting stuck. */
299 send_guest_global_virq(dom0, VIRQ_CONSOLE);
300 }
302 static void serial_rx(char c, struct cpu_user_regs *regs)
303 {
304 static int switch_code_count = 0;
306 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
307 {
308 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
309 if ( ++switch_code_count == 3 )
310 {
311 switch_serial_input();
312 switch_code_count = 0;
313 return;
314 }
315 }
316 else
317 {
318 switch_code_count = 0;
319 }
321 /* Finally process the just-received character. */
322 __serial_rx(c, regs);
323 }
325 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
326 {
327 char kbuf[128], *kptr;
328 int kcount;
330 while ( count > 0 )
331 {
332 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
333 {
334 if ( hypercall_preempt_check() )
335 break;
336 cpu_relax();
337 }
339 if ( hypercall_preempt_check() )
340 return hypercall_create_continuation(
341 __HYPERVISOR_console_io, "iih",
342 CONSOLEIO_write, count, buffer);
344 kcount = min_t(int, count, sizeof(kbuf)-1);
345 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
346 return -EFAULT;
347 kbuf[kcount] = '\0';
349 serial_puts(sercon_handle, kbuf);
351 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
352 putchar_console(*kptr);
354 guest_handle_add_offset(buffer, kcount);
355 count -= kcount;
356 }
358 return 0;
359 }
361 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
362 {
363 long rc;
364 unsigned int idx, len;
366 #ifndef VERBOSE
367 /* Only domain 0 may access the emergency console. */
368 if ( current->domain->domain_id != 0 )
369 return -EPERM;
370 #endif
372 switch ( cmd )
373 {
374 case CONSOLEIO_write:
375 rc = guest_console_write(buffer, count);
376 break;
377 case CONSOLEIO_read:
378 rc = 0;
379 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
380 {
381 idx = SERIAL_RX_MASK(serial_rx_cons);
382 len = serial_rx_prod - serial_rx_cons;
383 if ( (idx + len) > SERIAL_RX_SIZE )
384 len = SERIAL_RX_SIZE - idx;
385 if ( (rc + len) > count )
386 len = count - rc;
387 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
388 {
389 rc = -EFAULT;
390 break;
391 }
392 rc += len;
393 serial_rx_cons += len;
394 }
395 break;
396 default:
397 rc = -ENOSYS;
398 break;
399 }
401 return rc;
402 }
405 /*
406 * *****************************************************
407 * *************** GENERIC CONSOLE I/O *****************
408 * *****************************************************
409 */
411 static inline void __putstr(const char *str)
412 {
413 int c;
415 serial_puts(sercon_handle, str);
417 while ( (c = *str++) != '\0' )
418 {
419 putchar_console(c);
420 putchar_console_ring(c);
421 }
422 }
424 void printf(const char *fmt, ...)
425 {
426 static char buf[1024];
427 static int start_of_line = 1;
429 va_list args;
430 char *p, *q;
431 unsigned long flags;
433 spin_lock_irqsave(&console_lock, flags);
435 va_start(args, fmt);
436 (void)vsnprintf(buf, sizeof(buf), fmt, args);
437 va_end(args);
439 p = buf;
440 while ( (q = strchr(p, '\n')) != NULL )
441 {
442 *q = '\0';
443 if ( start_of_line )
444 __putstr(printk_prefix);
445 __putstr(p);
446 __putstr("\n");
447 start_of_line = 1;
448 p = q + 1;
449 }
451 if ( *p != '\0' )
452 {
453 if ( start_of_line )
454 __putstr(printk_prefix);
455 __putstr(p);
456 start_of_line = 0;
457 }
459 spin_unlock_irqrestore(&console_lock, flags);
460 }
462 void set_printk_prefix(const char *prefix)
463 {
464 strcpy(printk_prefix, prefix);
465 }
467 void init_console(void)
468 {
469 char *p;
471 /* Where should console output go? */
472 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
473 {
474 if ( *p == ',' )
475 p++;
476 if ( strncmp(p, "com", 3) == 0 )
477 sercon_handle = serial_parse_handle(p);
478 else if ( strncmp(p, "vga", 3) == 0 )
479 {
480 vgacon_enabled = 1;
481 if ( strncmp(p+3, "[keep]", 6) == 0 )
482 vgacon_enabled++;
483 }
484 }
486 init_vga();
488 serial_set_rx_handler(sercon_handle, serial_rx);
490 /* HELLO WORLD --- start-of-day banner text. */
491 printk(XEN_BANNER);
492 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
493 printk(" University of Cambridge Computer Laboratory\n\n");
494 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
495 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
496 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
497 XEN_COMPILER, XEN_COMPILE_DATE);
498 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
499 set_printk_prefix("(XEN) ");
501 if ( opt_sync_console )
502 {
503 serial_start_sync(sercon_handle);
504 add_taint(TAINT_SYNC_CONSOLE);
505 printk("Console output is synchronous.\n");
506 }
507 }
509 void console_endboot(void)
510 {
511 int i, j;
513 if ( opt_sync_console )
514 {
515 printk("**********************************************\n");
516 printk("******* WARNING: CONSOLE OUTPUT IS SYCHRONOUS\n");
517 printk("******* This option is intended to aid debugging "
518 "of Xen by ensuring\n");
519 printk("******* that all output is synchronously delivered "
520 "on the serial line.\n");
521 printk("******* However it can introduce SIGNIFICANT latencies "
522 "and affect\n");
523 printk("******* timekeeping. It is NOT recommended for "
524 "production use!\n");
525 printk("**********************************************\n");
526 for ( i = 0; i < 3; i++ )
527 {
528 printk("%d... ", 3-i);
529 for ( j = 0; j < 100; j++ )
530 {
531 if ( softirq_pending(smp_processor_id()) )
532 do_softirq();
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 printk("Reboot in five seconds...\n");
735 spin_unlock_irqrestore(&lock, flags);
737 debugger_trap_immediate();
739 watchdog_disable();
740 mdelay(5000);
741 machine_restart(0);
742 }
744 /*
745 * Local variables:
746 * mode: C
747 * c-set-style: "BSD"
748 * c-basic-offset: 4
749 * tab-width: 4
750 * indent-tabs-mode: nil
751 * End:
752 */