ia64/xen-unstable

view xen/drivers/char/console.c @ 3819:a5f68c9f9e52

bitkeeper revision 1.1159.262.1 (420e4084ZlJS5YFJWSpfbv7WfT4uSg)

Oops -- disable serial console buffer by default.
author mafetter@fleming.research
date Sat Feb 12 17:44:36 2005 +0000 (2005-02-12)
parents 3f8766806bdd
children 5fe5f4c3da20
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>
24 /* opt_console: comma-separated list of console outputs. */
25 static unsigned 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 #ifndef NDEBUG
54 static unsigned char *sercon_buffer = NULL;
55 static unsigned char *sercon_buffer_end = NULL;
56 static unsigned char *sercon_buffer_head = NULL;
57 static unsigned char *sercon_buffer_next = NULL;
59 static unsigned int opt_sercon_buffer_size = 128; /* kbytes */
60 integer_param("conbuf", opt_sercon_buffer_size);
62 static void sercon_buffer_puts(const unsigned char *s);
63 #endif
65 /*
66 * *******************************************************
67 * *************** OUTPUT TO VGA CONSOLE *****************
68 * *******************************************************
69 */
71 /* VGA text (mode 3) definitions. */
72 #define COLUMNS 80
73 #define LINES 25
74 #define ATTRIBUTE 7
76 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
77 static void cls(void)
78 {
79 memset(video, 0, COLUMNS * LINES * 2);
80 xpos = ypos = 0;
81 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
82 }
84 static int detect_video(void *video_base)
85 {
86 volatile u16 *p = (volatile u16 *)video_base;
87 u16 saved1 = p[0], saved2 = p[1];
88 int video_found = 1;
90 p[0] = 0xAA55;
91 p[1] = 0x55AA;
92 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
93 video_found = 0;
95 p[0] = 0x55AA;
96 p[1] = 0xAA55;
97 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
98 video_found = 0;
100 p[0] = saved1;
101 p[1] = saved2;
103 return video_found;
104 }
106 static int detect_vga(void)
107 {
108 /*
109 * Look at a number of well-known locations. Even if video is not at
110 * 0xB8000 right now, it will appear there when we set up text mode 3.
111 *
112 * We assume if there is any sign of a video adaptor then it is at least
113 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
114 *
115 * These checks are basically to detect headless server boxes.
116 */
117 return (detect_video(__va(0xA0000)) ||
118 detect_video(__va(0xB0000)) ||
119 detect_video(__va(0xB8000)));
120 }
122 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
123 static void init_vga(void)
124 {
125 /* The following VGA state was saved from a chip in text mode 3. */
126 static unsigned char regs[] = {
127 /* Sequencer registers */
128 0x03, 0x00, 0x03, 0x00, 0x02,
129 /* CRTC registers */
130 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
131 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
132 0xb9, 0xa3, 0xff,
133 /* Graphic registers */
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
135 /* Attribute registers */
136 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
137 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
138 };
140 int i, j = 0;
141 volatile unsigned char tmp;
143 if ( !vgacon_enabled )
144 return;
146 if ( !detect_vga() )
147 {
148 printk("No VGA adaptor detected!\n");
149 vgacon_enabled = 0;
150 return;
151 }
153 video = __va(0xB8000);
155 tmp = inb(0x3da);
156 outb(0x00, 0x3c0);
158 for ( i = 0; i < 5; i++ )
159 outw((regs[j++] << 8) | i, 0x3c4);
161 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
162 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
164 for ( i = 0; i < 25; i++ )
165 outw((regs[j++] << 8) | i, 0x3d4);
167 for ( i = 0; i < 9; i++ )
168 outw((regs[j++] << 8) | i, 0x3ce);
170 for ( i = 0; i < 21; i++ )
171 {
172 tmp = inb(0x3da);
173 outb(i, 0x3c0);
174 outb(regs[j++], 0x3c0);
175 }
177 tmp = inb(0x3da);
178 outb(0x20, 0x3c0);
180 cls();
181 }
183 static void put_newline(void)
184 {
185 xpos = 0;
186 ypos++;
188 if (ypos >= LINES)
189 {
190 static char zeroarr[2*COLUMNS] = { 0 };
191 ypos = LINES-1;
192 memcpy((char*)video,
193 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
194 memcpy((char*)video + (LINES-1)*2*COLUMNS,
195 zeroarr, 2*COLUMNS);
196 }
197 }
199 static void putchar_console(int c)
200 {
201 if ( !vgacon_enabled )
202 return;
204 if ( c == '\n' )
205 {
206 put_newline();
207 }
208 else
209 {
210 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
211 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
212 if ( ++xpos >= COLUMNS )
213 put_newline();
214 }
215 }
218 /*
219 * ********************************************************
220 * *************** ACCESS TO CONSOLE RING *****************
221 * ********************************************************
222 */
224 static void putchar_console_ring(int c)
225 {
226 if ( console_ring.len < CONSOLE_RING_SIZE )
227 console_ring.buf[console_ring.len++] = (char)c;
228 }
230 long read_console_ring(unsigned long str, unsigned int count, unsigned cmd)
231 {
232 unsigned int len;
234 len = (console_ring.len < count) ? console_ring.len : count;
236 if ( copy_to_user((char *)str, console_ring.buf, len) )
237 return -EFAULT;
239 if ( cmd & CONSOLE_RING_CLEAR )
240 console_ring.len = 0;
242 return len;
243 }
246 /*
247 * *******************************************************
248 * *************** ACCESS TO SERIAL LINE *****************
249 * *******************************************************
250 */
252 /* Characters received over the serial line are buffered for domain 0. */
253 #define SERIAL_RX_SIZE 128
254 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
255 static char serial_rx_ring[SERIAL_RX_SIZE];
256 static unsigned int serial_rx_cons, serial_rx_prod;
258 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
259 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
260 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
262 static void switch_serial_input(void)
263 {
264 static char *input_str[2] = { "DOM0", "Xen" };
265 xen_rx = !xen_rx;
266 if ( SWITCH_CODE != 0 )
267 {
268 int buffer_enable = sercon_buffer_bypass();
269 printk("*** Serial input -> %s "
270 "(type 'CTRL-%c' three times to switch input to %s).\n",
271 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
272 sercon_buffer_set(buffer_enable);
273 }
274 }
276 static void __serial_rx(unsigned char c, struct xen_regs *regs)
277 {
278 if ( xen_rx )
279 {
280 handle_keypress(c, regs);
281 }
282 else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
283 {
284 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
285 if ( serial_rx_prod++ == serial_rx_cons )
286 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
287 }
288 }
290 static void serial_rx(unsigned char c, struct xen_regs *regs)
291 {
292 static int switch_code_count = 0;
294 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
295 {
296 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
297 if ( ++switch_code_count == 3 )
298 {
299 switch_serial_input();
300 switch_code_count = 0;
301 }
302 }
303 else
304 {
305 switch_code_count = 0;
306 }
308 /* Finally process the just-received character. */
309 __serial_rx(c, regs);
310 }
312 long do_console_io(int cmd, int count, char *buffer)
313 {
314 char *kbuf;
315 long rc;
317 #ifndef VERBOSE
318 /* Only domain-0 may access the emergency console. */
319 if ( current->domain->id != 0 )
320 return -EPERM;
321 #endif
323 switch ( cmd )
324 {
325 case CONSOLEIO_write:
326 if ( count > (PAGE_SIZE-1) )
327 count = PAGE_SIZE-1;
328 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
329 return -ENOMEM;
330 kbuf[count] = '\0';
331 rc = count;
332 if ( copy_from_user(kbuf, buffer, count) )
333 rc = -EFAULT;
334 else
335 serial_puts(sercon_handle, kbuf);
336 free_xenheap_page((unsigned long)kbuf);
337 break;
338 case CONSOLEIO_read:
339 rc = 0;
340 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
341 {
342 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
343 &buffer[rc]) )
344 {
345 rc = -EFAULT;
346 break;
347 }
348 rc++;
349 serial_rx_cons++;
350 }
351 break;
352 default:
353 rc = -ENOSYS;
354 break;
355 }
357 return rc;
358 }
361 /*
362 * *****************************************************
363 * *************** GENERIC CONSOLE I/O *****************
364 * *****************************************************
365 */
367 static inline void __putstr(const char *str)
368 {
369 int c;
371 #ifndef NDEBUG
372 if ( sercon_handle & SERHND_BUFFERED )
373 sercon_buffer_puts(str);
374 else
375 #endif
376 serial_puts(sercon_handle, str);
378 while ( (c = *str++) != '\0' )
379 {
380 putchar_console(c);
381 putchar_console_ring(c);
382 }
383 }
385 void printf(const char *fmt, ...)
386 {
387 static char buf[1024];
388 static int start_of_line = 1;
390 va_list args;
391 char *p, *q;
392 unsigned long flags;
394 spin_lock_irqsave(&console_lock, flags);
396 va_start(args, fmt);
397 (void)vsnprintf(buf, sizeof(buf), fmt, args);
398 va_end(args);
400 p = buf;
401 while ( (q = strchr(p, '\n')) != NULL )
402 {
403 *q = '\0';
404 if ( start_of_line )
405 __putstr(printk_prefix);
406 __putstr(p);
407 __putstr("\n");
408 start_of_line = 1;
409 p = q + 1;
410 }
412 if ( *p != '\0' )
413 {
414 if ( start_of_line )
415 __putstr(printk_prefix);
416 __putstr(p);
417 start_of_line = 0;
418 }
420 spin_unlock_irqrestore(&console_lock, flags);
421 }
423 void set_printk_prefix(const char *prefix)
424 {
425 strcpy(printk_prefix, prefix);
426 }
428 void init_console(void)
429 {
430 unsigned char *p;
432 /* Where should console output go? */
433 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
434 {
435 if ( *p == ',' )
436 p++;
437 if ( strncmp(p, "com", 3) == 0 )
438 sercon_handle = parse_serial_handle(p);
439 else if ( strncmp(p, "vga", 3) == 0 )
440 vgacon_enabled = 1;
441 }
443 init_vga();
445 serial_set_rx_handler(sercon_handle, serial_rx);
447 /* HELLO WORLD --- start-of-day banner text. */
448 printk(XEN_BANNER);
449 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
450 printk(" University of Cambridge Computer Laboratory\n\n");
451 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
452 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
453 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
454 XEN_COMPILER, XEN_COMPILE_DATE);
455 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
456 set_printk_prefix("(XEN) ");
457 }
459 void console_endboot(int disable_vga)
460 {
461 if ( disable_vga )
462 vgacon_enabled = 0;
464 /*
465 * If user specifies so, we fool the switch routine to redirect input
466 * straight back to Xen. I use this convoluted method so we still print
467 * a useful 'how to switch' message.
468 */
469 if ( opt_conswitch[1] == 'x' )
470 xen_rx = !xen_rx;
472 /* Serial input is directed to DOM0 by default. */
473 switch_serial_input();
474 }
476 void console_force_unlock(void)
477 {
478 console_lock = SPIN_LOCK_UNLOCKED;
479 serial_force_unlock(sercon_handle);
480 }
482 void console_force_lock(void)
483 {
484 spin_lock(&console_lock);
485 }
487 // 09Feb2005: this appears to be unused...
488 void console_putc(char c)
489 {
490 serial_putc(sercon_handle, c);
491 }
493 // 09Feb2005: this appears to be unused...
494 int console_getc(void)
495 {
496 return serial_getc(sercon_handle);
497 }
499 // 09Feb2005: this appears to be unused...
500 int irq_console_getc(void)
501 {
502 return irq_serial_getc(sercon_handle);
503 }
506 /*
507 * **************************************************************
508 * *************** serial console ring buffer *******************
509 * **************************************************************
510 */
512 #ifndef NDEBUG
513 static void sercon_buffer_putc(const unsigned char c)
514 {
515 if ( !sercon_buffer )
516 return;
517 if ( !c )
518 return;
520 if ( sercon_buffer_next == sercon_buffer_end )
521 {
522 // buffer wrap-around case...
523 sercon_buffer_head = sercon_buffer + 1;
524 sercon_buffer_next = sercon_buffer;
525 }
526 if ( sercon_buffer_head == sercon_buffer_next + 1 )
527 {
528 // the buffer is already full...
529 sercon_buffer_head++;
530 }
531 *sercon_buffer_next++ = c;
532 *sercon_buffer_next = 0;
533 }
535 static void sercon_buffer_puts(const unsigned char *s)
536 {
537 // inefficient but simple...
538 while ( *s )
539 sercon_buffer_putc(*s++);
540 }
542 static void sercon_buffer_reset(void)
543 {
544 sercon_buffer_head = sercon_buffer;
545 sercon_buffer_next = sercon_buffer;
546 sercon_buffer_head[0] = 0;
547 }
549 static void sercon_buffer_flush(void)
550 {
551 serial_puts(sercon_handle, sercon_buffer_head);
552 if ( sercon_buffer_head != sercon_buffer )
553 serial_puts(sercon_handle, sercon_buffer);
554 sercon_buffer_reset();
555 }
557 void _sercon_buffer_dump(void)
558 {
559 sercon_buffer_flush();
560 sercon_handle &= ~SERHND_BUFFERED;
561 }
563 void sercon_buffer_toggle(unsigned char key)
564 {
565 if ( !sercon_buffer )
566 {
567 printk("serial console buffer not allocated\n");
568 return;
569 }
571 if ( sercon_handle & SERHND_BUFFERED )
572 sercon_buffer_flush();
573 sercon_handle ^= SERHND_BUFFERED;
574 }
576 void _sercon_buffer_set(int enable)
577 {
578 if (enable)
579 sercon_handle |= SERHND_BUFFERED;
580 else
581 sercon_handle &= ~SERHND_BUFFERED;
582 }
584 int _sercon_buffer_bypass(void)
585 {
586 int buffering = !!(sercon_handle & SERHND_BUFFERED);
587 sercon_handle &= ~SERHND_BUFFERED;
589 return buffering;
590 }
592 static int __init sercon_buffer_init(void)
593 {
594 int order;
595 int kbytes = opt_sercon_buffer_size;
597 if ( !kbytes )
598 return 0;
600 order = get_order(kbytes * 1024);
601 sercon_buffer = (void *)alloc_xenheap_pages(order);
602 ASSERT( sercon_buffer );
604 sercon_buffer_end = sercon_buffer + kbytes*1024 - 1;
605 *sercon_buffer_end = 0;
607 sercon_buffer_reset();
609 return 0;
610 }
611 __initcall(sercon_buffer_init);
613 #endif /* not NDEBUG */
616 /*
617 * **************************************************************
618 * *************** Debugging/tracing/error-report ***************
619 * **************************************************************
620 */
622 void panic(const char *fmt, ...)
623 {
624 va_list args;
625 char buf[128];
626 unsigned long flags;
627 extern void machine_restart(char *);
629 va_start(args, fmt);
630 (void)vsnprintf(buf, sizeof(buf), fmt, args);
631 va_end(args);
633 /* Spit out multiline message in one go. */
634 spin_lock_irqsave(&console_lock, flags);
635 __putstr("\n****************************************\n");
636 __putstr(buf);
637 __putstr("Aieee! CPU");
638 sprintf(buf, "%d", smp_processor_id());
639 __putstr(buf);
640 __putstr(" is toast...\n");
641 __putstr("****************************************\n\n");
642 __putstr("Reboot in five seconds...\n");
643 spin_unlock_irqrestore(&console_lock, flags);
645 watchdog_on = 0;
646 sercon_buffer_dump();
648 mdelay(5000);
649 machine_restart(0);
650 }
653 void __out_of_line_bug(int line)
654 {
655 printk("kernel BUG in header file at line %d\n", line);
656 BUG();
657 for ( ; ; ) ;
658 }