source: trunk/packages/xen-3.1/xen-3.1/xen/drivers/char/console.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 24.1 KB
Line 
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 */
12
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
36/* console: comma-separated list of console outputs. */
37static char opt_console[30] = OPT_CONSOLE_STR;
38string_param("console", opt_console);
39
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 */
44static unsigned char opt_conswitch[5] = "a";
45string_param("conswitch", opt_conswitch);
46
47/* sync_console: force synchronous console output (useful for debugging). */
48static int opt_sync_console;
49boolean_param("sync_console", opt_sync_console);
50
51/* console_to_ring: send guest (incl. dom 0) console data to console ring. */
52static int opt_console_to_ring;
53boolean_param("console_to_ring", opt_console_to_ring);
54
55#define CONRING_SIZE 16384
56#define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
57static char conring[CONRING_SIZE];
58static unsigned int conringc, conringp;
59
60static char printk_prefix[16] = "";
61
62static int sercon_handle = -1;
63
64static DEFINE_SPINLOCK(console_lock);
65
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 */
96
97static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
98static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
99static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
100static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
101
102static void parse_loglvl(char *s);
103static void parse_guest_loglvl(char *s);
104
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 */
113custom_param("loglvl", parse_loglvl);
114custom_param("guest_loglvl", parse_guest_loglvl);
115
116static atomic_t print_everything = ATOMIC_INIT(0);
117
118#define ___parse_loglvl(s, ps, lvlstr, lvlnum)          \
119    if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) {    \
120        *(ps) = (s) + strlen(lvlstr);                   \
121        return (lvlnum);                                \
122    }
123
124static 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}
134
135static 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}
143
144static void parse_loglvl(char *s)
145{
146    _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
147}
148
149static void parse_guest_loglvl(char *s)
150{
151    _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
152}
153
154static 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}
166
167/*
168 * ********************************************************
169 * *************** ACCESS TO CONSOLE RING *****************
170 * ********************************************************
171 */
172
173static 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}
179
180long 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;
184
185    max   = *pcount;
186    sofar = 0;
187
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    }
202
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    }
212
213    *pcount = sofar;
214    return 0;
215}
216
217
218/*
219 * *******************************************************
220 * *************** ACCESS TO SERIAL LINE *****************
221 * *******************************************************
222 */
223
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))
227static char serial_rx_ring[SERIAL_RX_SIZE];
228static unsigned int serial_rx_cons, serial_rx_prod;
229
230static void (*serial_steal_fn)(const char *);
231
232int console_steal(int handle, void (*fn)(const char *))
233{
234    if ( (handle == -1) || (handle != sercon_handle) )
235        return 0;
236
237    if ( serial_steal_fn != NULL )
238        return -EBUSY;
239
240    serial_steal_fn = fn;
241    return 1;
242}
243
244void console_giveback(int id)
245{
246    if ( id == 1 )
247        serial_steal_fn = NULL;
248}
249
250static 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}
257
258/* CTRL-<switch_char> switches input direction between Xen and DOM0. */
259#define SWITCH_CODE (opt_conswitch[0]-'a'+1)
260static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
261
262static 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}
273
274static void __serial_rx(char c, struct cpu_user_regs *regs)
275{
276    if ( xen_rx )
277        return handle_keypress(c, regs);
278
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}
285
286static void serial_rx(char c, struct cpu_user_regs *regs)
287{
288    static int switch_code_count = 0;
289
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    }
304
305    /* Finally process the just-received character. */
306    __serial_rx(c, regs);
307}
308
309static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
310{
311    char kbuf[128], *kptr;
312    int kcount;
313
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        }
322
323        if ( hypercall_preempt_check() )
324            return hypercall_create_continuation(
325                __HYPERVISOR_console_io, "iih",
326                CONSOLEIO_write, count, buffer);
327
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';
332
333        sercon_puts(kbuf);
334
335        for ( kptr = kbuf; *kptr != '\0'; kptr++ )
336        {
337            vga_putchar(*kptr);
338            if ( opt_console_to_ring )
339                putchar_console_ring(*kptr);
340        }
341
342        if ( opt_console_to_ring )
343            send_guest_global_virq(dom0, VIRQ_CON_RING);
344
345        guest_handle_add_offset(buffer, kcount);
346        count -= kcount;
347    }
348
349    return 0;
350}
351
352long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
353{
354    long rc;
355    unsigned int idx, len;
356
357#ifndef VERBOSE
358    /* Only domain 0 may access the emergency console. */
359    if ( current->domain->domain_id != 0 )
360        return -EPERM;
361#endif
362
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    }
391
392    return rc;
393}
394
395
396/*
397 * *****************************************************
398 * *************** GENERIC CONSOLE I/O *****************
399 * *****************************************************
400 */
401
402static void __putstr(const char *str)
403{
404    int c;
405
406    sercon_puts(str);
407
408    while ( (c = *str++) != '\0' )
409    {
410        vga_putchar(c);
411        putchar_console_ring(c);
412    }
413
414    send_guest_global_virq(dom0, VIRQ_CON_RING);
415}
416
417static 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;
422
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    }
439
440    if ( loglvl == -1 )
441        loglvl = XENLOG_DEFAULT;
442
443    *pp = p;
444
445    return ((atomic_read(&print_everything) != 0) ||
446            (loglvl < lower_thresh) ||
447            ((loglvl < upper_thresh) && printk_ratelimit()));
448} 
449
450void printk(const char *fmt, ...)
451{
452    static char   buf[1024];
453    static int    start_of_line = 1, do_print;
454
455    va_list       args;
456    char         *p, *q;
457    unsigned long flags;
458
459    /* console_lock can be acquired recursively from __printk_ratelimit(). */
460    local_irq_save(flags);
461    spin_lock_recursive(&console_lock);
462
463    va_start(args, fmt);
464    (void)vsnprintf(buf, sizeof(buf), fmt, args);
465    va_end(args);       
466
467    p = buf;
468
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    }
484
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    }
497
498    spin_unlock_recursive(&console_lock);
499    local_irq_restore(flags);
500}
501
502void set_printk_prefix(const char *prefix)
503{
504    safe_strcpy(printk_prefix, prefix);
505}
506
507void init_console(void)
508{
509    char *p;
510
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    }
521
522    serial_set_rx_handler(sercon_handle, serial_rx);
523
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) ");
534
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}
542
543void console_endboot(void)
544{
545    int i, j;
546
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");
554
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    }
579
580    vga_endboot();
581
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;
589
590    /* Serial input is directed to DOM0 by default. */
591    switch_serial_input();
592}
593
594void console_start_log_everything(void)
595{
596    atomic_inc(&print_everything);
597}
598
599void console_end_log_everything(void)
600{
601    atomic_dec(&print_everything);
602}
603
604void console_force_unlock(void)
605{
606    spin_lock_init(&console_lock);
607    serial_force_unlock(sercon_handle);
608    console_start_sync();
609}
610
611void console_force_lock(void)
612{
613    spin_lock(&console_lock);
614}
615
616void console_start_sync(void)
617{
618    console_start_log_everything();
619    serial_start_sync(sercon_handle);
620}
621
622void console_end_sync(void)
623{
624    serial_end_sync(sercon_handle);
625    console_end_log_everything();
626}
627
628void console_putc(char c)
629{
630    serial_putc(sercon_handle, c);
631}
632
633int console_getc(void)
634{
635    return serial_getc(sercon_handle);
636}
637
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 */
644int __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;
653
654    do_div(now, 1000000);
655    ms = (unsigned long)now;
656
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}
687
688/* minimum time in ms between messages */
689int printk_ratelimit_ms = 5 * 1000;
690
691/* number of messages we send before ratelimiting */
692int printk_ratelimit_burst = 10;
693
694int printk_ratelimit(void)
695{
696    return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
697}
698
699/*
700 * **************************************************************
701 * *************** Serial console ring buffer *******************
702 * **************************************************************
703 */
704
705#ifdef DEBUG_TRACE_DUMP
706
707/* Send output direct to console, or buffer it? */
708static volatile int debugtrace_send_to_console;
709
710static char        *debugtrace_buf; /* Debug-trace buffer */
711static unsigned int debugtrace_prd; /* Producer index     */
712static unsigned int debugtrace_kilobytes = 128, debugtrace_bytes;
713static unsigned int debugtrace_used;
714static DEFINE_SPINLOCK(debugtrace_lock);
715integer_param("debugtrace", debugtrace_kilobytes);
716
717static void debugtrace_dump_worker(void)
718{
719    if ( (debugtrace_bytes == 0) || !debugtrace_used )
720        return;
721
722    printk("debugtrace_dump() starting\n");
723
724    /* Print oldest portion of the ring. */
725    ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
726    sercon_puts(&debugtrace_buf[debugtrace_prd]);
727
728    /* Print youngest portion of the ring. */
729    debugtrace_buf[debugtrace_prd] = '\0';
730    sercon_puts(&debugtrace_buf[0]);
731
732    memset(debugtrace_buf, '\0', debugtrace_bytes);
733
734    printk("debugtrace_dump() finished\n");
735}
736
737static void debugtrace_toggle(void)
738{
739    unsigned long flags;
740
741    watchdog_disable();
742    spin_lock_irqsave(&debugtrace_lock, flags);
743
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();
752
753    debugtrace_send_to_console = !debugtrace_send_to_console;
754
755    spin_unlock_irqrestore(&debugtrace_lock, flags);
756    watchdog_enable();
757
758}
759
760void debugtrace_dump(void)
761{
762    unsigned long flags;
763
764    watchdog_disable();
765    spin_lock_irqsave(&debugtrace_lock, flags);
766
767    debugtrace_dump_worker();
768
769    spin_unlock_irqrestore(&debugtrace_lock, flags);
770    watchdog_enable();
771}
772
773void debugtrace_printk(const char *fmt, ...)
774{
775    static char    buf[1024];
776    static u32 count;
777
778    va_list       args;
779    char         *p;
780    unsigned long flags;
781
782    if ( debugtrace_bytes == 0 )
783        return;
784
785    debugtrace_used = 1;
786
787    spin_lock_irqsave(&debugtrace_lock, flags);
788
789    ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
790
791    snprintf(buf, sizeof(buf), "%u ", ++count);
792
793    va_start(args, fmt);
794    (void)vsnprintf(buf + strlen(buf), sizeof(buf), fmt, args);
795    va_end(args);
796
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    }
811
812    spin_unlock_irqrestore(&debugtrace_lock, flags);
813}
814
815static void debugtrace_key(unsigned char key)
816{
817    debugtrace_toggle();
818}
819
820static int __init debugtrace_init(void)
821{
822    int order;
823    unsigned int kbytes, bytes;
824
825    /* Round size down to next power of two. */
826    while ( (kbytes = (debugtrace_kilobytes & (debugtrace_kilobytes-1))) != 0 )
827        debugtrace_kilobytes = kbytes;
828
829    bytes = debugtrace_kilobytes << 10;
830    if ( bytes == 0 )
831        return 0;
832
833    order = get_order_from_bytes(bytes);
834    debugtrace_buf = alloc_xenheap_pages(order);
835    ASSERT(debugtrace_buf != NULL);
836
837    memset(debugtrace_buf, '\0', bytes);
838
839    debugtrace_bytes = bytes;
840
841    register_keyhandler(
842        'T', debugtrace_key, "toggle debugtrace to console/buffer");
843
844    return 0;
845}
846__initcall(debugtrace_init);
847
848#endif /* !NDEBUG */
849
850
851
852/*
853 * **************************************************************
854 * *************** Debugging/tracing/error-report ***************
855 * **************************************************************
856 */
857
858void panic(const char *fmt, ...)
859{
860    va_list args;
861    unsigned long flags;
862    static DEFINE_SPINLOCK(lock);
863    static char buf[128];
864   
865    debugtrace_dump();
866
867    /* Protects buf[] and ensure multi-line message prints atomically. */
868    spin_lock_irqsave(&lock, flags);
869
870    va_start(args, fmt);
871    (void)vsnprintf(buf, sizeof(buf), fmt, args);
872    va_end(args);
873
874    console_start_sync();
875    printk("\n****************************************\n");
876    printk("Panic on CPU %d:\n", smp_processor_id());
877    printk(buf);
878    printk("****************************************\n\n");
879    if ( opt_noreboot )
880        printk("Manual reset required ('noreboot' specified)\n");
881    else
882        printk("Reboot in five seconds...\n");
883
884    spin_unlock_irqrestore(&lock, flags);
885
886    debugger_trap_immediate();
887
888    kexec_crash();
889
890    if ( opt_noreboot )
891    {
892        machine_halt();
893    }
894    else
895    {
896        watchdog_disable();
897        mdelay(5000);
898        machine_restart(NULL);
899    }
900}
901
902void __bug(char *file, int line)
903{
904    console_start_sync();
905    printk("Xen BUG at %s:%d\n", file, line);
906    dump_execution_state();
907    panic("Xen BUG at %s:%d\n", file, line);
908    for ( ; ; ) ;
909}
910
911void __warn(char *file, int line)
912{
913    printk("Xen WARN at %s:%d\n", file, line);
914    dump_execution_state();
915}
916
917/*
918 * Local variables:
919 * mode: C
920 * c-set-style: "BSD"
921 * c-basic-offset: 4
922 * tab-width: 4
923 * indent-tabs-mode: nil
924 * End:
925 */
926
Note: See TracBrowser for help on using the repository browser.