direct-io.hg

view xen/drivers/char/console.c @ 14287:38513d22d234

xen: Provide notification of console updates via VIRQ.

The readconsolering capabilities provide the opportunity to
provide console output to other clients (remote systems,
logging systems, etc). This patchs adds the ability to generate
a notification of a change in the console buffer.

Signed-off-by: Ben Thomas <ben@virtualiron.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Mar 08 15:21:10 2007 +0000 (2007-03-08)
parents c67a4115a471
children e9ef0808c09f
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 #define CONRING_SIZE 16384
52 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
53 static char conring[CONRING_SIZE];
54 static unsigned int conringc, conringp;
56 static char printk_prefix[16] = "";
58 static int sercon_handle = -1;
60 static DEFINE_SPINLOCK(console_lock);
62 /*
63 * To control the amount of printing, thresholds are added.
64 * These thresholds correspond to the XENLOG logging levels.
65 * There's an upper and lower threshold for non-guest messages and for
66 * guest-provoked messages. This works as follows, for a given log level L:
67 *
68 * L < lower_threshold : always logged
69 * lower_threshold <= L < upper_threshold : rate-limited logging
70 * upper_threshold <= L : never logged
71 *
72 * Note, in the above algorithm, to disable rate limiting simply make
73 * the lower threshold equal to the upper.
74 */
75 #ifdef NDEBUG
76 #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
77 #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
78 #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
79 #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
80 #else
81 #define XENLOG_UPPER_THRESHOLD 4 /* Do not discard anything */
82 #define XENLOG_LOWER_THRESHOLD 4 /* Print everything */
83 #define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything */
84 #define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything */
85 #endif
86 /*
87 * The XENLOG_DEFAULT is the default given to printks that
88 * do not have any print level associated with them.
89 */
90 #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
91 #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
93 static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
94 static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
95 static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
96 static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
98 static void parse_loglvl(char *s);
99 static void parse_guest_loglvl(char *s);
101 /*
102 * <lvl> := none|error|warning|info|debug|all
103 * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
104 * <lvl_print_always>: log level which is always printed
105 * <lvl_print_rlimit>: log level which is rate-limit printed
106 * Similar definitions for guest_loglvl, but applies to guest tracing.
107 * Defaults: loglvl=warning ; guest_loglvl=none/warning
108 */
109 custom_param("loglvl", parse_loglvl);
110 custom_param("guest_loglvl", parse_guest_loglvl);
112 static atomic_t print_everything = ATOMIC_INIT(0);
114 #define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
115 if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
116 *(ps) = (s) + strlen(lvlstr); \
117 return (lvlnum); \
118 }
120 static int __parse_loglvl(char *s, char **ps)
121 {
122 ___parse_loglvl(s, ps, "none", 0);
123 ___parse_loglvl(s, ps, "error", 1);
124 ___parse_loglvl(s, ps, "warning", 2);
125 ___parse_loglvl(s, ps, "info", 3);
126 ___parse_loglvl(s, ps, "debug", 4);
127 ___parse_loglvl(s, ps, "all", 4);
128 return 2; /* sane fallback */
129 }
131 static void _parse_loglvl(char *s, int *lower, int *upper)
132 {
133 *lower = *upper = __parse_loglvl(s, &s);
134 if ( *s == '/' )
135 *upper = __parse_loglvl(s+1, &s);
136 if ( *upper < *lower )
137 *upper = *lower;
138 }
140 static void parse_loglvl(char *s)
141 {
142 _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
143 }
145 static void parse_guest_loglvl(char *s)
146 {
147 _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
148 }
150 static char *loglvl_str(int lvl)
151 {
152 switch ( lvl )
153 {
154 case 0: return "Nothing";
155 case 1: return "Errors";
156 case 2: return "Errors and warnings";
157 case 3: return "Errors, warnings and info";
158 case 4: return "All";
159 }
160 return "???";
161 }
163 /*
164 * ********************************************************
165 * *************** ACCESS TO CONSOLE RING *****************
166 * ********************************************************
167 */
169 static void putchar_console_ring(int c)
170 {
171 conring[CONRING_IDX_MASK(conringp++)] = c;
172 if ( (conringp - conringc) > CONRING_SIZE )
173 conringc = conringp - CONRING_SIZE;
174 }
176 long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
177 {
178 unsigned int idx, len, max, sofar, c;
179 unsigned long flags;
181 max = *pcount;
182 sofar = 0;
184 c = conringc;
185 while ( (c != conringp) && (sofar < max) )
186 {
187 idx = CONRING_IDX_MASK(c);
188 len = conringp - c;
189 if ( (idx + len) > CONRING_SIZE )
190 len = CONRING_SIZE - idx;
191 if ( (sofar + len) > max )
192 len = max - sofar;
193 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
194 return -EFAULT;
195 sofar += len;
196 c += len;
197 }
199 if ( clear )
200 {
201 spin_lock_irqsave(&console_lock, flags);
202 if ( (conringp - c) > CONRING_SIZE )
203 conringc = conringp - CONRING_SIZE;
204 else
205 conringc = c;
206 spin_unlock_irqrestore(&console_lock, flags);
207 }
209 *pcount = sofar;
210 return 0;
211 }
214 /*
215 * *******************************************************
216 * *************** ACCESS TO SERIAL LINE *****************
217 * *******************************************************
218 */
220 /* Characters received over the serial line are buffered for domain 0. */
221 #define SERIAL_RX_SIZE 128
222 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
223 static char serial_rx_ring[SERIAL_RX_SIZE];
224 static unsigned int serial_rx_cons, serial_rx_prod;
226 static void (*serial_steal_fn)(const char *);
228 int console_steal(int handle, void (*fn)(const char *))
229 {
230 if ( (handle == -1) || (handle != sercon_handle) )
231 return 0;
233 if ( serial_steal_fn != NULL )
234 return -EBUSY;
236 serial_steal_fn = fn;
237 return 1;
238 }
240 void console_giveback(int id)
241 {
242 if ( id == 1 )
243 serial_steal_fn = NULL;
244 }
246 static void sercon_puts(const char *s)
247 {
248 if ( serial_steal_fn != NULL )
249 (*serial_steal_fn)(s);
250 else
251 serial_puts(sercon_handle, s);
252 }
254 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
255 #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
256 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
258 static void switch_serial_input(void)
259 {
260 static char *input_str[2] = { "DOM0", "Xen" };
261 xen_rx = !xen_rx;
262 if ( (SWITCH_CODE != 0) && (dom0 != NULL) )
263 {
264 printk("*** Serial input -> %s "
265 "(type 'CTRL-%c' three times to switch input to %s).\n",
266 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
267 }
268 }
270 static void __serial_rx(char c, struct cpu_user_regs *regs)
271 {
272 if ( xen_rx )
273 return handle_keypress(c, regs);
275 /* Deliver input to guest buffer, unless it is already full. */
276 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
277 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
278 /* Always notify the guest: prevents receive path from getting stuck. */
279 send_guest_global_virq(dom0, VIRQ_CONSOLE);
280 }
282 static void serial_rx(char c, struct cpu_user_regs *regs)
283 {
284 static int switch_code_count = 0;
286 if ( (SWITCH_CODE != 0) && (c == SWITCH_CODE) )
287 {
288 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
289 if ( ++switch_code_count == 3 )
290 {
291 switch_serial_input();
292 switch_code_count = 0;
293 return;
294 }
295 }
296 else
297 {
298 switch_code_count = 0;
299 }
301 /* Finally process the just-received character. */
302 __serial_rx(c, regs);
303 }
305 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
306 {
307 char kbuf[128], *kptr;
308 int kcount;
310 while ( count > 0 )
311 {
312 while ( serial_tx_space(sercon_handle) < (SERIAL_TXBUFSZ / 2) )
313 {
314 if ( hypercall_preempt_check() )
315 break;
316 cpu_relax();
317 }
319 if ( hypercall_preempt_check() )
320 return hypercall_create_continuation(
321 __HYPERVISOR_console_io, "iih",
322 CONSOLEIO_write, count, buffer);
324 kcount = min_t(int, count, sizeof(kbuf)-1);
325 if ( copy_from_guest((char *)kbuf, buffer, kcount) )
326 return -EFAULT;
327 kbuf[kcount] = '\0';
329 sercon_puts(kbuf);
331 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
332 vga_putchar(*kptr);
334 guest_handle_add_offset(buffer, kcount);
335 count -= kcount;
336 }
338 return 0;
339 }
341 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
342 {
343 long rc;
344 unsigned int idx, len;
346 #ifndef VERBOSE
347 /* Only domain 0 may access the emergency console. */
348 if ( current->domain->domain_id != 0 )
349 return -EPERM;
350 #endif
352 switch ( cmd )
353 {
354 case CONSOLEIO_write:
355 rc = guest_console_write(buffer, count);
356 break;
357 case CONSOLEIO_read:
358 rc = 0;
359 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
360 {
361 idx = SERIAL_RX_MASK(serial_rx_cons);
362 len = serial_rx_prod - serial_rx_cons;
363 if ( (idx + len) > SERIAL_RX_SIZE )
364 len = SERIAL_RX_SIZE - idx;
365 if ( (rc + len) > count )
366 len = count - rc;
367 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
368 {
369 rc = -EFAULT;
370 break;
371 }
372 rc += len;
373 serial_rx_cons += len;
374 }
375 break;
376 default:
377 rc = -ENOSYS;
378 break;
379 }
381 return rc;
382 }
385 /*
386 * *****************************************************
387 * *************** GENERIC CONSOLE I/O *****************
388 * *****************************************************
389 */
391 static void __putstr(const char *str)
392 {
393 int c;
395 sercon_puts(str);
397 while ( (c = *str++) != '\0' )
398 {
399 vga_putchar(c);
400 putchar_console_ring(c);
401 }
403 send_guest_global_virq(dom0, VIRQ_CON_RING);
404 }
406 static int printk_prefix_check(char *p, char **pp)
407 {
408 int loglvl = -1;
409 int upper_thresh = xenlog_upper_thresh;
410 int lower_thresh = xenlog_lower_thresh;
412 while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
413 {
414 switch ( p[1] )
415 {
416 case 'G':
417 upper_thresh = xenlog_guest_upper_thresh;
418 lower_thresh = xenlog_guest_lower_thresh;
419 if ( loglvl == -1 )
420 loglvl = XENLOG_GUEST_DEFAULT;
421 break;
422 case '0' ... '3':
423 loglvl = p[1] - '0';
424 break;
425 }
426 p += 3;
427 }
429 if ( loglvl == -1 )
430 loglvl = XENLOG_DEFAULT;
432 *pp = p;
434 return ((atomic_read(&print_everything) != 0) ||
435 (loglvl < lower_thresh) ||
436 ((loglvl < upper_thresh) && printk_ratelimit()));
437 }
439 void printk(const char *fmt, ...)
440 {
441 static char buf[1024];
442 static int start_of_line = 1, do_print;
444 va_list args;
445 char *p, *q;
446 unsigned long flags;
448 /* console_lock can be acquired recursively from __printk_ratelimit(). */
449 local_irq_save(flags);
450 spin_lock_recursive(&console_lock);
452 va_start(args, fmt);
453 (void)vsnprintf(buf, sizeof(buf), fmt, args);
454 va_end(args);
456 p = buf;
458 while ( (q = strchr(p, '\n')) != NULL )
459 {
460 *q = '\0';
461 if ( start_of_line )
462 do_print = printk_prefix_check(p, &p);
463 if ( do_print )
464 {
465 if ( start_of_line )
466 __putstr(printk_prefix);
467 __putstr(p);
468 __putstr("\n");
469 }
470 start_of_line = 1;
471 p = q + 1;
472 }
474 if ( *p != '\0' )
475 {
476 if ( start_of_line )
477 do_print = printk_prefix_check(p, &p);
478 if ( do_print )
479 {
480 if ( start_of_line )
481 __putstr(printk_prefix);
482 __putstr(p);
483 }
484 start_of_line = 0;
485 }
487 spin_unlock_recursive(&console_lock);
488 local_irq_restore(flags);
489 }
491 void set_printk_prefix(const char *prefix)
492 {
493 safe_strcpy(printk_prefix, prefix);
494 }
496 void init_console(void)
497 {
498 char *p;
500 /* Where should console output go? */
501 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
502 {
503 if ( *p == ',' )
504 p++;
505 if ( strncmp(p, "com", 3) == 0 )
506 sercon_handle = serial_parse_handle(p);
507 else if ( strncmp(p, "vga", 3) == 0 )
508 vga_init();
509 }
511 serial_set_rx_handler(sercon_handle, serial_rx);
513 /* HELLO WORLD --- start-of-day banner text. */
514 printk(xen_banner());
515 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
516 printk(" University of Cambridge Computer Laboratory\n\n");
517 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n",
518 xen_major_version(), xen_minor_version(), xen_extra_version(),
519 xen_compile_by(), xen_compile_domain(),
520 xen_compiler(), xen_compile_date());
521 printk(" Latest ChangeSet: %s\n\n", xen_changeset());
522 set_printk_prefix("(XEN) ");
524 if ( opt_sync_console )
525 {
526 serial_start_sync(sercon_handle);
527 add_taint(TAINT_SYNC_CONSOLE);
528 printk("Console output is synchronous.\n");
529 }
530 }
532 void console_endboot(void)
533 {
534 int i, j;
536 printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
537 if ( xenlog_upper_thresh != xenlog_lower_thresh )
538 printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
539 printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
540 if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
541 printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
542 printk("\n");
544 if ( opt_sync_console )
545 {
546 printk("**********************************************\n");
547 printk("******* WARNING: CONSOLE OUTPUT IS SYNCHRONOUS\n");
548 printk("******* This option is intended to aid debugging "
549 "of Xen by ensuring\n");
550 printk("******* that all output is synchronously delivered "
551 "on the serial line.\n");
552 printk("******* However it can introduce SIGNIFICANT latencies "
553 "and affect\n");
554 printk("******* timekeeping. It is NOT recommended for "
555 "production use!\n");
556 printk("**********************************************\n");
557 for ( i = 0; i < 3; i++ )
558 {
559 printk("%d... ", 3-i);
560 for ( j = 0; j < 100; j++ )
561 {
562 process_pending_timers();
563 mdelay(10);
564 }
565 }
566 printk("\n");
567 }
569 vga_endboot();
571 /*
572 * If user specifies so, we fool the switch routine to redirect input
573 * straight back to Xen. I use this convoluted method so we still print
574 * a useful 'how to switch' message.
575 */
576 if ( opt_conswitch[1] == 'x' )
577 xen_rx = !xen_rx;
579 /* Serial input is directed to DOM0 by default. */
580 switch_serial_input();
581 }
583 void console_start_log_everything(void)
584 {
585 atomic_inc(&print_everything);
586 }
588 void console_end_log_everything(void)
589 {
590 atomic_dec(&print_everything);
591 }
593 void console_force_unlock(void)
594 {
595 spin_lock_init(&console_lock);
596 serial_force_unlock(sercon_handle);
597 console_start_sync();
598 }
600 void console_force_lock(void)
601 {
602 spin_lock(&console_lock);
603 }
605 void console_start_sync(void)
606 {
607 console_start_log_everything();
608 serial_start_sync(sercon_handle);
609 }
611 void console_end_sync(void)
612 {
613 serial_end_sync(sercon_handle);
614 console_end_log_everything();
615 }
617 void console_putc(char c)
618 {
619 serial_putc(sercon_handle, c);
620 }
622 int console_getc(void)
623 {
624 return serial_getc(sercon_handle);
625 }
627 /*
628 * printk rate limiting, lifted from Linux.
629 *
630 * This enforces a rate limit: not more than one kernel message
631 * every printk_ratelimit_ms (millisecs).
632 */
633 int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
634 {
635 static DEFINE_SPINLOCK(ratelimit_lock);
636 static unsigned long toks = 10 * 5 * 1000;
637 static unsigned long last_msg;
638 static int missed;
639 unsigned long flags;
640 unsigned long long now = NOW(); /* ns */
641 unsigned long ms;
643 do_div(now, 1000000);
644 ms = (unsigned long)now;
646 spin_lock_irqsave(&ratelimit_lock, flags);
647 toks += ms - last_msg;
648 last_msg = ms;
649 if ( toks > (ratelimit_burst * ratelimit_ms))
650 toks = ratelimit_burst * ratelimit_ms;
651 if ( toks >= ratelimit_ms )
652 {
653 int lost = missed;
654 missed = 0;
655 toks -= ratelimit_ms;
656 spin_unlock(&ratelimit_lock);
657 if ( lost )
658 {
659 char lost_str[8];
660 snprintf(lost_str, sizeof(lost_str), "%d", lost);
661 /* console_lock may already be acquired by printk(). */
662 spin_lock_recursive(&console_lock);
663 __putstr(printk_prefix);
664 __putstr("printk: ");
665 __putstr(lost_str);
666 __putstr(" messages suppressed.\n");
667 spin_unlock_recursive(&console_lock);
668 }
669 local_irq_restore(flags);
670 return 1;
671 }
672 missed++;
673 spin_unlock_irqrestore(&ratelimit_lock, flags);
674 return 0;
675 }
677 /* minimum time in ms between messages */
678 int printk_ratelimit_ms = 5 * 1000;
680 /* number of messages we send before ratelimiting */
681 int printk_ratelimit_burst = 10;
683 int printk_ratelimit(void)
684 {
685 return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
686 }
688 /*
689 * **************************************************************
690 * *************** Serial console ring buffer *******************
691 * **************************************************************
692 */
694 #ifdef DEBUG_TRACE_DUMP
696 /* Send output direct to console, or buffer it? */
697 static volatile int debugtrace_send_to_console;
699 static char *debugtrace_buf; /* Debug-trace buffer */
700 static unsigned int debugtrace_prd; /* Producer index */
701 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
702 static unsigned int debugtrace_used;
703 static DEFINE_SPINLOCK(debugtrace_lock);
704 integer_param("debugtrace", debugtrace_kilobytes);
706 static void debugtrace_dump_worker(void)
707 {
708 if ( (debugtrace_bytes == 0) || !debugtrace_used )
709 return;
711 printk("debugtrace_dump() starting\n");
713 /* Print oldest portion of the ring. */
714 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
715 sercon_puts(&debugtrace_buf[debugtrace_prd]);
717 /* Print youngest portion of the ring. */
718 debugtrace_buf[debugtrace_prd] = '\0';
719 sercon_puts(&debugtrace_buf[0]);
721 memset(debugtrace_buf, '\0', debugtrace_bytes);
723 printk("debugtrace_dump() finished\n");
724 }
726 static void debugtrace_toggle(void)
727 {
728 unsigned long flags;
730 watchdog_disable();
731 spin_lock_irqsave(&debugtrace_lock, flags);
733 /*
734 * Dump the buffer *before* toggling, in case the act of dumping the
735 * buffer itself causes more printk() invocations.
736 */
737 printk("debugtrace_printk now writing to %s.\n",
738 !debugtrace_send_to_console ? "console": "buffer");
739 if ( !debugtrace_send_to_console )
740 debugtrace_dump_worker();
742 debugtrace_send_to_console = !debugtrace_send_to_console;
744 spin_unlock_irqrestore(&debugtrace_lock, flags);
745 watchdog_enable();
747 }
749 void debugtrace_dump(void)
750 {
751 unsigned long flags;
753 watchdog_disable();
754 spin_lock_irqsave(&debugtrace_lock, flags);
756 debugtrace_dump_worker();
758 spin_unlock_irqrestore(&debugtrace_lock, flags);
759 watchdog_enable();
760 }
762 void debugtrace_printk(const char *fmt, ...)
763 {
764 static char buf[1024];
765 static u32 count;
767 va_list args;
768 char *p;
769 unsigned long flags;
771 if ( debugtrace_bytes == 0 )
772 return;
774 debugtrace_used = 1;
776 spin_lock_irqsave(&debugtrace_lock, flags);
778 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
780 snprintf(buf, sizeof(buf), "%u ", ++count);
782 va_start(args, fmt);
783 (void)vsnprintf(buf + strlen(buf), sizeof(buf), fmt, args);
784 va_end(args);
786 if ( debugtrace_send_to_console )
787 {
788 serial_puts(sercon_handle, buf);
789 }
790 else
791 {
792 for ( p = buf; *p != '\0'; p++ )
793 {
794 debugtrace_buf[debugtrace_prd++] = *p;
795 /* Always leave a nul byte at the end of the buffer. */
796 if ( debugtrace_prd == (debugtrace_bytes - 1) )
797 debugtrace_prd = 0;
798 }
799 }
801 spin_unlock_irqrestore(&debugtrace_lock, flags);
802 }
804 static void debugtrace_key(unsigned char key)
805 {
806 debugtrace_toggle();
807 }
809 static int __init debugtrace_init(void)
810 {
811 int order;
812 unsigned int kbytes, bytes;
814 /* Round size down to next power of two. */
815 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
816 debugtrace_kilobytes = kbytes;
818 bytes = debugtrace_kilobytes << 10;
819 if ( bytes == 0 )
820 return 0;
822 order = get_order_from_bytes(bytes);
823 debugtrace_buf = alloc_xenheap_pages(order);
824 ASSERT(debugtrace_buf != NULL);
826 memset(debugtrace_buf, '\0', bytes);
828 debugtrace_bytes = bytes;
830 register_keyhandler(
831 'T', debugtrace_key, "toggle debugtrace to console/buffer");
833 return 0;
834 }
835 __initcall(debugtrace_init);
837 #endif /* !NDEBUG */
841 /*
842 * **************************************************************
843 * *************** Debugging/tracing/error-report ***************
844 * **************************************************************
845 */
847 void panic(const char *fmt, ...)
848 {
849 va_list args;
850 char buf[128];
851 unsigned long flags;
852 static DEFINE_SPINLOCK(lock);
854 debugtrace_dump();
856 va_start(args, fmt);
857 (void)vsnprintf(buf, sizeof(buf), fmt, args);
858 va_end(args);
860 /* Spit out multiline message in one go. */
861 console_start_sync();
862 spin_lock_irqsave(&lock, flags);
863 printk("\n****************************************\n");
864 printk("Panic on CPU %d:\n", smp_processor_id());
865 printk(buf);
866 printk("****************************************\n\n");
867 if ( opt_noreboot )
868 printk("Manual reset required ('noreboot' specified)\n");
869 else
870 printk("Reboot in five seconds...\n");
871 spin_unlock_irqrestore(&lock, flags);
873 debugger_trap_immediate();
875 kexec_crash();
877 if ( opt_noreboot )
878 {
879 machine_halt();
880 }
881 else
882 {
883 watchdog_disable();
884 mdelay(5000);
885 machine_restart(NULL);
886 }
887 }
889 void __bug(char *file, int line)
890 {
891 console_start_sync();
892 printk("BUG at %s:%d\n", file, line);
893 dump_execution_state();
894 panic("BUG at %s:%d\n", file, line);
895 for ( ; ; ) ;
896 }
898 /*
899 * Local variables:
900 * mode: C
901 * c-set-style: "BSD"
902 * c-basic-offset: 4
903 * tab-width: 4
904 * indent-tabs-mode: nil
905 * End:
906 */