ia64/xen-unstable

view xen/drivers/char/console.c @ 12232:dd62270df2ad

[XEN] Add 'loglvl' and 'guest_loglvl' boot parameters.

<lvl> := none|error|warning|info|debug|all

loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
<lvl_print_always>: log level which is always printed
<lvl_print_rlimit>: log level which is rate-limit printed

'loglvl' applies to non-guest-related messages.
'guest_loglvl' applies to guest-related messages.

Defaults: loglvl=warning ; guest_loglvl=none/warning

Also clean up hvm_print_line().

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Thu Nov 02 22:24:20 2006 +0000 (2006-11-02)
parents 874cc0ff214d
children fac36a01c06e
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 <asm/current.h>
31 #include <asm/debugger.h>
32 #include <asm/io.h>
33 #include <asm/div64.h>
35 /* console: comma-separated list of console outputs. */
36 static char opt_console[30] = OPT_CONSOLE_STR;
37 string_param("console", opt_console);
39 /* conswitch: a character pair controlling console switching. */
40 /* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 */
41 /* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it */
42 /* boots. Any other value, or omitting the char, enables auto-switch */
43 static unsigned char opt_conswitch[5] = "a";
44 string_param("conswitch", opt_conswitch);
46 /* sync_console: force synchronous console output (useful for debugging). */
47 static int opt_sync_console;
48 boolean_param("sync_console", opt_sync_console);
50 #define CONRING_SIZE 16384
51 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
52 static char conring[CONRING_SIZE];
53 static unsigned int conringc, conringp;
55 static char printk_prefix[16] = "";
57 static int sercon_handle = -1;
59 static DEFINE_SPINLOCK(console_lock);
61 /*
62 * To control the amount of printing, thresholds are added.
63 * These thresholds correspond to the XENLOG logging levels.
64 * There's an upper and lower threshold for non-guest messages and for
65 * guest-provoked messages. This works as follows, for a given log level L:
66 *
67 * L < lower_threshold : always logged
68 * lower_threshold <= L < upper_threshold : rate-limited logging
69 * upper_threshold <= L : never logged
70 *
71 * Note, in the above algorithm, to disable rate limiting simply make
72 * the lower threshold equal to the upper.
73 */
74 #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
75 #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
76 #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
77 #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
78 /*
79 * The XENLOG_DEFAULT is the default given to printks that
80 * do not have any print level associated with them.
81 */
82 #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
83 #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
85 static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
86 static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
87 static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
88 static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
90 static void parse_loglvl(char *s);
91 static void parse_guest_loglvl(char *s);
93 /*
94 * <lvl> := none|error|warning|info|debug|all
95 * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
96 * <lvl_print_always>: log level which is always printed
97 * <lvl_print_rlimit>: log level which is rate-limit printed
98 * Similar definitions for guest_loglvl, but applies to guest tracing.
99 * Defaults: loglvl=warning ; guest_loglvl=none/warning
100 */
101 custom_param("loglvl", parse_loglvl);
102 custom_param("guest_loglvl", parse_guest_loglvl);
104 static int xen_startup = 1;
106 #define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
107 if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
108 *(ps) = (s) + strlen(lvlstr); \
109 return (lvlnum); \
110 }
112 static int __parse_loglvl(char *s, char **ps)
113 {
114 ___parse_loglvl(s, ps, "none", 0);
115 ___parse_loglvl(s, ps, "error", 1);
116 ___parse_loglvl(s, ps, "warning", 2);
117 ___parse_loglvl(s, ps, "info", 3);
118 ___parse_loglvl(s, ps, "debug", 4);
119 ___parse_loglvl(s, ps, "all", 4);
120 return 2; /* sane fallback */
121 }
123 static void _parse_loglvl(char *s, int *lower, int *upper)
124 {
125 *lower = *upper = __parse_loglvl(s, &s);
126 if ( *s == '/' )
127 *upper = __parse_loglvl(s+1, &s);
128 if ( *upper < *lower )
129 *upper = *lower;
130 }
132 static void parse_loglvl(char *s)
133 {
134 _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
135 }
137 static void parse_guest_loglvl(char *s)
138 {
139 _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
140 }
142 static char *loglvl_str(int lvl)
143 {
144 switch ( lvl )
145 {
146 case 0: return "Nothing";
147 case 1: return "Errors";
148 case 2: return "Errors and warnings";
149 case 3: return "Errors, warnings and info";
150 case 4: return "All";
151 }
152 return "???";
153 }
155 /*
156 * ********************************************************
157 * *************** ACCESS TO CONSOLE RING *****************
158 * ********************************************************
159 */
161 static void putchar_console_ring(int c)
162 {
163 conring[CONRING_IDX_MASK(conringp++)] = c;
164 if ( (conringp - conringc) > CONRING_SIZE )
165 conringc = conringp - CONRING_SIZE;
166 }
168 long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
169 {
170 unsigned int idx, len, max, sofar, c;
171 unsigned long flags;
173 max = *pcount;
174 sofar = 0;
176 c = conringc;
177 while ( (c != conringp) && (sofar < max) )
178 {
179 idx = CONRING_IDX_MASK(c);
180 len = conringp - c;
181 if ( (idx + len) > CONRING_SIZE )
182 len = CONRING_SIZE - idx;
183 if ( (sofar + len) > max )
184 len = max - sofar;
185 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
186 return -EFAULT;
187 sofar += len;
188 c += len;
189 }
191 if ( clear )
192 {
193 spin_lock_irqsave(&console_lock, flags);
194 if ( (conringp - c) > CONRING_SIZE )
195 conringc = conringp - CONRING_SIZE;
196 else
197 conringc = c;
198 spin_unlock_irqrestore(&console_lock, flags);
199 }
201 *pcount = sofar;
202 return 0;
203 }
206 /*
207 * *******************************************************
208 * *************** ACCESS TO SERIAL LINE *****************
209 * *******************************************************
210 */
212 /* Characters received over the serial line are buffered for domain 0. */
213 #define SERIAL_RX_SIZE 128
214 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
215 static char serial_rx_ring[SERIAL_RX_SIZE];
216 static unsigned int serial_rx_cons, serial_rx_prod;
218 static void (*serial_steal_fn)(const char *);
220 int console_steal(int handle, void (*fn)(const char *))
221 {
222 if ( (handle == -1) || (handle != sercon_handle) )
223 return 0;
225 if ( serial_steal_fn == NULL )
226 return -EBUSY;
228 serial_steal_fn = fn;
229 return 1;
230 }
232 void console_giveback(int id)
233 {
234 if ( id == 1 )
235 serial_steal_fn = NULL;
236 }
238 static void sercon_puts(const char *s)
239 {
240 if ( serial_steal_fn != NULL )
241 (*serial_steal_fn)(s);
242 else
243 serial_puts(sercon_handle, s);
244 }
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) && (dom0 != NULL) )
255 {
256 printk("*** Serial input -> %s "
257 "(type 'CTRL-%c' three times to switch input to %s).\n",
258 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
259 }
260 }
262 static void __serial_rx(char c, struct cpu_user_regs *regs)
263 {
264 if ( xen_rx )
265 return handle_keypress(c, regs);
267 /* Deliver input to guest buffer, unless it is already full. */
268 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
269 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
270 /* Always notify the guest: prevents receive path from getting stuck. */
271 send_guest_global_virq(dom0, VIRQ_CONSOLE);
272 }
274 static void serial_rx(char c, struct cpu_user_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 return;
286 }
287 }
288 else
289 {
290 switch_code_count = 0;
291 }
293 /* Finally process the just-received character. */
294 __serial_rx(c, regs);
295 }
297 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
298 {
299 char kbuf[128], *kptr;
300 int kcount;
302 while ( count > 0 )
303 {
304 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
305 {
306 if ( hypercall_preempt_check() )
307 break;
308 cpu_relax();
309 }
311 if ( hypercall_preempt_check() )
312 return hypercall_create_continuation(
313 __HYPERVISOR_console_io, "iih",
314 CONSOLEIO_write, count, buffer);
316 kcount = min_t(int, count, sizeof(kbuf)-1);
317 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
318 return -EFAULT;
319 kbuf[kcount] = '\0';
321 sercon_puts(kbuf);
323 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
324 vga_putchar(*kptr);
326 guest_handle_add_offset(buffer, kcount);
327 count -= kcount;
328 }
330 return 0;
331 }
333 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
334 {
335 long rc;
336 unsigned int idx, len;
338 #ifndef VERBOSE
339 /* Only domain 0 may access the emergency console. */
340 if ( current->domain->domain_id != 0 )
341 return -EPERM;
342 #endif
344 switch ( cmd )
345 {
346 case CONSOLEIO_write:
347 rc = guest_console_write(buffer, count);
348 break;
349 case CONSOLEIO_read:
350 rc = 0;
351 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
352 {
353 idx = SERIAL_RX_MASK(serial_rx_cons);
354 len = serial_rx_prod - serial_rx_cons;
355 if ( (idx + len) > SERIAL_RX_SIZE )
356 len = SERIAL_RX_SIZE - idx;
357 if ( (rc + len) > count )
358 len = count - rc;
359 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
360 {
361 rc = -EFAULT;
362 break;
363 }
364 rc += len;
365 serial_rx_cons += len;
366 }
367 break;
368 default:
369 rc = -ENOSYS;
370 break;
371 }
373 return rc;
374 }
377 /*
378 * *****************************************************
379 * *************** GENERIC CONSOLE I/O *****************
380 * *****************************************************
381 */
383 static inline void __putstr(const char *str)
384 {
385 int c;
387 sercon_puts(str);
389 while ( (c = *str++) != '\0' )
390 {
391 vga_putchar(c);
392 putchar_console_ring(c);
393 }
394 }
396 void printk(const char *fmt, ...)
397 {
398 static char buf[1024];
399 static int start_of_line = 1;
401 va_list args;
402 char *p, *q;
403 unsigned long flags;
404 int level = -1;
405 int upper_thresh = xenlog_upper_thresh;
406 int lower_thresh = xenlog_lower_thresh;
407 int print_regardless = xen_startup;
409 /* console_lock can be acquired recursively from __printk_ratelimit(). */
410 local_irq_save(flags);
411 spin_lock_recursive(&console_lock);
413 va_start(args, fmt);
414 (void)vsnprintf(buf, sizeof(buf), fmt, args);
415 va_end(args);
417 p = buf;
419 while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
420 {
421 switch ( p[1] )
422 {
423 case 'G':
424 upper_thresh = xenlog_guest_upper_thresh;
425 lower_thresh = xenlog_guest_lower_thresh;
426 if ( level == -1 )
427 level = XENLOG_GUEST_DEFAULT;
428 break;
429 case '0' ... '3':
430 level = p[1] - '0';
431 break;
432 }
433 p += 3;
434 }
436 if ( level == -1 )
437 level = XENLOG_DEFAULT;
439 if ( !print_regardless )
440 {
441 if ( level >= upper_thresh )
442 goto out;
443 if ( (level >= lower_thresh) && (!printk_ratelimit()) )
444 goto out;
445 }
447 while ( (q = strchr(p, '\n')) != NULL )
448 {
449 *q = '\0';
450 if ( start_of_line )
451 __putstr(printk_prefix);
452 __putstr(p);
453 __putstr("\n");
454 start_of_line = 1;
455 p = q + 1;
456 }
458 if ( *p != '\0' )
459 {
460 if ( start_of_line )
461 __putstr(printk_prefix);
462 __putstr(p);
463 start_of_line = 0;
464 }
466 out:
467 spin_unlock_recursive(&console_lock);
468 local_irq_restore(flags);
469 }
471 void set_printk_prefix(const char *prefix)
472 {
473 strcpy(printk_prefix, prefix);
474 }
476 void init_console(void)
477 {
478 char *p;
480 /* Where should console output go? */
481 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
482 {
483 if ( *p == ',' )
484 p++;
485 if ( strncmp(p, "com", 3) == 0 )
486 sercon_handle = serial_parse_handle(p);
487 else if ( strncmp(p, "vga", 3) == 0 )
488 vga_init();
489 }
491 serial_set_rx_handler(sercon_handle, serial_rx);
493 /* HELLO WORLD --- start-of-day banner text. */
494 printk(xen_banner());
495 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
496 printk(" University of Cambridge Computer Laboratory\n\n");
497 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
498 xen_major_version(), xen_minor_version(), xen_extra_version(),
499 xen_compile_by(), xen_compile_domain(),
500 xen_compiler(), xen_compile_date());
501 printk(" Latest ChangeSet: %s\n\n", xen_changeset());
502 set_printk_prefix("(XEN) ");
504 if ( opt_sync_console )
505 {
506 serial_start_sync(sercon_handle);
507 add_taint(TAINT_SYNC_CONSOLE);
508 printk("Console output is synchronous.\n");
509 }
510 }
512 void console_endboot(void)
513 {
514 int i, j;
516 printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
517 if ( xenlog_upper_thresh != xenlog_lower_thresh )
518 printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
519 printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
520 if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
521 printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
522 printk("\n");
524 if ( opt_sync_console )
525 {
526 printk("**********************************************\n");
527 printk("******* WARNING: CONSOLE OUTPUT IS SYCHRONOUS\n");
528 printk("******* This option is intended to aid debugging "
529 "of Xen by ensuring\n");
530 printk("******* that all output is synchronously delivered "
531 "on the serial line.\n");
532 printk("******* However it can introduce SIGNIFICANT latencies "
533 "and affect\n");
534 printk("******* timekeeping. It is NOT recommended for "
535 "production use!\n");
536 printk("**********************************************\n");
537 for ( i = 0; i < 3; i++ )
538 {
539 printk("%d... ", 3-i);
540 for ( j = 0; j < 100; j++ )
541 {
542 process_pending_timers();
543 mdelay(10);
544 }
545 }
546 printk("\n");
547 }
549 vga_endboot();
551 /*
552 * If user specifies so, we fool the switch routine to redirect input
553 * straight back to Xen. I use this convoluted method so we still print
554 * a useful 'how to switch' message.
555 */
556 if ( opt_conswitch[1] == 'x' )
557 xen_rx = !xen_rx;
559 /* Serial input is directed to DOM0 by default. */
560 switch_serial_input();
562 /* Now we implement the logging thresholds. */
563 xen_startup = 0;
564 }
566 void console_force_unlock(void)
567 {
568 spin_lock_init(&console_lock);
569 serial_force_unlock(sercon_handle);
570 console_start_sync();
571 }
573 void console_force_lock(void)
574 {
575 spin_lock(&console_lock);
576 }
578 void console_start_sync(void)
579 {
580 serial_start_sync(sercon_handle);
581 }
583 void console_end_sync(void)
584 {
585 serial_end_sync(sercon_handle);
586 }
588 void console_putc(char c)
589 {
590 serial_putc(sercon_handle, c);
591 }
593 int console_getc(void)
594 {
595 return serial_getc(sercon_handle);
596 }
598 /*
599 * printk rate limiting, lifted from Linux.
600 *
601 * This enforces a rate limit: not more than one kernel message
602 * every printk_ratelimit_ms (millisecs).
603 */
604 int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
605 {
606 static DEFINE_SPINLOCK(ratelimit_lock);
607 static unsigned long toks = 10 * 5 * 1000;
608 static unsigned long last_msg;
609 static int missed;
610 unsigned long flags;
611 unsigned long long now = NOW(); /* ns */
612 unsigned long ms;
614 do_div(now, 1000000);
615 ms = (unsigned long)now;
617 spin_lock_irqsave(&ratelimit_lock, flags);
618 toks += ms - last_msg;
619 last_msg = ms;
620 if ( toks > (ratelimit_burst * ratelimit_ms))
621 toks = ratelimit_burst * ratelimit_ms;
622 if ( toks >= ratelimit_ms )
623 {
624 int lost = missed;
625 missed = 0;
626 toks -= ratelimit_ms;
627 spin_unlock(&ratelimit_lock);
628 if ( lost )
629 {
630 char lost_str[8];
631 snprintf(lost_str, sizeof(lost_str), "%d", lost);
632 /* console_lock may already be acquired by printk(). */
633 spin_lock_recursive(&console_lock);
634 __putstr(printk_prefix);
635 __putstr("printk: ");
636 __putstr(lost_str);
637 __putstr(" messages suppressed.\n");
638 spin_unlock_recursive(&console_lock);
639 }
640 local_irq_restore(flags);
641 return 1;
642 }
643 missed++;
644 spin_unlock_irqrestore(&ratelimit_lock, flags);
645 return 0;
646 }
648 /* minimum time in ms between messages */
649 int printk_ratelimit_ms = 5 * 1000;
651 /* number of messages we send before ratelimiting */
652 int printk_ratelimit_burst = 10;
654 int printk_ratelimit(void)
655 {
656 return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
657 }
659 /*
660 * **************************************************************
661 * *************** Serial console ring buffer *******************
662 * **************************************************************
663 */
665 #ifdef DEBUG_TRACE_DUMP
667 /* Send output direct to console, or buffer it? */
668 static volatile int debugtrace_send_to_console;
670 static char *debugtrace_buf; /* Debug-trace buffer */
671 static unsigned int debugtrace_prd; /* Producer index */
672 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
673 static unsigned int debugtrace_used;
674 static DEFINE_SPINLOCK(debugtrace_lock);
675 integer_param("debugtrace", debugtrace_kilobytes);
677 static void debugtrace_dump_worker(void)
678 {
679 if ( (debugtrace_bytes == 0) || !debugtrace_used )
680 return;
682 printk("debugtrace_dump() starting\n");
684 /* Print oldest portion of the ring. */
685 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
686 sercon_puts(&debugtrace_buf[debugtrace_prd]);
688 /* Print youngest portion of the ring. */
689 debugtrace_buf[debugtrace_prd] = '\0';
690 sercon_puts(&debugtrace_buf[0]);
692 memset(debugtrace_buf, '\0', debugtrace_bytes);
694 printk("debugtrace_dump() finished\n");
695 }
697 static void debugtrace_toggle(void)
698 {
699 unsigned long flags;
701 watchdog_disable();
702 spin_lock_irqsave(&debugtrace_lock, flags);
704 // dump the buffer *before* toggling, in case the act of dumping the
705 // buffer itself causes more printk's...
706 //
707 printk("debugtrace_printk now writing to %s.\n",
708 !debugtrace_send_to_console ? "console": "buffer");
709 if ( !debugtrace_send_to_console )
710 debugtrace_dump_worker();
712 debugtrace_send_to_console = !debugtrace_send_to_console;
714 spin_unlock_irqrestore(&debugtrace_lock, flags);
715 watchdog_enable();
717 }
719 void debugtrace_dump(void)
720 {
721 unsigned long flags;
723 watchdog_disable();
724 spin_lock_irqsave(&debugtrace_lock, flags);
726 debugtrace_dump_worker();
728 spin_unlock_irqrestore(&debugtrace_lock, flags);
729 watchdog_enable();
730 }
732 void debugtrace_printk(const char *fmt, ...)
733 {
734 static char buf[1024];
735 static u32 count;
737 va_list args;
738 char *p;
739 unsigned long flags;
741 if ( debugtrace_bytes == 0 )
742 return;
744 debugtrace_used = 1;
746 spin_lock_irqsave(&debugtrace_lock, flags);
748 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
750 sprintf(buf, "%u ", ++count);
752 va_start(args, fmt);
753 (void)vsnprintf(buf + strlen(buf), sizeof(buf), fmt, args);
754 va_end(args);
756 if ( debugtrace_send_to_console )
757 {
758 serial_puts(sercon_handle, buf);
759 }
760 else
761 {
762 for ( p = buf; *p != '\0'; p++ )
763 {
764 debugtrace_buf[debugtrace_prd++] = *p;
765 /* Always leave a nul byte at the end of the buffer. */
766 if ( debugtrace_prd == (debugtrace_bytes - 1) )
767 debugtrace_prd = 0;
768 }
769 }
771 spin_unlock_irqrestore(&debugtrace_lock, flags);
772 }
774 static void debugtrace_key(unsigned char key)
775 {
776 debugtrace_toggle();
777 }
779 static int __init debugtrace_init(void)
780 {
781 int order;
782 unsigned int kbytes, bytes;
784 /* Round size down to next power of two. */
785 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
786 debugtrace_kilobytes = kbytes;
788 bytes = debugtrace_kilobytes << 10;
789 if ( bytes == 0 )
790 return 0;
792 order = get_order_from_bytes(bytes);
793 debugtrace_buf = alloc_xenheap_pages(order);
794 ASSERT(debugtrace_buf != NULL);
796 memset(debugtrace_buf, '\0', bytes);
798 debugtrace_bytes = bytes;
800 register_keyhandler(
801 'T', debugtrace_key, "toggle debugtrace to console/buffer");
803 return 0;
804 }
805 __initcall(debugtrace_init);
807 #endif /* !NDEBUG */
811 /*
812 * **************************************************************
813 * *************** Debugging/tracing/error-report ***************
814 * **************************************************************
815 */
817 void panic(const char *fmt, ...)
818 {
819 va_list args;
820 char buf[128];
821 unsigned long flags;
822 static DEFINE_SPINLOCK(lock);
824 debugtrace_dump();
826 va_start(args, fmt);
827 (void)vsnprintf(buf, sizeof(buf), fmt, args);
828 va_end(args);
830 /* Spit out multiline message in one go. */
831 console_start_sync();
832 spin_lock_irqsave(&lock, flags);
833 printk("\n****************************************\n");
834 printk("Panic on CPU %d:\n", smp_processor_id());
835 printk(buf);
836 printk("****************************************\n\n");
837 if ( opt_noreboot )
838 printk("Manual reset required ('noreboot' specified)\n");
839 else
840 printk("Reboot in five seconds...\n");
841 spin_unlock_irqrestore(&lock, flags);
843 debugger_trap_immediate();
845 if ( opt_noreboot )
846 {
847 machine_halt();
848 }
849 else
850 {
851 watchdog_disable();
852 mdelay(5000);
853 machine_restart(NULL);
854 }
855 }
857 void __bug(char *file, int line)
858 {
859 console_start_sync();
860 debugtrace_dump();
861 printk("BUG at %s:%d\n", file, line);
862 FORCE_CRASH();
863 for ( ; ; ) ;
864 }
866 /*
867 * Local variables:
868 * mode: C
869 * c-set-style: "BSD"
870 * c-basic-offset: 4
871 * tab-width: 4
872 * indent-tabs-mode: nil
873 * End:
874 */