ia64/xen-unstable

view xen/drivers/char/console.c @ 5062:2562daa95e37

bitkeeper revision 1.1495 (428e6e55_iTSnZRUSmqgYyK-Bql7Lg)

Merge freefall.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-2.0-testing.bk
into freefall.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
author iap10@freefall.cl.cam.ac.uk
date Fri May 20 23:10:13 2005 +0000 (2005-05-20)
parents bdc5114b6f20 312df7388796
children 4c63d91b687f
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 <xen/mm.h>
21 #include <asm/uaccess.h>
22 #include <asm/debugger.h>
23 #include <asm/io.h>
25 /* opt_console: comma-separated list of console outputs. */
26 static char opt_console[30] = OPT_CONSOLE_STR;
27 string_param("console", opt_console);
29 /* opt_conswitch: a character pair controlling console switching. */
30 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
31 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
32 /* boots. Any other value, or omitting the char, enables auto-switch */
33 static unsigned char opt_conswitch[5] = "a";
34 string_param("conswitch", opt_conswitch);
36 static int xpos, ypos;
37 static unsigned char *video;
39 #define CONSOLE_RING_SIZE 16392
40 typedef struct console_ring_st
41 {
42 char buf[CONSOLE_RING_SIZE];
43 unsigned int len;
44 } console_ring_t;
45 static console_ring_t console_ring;
47 static char printk_prefix[16] = "";
49 static int sercon_handle = -1;
50 static int vgacon_enabled = 0;
52 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 {
257 printk("*** Serial input -> %s "
258 "(type 'CTRL-%c' three times to switch input to %s).\n",
259 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
260 }
261 }
263 static void __serial_rx(unsigned char c, struct cpu_user_regs *regs)
264 {
265 if ( xen_rx )
266 return handle_keypress(c, regs);
268 /* Deliver input to guest buffer, unless it is already full. */
269 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
270 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
271 /* Always notify the guest: prevents receive path from getting stuck. */
272 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
273 }
275 static void serial_rx(unsigned char c, struct cpu_user_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 return;
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->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 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 unsigned int debugtrace_used;
499 static spinlock_t debugtrace_lock = SPIN_LOCK_UNLOCKED;
500 integer_param("debugtrace", debugtrace_kilobytes);
502 void debugtrace_dump(void)
503 {
504 unsigned long flags;
506 if ( (debugtrace_bytes == 0) || !debugtrace_used )
507 return;
509 watchdog_disable();
511 spin_lock_irqsave(&debugtrace_lock, flags);
513 printk("debugtrace_dump() starting\n");
515 /* Print oldest portion of the ring. */
516 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
517 serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
519 /* Print youngest portion of the ring. */
520 debugtrace_buf[debugtrace_prd] = '\0';
521 serial_puts(sercon_handle, &debugtrace_buf[0]);
523 memset(debugtrace_buf, '\0', debugtrace_bytes);
525 printk("debugtrace_dump() finished\n");
527 spin_unlock_irqrestore(&debugtrace_lock, flags);
529 watchdog_enable();
530 }
532 void debugtrace_printk(const char *fmt, ...)
533 {
534 static char buf[1024];
536 va_list args;
537 char *p;
538 unsigned long flags;
540 if ( debugtrace_bytes == 0 )
541 return;
543 debugtrace_used = 1;
545 spin_lock_irqsave(&debugtrace_lock, flags);
547 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
549 va_start(args, fmt);
550 (void)vsnprintf(buf, sizeof(buf), fmt, args);
551 va_end(args);
553 if ( debugtrace_send_to_console )
554 {
555 serial_puts(sercon_handle, buf);
556 }
557 else
558 {
559 for ( p = buf; *p != '\0'; p++ )
560 {
561 debugtrace_buf[debugtrace_prd++] = *p;
562 /* Always leave a nul byte at the end of the buffer. */
563 if ( debugtrace_prd == (debugtrace_bytes - 1) )
564 debugtrace_prd = 0;
565 }
566 }
568 spin_unlock_irqrestore(&debugtrace_lock, flags);
569 }
571 static int __init debugtrace_init(void)
572 {
573 int order;
574 unsigned int kbytes, bytes;
576 /* Round size down to next power of two. */
577 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
578 debugtrace_kilobytes = kbytes;
580 bytes = debugtrace_kilobytes << 10;
581 if ( bytes == 0 )
582 return 0;
584 order = get_order(bytes);
585 debugtrace_buf = (char *)alloc_xenheap_pages(order);
586 ASSERT(debugtrace_buf != NULL);
588 memset(debugtrace_buf, '\0', bytes);
590 debugtrace_bytes = bytes;
592 memset(debugtrace_buf, '\0', debugtrace_bytes);
594 return 0;
595 }
596 __initcall(debugtrace_init);
598 #endif /* !NDEBUG */
602 /*
603 * **************************************************************
604 * *************** Debugging/tracing/error-report ***************
605 * **************************************************************
606 */
608 void panic(const char *fmt, ...)
609 {
610 va_list args;
611 char buf[128], cpustr[10];
612 unsigned long flags;
613 extern void machine_restart(char *);
615 debugtrace_dump();
617 va_start(args, fmt);
618 (void)vsnprintf(buf, sizeof(buf), fmt, args);
619 va_end(args);
621 debugger_trap_immediate();
623 /* Spit out multiline message in one go. */
624 spin_lock_irqsave(&console_lock, flags);
625 __putstr("\n****************************************\n");
626 __putstr("Panic on CPU");
627 sprintf(cpustr, "%d", smp_processor_id());
628 __putstr(cpustr);
629 __putstr(":\n");
630 __putstr(buf);
631 __putstr("****************************************\n\n");
632 __putstr("Reboot in five seconds...\n");
633 spin_unlock_irqrestore(&console_lock, flags);
635 watchdog_disable();
636 mdelay(5000);
637 machine_restart(0);
638 }
640 /*
641 * Local variables:
642 * mode: C
643 * c-set-style: "BSD"
644 * c-basic-offset: 4
645 * tab-width: 4
646 * indent-tabs-mode: nil
647 * End:
648 */