ia64/xen-unstable

view xen/drivers/char/console.c @ 19543:81d6b5762c40

New option conring_size= to allow larger console ring.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 14 14:52:27 2009 +0100 (2009-04-14)
parents f57ac4af36b4
children
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 /* conring_size: allows a large console ring than default (16kB). */
62 static uint32_t opt_conring_size;
63 static void parse_conring_size(char *s)
64 { opt_conring_size = parse_size_and_unit(s, NULL); }
65 custom_param("conring_size", parse_conring_size);
67 #define _CONRING_SIZE 16384
68 #define CONRING_IDX_MASK(i) ((i)&(conring_size-1))
69 static char _conring[_CONRING_SIZE], *conring = _conring;
70 static uint32_t conring_size = _CONRING_SIZE, conringc, conringp;
72 static int sercon_handle = -1;
74 static DEFINE_SPINLOCK(console_lock);
76 /*
77 * To control the amount of printing, thresholds are added.
78 * These thresholds correspond to the XENLOG logging levels.
79 * There's an upper and lower threshold for non-guest messages and for
80 * guest-provoked messages. This works as follows, for a given log level L:
81 *
82 * L < lower_threshold : always logged
83 * lower_threshold <= L < upper_threshold : rate-limited logging
84 * upper_threshold <= L : never logged
85 *
86 * Note, in the above algorithm, to disable rate limiting simply make
87 * the lower threshold equal to the upper.
88 */
89 #ifdef NDEBUG
90 #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
91 #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
92 #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
93 #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
94 #else
95 #define XENLOG_UPPER_THRESHOLD 4 /* Do not discard anything */
96 #define XENLOG_LOWER_THRESHOLD 4 /* Print everything */
97 #define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything */
98 #define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything */
99 #endif
100 /*
101 * The XENLOG_DEFAULT is the default given to printks that
102 * do not have any print level associated with them.
103 */
104 #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
105 #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
107 static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
108 static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
109 static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
110 static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
112 static void parse_loglvl(char *s);
113 static void parse_guest_loglvl(char *s);
115 /*
116 * <lvl> := none|error|warning|info|debug|all
117 * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
118 * <lvl_print_always>: log level which is always printed
119 * <lvl_print_rlimit>: log level which is rate-limit printed
120 * Similar definitions for guest_loglvl, but applies to guest tracing.
121 * Defaults: loglvl=warning ; guest_loglvl=none/warning
122 */
123 custom_param("loglvl", parse_loglvl);
124 custom_param("guest_loglvl", parse_guest_loglvl);
126 static atomic_t print_everything = ATOMIC_INIT(0);
128 #define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
129 if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
130 *(ps) = (s) + strlen(lvlstr); \
131 return (lvlnum); \
132 }
134 static int __init __parse_loglvl(char *s, char **ps)
135 {
136 ___parse_loglvl(s, ps, "none", 0);
137 ___parse_loglvl(s, ps, "error", 1);
138 ___parse_loglvl(s, ps, "warning", 2);
139 ___parse_loglvl(s, ps, "info", 3);
140 ___parse_loglvl(s, ps, "debug", 4);
141 ___parse_loglvl(s, ps, "all", 4);
142 return 2; /* sane fallback */
143 }
145 static void __init _parse_loglvl(char *s, int *lower, int *upper)
146 {
147 *lower = *upper = __parse_loglvl(s, &s);
148 if ( *s == '/' )
149 *upper = __parse_loglvl(s+1, &s);
150 if ( *upper < *lower )
151 *upper = *lower;
152 }
154 static void __init parse_loglvl(char *s)
155 {
156 _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
157 }
159 static void __init parse_guest_loglvl(char *s)
160 {
161 _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
162 }
164 static char * __init loglvl_str(int lvl)
165 {
166 switch ( lvl )
167 {
168 case 0: return "Nothing";
169 case 1: return "Errors";
170 case 2: return "Errors and warnings";
171 case 3: return "Errors, warnings and info";
172 case 4: return "All";
173 }
174 return "???";
175 }
177 /*
178 * ********************************************************
179 * *************** ACCESS TO CONSOLE RING *****************
180 * ********************************************************
181 */
183 static void putchar_console_ring(int c)
184 {
185 ASSERT(spin_is_locked(&console_lock));
186 conring[CONRING_IDX_MASK(conringp++)] = c;
187 if ( (uint32_t)(conringp - conringc) > conring_size )
188 conringc = conringp - conring_size;
189 }
191 long read_console_ring(struct xen_sysctl_readconsole *op)
192 {
193 XEN_GUEST_HANDLE(char) str;
194 uint32_t idx, len, max, sofar, c;
196 str = guest_handle_cast(op->buffer, char),
197 max = op->count;
198 sofar = 0;
200 c = conringc;
201 if ( op->incremental && ((int32_t)(op->index - c) < 0) )
202 c = op->index;
204 while ( (c != conringp) && (sofar < max) )
205 {
206 idx = CONRING_IDX_MASK(c);
207 len = conringp - c;
208 if ( (idx + len) > conring_size )
209 len = conring_size - idx;
210 if ( (sofar + len) > max )
211 len = max - sofar;
212 if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )
213 return -EFAULT;
214 sofar += len;
215 c += len;
216 }
218 if ( op->clear )
219 {
220 spin_lock_irq(&console_lock);
221 if ( (uint32_t)(conringp - c) > conring_size )
222 conringc = conringp - conring_size;
223 else
224 conringc = c;
225 spin_unlock_irq(&console_lock);
226 }
228 op->count = sofar;
229 op->index = c;
231 return 0;
232 }
235 /*
236 * *******************************************************
237 * *************** ACCESS TO SERIAL LINE *****************
238 * *******************************************************
239 */
241 /* Characters received over the serial line are buffered for domain 0. */
242 #define SERIAL_RX_SIZE 128
243 #define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))
244 static char serial_rx_ring[SERIAL_RX_SIZE];
245 static unsigned int serial_rx_cons, serial_rx_prod;
247 static void (*serial_steal_fn)(const char *);
249 int console_steal(int handle, void (*fn)(const char *))
250 {
251 if ( (handle == -1) || (handle != sercon_handle) )
252 return 0;
254 if ( serial_steal_fn != NULL )
255 return -EBUSY;
257 serial_steal_fn = fn;
258 return 1;
259 }
261 void console_giveback(int id)
262 {
263 if ( id == 1 )
264 serial_steal_fn = NULL;
265 }
267 static void sercon_puts(const char *s)
268 {
269 if ( serial_steal_fn != NULL )
270 (*serial_steal_fn)(s);
271 else
272 serial_puts(sercon_handle, s);
273 }
275 /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
276 #define switch_code (opt_conswitch[0]-'a'+1)
277 static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
279 static void switch_serial_input(void)
280 {
281 static char *input_str[2] = { "DOM0", "Xen" };
282 xen_rx = !xen_rx;
283 printk("*** Serial input -> %s", input_str[xen_rx]);
284 if ( switch_code )
285 printk(" (type 'CTRL-%c' three times to switch input to %s)",
286 opt_conswitch[0], input_str[!xen_rx]);
287 printk("\n");
288 }
290 static void __serial_rx(char c, struct cpu_user_regs *regs)
291 {
292 if ( xen_rx )
293 return handle_keypress(c, regs);
295 /* Deliver input to guest buffer, unless it is already full. */
296 if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
297 serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
298 /* Always notify the guest: prevents receive path from getting stuck. */
299 send_guest_global_virq(dom0, VIRQ_CONSOLE);
300 }
302 static void serial_rx(char c, struct cpu_user_regs *regs)
303 {
304 static int switch_code_count = 0;
306 if ( switch_code && (c == switch_code) )
307 {
308 /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */
309 if ( ++switch_code_count == 3 )
310 {
311 switch_serial_input();
312 switch_code_count = 0;
313 }
314 return;
315 }
317 for ( ; switch_code_count != 0; switch_code_count-- )
318 __serial_rx(switch_code, regs);
320 /* Finally process the just-received character. */
321 __serial_rx(c, regs);
322 }
324 static void notify_dom0_con_ring(unsigned long unused)
325 {
326 send_guest_global_virq(dom0, VIRQ_CON_RING);
327 }
328 static DECLARE_TASKLET(notify_dom0_con_ring_tasklet, notify_dom0_con_ring, 0);
330 static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
331 {
332 char kbuf[128], *kptr;
333 int kcount;
335 while ( count > 0 )
336 {
337 while ( serial_tx_space(sercon_handle) < (serial_txbufsz / 2) )
338 {
339 if ( hypercall_preempt_check() )
340 break;
341 cpu_relax();
342 }
344 if ( hypercall_preempt_check() )
345 return hypercall_create_continuation(
346 __HYPERVISOR_console_io, "iih",
347 CONSOLEIO_write, count, buffer);
349 kcount = min_t(int, count, sizeof(kbuf)-1);
350 if ( copy_from_guest(kbuf, buffer, kcount) )
351 return -EFAULT;
352 kbuf[kcount] = '\0';
354 spin_lock_irq(&console_lock);
356 sercon_puts(kbuf);
357 vga_puts(kbuf);
359 if ( opt_console_to_ring )
360 {
361 for ( kptr = kbuf; *kptr != '\0'; kptr++ )
362 putchar_console_ring(*kptr);
363 tasklet_schedule(&notify_dom0_con_ring_tasklet);
364 }
366 spin_unlock_irq(&console_lock);
368 guest_handle_add_offset(buffer, kcount);
369 count -= kcount;
370 }
372 return 0;
373 }
375 long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
376 {
377 long rc;
378 unsigned int idx, len;
380 #ifndef VERBOSE
381 /* Only domain 0 may access the emergency console. */
382 if ( current->domain->domain_id != 0 )
383 return -EPERM;
384 #endif
386 rc = xsm_console_io(current->domain, cmd);
387 if ( rc )
388 return rc;
390 switch ( cmd )
391 {
392 case CONSOLEIO_write:
393 rc = guest_console_write(buffer, count);
394 break;
395 case CONSOLEIO_read:
396 rc = 0;
397 while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
398 {
399 idx = SERIAL_RX_MASK(serial_rx_cons);
400 len = serial_rx_prod - serial_rx_cons;
401 if ( (idx + len) > SERIAL_RX_SIZE )
402 len = SERIAL_RX_SIZE - idx;
403 if ( (rc + len) > count )
404 len = count - rc;
405 if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )
406 {
407 rc = -EFAULT;
408 break;
409 }
410 rc += len;
411 serial_rx_cons += len;
412 }
413 break;
414 default:
415 rc = -ENOSYS;
416 break;
417 }
419 return rc;
420 }
423 /*
424 * *****************************************************
425 * *************** GENERIC CONSOLE I/O *****************
426 * *****************************************************
427 */
429 static bool_t console_locks_busted;
431 static void __putstr(const char *str)
432 {
433 int c;
435 ASSERT(spin_is_locked(&console_lock));
437 sercon_puts(str);
438 vga_puts(str);
440 if ( !console_locks_busted )
441 {
442 while ( (c = *str++) != '\0' )
443 putchar_console_ring(c);
444 tasklet_schedule(&notify_dom0_con_ring_tasklet);
445 }
446 }
448 static int printk_prefix_check(char *p, char **pp)
449 {
450 int loglvl = -1;
451 int upper_thresh = xenlog_upper_thresh;
452 int lower_thresh = xenlog_lower_thresh;
454 while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
455 {
456 switch ( p[1] )
457 {
458 case 'G':
459 upper_thresh = xenlog_guest_upper_thresh;
460 lower_thresh = xenlog_guest_lower_thresh;
461 if ( loglvl == -1 )
462 loglvl = XENLOG_GUEST_DEFAULT;
463 break;
464 case '0' ... '3':
465 loglvl = p[1] - '0';
466 break;
467 }
468 p += 3;
469 }
471 if ( loglvl == -1 )
472 loglvl = XENLOG_DEFAULT;
474 *pp = p;
476 return ((atomic_read(&print_everything) != 0) ||
477 (loglvl < lower_thresh) ||
478 ((loglvl < upper_thresh) && printk_ratelimit()));
479 }
481 static void printk_start_of_line(void)
482 {
483 struct tm tm;
484 char tstr[32];
486 __putstr("(XEN) ");
488 if ( !opt_console_timestamps )
489 return;
491 tm = wallclock_time();
492 if ( tm.tm_mday == 0 )
493 return;
495 snprintf(tstr, sizeof(tstr), "[%04u-%02u-%02u %02u:%02u:%02u] ",
496 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
497 tm.tm_hour, tm.tm_min, tm.tm_sec);
498 __putstr(tstr);
499 }
501 void printk(const char *fmt, ...)
502 {
503 static char buf[1024];
504 static int start_of_line = 1, do_print;
506 va_list args;
507 char *p, *q;
508 unsigned long flags;
510 /* console_lock can be acquired recursively from __printk_ratelimit(). */
511 local_irq_save(flags);
512 spin_lock_recursive(&console_lock);
514 va_start(args, fmt);
515 (void)vsnprintf(buf, sizeof(buf), fmt, args);
516 va_end(args);
518 p = buf;
520 while ( (q = strchr(p, '\n')) != NULL )
521 {
522 *q = '\0';
523 if ( start_of_line )
524 do_print = printk_prefix_check(p, &p);
525 if ( do_print )
526 {
527 if ( start_of_line )
528 printk_start_of_line();
529 __putstr(p);
530 __putstr("\n");
531 }
532 start_of_line = 1;
533 p = q + 1;
534 }
536 if ( *p != '\0' )
537 {
538 if ( start_of_line )
539 do_print = printk_prefix_check(p, &p);
540 if ( do_print )
541 {
542 if ( start_of_line )
543 printk_start_of_line();
544 __putstr(p);
545 }
546 start_of_line = 0;
547 }
549 spin_unlock_recursive(&console_lock);
550 local_irq_restore(flags);
551 }
553 void __init console_init_preirq(void)
554 {
555 char *p;
557 serial_init_preirq();
559 /* Where should console output go? */
560 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
561 {
562 if ( *p == ',' )
563 p++;
564 if ( !strncmp(p, "vga", 3) )
565 vga_init();
566 else if ( strncmp(p, "com", 3) ||
567 (sercon_handle = serial_parse_handle(p)) == -1 )
568 {
569 char *q = strchr(p, ',');
570 if ( q != NULL )
571 *q = '\0';
572 printk("Bad console= option '%s'\n", p);
573 if ( q != NULL )
574 *q = ',';
575 }
576 }
578 serial_set_rx_handler(sercon_handle, serial_rx);
580 /* HELLO WORLD --- start-of-day banner text. */
581 spin_lock(&console_lock);
582 __putstr(xen_banner());
583 spin_unlock(&console_lock);
584 printk("Xen version %d.%d%s (%s@%s) (%s) %s\n",
585 xen_major_version(), xen_minor_version(), xen_extra_version(),
586 xen_compile_by(), xen_compile_domain(),
587 xen_compiler(), xen_compile_date());
588 printk("Latest ChangeSet: %s\n", xen_changeset());
590 if ( opt_sync_console )
591 {
592 serial_start_sync(sercon_handle);
593 add_taint(TAINT_SYNC_CONSOLE);
594 printk("Console output is synchronous.\n");
595 }
596 }
598 void __init console_init_postirq(void)
599 {
600 char *ring;
601 unsigned int i;
603 serial_init_postirq();
605 /* Round size down to a power of two. */
606 while ( opt_conring_size & (opt_conring_size - 1) )
607 opt_conring_size &= opt_conring_size - 1;
608 if ( opt_conring_size < conring_size )
609 return;
611 ring = xmalloc_bytes(opt_conring_size);
612 if ( ring == NULL )
613 {
614 printk("Unable to allocate console ring of %u bytes.\n",
615 opt_conring_size);
616 return;
617 }
619 spin_lock_irq(&console_lock);
620 for ( i = conringc ; i != conringp; i++ )
621 ring[i & (opt_conring_size - 1)] = conring[i & (conring_size - 1)];
622 conring_size = opt_conring_size;
623 conring = ring;
624 spin_unlock_irq(&console_lock);
626 printk("Allocated console ring of %u bytes.\n", opt_conring_size);
627 }
629 void __init console_endboot(void)
630 {
631 int i, j;
633 printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
634 if ( xenlog_upper_thresh != xenlog_lower_thresh )
635 printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
636 printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
637 if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
638 printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
639 printk("\n");
641 if ( opt_sync_console )
642 {
643 printk("**********************************************\n");
644 printk("******* WARNING: CONSOLE OUTPUT IS SYNCHRONOUS\n");
645 printk("******* This option is intended to aid debugging "
646 "of Xen by ensuring\n");
647 printk("******* that all output is synchronously delivered "
648 "on the serial line.\n");
649 printk("******* However it can introduce SIGNIFICANT latencies "
650 "and affect\n");
651 printk("******* timekeeping. It is NOT recommended for "
652 "production use!\n");
653 printk("**********************************************\n");
654 for ( i = 0; i < 3; i++ )
655 {
656 printk("%d... ", 3-i);
657 for ( j = 0; j < 100; j++ )
658 {
659 process_pending_timers();
660 mdelay(10);
661 }
662 }
663 printk("\n");
664 }
666 vga_endboot();
668 /*
669 * If user specifies so, we fool the switch routine to redirect input
670 * straight back to Xen. I use this convoluted method so we still print
671 * a useful 'how to switch' message.
672 */
673 if ( opt_conswitch[1] == 'x' )
674 xen_rx = !xen_rx;
676 /* Serial input is directed to DOM0 by default. */
677 switch_serial_input();
678 }
680 int console_has(const char *device)
681 {
682 char *p;
684 for ( p = opt_console; p != NULL; p = strchr(p, ',') )
685 {
686 if ( *p == ',' )
687 p++;
688 if ( strncmp(p, device, strlen(device)) == 0 )
689 return 1;
690 }
692 return 0;
693 }
695 void console_start_log_everything(void)
696 {
697 serial_start_log_everything(sercon_handle);
698 atomic_inc(&print_everything);
699 }
701 void console_end_log_everything(void)
702 {
703 serial_end_log_everything(sercon_handle);
704 atomic_dec(&print_everything);
705 }
707 void console_force_unlock(void)
708 {
709 spin_lock_init(&console_lock);
710 serial_force_unlock(sercon_handle);
711 console_locks_busted = 1;
712 console_start_sync();
713 }
715 void console_force_lock(void)
716 {
717 spin_lock(&console_lock);
718 }
720 void console_start_sync(void)
721 {
722 atomic_inc(&print_everything);
723 serial_start_sync(sercon_handle);
724 }
726 void console_end_sync(void)
727 {
728 serial_end_sync(sercon_handle);
729 atomic_dec(&print_everything);
730 }
732 void console_putc(char c)
733 {
734 serial_putc(sercon_handle, c);
735 }
737 int console_getc(void)
738 {
739 return serial_getc(sercon_handle);
740 }
742 /*
743 * printk rate limiting, lifted from Linux.
744 *
745 * This enforces a rate limit: not more than one kernel message
746 * every printk_ratelimit_ms (millisecs).
747 */
748 int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
749 {
750 static DEFINE_SPINLOCK(ratelimit_lock);
751 static unsigned long toks = 10 * 5 * 1000;
752 static unsigned long last_msg;
753 static int missed;
754 unsigned long flags;
755 unsigned long long now = NOW(); /* ns */
756 unsigned long ms;
758 do_div(now, 1000000);
759 ms = (unsigned long)now;
761 spin_lock_irqsave(&ratelimit_lock, flags);
762 toks += ms - last_msg;
763 last_msg = ms;
764 if ( toks > (ratelimit_burst * ratelimit_ms))
765 toks = ratelimit_burst * ratelimit_ms;
766 if ( toks >= ratelimit_ms )
767 {
768 int lost = missed;
769 missed = 0;
770 toks -= ratelimit_ms;
771 spin_unlock(&ratelimit_lock);
772 if ( lost )
773 {
774 char lost_str[8];
775 snprintf(lost_str, sizeof(lost_str), "%d", lost);
776 /* console_lock may already be acquired by printk(). */
777 spin_lock_recursive(&console_lock);
778 printk_start_of_line();
779 __putstr("printk: ");
780 __putstr(lost_str);
781 __putstr(" messages suppressed.\n");
782 spin_unlock_recursive(&console_lock);
783 }
784 local_irq_restore(flags);
785 return 1;
786 }
787 missed++;
788 spin_unlock_irqrestore(&ratelimit_lock, flags);
789 return 0;
790 }
792 /* minimum time in ms between messages */
793 int printk_ratelimit_ms = 5 * 1000;
795 /* number of messages we send before ratelimiting */
796 int printk_ratelimit_burst = 10;
798 int printk_ratelimit(void)
799 {
800 return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
801 }
803 /*
804 * **************************************************************
805 * *************** Serial console ring buffer *******************
806 * **************************************************************
807 */
809 #ifdef DEBUG_TRACE_DUMP
811 /* Send output direct to console, or buffer it? */
812 static volatile int debugtrace_send_to_console;
814 static char *debugtrace_buf; /* Debug-trace buffer */
815 static unsigned int debugtrace_prd; /* Producer index */
816 static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
817 static unsigned int debugtrace_used;
818 static DEFINE_SPINLOCK(debugtrace_lock);
819 integer_param("debugtrace", debugtrace_kilobytes);
821 static void debugtrace_dump_worker(void)
822 {
823 if ( (debugtrace_bytes == 0) || !debugtrace_used )
824 return;
826 printk("debugtrace_dump() starting\n");
828 /* Print oldest portion of the ring. */
829 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
830 sercon_puts(&debugtrace_buf[debugtrace_prd]);
832 /* Print youngest portion of the ring. */
833 debugtrace_buf[debugtrace_prd] = '\0';
834 sercon_puts(&debugtrace_buf[0]);
836 memset(debugtrace_buf, '\0', debugtrace_bytes);
838 printk("debugtrace_dump() finished\n");
839 }
841 static void debugtrace_toggle(void)
842 {
843 unsigned long flags;
845 watchdog_disable();
846 spin_lock_irqsave(&debugtrace_lock, flags);
848 /*
849 * Dump the buffer *before* toggling, in case the act of dumping the
850 * buffer itself causes more printk() invocations.
851 */
852 printk("debugtrace_printk now writing to %s.\n",
853 !debugtrace_send_to_console ? "console": "buffer");
854 if ( !debugtrace_send_to_console )
855 debugtrace_dump_worker();
857 debugtrace_send_to_console = !debugtrace_send_to_console;
859 spin_unlock_irqrestore(&debugtrace_lock, flags);
860 watchdog_enable();
862 }
864 void debugtrace_dump(void)
865 {
866 unsigned long flags;
868 watchdog_disable();
869 spin_lock_irqsave(&debugtrace_lock, flags);
871 debugtrace_dump_worker();
873 spin_unlock_irqrestore(&debugtrace_lock, flags);
874 watchdog_enable();
875 }
877 void debugtrace_printk(const char *fmt, ...)
878 {
879 static char buf[1024];
880 static u32 count;
882 va_list args;
883 char *p;
884 unsigned long flags;
886 if ( debugtrace_bytes == 0 )
887 return;
889 debugtrace_used = 1;
891 spin_lock_irqsave(&debugtrace_lock, flags);
893 ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
895 snprintf(buf, sizeof(buf), "%u ", ++count);
897 va_start(args, fmt);
898 (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, args);
899 va_end(args);
901 if ( debugtrace_send_to_console )
902 {
903 serial_puts(sercon_handle, buf);
904 }
905 else
906 {
907 for ( p = buf; *p != '\0'; p++ )
908 {
909 debugtrace_buf[debugtrace_prd++] = *p;
910 /* Always leave a nul byte at the end of the buffer. */
911 if ( debugtrace_prd == (debugtrace_bytes - 1) )
912 debugtrace_prd = 0;
913 }
914 }
916 spin_unlock_irqrestore(&debugtrace_lock, flags);
917 }
919 static void debugtrace_key(unsigned char key)
920 {
921 debugtrace_toggle();
922 }
924 static int __init debugtrace_init(void)
925 {
926 int order;
927 unsigned int kbytes, bytes;
929 /* Round size down to next power of two. */
930 while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
931 debugtrace_kilobytes = kbytes;
933 bytes = debugtrace_kilobytes << 10;
934 if ( bytes == 0 )
935 return 0;
937 order = get_order_from_bytes(bytes);
938 debugtrace_buf = alloc_xenheap_pages(order, 0);
939 ASSERT(debugtrace_buf != NULL);
941 memset(debugtrace_buf, '\0', bytes);
943 debugtrace_bytes = bytes;
945 register_keyhandler(
946 'T', debugtrace_key, "toggle debugtrace to console/buffer");
948 return 0;
949 }
950 __initcall(debugtrace_init);
952 #endif /* !NDEBUG */
955 /*
956 * **************************************************************
957 * *************** Debugging/tracing/error-report ***************
958 * **************************************************************
959 */
961 void panic(const char *fmt, ...)
962 {
963 va_list args;
964 unsigned long flags;
965 static DEFINE_SPINLOCK(lock);
966 static char buf[128];
968 debugtrace_dump();
970 /* Protects buf[] and ensure multi-line message prints atomically. */
971 spin_lock_irqsave(&lock, flags);
973 va_start(args, fmt);
974 (void)vsnprintf(buf, sizeof(buf), fmt, args);
975 va_end(args);
977 console_start_sync();
978 printk("\n****************************************\n");
979 printk("Panic on CPU %d:\n", smp_processor_id());
980 printk("%s", buf);
981 printk("****************************************\n\n");
982 if ( opt_noreboot )
983 printk("Manual reset required ('noreboot' specified)\n");
984 else
985 printk("Reboot in five seconds...\n");
987 spin_unlock_irqrestore(&lock, flags);
989 debugger_trap_immediate();
991 kexec_crash();
993 if ( opt_noreboot )
994 {
995 machine_halt();
996 }
997 else
998 {
999 watchdog_disable();
1000 machine_restart(5000);
1004 void __bug(char *file, int line)
1006 console_start_sync();
1007 printk("Xen BUG at %s:%d\n", file, line);
1008 dump_execution_state();
1009 panic("Xen BUG at %s:%d\n", file, line);
1010 for ( ; ; ) ;
1013 void __warn(char *file, int line)
1015 printk("Xen WARN at %s:%d\n", file, line);
1016 dump_execution_state();
1020 /*
1021 * **************************************************************
1022 * ****************** Console suspend/resume ********************
1023 * **************************************************************
1024 */
1026 static void suspend_steal_fn(const char *str) { }
1027 static int suspend_steal_id;
1029 int console_suspend(void)
1031 suspend_steal_id = console_steal(sercon_handle, suspend_steal_fn);
1032 serial_suspend();
1033 return 0;
1036 int console_resume(void)
1038 serial_resume();
1039 console_giveback(suspend_steal_id);
1040 return 0;
1043 /*
1044 * Local variables:
1045 * mode: C
1046 * c-set-style: "BSD"
1047 * c-basic-offset: 4
1048 * tab-width: 4
1049 * indent-tabs-mode: nil
1050 * End:
1051 */