ia64/xen-unstable

view xen/drivers/char/console.c @ 3884:8406b26684e2

bitkeeper revision 1.1230.2.2 (421a8798mvsMIGmWCHsDOB-iq7xzGg)

Bring back the console_{putc,getc} set of functions, which
export access to the console without exporting the sercon_handle.
Signed-off-by: chris@xensource.com
author cl349@arcadians.cl.cam.ac.uk
date Tue Feb 22 01:15:04 2005 +0000 (2005-02-22)
parents ffb2d7ac4b7f
children ff8c9a2be5f7
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>
23 #include <asm/debugger.h>
25 /* opt_console: comma-separated list of console outputs. */
26 static unsigned 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 xen_regs *regs)
264 {
265 if ( xen_rx )
266 {
267 handle_keypress(c, regs);
268 }
269 else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
270 {
271 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
272 if ( serial_rx_prod++ == serial_rx_cons )
273 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
274 }
275 }
277 static void serial_rx(unsigned char c, struct xen_regs *regs)
278 {
279 static int switch_code_count = 0;
281 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
282 {
283 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
284 if ( ++switch_code_count == 3 )
285 {
286 switch_serial_input();
287 switch_code_count = 0;
288 }
289 }
290 else
291 {
292 switch_code_count = 0;
293 }
295 /* Finally process the just-received character. */
296 __serial_rx(c, regs);
297 }
299 long do_console_io(int cmd, int count, char *buffer)
300 {
301 char *kbuf;
302 long rc;
304 #ifndef VERBOSE
305 /* Only domain-0 may access the emergency console. */
306 if ( current->domain->id != 0 )
307 return -EPERM;
308 #endif
310 switch ( cmd )
311 {
312 case CONSOLEIO_write:
313 if ( count > (PAGE_SIZE-1) )
314 count = PAGE_SIZE-1;
315 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
316 return -ENOMEM;
317 kbuf[count] = '\0';
318 rc = count;
319 if ( copy_from_user(kbuf, buffer, count) )
320 rc = -EFAULT;
321 else
322 serial_puts(sercon_handle, kbuf);
323 free_xenheap_page((unsigned long)kbuf);
324 break;
325 case CONSOLEIO_read:
326 rc = 0;
327 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
328 {
329 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
330 &buffer[rc]) )
331 {
332 rc = -EFAULT;
333 break;
334 }
335 rc++;
336 serial_rx_cons++;
337 }
338 break;
339 default:
340 rc = -ENOSYS;
341 break;
342 }
344 return rc;
345 }
348 /*
349 * *****************************************************
350 * *************** GENERIC CONSOLE I/O *****************
351 * *****************************************************
352 */
354 static inline void __putstr(const char *str)
355 {
356 int c;
358 serial_puts(sercon_handle, str);
360 while ( (c = *str++) != '\0' )
361 {
362 putchar_console(c);
363 putchar_console_ring(c);
364 }
365 }
367 void printf(const char *fmt, ...)
368 {
369 static char buf[1024];
370 static int start_of_line = 1;
372 va_list args;
373 char *p, *q;
374 unsigned long flags;
376 spin_lock_irqsave(&console_lock, flags);
378 va_start(args, fmt);
379 (void)vsnprintf(buf, sizeof(buf), fmt, args);
380 va_end(args);
382 p = buf;
383 while ( (q = strchr(p, '\n')) != NULL )
384 {
385 *q = '\0';
386 if ( start_of_line )
387 __putstr(printk_prefix);
388 __putstr(p);
389 __putstr("\n");
390 start_of_line = 1;
391 p = q + 1;
392 }
394 if ( *p != '\0' )
395 {
396 if ( start_of_line )
397 __putstr(printk_prefix);
398 __putstr(p);
399 start_of_line = 0;
400 }
402 spin_unlock_irqrestore(&console_lock, flags);
403 }
405 void set_printk_prefix(const char *prefix)
406 {
407 strcpy(printk_prefix, prefix);
408 }
410 void init_console(void)
411 {
412 unsigned char *p;
414 /* Where should console output go? */
415 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
416 {
417 if ( *p == ',' )
418 p++;
419 if ( strncmp(p, "com", 3) == 0 )
420 sercon_handle = parse_serial_handle(p);
421 else if ( strncmp(p, "vga", 3) == 0 )
422 vgacon_enabled = 1;
423 }
425 init_vga();
427 serial_set_rx_handler(sercon_handle, serial_rx);
429 /* HELLO WORLD --- start-of-day banner text. */
430 printk(XEN_BANNER);
431 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
432 printk(" University of Cambridge Computer Laboratory\n\n");
433 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
434 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
435 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
436 XEN_COMPILER, XEN_COMPILE_DATE);
437 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
438 set_printk_prefix("(XEN) ");
439 }
441 void console_endboot(int disable_vga)
442 {
443 if ( disable_vga )
444 vgacon_enabled = 0;
446 /*
447 * If user specifies so, we fool the switch routine to redirect input
448 * straight back to Xen. I use this convoluted method so we still print
449 * a useful 'how to switch' message.
450 */
451 if ( opt_conswitch[1] == 'x' )
452 xen_rx = !xen_rx;
454 /* Serial input is directed to DOM0 by default. */
455 switch_serial_input();
456 }
458 void console_force_unlock(void)
459 {
460 console_lock = SPIN_LOCK_UNLOCKED;
461 serial_force_unlock(sercon_handle);
462 }
464 void console_force_lock(void)
465 {
466 spin_lock(&console_lock);
467 }
469 void console_putc(char c)
470 {
471 serial_putc(sercon_handle, c);
472 }
474 int console_getc(void)
475 {
476 return serial_getc(sercon_handle);
477 }
479 int irq_console_getc(void)
480 {
481 return irq_serial_getc(sercon_handle);
482 }
485 /*
486 * **************************************************************
487 * *************** Serial console ring buffer *******************
488 * **************************************************************
489 */
491 #ifndef NDEBUG
493 /* Send output direct to console, or buffer it? */
494 int debugtrace_send_to_console;
496 static unsigned char *debugtrace_buf; /* Debug-trace buffer */
497 static unsigned int debugtrace_prd; /* Producer index */
498 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
499 static spinlock_t debugtrace_lock = SPIN_LOCK_UNLOCKED;
500 integer_param("debugtrace", debugtrace_kilobytes);
502 void debugtrace_dump(void)
503 {
504 int _watchdog_on = watchdog_on;
505 unsigned long flags;
507 if ( debugtrace_bytes == 0 )
508 return;
510 /* Watchdog can trigger if we print a really large buffer. */
511 watchdog_on = 0;
513 spin_lock_irqsave(&debugtrace_lock, flags);
515 /* Print oldest portion of the ring. */
516 serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
518 /* Print youngest portion of the ring. */
519 debugtrace_buf[debugtrace_prd] = '\0';
520 serial_puts(sercon_handle, &debugtrace_buf[0]);
522 memset(debugtrace_buf, '\0', debugtrace_bytes);
524 spin_unlock_irqrestore(&debugtrace_lock, flags);
526 watchdog_on = _watchdog_on;
527 }
529 void debugtrace_printk(const char *fmt, ...)
530 {
531 static char buf[1024];
533 va_list args;
534 unsigned char *p;
535 unsigned long flags;
537 if ( debugtrace_bytes == 0 )
538 return;
540 spin_lock_irqsave(&debugtrace_lock, flags);
542 va_start(args, fmt);
543 (void)vsnprintf(buf, sizeof(buf), fmt, args);
544 va_end(args);
546 if ( debugtrace_send_to_console )
547 {
548 serial_puts(sercon_handle, buf);
549 }
550 else
551 {
552 for ( p = buf; *p != '\0'; p++ )
553 {
554 debugtrace_buf[debugtrace_prd++] = *p;
555 /* Always leave a nul byte at the end of the buffer. */
556 if ( debugtrace_prd == (debugtrace_bytes - 1) )
557 debugtrace_prd = 0;
558 }
559 }
561 spin_unlock_irqrestore(&debugtrace_lock, flags);
562 }
564 static int __init debugtrace_init(void)
565 {
566 int order;
567 unsigned int kbytes;
569 /* Round size down to next power of two. */
570 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
571 debugtrace_kilobytes = kbytes;
573 debugtrace_bytes = debugtrace_kilobytes << 10;
574 if ( debugtrace_bytes == 0 )
575 return 0;
577 order = get_order(debugtrace_bytes);
578 debugtrace_buf = (unsigned char *)alloc_xenheap_pages(order);
579 ASSERT(debugtrace_buf != NULL);
581 return 0;
582 }
583 __initcall(debugtrace_init);
585 #endif /* !NDEBUG */
589 /*
590 * **************************************************************
591 * *************** Debugging/tracing/error-report ***************
592 * **************************************************************
593 */
595 extern void trap_to_xendbg(void);
597 void panic(const char *fmt, ...)
598 {
599 va_list args;
600 char buf[128];
601 unsigned long flags;
602 extern void machine_restart(char *);
604 debugtrace_dump();
606 va_start(args, fmt);
607 (void)vsnprintf(buf, sizeof(buf), fmt, args);
608 va_end(args);
610 debugger_trap_immediate();
612 /* Spit out multiline message in one go. */
613 spin_lock_irqsave(&console_lock, flags);
614 __putstr("\n****************************************\n");
615 __putstr(buf);
616 __putstr("Aieee! CPU");
617 sprintf(buf, "%d", smp_processor_id());
618 __putstr(buf);
619 __putstr(" is toast...\n");
620 __putstr("****************************************\n\n");
621 __putstr("Reboot in five seconds...\n");
622 spin_unlock_irqrestore(&console_lock, flags);
624 watchdog_on = 0;
625 mdelay(5000);
626 machine_restart(0);
627 }
630 void __out_of_line_bug(int line)
631 {
632 printk("kernel BUG in header file at line %d\n", line);
633 BUG();
634 for ( ; ; ) ;
635 }