ia64/xen-unstable

view xen/drivers/char/console.c @ 14414:e9ef0808c09f

Add boot option to allow console I/O to be placed into ring buffer

This option allows console I/O to be placed into the hypervisor
console ring buffer. When enabled, all output to the console
device will be reflected in the ring buffer. When disabled (the
default), only hypervisor output is available from the ring buffer.

Signed-off-by: Ben Thomas <ben@virtualiron.com>
author kfraser@localhost.localdomain
date Thu Mar 15 10:33:32 2007 +0000 (2007-03-15)
parents 38513d22d234
children 070cf119a7ec
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>
36 /* console: comma-separated list of console outputs. */
37 static char opt_console[30] = OPT_CONSOLE_STR;
38 string_param("console", opt_console);
40 /* conswitch: a character pair controlling console switching. */
41 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
42 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
43 /* boots. Any other value, or omitting the char, enables auto-switch */
44 static unsigned char opt_conswitch[5] = "a";
45 string_param("conswitch", opt_conswitch);
47 /* sync_console: force synchronous console output (useful for debugging). */
48 static int opt_sync_console;
49 boolean_param("sync_console", opt_sync_console);
51 /* console_to_ring: send guest (incl. dom 0) console data to console ring. */
52 static int opt_console_to_ring;
53 boolean_param("console_to_ring", opt_console_to_ring);
55 #define CONRING_SIZE 16384
56 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
57 static char conring[CONRING_SIZE];
58 static unsigned int conringc, conringp;
60 static char printk_prefix[16] = "";
62 static int sercon_handle = -1;
64 static DEFINE_SPINLOCK(console_lock);
66 /*
67 * To control the amount of printing, thresholds are added.
68 * These thresholds correspond to the XENLOG logging levels.
69 * There's an upper and lower threshold for non-guest messages and for
70 * guest-provoked messages. This works as follows, for a given log level L:
71 *
72 * L < lower_threshold : always logged
73 * lower_threshold <= L < upper_threshold : rate-limited logging
74 * upper_threshold <= L : never logged
75 *
76 * Note, in the above algorithm, to disable rate limiting simply make
77 * the lower threshold equal to the upper.
78 */
79 #ifdef NDEBUG
80 #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
81 #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
82 #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
83 #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
84 #else
85 #define XENLOG_UPPER_THRESHOLD 4 /* Do not discard anything */
86 #define XENLOG_LOWER_THRESHOLD 4 /* Print everything */
87 #define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything */
88 #define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything */
89 #endif
90 /*
91 * The XENLOG_DEFAULT is the default given to printks that
92 * do not have any print level associated with them.
93 */
94 #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
95 #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
97 static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
98 static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
99 static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
100 static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
102 static void parse_loglvl(char *s);
103 static void parse_guest_loglvl(char *s);
105 /*
106 * <lvl> := none|error|warning|info|debug|all
107 * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
108 * <lvl_print_always>: log level which is always printed
109 * <lvl_print_rlimit>: log level which is rate-limit printed
110 * Similar definitions for guest_loglvl, but applies to guest tracing.
111 * Defaults: loglvl=warning ; guest_loglvl=none/warning
112 */
113 custom_param("loglvl", parse_loglvl);
114 custom_param("guest_loglvl", parse_guest_loglvl);
116 static atomic_t print_everything = ATOMIC_INIT(0);
118 #define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
119 if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
120 *(ps) = (s) + strlen(lvlstr); \
121 return (lvlnum); \
122 }
124 static int __parse_loglvl(char *s, char **ps)
125 {
126 ___parse_loglvl(s, ps, "none", 0);
127 ___parse_loglvl(s, ps, "error", 1);
128 ___parse_loglvl(s, ps, "warning", 2);
129 ___parse_loglvl(s, ps, "info", 3);
130 ___parse_loglvl(s, ps, "debug", 4);
131 ___parse_loglvl(s, ps, "all", 4);
132 return 2; /* sane fallback */
133 }
135 static void _parse_loglvl(char *s, int *lower, int *upper)
136 {
137 *lower = *upper = __parse_loglvl(s, &s);
138 if ( *s == '/' )
139 *upper = __parse_loglvl(s+1, &s);
140 if ( *upper < *lower )
141 *upper = *lower;
142 }
144 static void parse_loglvl(char *s)
145 {
146 _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
147 }
149 static void parse_guest_loglvl(char *s)
150 {
151 _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
152 }
154 static char *loglvl_str(int lvl)
155 {
156 switch ( lvl )
157 {
158 case 0: return "Nothing";
159 case 1: return "Errors";
160 case 2: return "Errors and warnings";
161 case 3: return "Errors, warnings and info";
162 case 4: return "All";
163 }
164 return "???";
165 }
167 /*
168 * ********************************************************
169 * *************** ACCESS TO CONSOLE RING *****************
170 * ********************************************************
171 */
173 static void putchar_console_ring(int c)
174 {
175 conring[CONRING_IDX_MASK(conringp++)] = c;
176 if ( (conringp - conringc) > CONRING_SIZE )
177 conringc = conringp - CONRING_SIZE;
178 }
180 long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
181 {
182 unsigned int idx, len, max, sofar, c;
183 unsigned long flags;
185 max = *pcount;
186 sofar = 0;
188 c = conringc;
189 while ( (c != conringp) && (sofar < max) )
190 {
191 idx = CONRING_IDX_MASK(c);
192 len = conringp - c;
193 if ( (idx + len) > CONRING_SIZE )
194 len = CONRING_SIZE - idx;
195 if ( (sofar + len) > max )
196 len = max - sofar;
197 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
198 return -EFAULT;
199 sofar += len;
200 c += len;
201 }
203 if ( clear )
204 {
205 spin_lock_irqsave(&console_lock, flags);
206 if ( (conringp - c) > CONRING_SIZE )
207 conringc = conringp - CONRING_SIZE;
208 else
209 conringc = c;
210 spin_unlock_irqrestore(&console_lock, flags);
211 }
213 *pcount = sofar;
214 return 0;
215 }
218 /*
219 * *******************************************************
220 * *************** ACCESS TO SERIAL LINE *****************
221 * *******************************************************
222 */
224 /* Characters received over the serial line are buffered for domain 0. */
225 #define SERIAL_RX_SIZE 128
226 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
227 static char serial_rx_ring[SERIAL_RX_SIZE];
228 static unsigned int serial_rx_cons, serial_rx_prod;
230 static void (*serial_steal_fn)(const char *);
232 int console_steal(int handle, void (*fn)(const char *))
233 {
234 if ( (handle == -1) || (handle != sercon_handle) )
235 return 0;
237 if ( serial_steal_fn != NULL )
238 return -EBUSY;
240 serial_steal_fn = fn;
241 return 1;
242 }
244 void console_giveback(int id)
245 {
246 if ( id == 1 )
247 serial_steal_fn = NULL;
248 }
250 static void sercon_puts(const char *s)
251 {
252 if ( serial_steal_fn != NULL )
253 (*serial_steal_fn)(s);
254 else
255 serial_puts(sercon_handle, s);
256 }
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) && (dom0 != NULL) )
267 {
268 printk("*** Serial input -> %s "
269 "(type 'CTRL-%c' three times to switch input to %s).\n",
270 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
271 }
272 }
274 static void __serial_rx(char c, struct cpu_user_regs *regs)
275 {
276 if ( xen_rx )
277 return handle_keypress(c, regs);
279 /* Deliver input to guest buffer, unless it is already full. */
280 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
281 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
282 /* Always notify the guest: prevents receive path from getting stuck. */
283 send_guest_global_virq(dom0, VIRQ_CONSOLE);
284 }
286 static void serial_rx(char c, struct cpu_user_regs *regs)
287 {
288 static int switch_code_count = 0;
290 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
291 {
292 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
293 if ( ++switch_code_count == 3 )
294 {
295 switch_serial_input();
296 switch_code_count = 0;
297 return;
298 }
299 }
300 else
301 {
302 switch_code_count = 0;
303 }
305 /* Finally process the just-received character. */
306 __serial_rx(c, regs);
307 }
309 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
310 {
311 char kbuf[128], *kptr;
312 int kcount;
314 while ( count > 0 )
315 {
316 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
317 {
318 if ( hypercall_preempt_check() )
319 break;
320 cpu_relax();
321 }
323 if ( hypercall_preempt_check() )
324 return hypercall_create_continuation(
325 __HYPERVISOR_console_io, "iih",
326 CONSOLEIO_write, count, buffer);
328 kcount = min_t(int, count, sizeof(kbuf)-1);
329 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
330 return -EFAULT;
331 kbuf[kcount] = '\0';
333 sercon_puts(kbuf);
335 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
336 {
337 vga_putchar(*kptr);
338 if ( opt_console_to_ring )
339 putchar_console_ring(*kptr);
340 }
342 if ( opt_console_to_ring )
343 send_guest_global_virq(dom0, VIRQ_CON_RING);
345 guest_handle_add_offset(buffer, kcount);
346 count -= kcount;
347 }
349 return 0;
350 }
352 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
353 {
354 long rc;
355 unsigned int idx, len;
357 #ifndef VERBOSE
358 /* Only domain 0 may access the emergency console. */
359 if ( current->domain->domain_id != 0 )
360 return -EPERM;
361 #endif
363 switch ( cmd )
364 {
365 case CONSOLEIO_write:
366 rc = guest_console_write(buffer, count);
367 break;
368 case CONSOLEIO_read:
369 rc = 0;
370 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
371 {
372 idx = SERIAL_RX_MASK(serial_rx_cons);
373 len = serial_rx_prod - serial_rx_cons;
374 if ( (idx + len) > SERIAL_RX_SIZE )
375 len = SERIAL_RX_SIZE - idx;
376 if ( (rc + len) > count )
377 len = count - rc;
378 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
379 {
380 rc = -EFAULT;
381 break;
382 }
383 rc += len;
384 serial_rx_cons += len;
385 }
386 break;
387 default:
388 rc = -ENOSYS;
389 break;
390 }
392 return rc;
393 }
396 /*
397 * *****************************************************
398 * *************** GENERIC CONSOLE I/O *****************
399 * *****************************************************
400 */
402 static void __putstr(const char *str)
403 {
404 int c;
406 sercon_puts(str);
408 while ( (c = *str++) != '\0' )
409 {
410 vga_putchar(c);
411 putchar_console_ring(c);
412 }
414 send_guest_global_virq(dom0, VIRQ_CON_RING);
415 }
417 static int printk_prefix_check(char *p, char **pp)
418 {
419 int loglvl = -1;
420 int upper_thresh = xenlog_upper_thresh;
421 int lower_thresh = xenlog_lower_thresh;
423 while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
424 {
425 switch ( p[1] )
426 {
427 case 'G':
428 upper_thresh = xenlog_guest_upper_thresh;
429 lower_thresh = xenlog_guest_lower_thresh;
430 if ( loglvl == -1 )
431 loglvl = XENLOG_GUEST_DEFAULT;
432 break;
433 case '0' ... '3':
434 loglvl = p[1] - '0';
435 break;
436 }
437 p += 3;
438 }
440 if ( loglvl == -1 )
441 loglvl = XENLOG_DEFAULT;
443 *pp = p;
445 return ((atomic_read(&print_everything) != 0) ||
446 (loglvl < lower_thresh) ||
447 ((loglvl < upper_thresh) && printk_ratelimit()));
448 }
450 void printk(const char *fmt, ...)
451 {
452 static char buf[1024];
453 static int start_of_line = 1, do_print;
455 va_list args;
456 char *p, *q;
457 unsigned long flags;
459 /* console_lock can be acquired recursively from __printk_ratelimit(). */
460 local_irq_save(flags);
461 spin_lock_recursive(&console_lock);
463 va_start(args, fmt);
464 (void)vsnprintf(buf, sizeof(buf), fmt, args);
465 va_end(args);
467 p = buf;
469 while ( (q = strchr(p, '\n')) != NULL )
470 {
471 *q = '\0';
472 if ( start_of_line )
473 do_print = printk_prefix_check(p, &p);
474 if ( do_print )
475 {
476 if ( start_of_line )
477 __putstr(printk_prefix);
478 __putstr(p);
479 __putstr("\n");
480 }
481 start_of_line = 1;
482 p = q + 1;
483 }
485 if ( *p != '\0' )
486 {
487 if ( start_of_line )
488 do_print = printk_prefix_check(p, &p);
489 if ( do_print )
490 {
491 if ( start_of_line )
492 __putstr(printk_prefix);
493 __putstr(p);
494 }
495 start_of_line = 0;
496 }
498 spin_unlock_recursive(&console_lock);
499 local_irq_restore(flags);
500 }
502 void set_printk_prefix(const char *prefix)
503 {
504 safe_strcpy(printk_prefix, prefix);
505 }
507 void init_console(void)
508 {
509 char *p;
511 /* Where should console output go? */
512 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
513 {
514 if ( *p == ',' )
515 p++;
516 if ( strncmp(p, "com", 3) == 0 )
517 sercon_handle = serial_parse_handle(p);
518 else if ( strncmp(p, "vga", 3) == 0 )
519 vga_init();
520 }
522 serial_set_rx_handler(sercon_handle, serial_rx);
524 /* HELLO WORLD --- start-of-day banner text. */
525 printk(xen_banner());
526 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
527 printk(" University of Cambridge Computer Laboratory\n\n");
528 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
529 xen_major_version(), xen_minor_version(), xen_extra_version(),
530 xen_compile_by(), xen_compile_domain(),
531 xen_compiler(), xen_compile_date());
532 printk(" Latest ChangeSet: %s\n\n", xen_changeset());
533 set_printk_prefix("(XEN) ");
535 if ( opt_sync_console )
536 {
537 serial_start_sync(sercon_handle);
538 add_taint(TAINT_SYNC_CONSOLE);
539 printk("Console output is synchronous.\n");
540 }
541 }
543 void console_endboot(void)
544 {
545 int i, j;
547 printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
548 if ( xenlog_upper_thresh != xenlog_lower_thresh )
549 printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
550 printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
551 if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
552 printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
553 printk("\n");
555 if ( opt_sync_console )
556 {
557 printk("**********************************************\n");
558 printk("******* WARNING: CONSOLE OUTPUT IS SYNCHRONOUS\n");
559 printk("******* This option is intended to aid debugging "
560 "of Xen by ensuring\n");
561 printk("******* that all output is synchronously delivered "
562 "on the serial line.\n");
563 printk("******* However it can introduce SIGNIFICANT latencies "
564 "and affect\n");
565 printk("******* timekeeping. It is NOT recommended for "
566 "production use!\n");
567 printk("**********************************************\n");
568 for ( i = 0; i < 3; i++ )
569 {
570 printk("%d... ", 3-i);
571 for ( j = 0; j < 100; j++ )
572 {
573 process_pending_timers();
574 mdelay(10);
575 }
576 }
577 printk("\n");
578 }
580 vga_endboot();
582 /*
583 * If user specifies so, we fool the switch routine to redirect input
584 * straight back to Xen. I use this convoluted method so we still print
585 * a useful 'how to switch' message.
586 */
587 if ( opt_conswitch[1] == 'x' )
588 xen_rx = !xen_rx;
590 /* Serial input is directed to DOM0 by default. */
591 switch_serial_input();
592 }
594 void console_start_log_everything(void)
595 {
596 atomic_inc(&print_everything);
597 }
599 void console_end_log_everything(void)
600 {
601 atomic_dec(&print_everything);
602 }
604 void console_force_unlock(void)
605 {
606 spin_lock_init(&console_lock);
607 serial_force_unlock(sercon_handle);
608 console_start_sync();
609 }
611 void console_force_lock(void)
612 {
613 spin_lock(&console_lock);
614 }
616 void console_start_sync(void)
617 {
618 console_start_log_everything();
619 serial_start_sync(sercon_handle);
620 }
622 void console_end_sync(void)
623 {
624 serial_end_sync(sercon_handle);
625 console_end_log_everything();
626 }
628 void console_putc(char c)
629 {
630 serial_putc(sercon_handle, c);
631 }
633 int console_getc(void)
634 {
635 return serial_getc(sercon_handle);
636 }
638 /*
639 * printk rate limiting, lifted from Linux.
640 *
641 * This enforces a rate limit: not more than one kernel message
642 * every printk_ratelimit_ms (millisecs).
643 */
644 int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
645 {
646 static DEFINE_SPINLOCK(ratelimit_lock);
647 static unsigned long toks = 10 * 5 * 1000;
648 static unsigned long last_msg;
649 static int missed;
650 unsigned long flags;
651 unsigned long long now = NOW(); /* ns */
652 unsigned long ms;
654 do_div(now, 1000000);
655 ms = (unsigned long)now;
657 spin_lock_irqsave(&ratelimit_lock, flags);
658 toks += ms - last_msg;
659 last_msg = ms;
660 if ( toks > (ratelimit_burst * ratelimit_ms))
661 toks = ratelimit_burst * ratelimit_ms;
662 if ( toks >= ratelimit_ms )
663 {
664 int lost = missed;
665 missed = 0;
666 toks -= ratelimit_ms;
667 spin_unlock(&ratelimit_lock);
668 if ( lost )
669 {
670 char lost_str[8];
671 snprintf(lost_str, sizeof(lost_str), "%d", lost);
672 /* console_lock may already be acquired by printk(). */
673 spin_lock_recursive(&console_lock);
674 __putstr(printk_prefix);
675 __putstr("printk: ");
676 __putstr(lost_str);
677 __putstr(" messages suppressed.\n");
678 spin_unlock_recursive(&console_lock);
679 }
680 local_irq_restore(flags);
681 return 1;
682 }
683 missed++;
684 spin_unlock_irqrestore(&ratelimit_lock, flags);
685 return 0;
686 }
688 /* minimum time in ms between messages */
689 int printk_ratelimit_ms = 5 * 1000;
691 /* number of messages we send before ratelimiting */
692 int printk_ratelimit_burst = 10;
694 int printk_ratelimit(void)
695 {
696 return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
697 }
699 /*
700 * **************************************************************
701 * *************** Serial console ring buffer *******************
702 * **************************************************************
703 */
705 #ifdef DEBUG_TRACE_DUMP
707 /* Send output direct to console, or buffer it? */
708 static volatile int debugtrace_send_to_console;
710 static char *debugtrace_buf; /* Debug-trace buffer */
711 static unsigned int debugtrace_prd; /* Producer index */
712 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
713 static unsigned int debugtrace_used;
714 static DEFINE_SPINLOCK(debugtrace_lock);
715 integer_param("debugtrace", debugtrace_kilobytes);
717 static void debugtrace_dump_worker(void)
718 {
719 if ( (debugtrace_bytes == 0) || !debugtrace_used )
720 return;
722 printk("debugtrace_dump() starting\n");
724 /* Print oldest portion of the ring. */
725 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
726 sercon_puts(&debugtrace_buf[debugtrace_prd]);
728 /* Print youngest portion of the ring. */
729 debugtrace_buf[debugtrace_prd] = '\0';
730 sercon_puts(&debugtrace_buf[0]);
732 memset(debugtrace_buf, '\0', debugtrace_bytes);
734 printk("debugtrace_dump() finished\n");
735 }
737 static void debugtrace_toggle(void)
738 {
739 unsigned long flags;
741 watchdog_disable();
742 spin_lock_irqsave(&debugtrace_lock, flags);
744 /*
745 * Dump the buffer *before* toggling, in case the act of dumping the
746 * buffer itself causes more printk() invocations.
747 */
748 printk("debugtrace_printk now writing to %s.\n",
749 !debugtrace_send_to_console ? "console": "buffer");
750 if ( !debugtrace_send_to_console )
751 debugtrace_dump_worker();
753 debugtrace_send_to_console = !debugtrace_send_to_console;
755 spin_unlock_irqrestore(&debugtrace_lock, flags);
756 watchdog_enable();
758 }
760 void debugtrace_dump(void)
761 {
762 unsigned long flags;
764 watchdog_disable();
765 spin_lock_irqsave(&debugtrace_lock, flags);
767 debugtrace_dump_worker();
769 spin_unlock_irqrestore(&debugtrace_lock, flags);
770 watchdog_enable();
771 }
773 void debugtrace_printk(const char *fmt, ...)
774 {
775 static char buf[1024];
776 static u32 count;
778 va_list args;
779 char *p;
780 unsigned long flags;
782 if ( debugtrace_bytes == 0 )
783 return;
785 debugtrace_used = 1;
787 spin_lock_irqsave(&debugtrace_lock, flags);
789 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
791 snprintf(buf, sizeof(buf), "%u ", ++count);
793 va_start(args, fmt);
794 (void)vsnprintf(buf + strlen(buf), sizeof(buf), fmt, args);
795 va_end(args);
797 if ( debugtrace_send_to_console )
798 {
799 serial_puts(sercon_handle, buf);
800 }
801 else
802 {
803 for ( p = buf; *p != '\0'; p++ )
804 {
805 debugtrace_buf[debugtrace_prd++] = *p;
806 /* Always leave a nul byte at the end of the buffer. */
807 if ( debugtrace_prd == (debugtrace_bytes - 1) )
808 debugtrace_prd = 0;
809 }
810 }
812 spin_unlock_irqrestore(&debugtrace_lock, flags);
813 }
815 static void debugtrace_key(unsigned char key)
816 {
817 debugtrace_toggle();
818 }
820 static int __init debugtrace_init(void)
821 {
822 int order;
823 unsigned int kbytes, bytes;
825 /* Round size down to next power of two. */
826 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
827 debugtrace_kilobytes = kbytes;
829 bytes = debugtrace_kilobytes << 10;
830 if ( bytes == 0 )
831 return 0;
833 order = get_order_from_bytes(bytes);
834 debugtrace_buf = alloc_xenheap_pages(order);
835 ASSERT(debugtrace_buf != NULL);
837 memset(debugtrace_buf, '\0', bytes);
839 debugtrace_bytes = bytes;
841 register_keyhandler(
842 'T', debugtrace_key, "toggle debugtrace to console/buffer");
844 return 0;
845 }
846 __initcall(debugtrace_init);
848 #endif /* !NDEBUG */
852 /*
853 * **************************************************************
854 * *************** Debugging/tracing/error-report ***************
855 * **************************************************************
856 */
858 void panic(const char *fmt, ...)
859 {
860 va_list args;
861 char buf[128];
862 unsigned long flags;
863 static DEFINE_SPINLOCK(lock);
865 debugtrace_dump();
867 va_start(args, fmt);
868 (void)vsnprintf(buf, sizeof(buf), fmt, args);
869 va_end(args);
871 /* Spit out multiline message in one go. */
872 console_start_sync();
873 spin_lock_irqsave(&lock, flags);
874 printk("\n****************************************\n");
875 printk("Panic on CPU %d:\n", smp_processor_id());
876 printk(buf);
877 printk("****************************************\n\n");
878 if ( opt_noreboot )
879 printk("Manual reset required ('noreboot' specified)\n");
880 else
881 printk("Reboot in five seconds...\n");
882 spin_unlock_irqrestore(&lock, flags);
884 debugger_trap_immediate();
886 kexec_crash();
888 if ( opt_noreboot )
889 {
890 machine_halt();
891 }
892 else
893 {
894 watchdog_disable();
895 mdelay(5000);
896 machine_restart(NULL);
897 }
898 }
900 void __bug(char *file, int line)
901 {
902 console_start_sync();
903 printk("BUG at %s:%d\n", file, line);
904 dump_execution_state();
905 panic("BUG at %s:%d\n", file, line);
906 for ( ; ; ) ;
907 }
909 /*
910 * Local variables:
911 * mode: C
912 * c-set-style: "BSD"
913 * c-basic-offset: 4
914 * tab-width: 4
915 * indent-tabs-mode: nil
916 * End:
917 */