debuggers.hg

view xen/drivers/char/console.c @ 3683:1c55bbe02576

bitkeeper revision 1.1159.212.84 (42033fc2Q0eAAtQcKyCf8cXCt_Fgfg)

Common-code cleanups, for ia64.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Fri Feb 04 09:26:26 2005 +0000 (2005-02-04)
parents e922aa58971a
children bbe8541361dd 4294cfa9fad3
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 <asm/uaccess.h>
21 #include <asm/mm.h>
23 /* opt_console: comma-separated list of console outputs. */
24 static unsigned char opt_console[30] = OPT_CONSOLE_STR;
25 string_param("console", opt_console);
27 /* opt_conswitch: a character pair controlling console switching. */
28 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
29 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
30 /* boots. Any other value, or omitting the char, enables auto-switch */
31 static unsigned char opt_conswitch[5] = "a";
32 string_param("conswitch", opt_conswitch);
34 static int xpos, ypos;
35 static unsigned char *video;
37 #define CONSOLE_RING_SIZE 16392
38 typedef struct console_ring_st
39 {
40 char buf[CONSOLE_RING_SIZE];
41 unsigned int len;
42 } console_ring_t;
43 static console_ring_t console_ring;
45 static char printk_prefix[16] = "";
47 static int sercon_handle = -1;
48 static int vgacon_enabled = 0;
50 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
53 /*
54 * *******************************************************
55 * *************** OUTPUT TO VGA CONSOLE *****************
56 * *******************************************************
57 */
59 /* VGA text (mode 3) definitions. */
60 #define COLUMNS 80
61 #define LINES 25
62 #define ATTRIBUTE 7
64 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
65 static void cls(void)
66 {
67 memset(video, 0, COLUMNS * LINES * 2);
68 xpos = ypos = 0;
69 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
70 }
72 static int detect_video(void *video_base)
73 {
74 volatile u16 *p = (volatile u16 *)video_base;
75 u16 saved1 = p[0], saved2 = p[1];
76 int video_found = 1;
78 p[0] = 0xAA55;
79 p[1] = 0x55AA;
80 if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) )
81 video_found = 0;
83 p[0] = 0x55AA;
84 p[1] = 0xAA55;
85 if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) )
86 video_found = 0;
88 p[0] = saved1;
89 p[1] = saved2;
91 return video_found;
92 }
94 static int detect_vga(void)
95 {
96 /*
97 * Look at a number of well-known locations. Even if video is not at
98 * 0xB8000 right now, it will appear there when we set up text mode 3.
99 *
100 * We assume if there is any sign of a video adaptor then it is at least
101 * VGA-compatible (surely noone runs CGA, EGA, .... these days?).
102 *
103 * These checks are basically to detect headless server boxes.
104 */
105 return (detect_video(__va(0xA0000)) ||
106 detect_video(__va(0xB0000)) ||
107 detect_video(__va(0xB8000)));
108 }
110 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
111 static void init_vga(void)
112 {
113 /* The following VGA state was saved from a chip in text mode 3. */
114 static unsigned char regs[] = {
115 /* Sequencer registers */
116 0x03, 0x00, 0x03, 0x00, 0x02,
117 /* CRTC registers */
118 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
119 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
120 0xb9, 0xa3, 0xff,
121 /* Graphic registers */
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
123 /* Attribute registers */
124 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
125 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
126 };
128 int i, j = 0;
129 volatile unsigned char tmp;
131 if ( !vgacon_enabled )
132 return;
134 if ( !detect_vga() )
135 {
136 printk("No VGA adaptor detected!\n");
137 vgacon_enabled = 0;
138 return;
139 }
141 video = __va(0xB8000);
143 tmp = inb(0x3da);
144 outb(0x00, 0x3c0);
146 for ( i = 0; i < 5; i++ )
147 outw((regs[j++] << 8) | i, 0x3c4);
149 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
150 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
152 for ( i = 0; i < 25; i++ )
153 outw((regs[j++] << 8) | i, 0x3d4);
155 for ( i = 0; i < 9; i++ )
156 outw((regs[j++] << 8) | i, 0x3ce);
158 for ( i = 0; i < 21; i++ )
159 {
160 tmp = inb(0x3da);
161 outb(i, 0x3c0);
162 outb(regs[j++], 0x3c0);
163 }
165 tmp = inb(0x3da);
166 outb(0x20, 0x3c0);
168 cls();
169 }
171 static void put_newline(void)
172 {
173 xpos = 0;
174 ypos++;
176 if (ypos >= LINES)
177 {
178 static char zeroarr[2*COLUMNS] = { 0 };
179 ypos = LINES-1;
180 memcpy((char*)video,
181 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
182 memcpy((char*)video + (LINES-1)*2*COLUMNS,
183 zeroarr, 2*COLUMNS);
184 }
185 }
187 static void putchar_console(int c)
188 {
189 if ( !vgacon_enabled )
190 return;
192 if ( c == '\n' )
193 {
194 put_newline();
195 }
196 else
197 {
198 video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
199 video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
200 if ( ++xpos >= COLUMNS )
201 put_newline();
202 }
203 }
206 /*
207 * ********************************************************
208 * *************** ACCESS TO CONSOLE RING *****************
209 * ********************************************************
210 */
212 static void putchar_console_ring(int c)
213 {
214 if ( console_ring.len < CONSOLE_RING_SIZE )
215 console_ring.buf[console_ring.len++] = (char)c;
216 }
218 long read_console_ring(unsigned long str, unsigned int count, unsigned cmd)
219 {
220 unsigned int len;
222 len = (console_ring.len < count) ? console_ring.len : count;
224 if ( copy_to_user((char *)str, console_ring.buf, len) )
225 return -EFAULT;
227 if ( cmd & CONSOLE_RING_CLEAR )
228 console_ring.len = 0;
230 return len;
231 }
234 /*
235 * *******************************************************
236 * *************** ACCESS TO SERIAL LINE *****************
237 * *******************************************************
238 */
240 /* Characters received over the serial line are buffered for domain 0. */
241 #define SERIAL_RX_SIZE 128
242 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
243 static char serial_rx_ring[SERIAL_RX_SIZE];
244 static unsigned int serial_rx_cons, serial_rx_prod;
246 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
247 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
248 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
250 static void switch_serial_input(void)
251 {
252 static char *input_str[2] = { "DOM0", "Xen" };
253 xen_rx = !xen_rx;
254 if ( SWITCH_CODE != 0 )
255 printk("*** Serial input -> %s "
256 "(type 'CTRL-%c' three times to switch input to %s).\n",
257 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
258 }
260 static void __serial_rx(unsigned char c, struct xen_regs *regs)
261 {
262 if ( xen_rx )
263 {
264 handle_keypress(c, regs);
265 }
266 else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
267 {
268 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
269 if ( serial_rx_prod++ == serial_rx_cons )
270 send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
271 }
272 }
274 static void serial_rx(unsigned char c, struct xen_regs *regs)
275 {
276 static int switch_code_count = 0;
278 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
279 {
280 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
281 if ( ++switch_code_count == 3 )
282 {
283 switch_serial_input();
284 switch_code_count = 0;
285 }
286 }
287 else
288 {
289 switch_code_count = 0;
290 }
292 /* Finally process the just-received character. */
293 __serial_rx(c, regs);
294 }
296 long do_console_io(int cmd, int count, char *buffer)
297 {
298 char *kbuf;
299 long rc;
301 #ifndef VERBOSE
302 /* Only domain-0 may access the emergency console. */
303 if ( current->domain->id != 0 )
304 return -EPERM;
305 #endif
307 switch ( cmd )
308 {
309 case CONSOLEIO_write:
310 if ( count > (PAGE_SIZE-1) )
311 count = PAGE_SIZE-1;
312 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
313 return -ENOMEM;
314 kbuf[count] = '\0';
315 rc = count;
316 if ( copy_from_user(kbuf, buffer, count) )
317 rc = -EFAULT;
318 else
319 serial_puts(sercon_handle, kbuf);
320 free_xenheap_page((unsigned long)kbuf);
321 break;
322 case CONSOLEIO_read:
323 rc = 0;
324 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
325 {
326 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
327 &buffer[rc]) )
328 {
329 rc = -EFAULT;
330 break;
331 }
332 rc++;
333 serial_rx_cons++;
334 }
335 break;
336 default:
337 rc = -ENOSYS;
338 break;
339 }
341 return rc;
342 }
345 /*
346 * *****************************************************
347 * *************** GENERIC CONSOLE I/O *****************
348 * *****************************************************
349 */
351 static inline void __putstr(const char *str)
352 {
353 int c;
354 serial_puts(sercon_handle, str);
355 while ( (c = *str++) != '\0' )
356 {
357 putchar_console(c);
358 putchar_console_ring(c);
359 }
360 }
362 void printf(const char *fmt, ...)
363 {
364 static char buf[1024];
365 static int start_of_line = 1;
367 va_list args;
368 char *p, *q;
369 unsigned long flags;
371 spin_lock_irqsave(&console_lock, flags);
373 va_start(args, fmt);
374 (void)vsnprintf(buf, sizeof(buf), fmt, args);
375 va_end(args);
377 p = buf;
378 while ( (q = strchr(p, '\n')) != NULL )
379 {
380 *q = '\0';
381 if ( start_of_line )
382 __putstr(printk_prefix);
383 __putstr(p);
384 __putstr("\n");
385 start_of_line = 1;
386 p = q + 1;
387 }
389 if ( *p != '\0' )
390 {
391 if ( start_of_line )
392 __putstr(printk_prefix);
393 __putstr(p);
394 start_of_line = 0;
395 }
397 spin_unlock_irqrestore(&console_lock, flags);
398 }
400 void set_printk_prefix(const char *prefix)
401 {
402 strcpy(printk_prefix, prefix);
403 }
405 void init_console(void)
406 {
407 unsigned char *p;
409 /* Where should console output go? */
410 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
411 {
412 if ( *p == ',' )
413 p++;
414 if ( strncmp(p, "com", 3) == 0 )
415 sercon_handle = parse_serial_handle(p);
416 else if ( strncmp(p, "vga", 3) == 0 )
417 vgacon_enabled = 1;
418 }
420 init_vga();
422 serial_set_rx_handler(sercon_handle, serial_rx);
424 /* HELLO WORLD --- start-of-day banner text. */
425 printk(XEN_BANNER);
426 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
427 printk(" University of Cambridge Computer Laboratory\n\n");
428 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
429 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
430 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
431 XEN_COMPILER, XEN_COMPILE_DATE);
432 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
433 set_printk_prefix("(XEN) ");
434 }
436 void console_endboot(int disable_vga)
437 {
438 if ( disable_vga )
439 vgacon_enabled = 0;
441 /*
442 * If user specifies so, we fool the switch routine to redirect input
443 * straight back to Xen. I use this convoluted method so we still print
444 * a useful 'how to switch' message.
445 */
446 if ( opt_conswitch[1] == 'x' )
447 xen_rx = !xen_rx;
449 /* Serial input is directed to DOM0 by default. */
450 switch_serial_input();
451 }
453 void console_force_unlock(void)
454 {
455 console_lock = SPIN_LOCK_UNLOCKED;
456 serial_force_unlock(sercon_handle);
457 }
459 void console_force_lock(void)
460 {
461 spin_lock(&console_lock);
462 }
464 void console_putc(char c)
465 {
466 serial_putc(sercon_handle, c);
467 }
469 int console_getc(void)
470 {
471 return serial_getc(sercon_handle);
472 }
474 int irq_console_getc(void)
475 {
476 return irq_serial_getc(sercon_handle);
477 }
480 /*
481 * **************************************************************
482 * *************** Debugging/tracing/error-report ***************
483 * **************************************************************
484 */
486 void panic(const char *fmt, ...)
487 {
488 va_list args;
489 char buf[128];
490 unsigned long flags;
491 extern void machine_restart(char *);
493 va_start(args, fmt);
494 (void)vsnprintf(buf, sizeof(buf), fmt, args);
495 va_end(args);
497 /* Spit out multiline message in one go. */
498 spin_lock_irqsave(&console_lock, flags);
499 __putstr("\n****************************************\n");
500 __putstr(buf);
501 __putstr("Aieee! CPU");
502 sprintf(buf, "%d", smp_processor_id());
503 __putstr(buf);
504 __putstr(" is toast...\n");
505 __putstr("****************************************\n\n");
506 __putstr("Reboot in five seconds...\n");
507 spin_unlock_irqrestore(&console_lock, flags);
509 watchdog_on = 0;
510 mdelay(5000);
511 machine_restart(0);
512 }
515 void __out_of_line_bug(int line)
516 {
517 printk("kernel BUG in header file at line %d\n", line);
518 BUG();
519 for ( ; ; ) ;
520 }