aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2007-12-27 12:53:57 +0000
committerKeir Fraser <keir.fraser@citrix.com>2007-12-27 12:53:57 +0000
commitfa56aa1711ef1a57d66cf99b599129459a808ef5 (patch)
tree186756efbfd8c4a77c7410482df9387edf6984a8
parente2d6a0473bbffb26177c0d4bb3ddbe6268c3ca70 (diff)
downloadxen-fa56aa1711ef1a57d66cf99b599129459a808ef5.tar.gz
xen-fa56aa1711ef1a57d66cf99b599129459a808ef5.tar.bz2
xen-fa56aa1711ef1a57d66cf99b599129459a808ef5.zip
gdbstub: Various fixes.
Highlights: - Removed panics and smp stop calls in favour of an smp pause mechanism. - Added x86_64 register mapping for gdb serial protocol support. Signed-off-by: Dan Doucette <doucette.daniel@gmail.com>
-rw-r--r--xen/arch/ia64/xen/gdbstub.c7
-rw-r--r--xen/arch/powerpc/gdbstub.c8
-rw-r--r--xen/arch/x86/gdbstub.c75
-rw-r--r--xen/arch/x86/traps.c14
-rw-r--r--xen/arch/x86/x86_32/Makefile2
-rw-r--r--xen/arch/x86/x86_32/gdbstub.c82
-rw-r--r--xen/arch/x86/x86_64/Makefile1
-rw-r--r--xen/arch/x86/x86_64/gdbstub.c151
-rw-r--r--xen/common/gdbstub.c155
-rw-r--r--xen/include/asm-x86/desc.h1
-rw-r--r--xen/include/xen/gdbstub.h3
11 files changed, 406 insertions, 93 deletions
diff --git a/xen/arch/ia64/xen/gdbstub.c b/xen/arch/ia64/xen/gdbstub.c
index 548ec6e51a..925d8ab508 100644
--- a/xen/arch/ia64/xen/gdbstub.c
+++ b/xen/arch/ia64/xen/gdbstub.c
@@ -62,6 +62,13 @@ gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx)
}
void
+gdb_arch_write_reg(unsigned long regnum, unsigned long val,
+ struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+ gdb_send_reply("", ctx);
+}
+
+void
gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf,
struct gdb_context *ctx)
{
diff --git a/xen/arch/powerpc/gdbstub.c b/xen/arch/powerpc/gdbstub.c
index dd9d4885ee..d512a9cbcd 100644
--- a/xen/arch/powerpc/gdbstub.c
+++ b/xen/arch/powerpc/gdbstub.c
@@ -132,6 +132,14 @@ gdb_arch_read_reg_array(struct cpu_user_regs *state, struct gdb_context *ctx)
gdb_send_packet(ctx);
}
+void
+gdb_arch_write_reg(unsigned long regnum, unsigned long val,
+ struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+ unimplemented();
+ gdb_send_reply("", ctx);
+}
+
void
gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char *buf,
struct gdb_context *ctx)
diff --git a/xen/arch/x86/gdbstub.c b/xen/arch/x86/gdbstub.c
index 3d0d0d0429..44165033d3 100644
--- a/xen/arch/x86/gdbstub.c
+++ b/xen/arch/x86/gdbstub.c
@@ -24,51 +24,7 @@
u16
gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long cookie)
{
- /* XXX */
- return 1;
-}
-
-void
-gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx)
-{
-#define GDB_REG(r) gdb_write_to_packet_hex(r, sizeof(r), ctx);
- GDB_REG(regs->eax);
- GDB_REG(regs->ecx);
- GDB_REG(regs->edx);
- GDB_REG(regs->ebx);
- GDB_REG(regs->esp);
- GDB_REG(regs->ebp);
- GDB_REG(regs->esi);
- GDB_REG(regs->edi);
- GDB_REG(regs->eip);
- GDB_REG(regs->eflags);
-#undef GDB_REG
-#define GDB_SEG_REG(s) gdb_write_to_packet_hex(s, sizeof(u32), ctx);
- /* sizeof(segment) = 16bit */
- /* but gdb requires its return value as 32bit value */
- GDB_SEG_REG(regs->cs);
- GDB_SEG_REG(regs->ss);
- GDB_SEG_REG(regs->ds);
- GDB_SEG_REG(regs->es);
- GDB_SEG_REG(regs->fs);
- GDB_SEG_REG(regs->gs);
-#undef GDB_SEG_REG
- gdb_send_packet(ctx);
-}
-
-void
-gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf,
- struct gdb_context *ctx)
-{
- /* XXX TODO */
- gdb_send_reply("E02", ctx);
-}
-
-void
-gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs,
- struct gdb_context *ctx)
-{
- gdb_send_reply("", ctx);
+ return 5; /* TRAP signal. see include/gdb/signals.h */
}
/*
@@ -87,17 +43,6 @@ gdb_arch_copy_to_user(void *dest, const void *src, unsigned len)
return __copy_to_user(dest, src, len);
}
-void
-gdb_arch_resume(struct cpu_user_regs *regs,
- unsigned long addr, unsigned long type,
- struct gdb_context *ctx)
-{
- /* XXX */
- if (type == GDB_STEP) {
- gdb_send_reply("S01", ctx);
- }
-}
-
void
gdb_arch_print_state(struct cpu_user_regs *regs)
{
@@ -116,6 +61,24 @@ gdb_arch_exit(struct cpu_user_regs *regs)
/* nothing */
}
+void
+gdb_arch_resume(struct cpu_user_regs *regs,
+ unsigned long addr, unsigned long type,
+ struct gdb_context *ctx)
+{
+ if ( addr != -1UL )
+ regs->eip = addr;
+
+ regs->eflags &= ~X86_EFLAGS_TF;
+
+ /* Set eflags.RF to ensure we do not re-enter. */
+ regs->eflags |= X86_EFLAGS_RF;
+
+ /* Set the trap flag if we are single stepping. */
+ if ( type == GDB_STEP )
+ regs->eflags |= X86_EFLAGS_TF;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index e8aa866239..9e7ade8c90 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -806,9 +806,8 @@ asmlinkage void do_int3(struct cpu_user_regs *regs)
if ( !guest_mode(regs) )
{
- DEBUGGER_trap_fatal(TRAP_int3, regs);
- show_execution_state(regs);
- panic("FATAL TRAP: vector = 3 (Int3)\n");
+ debugger_trap_fatal(TRAP_int3, regs);
+ return;
}
do_guest_trap(TRAP_int3, regs, 0);
@@ -2690,11 +2689,6 @@ void set_intr_gate(unsigned int n, void *addr)
_set_gate(&idt_table[n], 14, 0, addr);
}
-void set_system_gate(unsigned int n, void *addr)
-{
- _set_gate(idt_table+n,14,3,addr);
-}
-
void set_tss_desc(unsigned int n, void *addr)
{
_set_tssldt_desc(
@@ -2759,8 +2753,8 @@ void __init trap_init(void)
set_intr_gate(TRAP_divide_error,&divide_error);
set_intr_gate(TRAP_debug,&debug);
set_intr_gate(TRAP_nmi,&nmi);
- set_system_gate(TRAP_int3,&int3); /* usable from all privileges */
- set_system_gate(TRAP_overflow,&overflow); /* usable from all privileges */
+ set_intr_gate(TRAP_int3,&int3); /* usable from all privileges */
+ set_intr_gate(TRAP_overflow,&overflow); /* usable from all privileges */
set_intr_gate(TRAP_bounds,&bounds);
set_intr_gate(TRAP_invalid_op,&invalid_op);
set_intr_gate(TRAP_no_device,&device_not_available);
diff --git a/xen/arch/x86/x86_32/Makefile b/xen/arch/x86/x86_32/Makefile
index eb311f93d6..0154c366ba 100644
--- a/xen/arch/x86/x86_32/Makefile
+++ b/xen/arch/x86/x86_32/Makefile
@@ -5,4 +5,6 @@ obj-y += mm.o
obj-y += seg_fixup.o
obj-y += traps.o
+obj-$(crash_debug) += gdbstub.o
+
obj-$(supervisor_mode_kernel) += supervisor_mode_kernel.o
diff --git a/xen/arch/x86/x86_32/gdbstub.c b/xen/arch/x86/x86_32/gdbstub.c
new file mode 100644
index 0000000000..b5f753da96
--- /dev/null
+++ b/xen/arch/x86/x86_32/gdbstub.c
@@ -0,0 +1,82 @@
+/*
+ * x86-specific gdb stub routines
+ * based on x86 cdb(xen/arch/x86/cdb.c), but Extensively modified.
+ *
+ * Copyright (C) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan. K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/debugger.h>
+
+void
+gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+#define GDB_REG(r) gdb_write_to_packet_hex(r, sizeof(r), ctx);
+ GDB_REG(regs->eax);
+ GDB_REG(regs->ecx);
+ GDB_REG(regs->edx);
+ GDB_REG(regs->ebx);
+ GDB_REG(regs->esp);
+ GDB_REG(regs->ebp);
+ GDB_REG(regs->esi);
+ GDB_REG(regs->edi);
+ GDB_REG(regs->eip);
+ GDB_REG(regs->eflags);
+#undef GDB_REG
+#define GDB_SEG_REG(s) gdb_write_to_packet_hex(s, sizeof(u32), ctx);
+ /* sizeof(segment) = 16bit */
+ /* but gdb requires its return value as 32bit value */
+ GDB_SEG_REG(regs->cs);
+ GDB_SEG_REG(regs->ss);
+ GDB_SEG_REG(regs->ds);
+ GDB_SEG_REG(regs->es);
+ GDB_SEG_REG(regs->fs);
+ GDB_SEG_REG(regs->gs);
+#undef GDB_SEG_REG
+ gdb_send_packet(ctx);
+}
+
+void
+gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf,
+ struct gdb_context *ctx)
+{
+ /* XXX TODO */
+ gdb_send_reply("E02", ctx);
+}
+
+void
+gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs,
+ struct gdb_context *ctx)
+{
+ gdb_send_reply("", ctx);
+}
+
+void
+gdb_arch_write_reg(unsigned long regnum, unsigned long val,
+ struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+ gdb_send_reply("", ctx);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/xen/arch/x86/x86_64/Makefile b/xen/arch/x86/x86_64/Makefile
index f712ca66f3..b721970172 100644
--- a/xen/arch/x86/x86_64/Makefile
+++ b/xen/arch/x86/x86_64/Makefile
@@ -5,6 +5,7 @@ obj-y += gpr_switch.o
obj-y += mm.o
obj-y += traps.o
+obj-$(crash_debug) += gdbstub.o
obj-$(CONFIG_COMPAT) += compat.o
obj-$(CONFIG_COMPAT) += compat_kexec.o
obj-$(CONFIG_COMPAT) += domain.o
diff --git a/xen/arch/x86/x86_64/gdbstub.c b/xen/arch/x86/x86_64/gdbstub.c
new file mode 100644
index 0000000000..a91f468518
--- /dev/null
+++ b/xen/arch/x86/x86_64/gdbstub.c
@@ -0,0 +1,151 @@
+/*
+ * x86_64 -specific gdb stub routines
+ *
+ * Copyright (C) 2007 Dan Doucette ddoucette@teradici.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/debugger.h>
+
+#define GDB_REG64(r) gdb_write_to_packet_hex(r, sizeof(u64), ctx)
+#define GDB_REG32(r) gdb_write_to_packet_hex(r, sizeof(u32), ctx)
+
+void
+gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+ GDB_REG64(regs->rax);
+ GDB_REG64(regs->rbx);
+ GDB_REG64(regs->rcx);
+ GDB_REG64(regs->rdx);
+ GDB_REG64(regs->rsi);
+ GDB_REG64(regs->rdi);
+ GDB_REG64(regs->rbp);
+ GDB_REG64(regs->rsp);
+
+ GDB_REG64(regs->r8);
+ GDB_REG64(regs->r9);
+ GDB_REG64(regs->r10);
+ GDB_REG64(regs->r11);
+ GDB_REG64(regs->r12);
+ GDB_REG64(regs->r13);
+ GDB_REG64(regs->r14);
+ GDB_REG64(regs->r15);
+
+ GDB_REG64(regs->rip);
+ GDB_REG32(regs->eflags);
+
+ GDB_REG32(regs->cs);
+ GDB_REG32(regs->ss);
+ GDB_REG32(regs->ds);
+ GDB_REG32(regs->es);
+ GDB_REG32(regs->fs);
+ GDB_REG32(regs->gs);
+
+ gdb_send_packet(ctx);
+}
+
+void
+gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf,
+ struct gdb_context *ctx)
+{
+ gdb_send_reply("", ctx);
+}
+
+void
+gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs,
+ struct gdb_context *ctx)
+{
+ switch (regnum)
+ {
+ case 0: GDB_REG64(regs->rax); break;
+ case 1: GDB_REG64(regs->rbx); break;
+ case 2: GDB_REG64(regs->rcx); break;
+ case 3: GDB_REG64(regs->rdx); break;
+ case 4: GDB_REG64(regs->rsi); break;
+ case 5: GDB_REG64(regs->rdi); break;
+ case 6: GDB_REG64(regs->rbp); break;
+ case 7: GDB_REG64(regs->rsp); break;
+
+ case 8: GDB_REG64(regs->r8); break;
+ case 9: GDB_REG64(regs->r9); break;
+ case 10: GDB_REG64(regs->r10); break;
+ case 11: GDB_REG64(regs->r11); break;
+ case 12: GDB_REG64(regs->r12); break;
+ case 13: GDB_REG64(regs->r13); break;
+ case 14: GDB_REG64(regs->r14); break;
+ case 15: GDB_REG64(regs->r15); break;
+
+ case 16: GDB_REG64(regs->rip); break;
+ case 17: GDB_REG32(regs->rflags); break;
+ case 18: GDB_REG32(regs->cs); break;
+ case 19: GDB_REG32(regs->ss); break;
+ case 20: GDB_REG32(regs->ds); break;
+ case 21: GDB_REG32(regs->es); break;
+ case 22: GDB_REG32(regs->fs); break;
+ case 23: GDB_REG32(regs->gs); break;
+ default:
+ GDB_REG64(0xbaadf00ddeadbeef);
+ break;
+ }
+ gdb_send_packet(ctx);
+}
+
+void
+gdb_arch_write_reg(unsigned long regnum, unsigned long val,
+ struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+ switch (regnum)
+ {
+ case 0: regs->rax = val; break;
+ case 1: regs->rbx = val; break;
+ case 2: regs->rcx = val; break;
+ case 3: regs->rdx = val; break;
+ case 4: regs->rsi = val; break;
+ case 5: regs->rdi = val; break;
+ case 6: regs->rbp = val; break;
+ case 7: regs->rsp = val; break;
+
+ case 8: regs->r8 = val; break;
+ case 9: regs->r9 = val; break;
+ case 10: regs->r10 = val; break;
+ case 11: regs->r11 = val; break;
+ case 12: regs->r12 = val; break;
+ case 13: regs->r13 = val; break;
+ case 14: regs->r14 = val; break;
+ case 15: regs->r15 = val; break;
+
+ case 16: regs->rip = val; break;
+ case 17: regs->rflags = (u32)val; break;
+ case 18: regs->cs = (u16)val; break;
+ case 19: regs->ss = (u16)val; break;
+ case 20: regs->ds = (u16)val; break;
+ case 21: regs->es = (u16)val; break;
+ case 22: regs->fs = (u16)val; break;
+ case 23: regs->gs = (u16)val; break;
+ default:
+ break;
+ }
+ gdb_send_reply("OK", ctx);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c
index c0b2f4c474..7b8d231903 100644
--- a/xen/common/gdbstub.c
+++ b/xen/common/gdbstub.c
@@ -43,6 +43,7 @@
#include <xen/smp.h>
#include <xen/console.h>
#include <xen/errno.h>
+#include <xen/delay.h>
#include <asm/byteorder.h>
/* Printk isn't particularly safe just after we've trapped to the
@@ -52,6 +53,18 @@
#define GDB_RETRY_MAX 10
+struct gdb_cpu_info
+{
+ atomic_t paused;
+ atomic_t ack;
+};
+
+static struct gdb_cpu_info gdb_cpu[NR_CPUS];
+static atomic_t gdb_smp_paused_count;
+
+static void gdb_smp_pause(void);
+static void gdb_smp_resume(void);
+
static char opt_gdb[30] = "none";
string_param("gdb", opt_gdb);
@@ -234,7 +247,7 @@ gdb_write_to_packet_hex(unsigned long x, int int_size, struct gdb_context *ctx)
}
#ifdef __BIG_ENDIAN
- i = sizeof(unsigned long) * 2
+ i = sizeof(unsigned long) * 2
do {
buf[--i] = hex2char(x & 15);
x >>= 4;
@@ -245,13 +258,14 @@ gdb_write_to_packet_hex(unsigned long x, int int_size, struct gdb_context *ctx)
gdb_write_to_packet(&buf[i], width, ctx);
#elif defined(__LITTLE_ENDIAN)
- i = 0;
- while (i < width) {
- buf[i++] = hex2char(x>>4);
- buf[i++] = hex2char(x);
- x >>= 8;
- }
- gdb_write_to_packet(buf, width, ctx);
+ i = 0;
+ while ( i < width )
+ {
+ buf[i++] = hex2char(x>>4);
+ buf[i++] = hex2char(x);
+ x >>= 8;
+ }
+ gdb_write_to_packet(buf, width, ctx);
#else
# error unknown endian
#endif
@@ -396,8 +410,9 @@ static int
process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
{
const char *ptr;
- unsigned long addr, length;
+ unsigned long addr, length, val;
int resume = 0;
+ unsigned long type = GDB_CONTINUE;
/* XXX check ctx->in_bytes >= 2 or similar. */
@@ -460,30 +475,40 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
}
gdb_arch_read_reg(addr, regs, ctx);
break;
+ case 'P': /* write register */
+ addr = simple_strtoul(ctx->in_buf + 1, &ptr, 16);
+ if ( ptr == (ctx->in_buf + 1) )
+ {
+ gdb_send_reply("E03", ctx);
+ return 0;
+ }
+ if ( ptr[0] != '=' )
+ {
+ gdb_send_reply("E04", ctx);
+ return 0;
+ }
+ ptr++;
+ val = str2ulong(ptr, sizeof(unsigned long));
+ gdb_arch_write_reg(addr, val, regs, ctx);
+ break;
case 'D':
+ case 'k':
gdbstub_detach(ctx);
gdb_send_reply("OK", ctx);
- /* fall through */
- case 'k':
ctx->connected = 0;
- /* fall through */
+ resume = 1;
+ break;
case 's': /* Single step */
+ type = GDB_STEP;
case 'c': /* Resume at current address */
- {
- unsigned long addr = ~((unsigned long)0);
- unsigned long type = GDB_CONTINUE;
- if ( ctx->in_buf[0] == 's' )
- type = GDB_STEP;
- if ( ((ctx->in_buf[0] == 's') || (ctx->in_buf[0] == 'c')) &&
- ctx->in_buf[1] )
+ addr = ~((unsigned long)0);
+
+ if ( ctx->in_buf[1] )
addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long));
- if ( ctx->in_buf[0] != 'D' )
- gdbstub_attach(ctx);
+ gdbstub_attach(ctx);
resume = 1;
gdb_arch_resume(regs, addr, type, ctx);
break;
- }
-
default:
gdb_send_reply("", ctx);
break;
@@ -555,10 +580,8 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
gdb_ctx->connected = 1;
}
- smp_send_stop();
+ gdb_smp_pause();
- /* Try to make things a little more stable by disabling
- interrupts while we're here. */
local_irq_save(flags);
watchdog_disable();
@@ -587,6 +610,8 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
}
} while ( process_command(regs, gdb_ctx) == 0 );
+ gdb_smp_resume();
+
gdb_arch_exit(regs);
console_end_sync();
watchdog_enable();
@@ -606,6 +631,84 @@ initialise_gdb(void)
serial_start_sync(gdb_ctx->serhnd);
}
+static void gdb_pause_this_cpu(void *unused)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ atomic_set(&gdb_cpu[smp_processor_id()].ack, 1);
+ atomic_inc(&gdb_smp_paused_count);
+
+ while ( atomic_read(&gdb_cpu[smp_processor_id()].paused) )
+ mdelay(1);
+
+ atomic_dec(&gdb_smp_paused_count);
+ atomic_set(&gdb_cpu[smp_processor_id()].ack, 0);
+
+ /* Restore interrupts */
+ local_irq_restore(flags);
+}
+
+static void gdb_smp_pause(void)
+{
+ int timeout = 100;
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ {
+ atomic_set(&gdb_cpu[cpu].ack, 0);
+ atomic_set(&gdb_cpu[cpu].paused, 1);
+ }
+
+ atomic_set(&gdb_smp_paused_count, 0);
+
+ smp_call_function(gdb_pause_this_cpu, NULL, /* dont wait! */0, 0);
+
+ /* Wait 100ms for all other CPUs to enter pause loop */
+ while ( (atomic_read(&gdb_smp_paused_count) < (num_online_cpus() - 1))
+ && (timeout-- > 0) )
+ mdelay(1);
+
+ if ( atomic_read(&gdb_smp_paused_count) < (num_online_cpus() - 1) )
+ {
+ printk("GDB: Not all CPUs have paused, missing CPUs ");
+ for_each_online_cpu(cpu)
+ {
+ if ( (cpu != smp_processor_id()) &&
+ !atomic_read(&gdb_cpu[cpu].ack) )
+ printk("%d ", cpu);
+ }
+ printk("\n");
+ }
+}
+
+static void gdb_smp_resume(void)
+{
+ int cpu;
+ int timeout = 100;
+
+ for_each_online_cpu(cpu)
+ atomic_set(&gdb_cpu[cpu].paused, 0);
+
+ /* Make sure all CPUs resume */
+ while ( (atomic_read(&gdb_smp_paused_count) > 0)
+ && (timeout-- > 0) )
+ mdelay(1);
+
+ if ( atomic_read(&gdb_smp_paused_count) > 0 )
+ {
+ printk("GDB: Not all CPUs have resumed execution, missing CPUs ");
+ for_each_online_cpu(cpu)
+ {
+ if ( (cpu != smp_processor_id()) &&
+ atomic_read(&gdb_cpu[cpu].ack) )
+ printk("%d ", cpu);
+ }
+ printk("\n");
+ }
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h
index 079e9e158b..05c0e5a425 100644
--- a/xen/include/asm-x86/desc.h
+++ b/xen/include/asm-x86/desc.h
@@ -213,7 +213,6 @@ extern struct desc_struct compat_gdt_table[];
#endif
extern void set_intr_gate(unsigned int irq, void * addr);
-extern void set_system_gate(unsigned int n, void *addr);
extern void set_tss_desc(unsigned int n, void *addr);
#endif /* !__ASSEMBLY__ */
diff --git a/xen/include/xen/gdbstub.h b/xen/include/xen/gdbstub.h
index 09af6f3642..e87cf30470 100644
--- a/xen/include/xen/gdbstub.h
+++ b/xen/include/xen/gdbstub.h
@@ -69,6 +69,9 @@ void gdb_arch_write_reg_array(
struct cpu_user_regs *regs, const char* buf, struct gdb_context *ctx);
void gdb_arch_read_reg(
unsigned long regnum, struct cpu_user_regs *regs, struct gdb_context *ctx);
+void gdb_arch_write_reg(
+ unsigned long regnum, unsigned long val, struct cpu_user_regs *regs,
+ struct gdb_context *ctx);
unsigned int gdb_arch_copy_from_user(
void *dest, const void *src, unsigned len);
unsigned int gdb_arch_copy_to_user(