ia64/xen-unstable

view xen/drivers/char/console.c @ 9707:6692dd873e21

Use memmove instead of memcpy for overlapping areas (console scroll).
Use memset instead of memcpy to clear line.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author kaf24@firebug.cl.cam.ac.uk
date Thu Apr 13 11:25:03 2006 +0100 (2006-04-13)
parents be0a1f376223
children 2ae003c45ffe
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 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
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
69 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
70 static void cls(void)
71 {
72 memset(video, 0, COLUMNS * LINES * 2);
73 xpos = ypos = 0;
74 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
75 }
77 static int detect_video(void *video_base)
78 {
79 volatile u16 *p = (volatile u16 *)video_base;
80 u16 saved1 = p[0], saved2 = p[1];
81 int video_found = 1;
83 p[0] = 0xAA55;
84 p[1] = 0x55AA;
85 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
86 video_found = 0;
88 p[0] = 0x55AA;
89 p[1] = 0xAA55;
90 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
91 video_found = 0;
93 p[0] = saved1;
94 p[1] = saved2;
96 return video_found;
97 }
99 static int detect_vga(void)
100 {
101 /*
102 * Look at a number of well-known locations. Even if video is not at
103 * 0xB8000 right now, it will appear there when we set up text mode 3.
104 *
105 * We assume if there is any sign of a video adaptor then it is at least
106 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
107 *
108 * These checks are basically to detect headless server boxes.
109 */
110 return (detect_video(__va(0xA0000)) ||
111 detect_video(__va(0xB0000)) ||
112 detect_video(__va(0xB8000)));
113 }
115 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
116 static void init_vga(void)
117 {
118 /* The following VGA state was saved from a chip in text mode 3. */
119 static unsigned char regs[] = {
120 /* Sequencer registers */
121 0x03, 0x00, 0x03, 0x00, 0x02,
122 /* CRTC registers */
123 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
124 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
125 0xb9, 0xa3, 0xff,
126 /* Graphic registers */
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
128 /* Attribute registers */
129 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
130 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
131 };
133 int i, j = 0;
134 volatile unsigned char tmp;
136 if ( !vgacon_enabled )
137 return;
139 if ( !detect_vga() )
140 {
141 printk("No VGA adaptor detected!\n");
142 vgacon_enabled = 0;
143 return;
144 }
146 video = __va(0xB8000);
148 tmp = inb(0x3da);
149 outb(0x00, 0x3c0);
151 for ( i = 0; i < 5; i++ )
152 outw((regs[j++] << 8) | i, 0x3c4);
154 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
155 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
157 for ( i = 0; i < 25; i++ )
158 outw((regs[j++] << 8) | i, 0x3d4);
160 for ( i = 0; i < 9; i++ )
161 outw((regs[j++] << 8) | i, 0x3ce);
163 for ( i = 0; i < 21; i++ )
164 {
165 tmp = inb(0x3da);
166 outb(i, 0x3c0);
167 outb(regs[j++], 0x3c0);
168 }
170 tmp = inb(0x3da);
171 outb(0x20, 0x3c0);
173 cls();
174 }
176 static void put_newline(void)
177 {
178 xpos = 0;
179 ypos++;
181 if (ypos >= LINES)
182 {
183 ypos = LINES-1;
184 memmove((char*)video,
185 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
186 memset((char*)video + (LINES-1)*2*COLUMNS, 0, 2*COLUMNS);
187 }
188 }
190 static void putchar_console(int c)
191 {
192 if ( !vgacon_enabled )
193 return;
195 if ( c == '\n' )
196 {
197 put_newline();
198 }
199 else
200 {
201 if ( xpos >= COLUMNS )
202 put_newline();
203 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
204 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
205 ++xpos;
206 }
207 }
210 /*
211 * ********************************************************
212 * *************** ACCESS TO CONSOLE RING *****************
213 * ********************************************************
214 */
216 static void putchar_console_ring(int c)
217 {
218 conring[CONRING_IDX_MASK(conringp++)] = c;
219 if ( (conringp - conringc) > CONRING_SIZE )
220 conringc = conringp - CONRING_SIZE;
221 }
223 long read_console_ring(GUEST_HANDLE(char) str, u32 *pcount, int clear)
224 {
225 unsigned int idx, len, max, sofar, c;
226 unsigned long flags;
228 max = *pcount;
229 sofar = 0;
231 c = conringc;
232 while ( c != conringp )
233 {
234 idx = CONRING_IDX_MASK(c);
235 len = conringp - c;
236 if ( (idx + len) > CONRING_SIZE )
237 len = CONRING_SIZE - idx;
238 if ( (sofar + len) > max )
239 len = max - sofar;
240 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
241 return -EFAULT;
242 sofar += len;
243 c += len;
244 }
246 if ( clear )
247 {
248 spin_lock_irqsave(&console_lock, flags);
249 conringc = conringp;
250 spin_unlock_irqrestore(&console_lock, flags);
251 }
253 *pcount = sofar;
254 return 0;
255 }
258 /*
259 * *******************************************************
260 * *************** ACCESS TO SERIAL LINE *****************
261 * *******************************************************
262 */
264 /* Characters received over the serial line are buffered for domain 0. */
265 #define SERIAL_RX_SIZE 128
266 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
267 static char serial_rx_ring[SERIAL_RX_SIZE];
268 static unsigned int serial_rx_cons, serial_rx_prod;
270 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
271 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
272 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
274 static void switch_serial_input(void)
275 {
276 static char *input_str[2] = { "DOM0", "Xen" };
277 xen_rx = !xen_rx;
278 if ( SWITCH_CODE != 0 )
279 {
280 printk("*** Serial input -> %s "
281 "(type 'CTRL-%c' three times to switch input to %s).\n",
282 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
283 }
284 }
286 static void __serial_rx(char c, struct cpu_user_regs *regs)
287 {
288 if ( xen_rx )
289 return handle_keypress(c, regs);
291 /* Deliver input to guest buffer, unless it is already full. */
292 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
293 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
294 /* Always notify the guest: prevents receive path from getting stuck. */
295 send_guest_global_virq(dom0, VIRQ_CONSOLE);
296 }
298 static void serial_rx(char c, struct cpu_user_regs *regs)
299 {
300 static int switch_code_count = 0;
302 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
303 {
304 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
305 if ( ++switch_code_count == 3 )
306 {
307 switch_serial_input();
308 switch_code_count = 0;
309 return;
310 }
311 }
312 else
313 {
314 switch_code_count = 0;
315 }
317 /* Finally process the just-received character. */
318 __serial_rx(c, regs);
319 }
321 static long guest_console_write(GUEST_HANDLE(char) buffer, int count)
322 {
323 char kbuf[128], *kptr;
324 int kcount;
326 while ( count > 0 )
327 {
328 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
329 {
330 if ( hypercall_preempt_check() )
331 break;
332 cpu_relax();
333 }
335 if ( hypercall_preempt_check() )
336 return hypercall_create_continuation(
337 __HYPERVISOR_console_io, "iih",
338 CONSOLEIO_write, count, buffer);
340 kcount = min_t(int, count, sizeof(kbuf)-1);
341 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
342 return -EFAULT;
343 kbuf[kcount] = '\0';
345 serial_puts(sercon_handle, kbuf);
347 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
348 putchar_console(*kptr);
350 guest_handle_add_offset(buffer, kcount);
351 count -= kcount;
352 }
354 return 0;
355 }
357 long do_console_io(int cmd, int count, GUEST_HANDLE(char) buffer)
358 {
359 long rc;
360 unsigned int idx, len;
362 #ifndef VERBOSE
363 /* Only domain 0 may access the emergency console. */
364 if ( current->domain->domain_id != 0 )
365 return -EPERM;
366 #endif
368 switch ( cmd )
369 {
370 case CONSOLEIO_write:
371 rc = guest_console_write(buffer, count);
372 break;
373 case CONSOLEIO_read:
374 rc = 0;
375 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
376 {
377 idx = SERIAL_RX_MASK(serial_rx_cons);
378 len = serial_rx_prod - serial_rx_cons;
379 if ( (idx + len) > SERIAL_RX_SIZE )
380 len = SERIAL_RX_SIZE - idx;
381 if ( (rc + len) > count )
382 len = count - rc;
383 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
384 {
385 rc = -EFAULT;
386 break;
387 }
388 rc += len;
389 serial_rx_cons += len;
390 }
391 break;
392 default:
393 rc = -ENOSYS;
394 break;
395 }
397 return rc;
398 }
401 /*
402 * *****************************************************
403 * *************** GENERIC CONSOLE I/O *****************
404 * *****************************************************
405 */
407 static inline void __putstr(const char *str)
408 {
409 int c;
411 serial_puts(sercon_handle, str);
413 while ( (c = *str++) != '\0' )
414 {
415 putchar_console(c);
416 putchar_console_ring(c);
417 }
418 }
420 void printf(const char *fmt, ...)
421 {
422 static char buf[1024];
423 static int start_of_line = 1;
425 va_list args;
426 char *p, *q;
427 unsigned long flags;
429 spin_lock_irqsave(&console_lock, flags);
431 va_start(args, fmt);
432 (void)vsnprintf(buf, sizeof(buf), fmt, args);
433 va_end(args);
435 p = buf;
436 while ( (q = strchr(p, '\n')) != NULL )
437 {
438 *q = '\0';
439 if ( start_of_line )
440 __putstr(printk_prefix);
441 __putstr(p);
442 __putstr("\n");
443 start_of_line = 1;
444 p = q + 1;
445 }
447 if ( *p != '\0' )
448 {
449 if ( start_of_line )
450 __putstr(printk_prefix);
451 __putstr(p);
452 start_of_line = 0;
453 }
455 spin_unlock_irqrestore(&console_lock, flags);
456 }
458 void set_printk_prefix(const char *prefix)
459 {
460 strcpy(printk_prefix, prefix);
461 }
463 void init_console(void)
464 {
465 char *p;
467 /* Where should console output go? */
468 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
469 {
470 if ( *p == ',' )
471 p++;
472 if ( strncmp(p, "com", 3) == 0 )
473 sercon_handle = serial_parse_handle(p);
474 else if ( strncmp(p, "vga", 3) == 0 )
475 vgacon_enabled = 1;
476 }
478 init_vga();
480 serial_set_rx_handler(sercon_handle, serial_rx);
482 /* HELLO WORLD --- start-of-day banner text. */
483 printk(XEN_BANNER);
484 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
485 printk(" University of Cambridge Computer Laboratory\n\n");
486 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
487 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
488 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
489 XEN_COMPILER, XEN_COMPILE_DATE);
490 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
491 set_printk_prefix("(XEN) ");
493 if ( opt_sync_console )
494 {
495 serial_start_sync(sercon_handle);
496 printk("Console output is synchronous.\n");
497 }
498 }
500 void console_endboot(int disable_vga)
501 {
502 if ( disable_vga )
503 vgacon_enabled = 0;
505 /*
506 * If user specifies so, we fool the switch routine to redirect input
507 * straight back to Xen. I use this convoluted method so we still print
508 * a useful 'how to switch' message.
509 */
510 if ( opt_conswitch[1] == 'x' )
511 xen_rx = !xen_rx;
513 /* Serial input is directed to DOM0 by default. */
514 switch_serial_input();
515 }
517 void console_force_unlock(void)
518 {
519 console_lock = SPIN_LOCK_UNLOCKED;
520 serial_force_unlock(sercon_handle);
521 console_start_sync();
522 }
524 void console_force_lock(void)
525 {
526 spin_lock(&console_lock);
527 }
529 void console_start_sync(void)
530 {
531 serial_start_sync(sercon_handle);
532 }
534 void console_end_sync(void)
535 {
536 serial_end_sync(sercon_handle);
537 }
539 void console_putc(char c)
540 {
541 serial_putc(sercon_handle, c);
542 }
544 int console_getc(void)
545 {
546 return serial_getc(sercon_handle);
547 }
550 /*
551 * **************************************************************
552 * *************** Serial console ring buffer *******************
553 * **************************************************************
554 */
556 #ifndef NDEBUG
558 /* Send output direct to console, or buffer it? */
559 int debugtrace_send_to_console;
561 static char *debugtrace_buf; /* Debug-trace buffer */
562 static unsigned int debugtrace_prd; /* Producer index */
563 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
564 static unsigned int debugtrace_used;
565 static spinlock_t debugtrace_lock = SPIN_LOCK_UNLOCKED;
566 integer_param("debugtrace", debugtrace_kilobytes);
568 void debugtrace_dump(void)
569 {
570 unsigned long flags;
572 if ( (debugtrace_bytes == 0) || !debugtrace_used )
573 return;
575 watchdog_disable();
577 spin_lock_irqsave(&debugtrace_lock, flags);
579 printk("debugtrace_dump() starting\n");
581 /* Print oldest portion of the ring. */
582 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
583 serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
585 /* Print youngest portion of the ring. */
586 debugtrace_buf[debugtrace_prd] = '\0';
587 serial_puts(sercon_handle, &debugtrace_buf[0]);
589 memset(debugtrace_buf, '\0', debugtrace_bytes);
591 printk("debugtrace_dump() finished\n");
593 spin_unlock_irqrestore(&debugtrace_lock, flags);
595 watchdog_enable();
596 }
598 void debugtrace_printk(const char *fmt, ...)
599 {
600 static char buf[1024];
602 va_list args;
603 char *p;
604 unsigned long flags;
606 if ( debugtrace_bytes == 0 )
607 return;
609 debugtrace_used = 1;
611 spin_lock_irqsave(&debugtrace_lock, flags);
613 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
615 va_start(args, fmt);
616 (void)vsnprintf(buf, sizeof(buf), fmt, args);
617 va_end(args);
619 if ( debugtrace_send_to_console )
620 {
621 serial_puts(sercon_handle, buf);
622 }
623 else
624 {
625 for ( p = buf; *p != '\0'; p++ )
626 {
627 debugtrace_buf[debugtrace_prd++] = *p;
628 /* Always leave a nul byte at the end of the buffer. */
629 if ( debugtrace_prd == (debugtrace_bytes - 1) )
630 debugtrace_prd = 0;
631 }
632 }
634 spin_unlock_irqrestore(&debugtrace_lock, flags);
635 }
637 static int __init debugtrace_init(void)
638 {
639 int order;
640 unsigned int kbytes, bytes;
642 /* Round size down to next power of two. */
643 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
644 debugtrace_kilobytes = kbytes;
646 bytes = debugtrace_kilobytes << 10;
647 if ( bytes == 0 )
648 return 0;
650 order = get_order_from_bytes(bytes);
651 debugtrace_buf = alloc_xenheap_pages(order);
652 ASSERT(debugtrace_buf != NULL);
654 memset(debugtrace_buf, '\0', bytes);
656 debugtrace_bytes = bytes;
658 return 0;
659 }
660 __initcall(debugtrace_init);
662 #endif /* !NDEBUG */
666 /*
667 * **************************************************************
668 * *************** Debugging/tracing/error-report ***************
669 * **************************************************************
670 */
672 void panic(const char *fmt, ...)
673 {
674 va_list args;
675 char buf[128];
676 unsigned long flags;
677 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
678 extern void machine_restart(char *);
680 debugtrace_dump();
682 va_start(args, fmt);
683 (void)vsnprintf(buf, sizeof(buf), fmt, args);
684 va_end(args);
686 /* Spit out multiline message in one go. */
687 console_start_sync();
688 spin_lock_irqsave(&lock, flags);
689 printk("\n****************************************\n");
690 printk("Panic on CPU %d:\n", smp_processor_id());
691 printk(buf);
692 printk("****************************************\n\n");
693 printk("Reboot in five seconds...\n");
694 spin_unlock_irqrestore(&lock, flags);
696 debugger_trap_immediate();
698 watchdog_disable();
699 mdelay(5000);
700 machine_restart(0);
701 }
703 /*
704 * Local variables:
705 * mode: C
706 * c-set-style: "BSD"
707 * c-basic-offset: 4
708 * tab-width: 4
709 * indent-tabs-mode: nil
710 * End:
711 */