ia64/xen-unstable

view xen/drivers/char/console.c @ 17864:d4dcd4d39952

Bring back console_start_log_everything() as a milder alternative to
console_start_sync(). Revert keyhandler logic to use it. The
difference now is that serial logic is updated to not drop characters
if inb a log_everything region. Still this is milder than a sync
region since the async buffer must be filled before we start to
busy-wait on each character.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 13 14:15:00 2008 +0100 (2008-06-13)
parents 7eab5d8788a6
children 0c857419d354
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 *
8 * Added printf_ratelimit
9 * Taken from Linux - Author: Andi Kleen (net_ratelimit)
10 * Ported to Xen - Steven Rostedt - Red Hat
11 */
13 #include <xen/stdarg.h>
14 #include <xen/config.h>
15 #include <xen/version.h>
16 #include <xen/init.h>
17 #include <xen/lib.h>
18 #include <xen/errno.h>
19 #include <xen/event.h>
20 #include <xen/spinlock.h>
21 #include <xen/console.h>
22 #include <xen/serial.h>
23 #include <xen/softirq.h>
24 #include <xen/keyhandler.h>
25 #include <xen/mm.h>
26 #include <xen/delay.h>
27 #include <xen/guest_access.h>
28 #include <xen/shutdown.h>
29 #include <xen/vga.h>
30 #include <xen/kexec.h>
31 #include <asm/current.h>
32 #include <asm/debugger.h>
33 #include <asm/io.h>
34 #include <asm/div64.h>
35 #include <xsm/xsm.h>
36 #include <public/sysctl.h>
38 /* console: comma-separated list of console outputs. */
39 static char opt_console[30] = OPT_CONSOLE_STR;
40 string_param("console", opt_console);
42 /* conswitch: a character pair controlling console switching. */
43 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
44 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
45 /* boots. Any other value, or omitting the char, enables auto-switch */
46 static unsigned char opt_conswitch[3] = "a";
47 string_param("conswitch", opt_conswitch);
49 /* sync_console: force synchronous console output (useful for debugging). */
50 static int opt_sync_console;
51 boolean_param("sync_console", opt_sync_console);
53 /* console_to_ring: send guest (incl. dom 0) console data to console ring. */
54 static int opt_console_to_ring;
55 boolean_param("console_to_ring", opt_console_to_ring);
57 /* console_timestamps: include a timestamp prefix on every Xen console line. */
58 static int opt_console_timestamps;
59 boolean_param("console_timestamps", opt_console_timestamps);
61 #define CONRING_SIZE 16384
62 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
63 static char conring[CONRING_SIZE];
64 static uint32_t conringc, conringp;
66 static int sercon_handle = -1;
68 static DEFINE_SPINLOCK(console_lock);
70 /*
71 * To control the amount of printing, thresholds are added.
72 * These thresholds correspond to the XENLOG logging levels.
73 * There's an upper and lower threshold for non-guest messages and for
74 * guest-provoked messages. This works as follows, for a given log level L:
75 *
76 * L < lower_threshold : always logged
77 * lower_threshold <= L < upper_threshold : rate-limited logging
78 * upper_threshold <= L : never logged
79 *
80 * Note, in the above algorithm, to disable rate limiting simply make
81 * the lower threshold equal to the upper.
82 */
83 #ifdef NDEBUG
84 #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
85 #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
86 #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
87 #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
88 #else
89 #define XENLOG_UPPER_THRESHOLD 4 /* Do not discard anything */
90 #define XENLOG_LOWER_THRESHOLD 4 /* Print everything */
91 #define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything */
92 #define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything */
93 #endif
94 /*
95 * The XENLOG_DEFAULT is the default given to printks that
96 * do not have any print level associated with them.
97 */
98 #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
99 #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
101 static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
102 static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
103 static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
104 static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
106 static void parse_loglvl(char *s);
107 static void parse_guest_loglvl(char *s);
109 /*
110 * <lvl> := none|error|warning|info|debug|all
111 * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
112 * <lvl_print_always>: log level which is always printed
113 * <lvl_print_rlimit>: log level which is rate-limit printed
114 * Similar definitions for guest_loglvl, but applies to guest tracing.
115 * Defaults: loglvl=warning ; guest_loglvl=none/warning
116 */
117 custom_param("loglvl", parse_loglvl);
118 custom_param("guest_loglvl", parse_guest_loglvl);
120 static atomic_t print_everything = ATOMIC_INIT(0);
122 #define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
123 if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
124 *(ps) = (s) + strlen(lvlstr); \
125 return (lvlnum); \
126 }
128 static int __init __parse_loglvl(char *s, char **ps)
129 {
130 ___parse_loglvl(s, ps, "none", 0);
131 ___parse_loglvl(s, ps, "error", 1);
132 ___parse_loglvl(s, ps, "warning", 2);
133 ___parse_loglvl(s, ps, "info", 3);
134 ___parse_loglvl(s, ps, "debug", 4);
135 ___parse_loglvl(s, ps, "all", 4);
136 return 2; /* sane fallback */
137 }
139 static void __init _parse_loglvl(char *s, int *lower, int *upper)
140 {
141 *lower = *upper = __parse_loglvl(s, &s);
142 if ( *s == '/' )
143 *upper = __parse_loglvl(s+1, &s);
144 if ( *upper < *lower )
145 *upper = *lower;
146 }
148 static void __init parse_loglvl(char *s)
149 {
150 _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
151 }
153 static void __init parse_guest_loglvl(char *s)
154 {
155 _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
156 }
158 static char * __init loglvl_str(int lvl)
159 {
160 switch ( lvl )
161 {
162 case 0: return "Nothing";
163 case 1: return "Errors";
164 case 2: return "Errors and warnings";
165 case 3: return "Errors, warnings and info";
166 case 4: return "All";
167 }
168 return "???";
169 }
171 /*
172 * ********************************************************
173 * *************** ACCESS TO CONSOLE RING *****************
174 * ********************************************************
175 */
177 static void putchar_console_ring(int c)
178 {
179 ASSERT(spin_is_locked(&console_lock));
180 conring[CONRING_IDX_MASK(conringp++)] = c;
181 if ( (uint32_t)(conringp - conringc) > CONRING_SIZE )
182 conringc = conringp - CONRING_SIZE;
183 }
185 long read_console_ring(struct xen_sysctl_readconsole *op)
186 {
187 XEN_GUEST_HANDLE(char) str;
188 uint32_t idx, len, max, sofar, c;
190 str = guest_handle_cast(op->buffer, char),
191 max = op->count;
192 sofar = 0;
194 c = conringc;
195 if ( op->incremental && ((int32_t)(op->index - c) < 0) )
196 c = op->index;
198 while ( (c != conringp) && (sofar < max) )
199 {
200 idx = CONRING_IDX_MASK(c);
201 len = conringp - c;
202 if ( (idx + len) > CONRING_SIZE )
203 len = CONRING_SIZE - idx;
204 if ( (sofar + len) > max )
205 len = max - sofar;
206 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
207 return -EFAULT;
208 sofar += len;
209 c += len;
210 }
212 if ( op->clear )
213 {
214 spin_lock_irq(&console_lock);
215 if ( (uint32_t)(conringp - c) > CONRING_SIZE )
216 conringc = conringp - CONRING_SIZE;
217 else
218 conringc = c;
219 spin_unlock_irq(&console_lock);
220 }
222 op->count = sofar;
223 op->index = c;
225 return 0;
226 }
229 /*
230 * *******************************************************
231 * *************** ACCESS TO SERIAL LINE *****************
232 * *******************************************************
233 */
235 /* Characters received over the serial line are buffered for domain 0. */
236 #define SERIAL_RX_SIZE 128
237 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
238 static char serial_rx_ring[SERIAL_RX_SIZE];
239 static unsigned int serial_rx_cons, serial_rx_prod;
241 static void (*serial_steal_fn)(const char *);
243 int console_steal(int handle, void (*fn)(const char *))
244 {
245 if ( (handle == -1) || (handle != sercon_handle) )
246 return 0;
248 if ( serial_steal_fn != NULL )
249 return -EBUSY;
251 serial_steal_fn = fn;
252 return 1;
253 }
255 void console_giveback(int id)
256 {
257 if ( id == 1 )
258 serial_steal_fn = NULL;
259 }
261 static void sercon_puts(const char *s)
262 {
263 if ( serial_steal_fn != NULL )
264 (*serial_steal_fn)(s);
265 else
266 serial_puts(sercon_handle, s);
267 }
269 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
270 #define switch_code (opt_conswitch[0]-'a'+1)
271 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
273 static void switch_serial_input(void)
274 {
275 static char *input_str[2] = { "DOM0", "Xen" };
276 xen_rx = !xen_rx;
277 printk("*** Serial input -> %s", input_str[xen_rx]);
278 if ( switch_code )
279 printk(" (type 'CTRL-%c' three times to switch input to %s)",
280 opt_conswitch[0], input_str[!xen_rx]);
281 printk("\n");
282 }
284 static void __serial_rx(char c, struct cpu_user_regs *regs)
285 {
286 if ( xen_rx )
287 return handle_keypress(c, regs);
289 /* Deliver input to guest buffer, unless it is already full. */
290 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
291 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
292 /* Always notify the guest: prevents receive path from getting stuck. */
293 send_guest_global_virq(dom0, VIRQ_CONSOLE);
294 }
296 static void serial_rx(char c, struct cpu_user_regs *regs)
297 {
298 static int switch_code_count = 0;
300 if ( switch_code && (c == switch_code) )
301 {
302 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
303 if ( ++switch_code_count == 3 )
304 {
305 switch_serial_input();
306 switch_code_count = 0;
307 }
308 return;
309 }
311 for ( ; switch_code_count != 0; switch_code_count-- )
312 __serial_rx(switch_code, regs);
314 /* Finally process the just-received character. */
315 __serial_rx(c, regs);
316 }
318 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
319 {
320 char kbuf[128], *kptr;
321 int kcount;
323 while ( count > 0 )
324 {
325 while ( serial_tx_space(sercon_handle) < (serial_txbufsz / 2) )
326 {
327 if ( hypercall_preempt_check() )
328 break;
329 cpu_relax();
330 }
332 if ( hypercall_preempt_check() )
333 return hypercall_create_continuation(
334 __HYPERVISOR_console_io, "iih",
335 CONSOLEIO_write, count, buffer);
337 kcount = min_t(int, count, sizeof(kbuf)-1);
338 if ( copy_from_guest(kbuf, buffer, kcount) )
339 return -EFAULT;
340 kbuf[kcount] = '\0';
342 spin_lock_irq(&console_lock);
344 sercon_puts(kbuf);
345 vga_puts(kbuf);
347 if ( opt_console_to_ring )
348 {
349 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
350 putchar_console_ring(*kptr);
351 send_guest_global_virq(dom0, VIRQ_CON_RING);
352 }
354 spin_unlock_irq(&console_lock);
356 guest_handle_add_offset(buffer, kcount);
357 count -= kcount;
358 }
360 return 0;
361 }
363 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
364 {
365 long rc;
366 unsigned int idx, len;
368 #ifndef VERBOSE
369 /* Only domain 0 may access the emergency console. */
370 if ( current->domain->domain_id != 0 )
371 return -EPERM;
372 #endif
374 rc = xsm_console_io(current->domain, cmd);
375 if ( rc )
376 return rc;
378 switch ( cmd )
379 {
380 case CONSOLEIO_write:
381 rc = guest_console_write(buffer, count);
382 break;
383 case CONSOLEIO_read:
384 rc = 0;
385 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
386 {
387 idx = SERIAL_RX_MASK(serial_rx_cons);
388 len = serial_rx_prod - serial_rx_cons;
389 if ( (idx + len) > SERIAL_RX_SIZE )
390 len = SERIAL_RX_SIZE - idx;
391 if ( (rc + len) > count )
392 len = count - rc;
393 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
394 {
395 rc = -EFAULT;
396 break;
397 }
398 rc += len;
399 serial_rx_cons += len;
400 }
401 break;
402 default:
403 rc = -ENOSYS;
404 break;
405 }
407 return rc;
408 }
411 /*
412 * *****************************************************
413 * *************** GENERIC CONSOLE I/O *****************
414 * *****************************************************
415 */
417 static void __putstr(const char *str)
418 {
419 int c;
421 ASSERT(spin_is_locked(&console_lock));
423 sercon_puts(str);
424 vga_puts(str);
426 while ( (c = *str++) != '\0' )
427 putchar_console_ring(c);
429 send_guest_global_virq(dom0, VIRQ_CON_RING);
430 }
432 static int printk_prefix_check(char *p, char **pp)
433 {
434 int loglvl = -1;
435 int upper_thresh = xenlog_upper_thresh;
436 int lower_thresh = xenlog_lower_thresh;
438 while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
439 {
440 switch ( p[1] )
441 {
442 case 'G':
443 upper_thresh = xenlog_guest_upper_thresh;
444 lower_thresh = xenlog_guest_lower_thresh;
445 if ( loglvl == -1 )
446 loglvl = XENLOG_GUEST_DEFAULT;
447 break;
448 case '0' ... '3':
449 loglvl = p[1] - '0';
450 break;
451 }
452 p += 3;
453 }
455 if ( loglvl == -1 )
456 loglvl = XENLOG_DEFAULT;
458 *pp = p;
460 return ((atomic_read(&print_everything) != 0) ||
461 (loglvl < lower_thresh) ||
462 ((loglvl < upper_thresh) && printk_ratelimit()));
463 }
465 static void printk_start_of_line(void)
466 {
467 struct tm tm;
468 char tstr[32];
470 __putstr("(XEN) ");
472 if ( !opt_console_timestamps )
473 return;
475 tm = wallclock_time();
476 if ( tm.tm_mday == 0 )
477 return;
479 snprintf(tstr, sizeof(tstr), "[%04u-%02u-%02u %02u:%02u:%02u] ",
480 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
481 tm.tm_hour, tm.tm_min, tm.tm_sec);
482 __putstr(tstr);
483 }
485 void printk(const char *fmt, ...)
486 {
487 static char buf[1024];
488 static int start_of_line = 1, do_print;
490 va_list args;
491 char *p, *q;
492 unsigned long flags;
494 /* console_lock can be acquired recursively from __printk_ratelimit(). */
495 local_irq_save(flags);
496 spin_lock_recursive(&console_lock);
498 va_start(args, fmt);
499 (void)vsnprintf(buf, sizeof(buf), fmt, args);
500 va_end(args);
502 p = buf;
504 while ( (q = strchr(p, '\n')) != NULL )
505 {
506 *q = '\0';
507 if ( start_of_line )
508 do_print = printk_prefix_check(p, &p);
509 if ( do_print )
510 {
511 if ( start_of_line )
512 printk_start_of_line();
513 __putstr(p);
514 __putstr("\n");
515 }
516 start_of_line = 1;
517 p = q + 1;
518 }
520 if ( *p != '\0' )
521 {
522 if ( start_of_line )
523 do_print = printk_prefix_check(p, &p);
524 if ( do_print )
525 {
526 if ( start_of_line )
527 printk_start_of_line();
528 __putstr(p);
529 }
530 start_of_line = 0;
531 }
533 spin_unlock_recursive(&console_lock);
534 local_irq_restore(flags);
535 }
537 void __init init_console(void)
538 {
539 char *p;
541 /* Where should console output go? */
542 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
543 {
544 if ( *p == ',' )
545 p++;
546 if ( strncmp(p, "com", 3) == 0 )
547 sercon_handle = serial_parse_handle(p);
548 else if ( strncmp(p, "vga", 3) == 0 )
549 vga_init();
550 }
552 serial_set_rx_handler(sercon_handle, serial_rx);
554 /* HELLO WORLD --- start-of-day banner text. */
555 spin_lock(&console_lock);
556 __putstr(xen_banner());
557 spin_unlock(&console_lock);
558 printk("Xen version %d.%d%s (%s@%s) (%s) %s\n",
559 xen_major_version(), xen_minor_version(), xen_extra_version(),
560 xen_compile_by(), xen_compile_domain(),
561 xen_compiler(), xen_compile_date());
562 printk("Latest ChangeSet: %s\n", xen_changeset());
564 if ( opt_sync_console )
565 {
566 serial_start_sync(sercon_handle);
567 add_taint(TAINT_SYNC_CONSOLE);
568 printk("Console output is synchronous.\n");
569 }
570 }
572 void __init console_endboot(void)
573 {
574 int i, j;
576 printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
577 if ( xenlog_upper_thresh != xenlog_lower_thresh )
578 printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
579 printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
580 if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
581 printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
582 printk("\n");
584 if ( opt_sync_console )
585 {
586 printk("**********************************************\n");
587 printk("******* WARNING: CONSOLE OUTPUT IS SYNCHRONOUS\n");
588 printk("******* This option is intended to aid debugging "
589 "of Xen by ensuring\n");
590 printk("******* that all output is synchronously delivered "
591 "on the serial line.\n");
592 printk("******* However it can introduce SIGNIFICANT latencies "
593 "and affect\n");
594 printk("******* timekeeping. It is NOT recommended for "
595 "production use!\n");
596 printk("**********************************************\n");
597 for ( i = 0; i < 3; i++ )
598 {
599 printk("%d... ", 3-i);
600 for ( j = 0; j < 100; j++ )
601 {
602 process_pending_timers();
603 mdelay(10);
604 }
605 }
606 printk("\n");
607 }
609 vga_endboot();
611 /*
612 * If user specifies so, we fool the switch routine to redirect input
613 * straight back to Xen. I use this convoluted method so we still print
614 * a useful 'how to switch' message.
615 */
616 if ( opt_conswitch[1] == 'x' )
617 xen_rx = !xen_rx;
619 /* Serial input is directed to DOM0 by default. */
620 switch_serial_input();
621 }
623 int console_has(const char *device)
624 {
625 char *p;
627 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
628 {
629 if ( *p == ',' )
630 p++;
631 if ( strncmp(p, device, strlen(device)) == 0 )
632 return 1;
633 }
635 return 0;
636 }
638 void console_start_log_everything(void)
639 {
640 serial_start_log_everything(sercon_handle);
641 atomic_inc(&print_everything);
642 }
644 void console_end_log_everything(void)
645 {
646 serial_end_log_everything(sercon_handle);
647 atomic_dec(&print_everything);
648 }
650 void console_force_unlock(void)
651 {
652 spin_lock_init(&console_lock);
653 serial_force_unlock(sercon_handle);
654 console_start_sync();
655 }
657 void console_force_lock(void)
658 {
659 spin_lock(&console_lock);
660 }
662 void console_start_sync(void)
663 {
664 atomic_inc(&print_everything);
665 serial_start_sync(sercon_handle);
666 }
668 void console_end_sync(void)
669 {
670 serial_end_sync(sercon_handle);
671 atomic_dec(&print_everything);
672 }
674 void console_putc(char c)
675 {
676 serial_putc(sercon_handle, c);
677 }
679 int console_getc(void)
680 {
681 return serial_getc(sercon_handle);
682 }
684 /*
685 * printk rate limiting, lifted from Linux.
686 *
687 * This enforces a rate limit: not more than one kernel message
688 * every printk_ratelimit_ms (millisecs).
689 */
690 int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
691 {
692 static DEFINE_SPINLOCK(ratelimit_lock);
693 static unsigned long toks = 10 * 5 * 1000;
694 static unsigned long last_msg;
695 static int missed;
696 unsigned long flags;
697 unsigned long long now = NOW(); /* ns */
698 unsigned long ms;
700 do_div(now, 1000000);
701 ms = (unsigned long)now;
703 spin_lock_irqsave(&ratelimit_lock, flags);
704 toks += ms - last_msg;
705 last_msg = ms;
706 if ( toks > (ratelimit_burst * ratelimit_ms))
707 toks = ratelimit_burst * ratelimit_ms;
708 if ( toks >= ratelimit_ms )
709 {
710 int lost = missed;
711 missed = 0;
712 toks -= ratelimit_ms;
713 spin_unlock(&ratelimit_lock);
714 if ( lost )
715 {
716 char lost_str[8];
717 snprintf(lost_str, sizeof(lost_str), "%d", lost);
718 /* console_lock may already be acquired by printk(). */
719 spin_lock_recursive(&console_lock);
720 printk_start_of_line();
721 __putstr("printk: ");
722 __putstr(lost_str);
723 __putstr(" messages suppressed.\n");
724 spin_unlock_recursive(&console_lock);
725 }
726 local_irq_restore(flags);
727 return 1;
728 }
729 missed++;
730 spin_unlock_irqrestore(&ratelimit_lock, flags);
731 return 0;
732 }
734 /* minimum time in ms between messages */
735 int printk_ratelimit_ms = 5 * 1000;
737 /* number of messages we send before ratelimiting */
738 int printk_ratelimit_burst = 10;
740 int printk_ratelimit(void)
741 {
742 return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
743 }
745 /*
746 * **************************************************************
747 * *************** Serial console ring buffer *******************
748 * **************************************************************
749 */
751 #ifdef DEBUG_TRACE_DUMP
753 /* Send output direct to console, or buffer it? */
754 static volatile int debugtrace_send_to_console;
756 static char *debugtrace_buf; /* Debug-trace buffer */
757 static unsigned int debugtrace_prd; /* Producer index */
758 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
759 static unsigned int debugtrace_used;
760 static DEFINE_SPINLOCK(debugtrace_lock);
761 integer_param("debugtrace", debugtrace_kilobytes);
763 static void debugtrace_dump_worker(void)
764 {
765 if ( (debugtrace_bytes == 0) || !debugtrace_used )
766 return;
768 printk("debugtrace_dump() starting\n");
770 /* Print oldest portion of the ring. */
771 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
772 sercon_puts(&debugtrace_buf[debugtrace_prd]);
774 /* Print youngest portion of the ring. */
775 debugtrace_buf[debugtrace_prd] = '\0';
776 sercon_puts(&debugtrace_buf[0]);
778 memset(debugtrace_buf, '\0', debugtrace_bytes);
780 printk("debugtrace_dump() finished\n");
781 }
783 static void debugtrace_toggle(void)
784 {
785 unsigned long flags;
787 watchdog_disable();
788 spin_lock_irqsave(&debugtrace_lock, flags);
790 /*
791 * Dump the buffer *before* toggling, in case the act of dumping the
792 * buffer itself causes more printk() invocations.
793 */
794 printk("debugtrace_printk now writing to %s.\n",
795 !debugtrace_send_to_console ? "console": "buffer");
796 if ( !debugtrace_send_to_console )
797 debugtrace_dump_worker();
799 debugtrace_send_to_console = !debugtrace_send_to_console;
801 spin_unlock_irqrestore(&debugtrace_lock, flags);
802 watchdog_enable();
804 }
806 void debugtrace_dump(void)
807 {
808 unsigned long flags;
810 watchdog_disable();
811 spin_lock_irqsave(&debugtrace_lock, flags);
813 debugtrace_dump_worker();
815 spin_unlock_irqrestore(&debugtrace_lock, flags);
816 watchdog_enable();
817 }
819 void debugtrace_printk(const char *fmt, ...)
820 {
821 static char buf[1024];
822 static u32 count;
824 va_list args;
825 char *p;
826 unsigned long flags;
828 if ( debugtrace_bytes == 0 )
829 return;
831 debugtrace_used = 1;
833 spin_lock_irqsave(&debugtrace_lock, flags);
835 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
837 snprintf(buf, sizeof(buf), "%u ", ++count);
839 va_start(args, fmt);
840 (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
841 va_end(args);
843 if ( debugtrace_send_to_console )
844 {
845 serial_puts(sercon_handle, buf);
846 }
847 else
848 {
849 for ( p = buf; *p != '\0'; p++ )
850 {
851 debugtrace_buf[debugtrace_prd++] = *p;
852 /* Always leave a nul byte at the end of the buffer. */
853 if ( debugtrace_prd == (debugtrace_bytes - 1) )
854 debugtrace_prd = 0;
855 }
856 }
858 spin_unlock_irqrestore(&debugtrace_lock, flags);
859 }
861 static void debugtrace_key(unsigned char key)
862 {
863 debugtrace_toggle();
864 }
866 static int __init debugtrace_init(void)
867 {
868 int order;
869 unsigned int kbytes, bytes;
871 /* Round size down to next power of two. */
872 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
873 debugtrace_kilobytes = kbytes;
875 bytes = debugtrace_kilobytes << 10;
876 if ( bytes == 0 )
877 return 0;
879 order = get_order_from_bytes(bytes);
880 debugtrace_buf = alloc_xenheap_pages(order);
881 ASSERT(debugtrace_buf != NULL);
883 memset(debugtrace_buf, '\0', bytes);
885 debugtrace_bytes = bytes;
887 register_keyhandler(
888 'T', debugtrace_key, "toggle debugtrace to console/buffer");
890 return 0;
891 }
892 __initcall(debugtrace_init);
894 #endif /* !NDEBUG */
897 /*
898 * **************************************************************
899 * *************** Debugging/tracing/error-report ***************
900 * **************************************************************
901 */
903 void panic(const char *fmt, ...)
904 {
905 va_list args;
906 unsigned long flags;
907 static DEFINE_SPINLOCK(lock);
908 static char buf[128];
910 debugtrace_dump();
912 /* Protects buf[] and ensure multi-line message prints atomically. */
913 spin_lock_irqsave(&lock, flags);
915 va_start(args, fmt);
916 (void)vsnprintf(buf, sizeof(buf), fmt, args);
917 va_end(args);
919 console_start_sync();
920 printk("\n****************************************\n");
921 printk("Panic on CPU %d:\n", smp_processor_id());
922 printk(buf);
923 printk("****************************************\n\n");
924 if ( opt_noreboot )
925 printk("Manual reset required ('noreboot' specified)\n");
926 else
927 printk("Reboot in five seconds...\n");
929 spin_unlock_irqrestore(&lock, flags);
931 debugger_trap_immediate();
933 kexec_crash();
935 if ( opt_noreboot )
936 {
937 machine_halt();
938 }
939 else
940 {
941 watchdog_disable();
942 mdelay(5000);
943 machine_restart();
944 }
945 }
947 void __bug(char *file, int line)
948 {
949 console_start_sync();
950 printk("Xen BUG at %s:%d\n", file, line);
951 dump_execution_state();
952 panic("Xen BUG at %s:%d\n", file, line);
953 for ( ; ; ) ;
954 }
956 void __warn(char *file, int line)
957 {
958 printk("Xen WARN at %s:%d\n", file, line);
959 dump_execution_state();
960 }
963 /*
964 * **************************************************************
965 * ****************** Console suspend/resume ********************
966 * **************************************************************
967 */
969 static void suspend_steal_fn(const char *str) { }
970 static int suspend_steal_id;
972 int console_suspend(void)
973 {
974 suspend_steal_id = console_steal(sercon_handle, suspend_steal_fn);
975 serial_suspend();
976 return 0;
977 }
979 int console_resume(void)
980 {
981 serial_resume();
982 console_giveback(suspend_steal_id);
983 return 0;
984 }
986 /*
987 * Local variables:
988 * mode: C
989 * c-set-style: "BSD"
990 * c-basic-offset: 4
991 * tab-width: 4
992 * indent-tabs-mode: nil
993 * End:
994 */