ia64/xen-unstable

changeset 11602:19b126974c1f

Use GDB 'O' packets for console output if the serial line is shared
and GDB is attached.

It may be necessary for gdb and the console to share a serial port.
This patch utilises the GDB protocol to encode console output.

Based on a patch from Tony Breeds <tony@bakeyournoodle.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Sat Sep 23 14:47:00 2006 +0100 (2006-09-23)
parents 828c0c89d830
children e4a496c2b2d1
files xen/common/gdbstub.c xen/drivers/char/console.c xen/include/xen/console.h xen/include/xen/gdbstub.h
line diff
     1.1 --- a/xen/common/gdbstub.c	Sat Sep 23 14:07:41 2006 +0100
     1.2 +++ b/xen/common/gdbstub.c	Sat Sep 23 14:47:00 2006 +0100
     1.3 @@ -357,6 +357,25 @@ gdb_cmd_write_mem(unsigned long addr, un
     1.4      gdb_send_packet(ctx);
     1.5  }
     1.6  
     1.7 +static void
     1.8 +gdbstub_attach(struct gdb_context *ctx)
     1.9 +{
    1.10 +    static void gdbstub_console_puts(const char *str);
    1.11 +    if ( ctx->currently_attached )
    1.12 +        return;    
    1.13 +    ctx->currently_attached = 1;
    1.14 +    ctx->console_steal_id = console_steal(ctx->serhnd, gdbstub_console_puts);
    1.15 +}
    1.16 +
    1.17 +static void
    1.18 +gdbstub_detach(struct gdb_context *ctx)
    1.19 +{
    1.20 +    if ( !ctx->currently_attached )
    1.21 +        return;
    1.22 +    ctx->currently_attached = 0;
    1.23 +    console_giveback(ctx->console_steal_id);
    1.24 +}
    1.25 +
    1.26  /* command dispatcher */
    1.27  static int 
    1.28  process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
    1.29 @@ -427,7 +446,7 @@ process_command(struct cpu_user_regs *re
    1.30          gdb_arch_read_reg(addr, regs, ctx);
    1.31          break;
    1.32      case 'D':
    1.33 -        ctx->currently_attached = 0;
    1.34 +        gdbstub_detach(ctx);
    1.35          gdb_send_reply("OK", ctx);
    1.36          /* fall through */
    1.37      case 'k':
    1.38 @@ -444,7 +463,7 @@ process_command(struct cpu_user_regs *re
    1.39               ctx->in_buf[1] )
    1.40              addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long));
    1.41          if ( ctx->in_buf[0] != 'D' )
    1.42 -            ctx->currently_attached = 1;
    1.43 +            gdbstub_attach(ctx);
    1.44          resume = 1;
    1.45          gdb_arch_resume(regs, addr, type, ctx);
    1.46          break;
    1.47 @@ -459,17 +478,29 @@ process_command(struct cpu_user_regs *re
    1.48  
    1.49  static struct gdb_context
    1.50  __gdb_ctx = {
    1.51 -    .serhnd             = -1,
    1.52 -    .currently_attached = 0,
    1.53 -    .running            = ATOMIC_INIT(1),
    1.54 -    .connected          = 0,
    1.55 -    .signum             = 1,
    1.56 -    .in_bytes           = 0,
    1.57 -    .out_offset         = 0,
    1.58 -    .out_csum           = 0,
    1.59 +    .serhnd  = -1,
    1.60 +    .running = ATOMIC_INIT(1),
    1.61 +    .signum  = 1
    1.62  };
    1.63  static struct gdb_context *gdb_ctx = &__gdb_ctx;
    1.64  
    1.65 +static void
    1.66 +gdbstub_console_puts(const char *str)
    1.67 +{
    1.68 +    const char *p;
    1.69 +
    1.70 +    gdb_start_packet(gdb_ctx);
    1.71 +    gdb_write_to_packet_char('O', gdb_ctx);
    1.72 +
    1.73 +    for ( p = str; *p != '\0'; p++ )
    1.74 +    {
    1.75 +        gdb_write_to_packet_char(hex2char((*p>>4) & 0x0f), gdb_ctx );
    1.76 +        gdb_write_to_packet_char(hex2char((*p) & 0x0f), gdb_ctx );
    1.77 +    }
    1.78 +
    1.79 +    gdb_send_packet(gdb_ctx);
    1.80 +}
    1.81 +
    1.82  /* trap handler: main entry point */
    1.83  int 
    1.84  __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
    1.85 @@ -525,6 +556,7 @@ int
    1.86  
    1.87      gdb_arch_enter(regs);
    1.88      gdb_ctx->signum = gdb_arch_signal_num(regs, cookie);
    1.89 +
    1.90      /* If gdb is already attached, tell it we've stopped again. */
    1.91      if ( gdb_ctx->currently_attached )
    1.92      {
     2.1 --- a/xen/drivers/char/console.c	Sat Sep 23 14:07:41 2006 +0100
     2.2 +++ b/xen/drivers/char/console.c	Sat Sep 23 14:47:00 2006 +0100
     2.3 @@ -116,6 +116,34 @@ long read_console_ring(XEN_GUEST_HANDLE(
     2.4  static char serial_rx_ring[SERIAL_RX_SIZE];
     2.5  static unsigned int serial_rx_cons, serial_rx_prod;
     2.6  
     2.7 +static void (*serial_steal_fn)(const char *);
     2.8 +
     2.9 +int console_steal(int handle, void (*fn)(const char *))
    2.10 +{
    2.11 +    if ( (handle == -1) || (handle != sercon_handle) )
    2.12 +        return 0;
    2.13 +
    2.14 +    if ( serial_steal_fn == NULL )
    2.15 +        return -EBUSY;
    2.16 +
    2.17 +    serial_steal_fn = fn;
    2.18 +    return 1;
    2.19 +}
    2.20 +
    2.21 +void console_giveback(int id)
    2.22 +{
    2.23 +    if ( id == 1 )
    2.24 +        serial_steal_fn = NULL;
    2.25 +}
    2.26 +
    2.27 +static void sercon_puts(const char *s)
    2.28 +{
    2.29 +    if ( serial_steal_fn != NULL )
    2.30 +        (*serial_steal_fn)(s);
    2.31 +    else
    2.32 +        serial_puts(sercon_handle, s);
    2.33 +}
    2.34 +
    2.35  /* CTRL-<switch_char> switches input direction between Xen and DOM0. */
    2.36  #define SWITCH_CODE (opt_conswitch[0]-'a'+1)
    2.37  static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
    2.38 @@ -191,7 +219,7 @@ static long guest_console_write(XEN_GUES
    2.39              return -EFAULT;
    2.40          kbuf[kcount] = '\0';
    2.41  
    2.42 -        serial_puts(sercon_handle, kbuf);
    2.43 +        sercon_puts(kbuf);
    2.44  
    2.45          for ( kptr = kbuf; *kptr != '\0'; kptr++ )
    2.46              vga_putchar(*kptr);
    2.47 @@ -257,7 +285,7 @@ static inline void __putstr(const char *
    2.48  {
    2.49      int c;
    2.50  
    2.51 -    serial_puts(sercon_handle, str);
    2.52 +    sercon_puts(str);
    2.53  
    2.54      while ( (c = *str++) != '\0' )
    2.55      {
    2.56 @@ -448,11 +476,11 @@ static void debugtrace_dump_worker(void)
    2.57  
    2.58      /* Print oldest portion of the ring. */
    2.59      ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
    2.60 -    serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
    2.61 +    sercon_puts(&debugtrace_buf[debugtrace_prd]);
    2.62  
    2.63      /* Print youngest portion of the ring. */
    2.64      debugtrace_buf[debugtrace_prd] = '\0';
    2.65 -    serial_puts(sercon_handle, &debugtrace_buf[0]);
    2.66 +    sercon_puts(&debugtrace_buf[0]);
    2.67  
    2.68      memset(debugtrace_buf, '\0', debugtrace_bytes);
    2.69  
     3.1 --- a/xen/include/xen/console.h	Sat Sep 23 14:07:41 2006 +0100
     3.2 +++ b/xen/include/xen/console.h	Sat Sep 23 14:47:00 2006 +0100
     3.3 @@ -26,4 +26,13 @@ void console_force_lock(void);
     3.4  void console_start_sync(void);
     3.5  void console_end_sync(void);
     3.6  
     3.7 +/*
     3.8 + * Steal output from the console. Returns +ve identifier, else -ve error.
     3.9 + * Takes the handle of the serial line to steal, and steal callback function.
    3.10 + */
    3.11 +int console_steal(int handle, void (*fn)(const char *));
    3.12 +
    3.13 +/* Give back stolen console. Takes the identifier returned by console_steal. */
    3.14 +void console_giveback(int id);
    3.15 +
    3.16  #endif /* __CONSOLE_H__ */
     4.1 --- a/xen/include/xen/gdbstub.h	Sat Sep 23 14:07:41 2006 +0100
     4.2 +++ b/xen/include/xen/gdbstub.h	Sat Sep 23 14:47:00 2006 +0100
     4.3 @@ -33,7 +33,8 @@ char str2hex(const char *str);
     4.4  unsigned long str2ulong(const char *str, unsigned long bytes);
     4.5  
     4.6  struct gdb_context {
     4.7 -    int                 serhnd;
     4.8 +    int                 serhnd;           /* handle on our serial line */
     4.9 +    int                 console_steal_id; /* handle on stolen console */
    4.10      int                 currently_attached:1;
    4.11      atomic_t            running;
    4.12      unsigned long       connected;