ia64/xen-unstable

view xen/drivers/char/console.c @ 5060:f0fb0b3becbe

bitkeeper revision 1.1159.284.1 (428e6db8MJ-JzmJYObnEqq381gyfSQ)

trivial fix to prevent a spurious ctrl-a when switching the console back from Xen to dom0.

Signed-off-by: ian@xensource.com
author iap10@freefall.cl.cam.ac.uk
date Fri May 20 23:07:36 2005 +0000 (2005-05-20)
parents aa22e2575a10
children 312df7388796
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] = "com1,vga";
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 return handle_keypress(c, regs);
265 /* Deliver input to guest buffer, unless it is already full. */
266 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
267 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
268 /* Always notify the guest: prevents receive path from getting stuck. */
269 send_guest_virq(dom0, VIRQ_CONSOLE);
270 }
272 static void serial_rx(unsigned char c, struct xen_regs *regs)
273 {
274 static int switch_code_count = 0;
276 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
277 {
278 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
279 if ( ++switch_code_count == 3 )
280 {
281 switch_serial_input();
282 switch_code_count = 0;
283 return;
284 }
285 }
286 else
287 {
288 switch_code_count = 0;
289 }
291 /* Finally process the just-received character. */
292 __serial_rx(c, regs);
293 }
295 long do_console_io(int cmd, int count, char *buffer)
296 {
297 char *kbuf;
298 long rc;
300 #ifndef VERBOSE
301 /* Only domain-0 may access the emergency console. */
302 if ( current->id != 0 )
303 return -EPERM;
304 #endif
306 switch ( cmd )
307 {
308 case CONSOLEIO_write:
309 if ( count > (PAGE_SIZE-1) )
310 count = PAGE_SIZE-1;
311 if ( (kbuf = (char *)alloc_xenheap_page()) == NULL )
312 return -ENOMEM;
313 kbuf[count] = '\0';
314 rc = count;
315 if ( copy_from_user(kbuf, buffer, count) )
316 rc = -EFAULT;
317 else
318 serial_puts(sercon_handle, kbuf);
319 free_xenheap_page((unsigned long)kbuf);
320 break;
321 case CONSOLEIO_read:
322 rc = 0;
323 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
324 {
325 if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)],
326 &buffer[rc]) )
327 {
328 rc = -EFAULT;
329 break;
330 }
331 rc++;
332 serial_rx_cons++;
333 }
334 break;
335 default:
336 rc = -ENOSYS;
337 break;
338 }
340 return rc;
341 }
344 /*
345 * *****************************************************
346 * *************** GENERIC CONSOLE I/O *****************
347 * *****************************************************
348 */
350 static inline void __putstr(const char *str)
351 {
352 int c;
353 serial_puts(sercon_handle, str);
354 while ( (c = *str++) != '\0' )
355 {
356 putchar_console(c);
357 putchar_console_ring(c);
358 }
359 }
361 void printf(const char *fmt, ...)
362 {
363 static char buf[1024];
364 static int start_of_line = 1;
366 va_list args;
367 char *p, *q;
368 unsigned long flags;
370 spin_lock_irqsave(&console_lock, flags);
372 va_start(args, fmt);
373 (void)vsnprintf(buf, sizeof(buf), fmt, args);
374 va_end(args);
376 p = buf;
377 while ( (q = strchr(p, '\n')) != NULL )
378 {
379 *q = '\0';
380 if ( start_of_line )
381 __putstr(printk_prefix);
382 __putstr(p);
383 __putstr("\n");
384 start_of_line = 1;
385 p = q + 1;
386 }
388 if ( *p != '\0' )
389 {
390 if ( start_of_line )
391 __putstr(printk_prefix);
392 __putstr(p);
393 start_of_line = 0;
394 }
396 spin_unlock_irqrestore(&console_lock, flags);
397 }
399 void set_printk_prefix(const char *prefix)
400 {
401 strcpy(printk_prefix, prefix);
402 }
404 void init_console(void)
405 {
406 unsigned char *p;
408 /* Where should console output go? */
409 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
410 {
411 if ( *p == ',' )
412 p++;
413 if ( strncmp(p, "com", 3) == 0 )
414 sercon_handle = parse_serial_handle(p);
415 else if ( strncmp(p, "vga", 3) == 0 )
416 vgacon_enabled = 1;
417 }
419 init_vga();
421 serial_set_rx_handler(sercon_handle, serial_rx);
423 /* HELLO WORLD --- start-of-day banner text. */
424 printk(XEN_BANNER);
425 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
426 printk(" University of Cambridge Computer Laboratory\n\n");
427 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
428 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
429 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
430 XEN_COMPILER, XEN_COMPILE_DATE);
431 printk(" Latest ChangeSet: %s\n\n", XEN_CHANGESET);
432 set_printk_prefix("(XEN) ");
433 }
435 void console_endboot(int disable_vga)
436 {
437 if ( disable_vga )
438 vgacon_enabled = 0;
440 /*
441 * If user specifies so, we fool the switch routine to redirect input
442 * straight back to Xen. I use this convoluted method so we still print
443 * a useful 'how to switch' message.
444 */
445 if ( opt_conswitch[1] == 'x' )
446 xen_rx = !xen_rx;
448 /* Serial input is directed to DOM0 by default. */
449 switch_serial_input();
450 }
452 void console_force_unlock(void)
453 {
454 console_lock = SPIN_LOCK_UNLOCKED;
455 serial_force_unlock(sercon_handle);
456 }
458 void console_force_lock(void)
459 {
460 spin_lock(&console_lock);
461 }
463 void console_putc(char c)
464 {
465 serial_putc(sercon_handle, c);
466 }
468 int console_getc(void)
469 {
470 return serial_getc(sercon_handle);
471 }
473 int irq_console_getc(void)
474 {
475 return irq_serial_getc(sercon_handle);
476 }
479 /*
480 * **************************************************************
481 * *************** Debugging/tracing/error-report ***************
482 * **************************************************************
483 */
485 void panic(const char *fmt, ...)
486 {
487 va_list args;
488 char buf[128];
489 unsigned long flags;
490 extern void machine_restart(char *);
492 va_start(args, fmt);
493 (void)vsnprintf(buf, sizeof(buf), fmt, args);
494 va_end(args);
496 /* Spit out multiline message in one go. */
497 spin_lock_irqsave(&console_lock, flags);
498 __putstr("\n****************************************\n");
499 __putstr(buf);
500 __putstr("Aieee! CPU");
501 sprintf(buf, "%d", smp_processor_id());
502 __putstr(buf);
503 __putstr(" is toast...\n");
504 __putstr("****************************************\n\n");
505 __putstr("Reboot in five seconds...\n");
506 spin_unlock_irqrestore(&console_lock, flags);
508 watchdog_on = 0;
509 mdelay(5000);
510 machine_restart(0);
511 }
514 void __out_of_line_bug(int line)
515 {
516 printk("kernel BUG in header file at line %d\n", line);
517 BUG();
518 for ( ; ; ) ;
519 }