ia64/xen-unstable

changeset 3816:3f8766806bdd

bitkeeper revision 1.1159.261.2 (420e3014BpIA6NnJTdNQGkfIDMtzmQ)

Added an in-memory ring buffer to which serial console output
can be temporarily redirected. Mode is toggled by the "c" key on
the Xen console.
Nice hack for printk() intensive debugging modes.
When switching back to serial output, the current contents of the
buffer are first dumped. Buffer defaults to 128Kb, but size can
be set on the Xen boot command line.
author mafetter@fleming.research
date Sat Feb 12 16:34:28 2005 +0000 (2005-02-12)
parents 5f7e800d87da
children 2e88f4d9217f a5f68c9f9e52
files xen/common/keyhandler.c xen/drivers/char/console.c xen/include/asm-x86/config.h xen/include/xen/console.h xen/include/xen/serial.h
line diff
     1.1 --- a/xen/common/keyhandler.c	Sat Feb 12 14:38:06 2005 +0000
     1.2 +++ b/xen/common/keyhandler.c	Sat Feb 12 16:34:28 2005 +0000
     1.3 @@ -74,12 +74,14 @@ void register_irq_keyhandler(
     1.4  static void show_handlers(unsigned char key)
     1.5  {
     1.6      int i; 
     1.7 +    int buffer_enable = sercon_buffer_bypass();
     1.8      printk("'%c' pressed -> showing installed handlers\n", key);
     1.9      for ( i = 0; i < KEY_MAX; i++ ) 
    1.10          if ( key_table[i].u.handler != NULL ) 
    1.11              printk(" key '%c' (ascii '%02x') => %s\n", 
    1.12                     (i<33 || i>126)?(' '):(i),i,
    1.13                     key_table[i].desc);
    1.14 +    sercon_buffer_set(buffer_enable);
    1.15  }
    1.16  
    1.17  static void dump_registers(unsigned char key, struct xen_regs *regs)
    1.18 @@ -168,6 +170,10 @@ void initialize_keytable(void)
    1.19  #ifndef NDEBUG
    1.20      register_keyhandler(
    1.21          'o', audit_domains_key,  "audit domains >0 EXPERIMENTAL"); 
    1.22 +
    1.23 +    register_keyhandler(
    1.24 +        'c', sercon_buffer_toggle,
    1.25 +        "toggle serial console output vs ring buffer capture");
    1.26  #endif
    1.27  
    1.28  #ifdef PERF_COUNTERS
     2.1 --- a/xen/drivers/char/console.c	Sat Feb 12 14:38:06 2005 +0000
     2.2 +++ b/xen/drivers/char/console.c	Sat Feb 12 16:34:28 2005 +0000
     2.3 @@ -50,6 +50,17 @@ static int vgacon_enabled = 0;
     2.4  
     2.5  spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
     2.6  
     2.7 +#ifndef NDEBUG
     2.8 +static unsigned char *sercon_buffer      = NULL;
     2.9 +static unsigned char *sercon_buffer_end  = NULL;
    2.10 +static unsigned char *sercon_buffer_head = NULL;
    2.11 +static unsigned char *sercon_buffer_next = NULL;
    2.12 +
    2.13 +static unsigned int opt_sercon_buffer_size = 128; /* kbytes */
    2.14 +integer_param("conbuf", opt_sercon_buffer_size);
    2.15 +
    2.16 +static void sercon_buffer_puts(const unsigned char *s);
    2.17 +#endif
    2.18  
    2.19  /*
    2.20   * *******************************************************
    2.21 @@ -253,9 +264,13 @@ static void switch_serial_input(void)
    2.22      static char *input_str[2] = { "DOM0", "Xen" };
    2.23      xen_rx = !xen_rx;
    2.24      if ( SWITCH_CODE != 0 )
    2.25 +    {
    2.26 +        int buffer_enable = sercon_buffer_bypass();
    2.27          printk("*** Serial input -> %s "
    2.28                 "(type 'CTRL-%c' three times to switch input to %s).\n",
    2.29                 input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]);
    2.30 +        sercon_buffer_set(buffer_enable);
    2.31 +    }
    2.32  }
    2.33  
    2.34  static void __serial_rx(unsigned char c, struct xen_regs *regs)
    2.35 @@ -352,7 +367,14 @@ long do_console_io(int cmd, int count, c
    2.36  static inline void __putstr(const char *str)
    2.37  {
    2.38      int c;
    2.39 -    serial_puts(sercon_handle, str);
    2.40 +
    2.41 +#ifndef NDEBUG
    2.42 +    if ( sercon_handle & SERHND_BUFFERED )
    2.43 +        sercon_buffer_puts(str);
    2.44 +    else
    2.45 +#endif
    2.46 +        serial_puts(sercon_handle, str);
    2.47 +
    2.48      while ( (c = *str++) != '\0' )
    2.49      {
    2.50          putchar_console(c);
    2.51 @@ -462,16 +484,19 @@ void console_force_lock(void)
    2.52      spin_lock(&console_lock);
    2.53  }
    2.54  
    2.55 +// 09Feb2005: this appears to be unused...
    2.56  void console_putc(char c)
    2.57  {
    2.58      serial_putc(sercon_handle, c);
    2.59  }
    2.60  
    2.61 +// 09Feb2005: this appears to be unused...
    2.62  int console_getc(void)
    2.63  {
    2.64      return serial_getc(sercon_handle);
    2.65  }
    2.66  
    2.67 +// 09Feb2005: this appears to be unused...
    2.68  int irq_console_getc(void)
    2.69  {
    2.70      return irq_serial_getc(sercon_handle);
    2.71 @@ -480,6 +505,117 @@ int irq_console_getc(void)
    2.72  
    2.73  /*
    2.74   * **************************************************************
    2.75 + * *************** serial console ring buffer *******************
    2.76 + * **************************************************************
    2.77 + */
    2.78 +
    2.79 +#ifndef NDEBUG
    2.80 +static void sercon_buffer_putc(const unsigned char c)
    2.81 +{
    2.82 +    if ( !sercon_buffer )
    2.83 +        return;
    2.84 +    if ( !c )
    2.85 +        return;
    2.86 +
    2.87 +    if ( sercon_buffer_next == sercon_buffer_end )
    2.88 +    {
    2.89 +        // buffer wrap-around case...
    2.90 +        sercon_buffer_head = sercon_buffer + 1;
    2.91 +        sercon_buffer_next = sercon_buffer;
    2.92 +    }
    2.93 +    if ( sercon_buffer_head == sercon_buffer_next + 1 )
    2.94 +    {
    2.95 +        // the buffer is already full...
    2.96 +        sercon_buffer_head++;
    2.97 +    }
    2.98 +    *sercon_buffer_next++ = c;
    2.99 +    *sercon_buffer_next = 0;
   2.100 +}
   2.101 +
   2.102 +static void sercon_buffer_puts(const unsigned char *s)
   2.103 +{
   2.104 +    // inefficient but simple...
   2.105 +    while ( *s )
   2.106 +        sercon_buffer_putc(*s++);
   2.107 +}
   2.108 +
   2.109 +static void sercon_buffer_reset(void)
   2.110 +{
   2.111 +    sercon_buffer_head = sercon_buffer;
   2.112 +    sercon_buffer_next = sercon_buffer;
   2.113 +    sercon_buffer_head[0] = 0;
   2.114 +}
   2.115 +
   2.116 +static void sercon_buffer_flush(void)
   2.117 +{
   2.118 +    serial_puts(sercon_handle, sercon_buffer_head);
   2.119 +    if ( sercon_buffer_head != sercon_buffer )
   2.120 +        serial_puts(sercon_handle, sercon_buffer);
   2.121 +    sercon_buffer_reset();
   2.122 +}
   2.123 +
   2.124 +void _sercon_buffer_dump(void)
   2.125 +{
   2.126 +    sercon_buffer_flush();
   2.127 +    sercon_handle &= ~SERHND_BUFFERED;
   2.128 +}
   2.129 +
   2.130 +void sercon_buffer_toggle(unsigned char key)
   2.131 +{
   2.132 +    if ( !sercon_buffer )
   2.133 +    {
   2.134 +        printk("serial console buffer not allocated\n");
   2.135 +        return;
   2.136 +    }
   2.137 +
   2.138 +    if ( sercon_handle & SERHND_BUFFERED )
   2.139 +        sercon_buffer_flush();
   2.140 +    sercon_handle ^= SERHND_BUFFERED;
   2.141 +}
   2.142 +
   2.143 +void _sercon_buffer_set(int enable)
   2.144 +{
   2.145 +    if (enable)
   2.146 +        sercon_handle |= SERHND_BUFFERED;
   2.147 +    else
   2.148 +        sercon_handle &= ~SERHND_BUFFERED;
   2.149 +}
   2.150 +
   2.151 +int _sercon_buffer_bypass(void)
   2.152 +{
   2.153 +    int buffering = !!(sercon_handle & SERHND_BUFFERED);
   2.154 +    sercon_handle &= ~SERHND_BUFFERED;
   2.155 +
   2.156 +    return buffering;
   2.157 +}
   2.158 +
   2.159 +static int __init sercon_buffer_init(void)
   2.160 +{
   2.161 +    int order;
   2.162 +    int kbytes = opt_sercon_buffer_size;
   2.163 +
   2.164 +    if ( !kbytes )
   2.165 +        return 0;
   2.166 +
   2.167 +    order = get_order(kbytes * 1024);
   2.168 +    sercon_buffer = (void *)alloc_xenheap_pages(order);
   2.169 +    ASSERT( sercon_buffer );
   2.170 +
   2.171 +    sercon_buffer_end = sercon_buffer + kbytes*1024 - 1;
   2.172 +    *sercon_buffer_end = 0;
   2.173 +
   2.174 +    sercon_buffer_reset();
   2.175 +    sercon_handle |= SERHND_BUFFERED;
   2.176 +
   2.177 +    return 0;
   2.178 +}
   2.179 +__initcall(sercon_buffer_init);
   2.180 +
   2.181 +#endif /* not NDEBUG */
   2.182 +
   2.183 +
   2.184 +/*
   2.185 + * **************************************************************
   2.186   * *************** Debugging/tracing/error-report ***************
   2.187   * **************************************************************
   2.188   */
   2.189 @@ -508,6 +644,8 @@ void panic(const char *fmt, ...)
   2.190      spin_unlock_irqrestore(&console_lock, flags);
   2.191  
   2.192      watchdog_on = 0;
   2.193 +    sercon_buffer_dump();
   2.194 +
   2.195      mdelay(5000);
   2.196      machine_restart(0);
   2.197  }
     3.1 --- a/xen/include/asm-x86/config.h	Sat Feb 12 14:38:06 2005 +0000
     3.2 +++ b/xen/include/asm-x86/config.h	Sat Feb 12 16:34:28 2005 +0000
     3.3 @@ -99,10 +99,19 @@ extern void __out_of_line_bug(int line) 
     3.4  #define out_of_line_bug() __out_of_line_bug(__LINE__)
     3.5  #endif /* __ASSEMBLY__ */
     3.6  
     3.7 +#ifndef __ASSEMBLY__
     3.8 +#ifndef NDEBUG
     3.9 +extern void _sercon_buffer_dump(void);
    3.10 +#define sercon_buffer_dump() _sercon_buffer_dump()
    3.11 +#else
    3.12 +#define sercon_buffer_dump() ((void)0)
    3.13 +#endif
    3.14  #define BUG() do {					\
    3.15  	printk("BUG at %s:%d\n", __FILE__, __LINE__);	\
    3.16 -	__asm__ __volatile__("ud2");			\
    3.17 +        watchdog_on = 0;                                \
    3.18 +        sercon_buffer_dump();                           \
    3.19  } while (0)
    3.20 +#endif /* __ASSEMBLY__ */
    3.21  
    3.22  #if defined(__x86_64__)
    3.23  
     4.1 --- a/xen/include/xen/console.h	Sat Feb 12 14:38:06 2005 +0000
     4.2 +++ b/xen/include/xen/console.h	Sat Feb 12 16:34:28 2005 +0000
     4.3 @@ -26,4 +26,22 @@ void console_putc(char c);
     4.4  int console_getc(void);
     4.5  int irq_console_getc(void);
     4.6  
     4.7 +#ifdef NDEBUG
     4.8 +#define sercon_buffer_bypass() (0)
     4.9 +#else
    4.10 +#define sercon_buffer_bypass() _sercon_buffer_bypass()
    4.11 +int _sercon_buffer_bypass(void);
    4.12  #endif
    4.13 +
    4.14 +#ifdef NDEBUG
    4.15 +#define sercon_buffer_set(_enable) ((void)(0 && (_enable)));
    4.16 +#else
    4.17 +#define sercon_buffer_set(_enable) _sercon_buffer_set(_enable)
    4.18 +void _sercon_buffer_set(int enable);
    4.19 +#endif
    4.20 +
    4.21 +#ifndef NDEBUG
    4.22 +void sercon_buffer_toggle(unsigned char key);
    4.23 +#endif
    4.24 +
    4.25 +#endif /* __CONSOLE_H__ */
     5.1 --- a/xen/include/xen/serial.h	Sat Feb 12 14:38:06 2005 +0000
     5.2 +++ b/xen/include/xen/serial.h	Sat Feb 12 16:34:28 2005 +0000
     5.3 @@ -18,6 +18,7 @@
     5.4  #define SERHND_HI       (1<<1) /* Mux/demux each transferred char by MSB. */
     5.5  #define SERHND_LO       (1<<2) /* Ditto, except that the MSB is cleared.  */
     5.6  #define SERHND_COOKED   (1<<3) /* Newline/carriage-return translation?    */
     5.7 +#define SERHND_BUFFERED (1<<4) /* Console serial port ring buffered?      */
     5.8  
     5.9  /* Two-stage initialisation (before/after IRQ-subsystem initialisation). */
    5.10  void serial_init_stage1(void);