summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAndreas Gunnarsson <andreas@cvs.openbsd.org>2004-06-25 17:27:02 +0000
committerAndreas Gunnarsson <andreas@cvs.openbsd.org>2004-06-25 17:27:02 +0000
commite7a05a23ee68d06836bb6b72fdca8a3512cae3d0 (patch)
treea3122fd61114e8d5d90eb2004b5211f6245ee34e /sys
parent13fc92a79fdc61156f083e7caab5dfe8b28c87a3 (diff)
'machine cpuinfo' and 'machine ddbcpu' in ddb for amd64
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/db_interface.c404
-rw-r--r--sys/arch/amd64/amd64/ipifuncs.c4
-rw-r--r--sys/arch/amd64/amd64/vector.S17
-rw-r--r--sys/arch/amd64/include/cpu.h12
-rw-r--r--sys/arch/amd64/include/db_machdep.h21
-rw-r--r--sys/arch/amd64/include/intrdefs.h7
6 files changed, 292 insertions, 173 deletions
diff --git a/sys/arch/amd64/amd64/db_interface.c b/sys/arch/amd64/amd64/db_interface.c
index 56c3dd5ce22..787d1b88d50 100644
--- a/sys/arch/amd64/amd64/db_interface.c
+++ b/sys/arch/amd64/amd64/db_interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_interface.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */
+/* $OpenBSD: db_interface.c,v 1.2 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: db_interface.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */
/*
@@ -59,88 +59,27 @@
extern label_t *db_recover;
extern char *trap_type[];
extern int trap_types;
+extern boolean_t db_cmd_loop_done;
-int db_active;
-db_regs_t ddb_regs; /* register state */
-db_regs_t *ddb_regp;
-
-void db_mach_cpu (db_expr_t, int, db_expr_t, char *);
-
-const struct db_command db_machine_command_table[] = {
-#ifdef MULTIPROCESSOR
- { "cpu", db_mach_cpu, 0, 0 },
-#endif
- { (char *)0, },
-};
-
-void kdbprinttrap(int, int);
#ifdef MULTIPROCESSOR
-extern void ddb_ipi(struct trapframe);
-static void ddb_suspend(struct trapframe *);
-int ddb_vec;
+struct SIMPLELOCK ddb_mp_slock;
+volatile int ddb_state = DDB_STATE_NOT_RUNNING;
+volatile cpuid_t ddb_active_cpu;
+extern volatile int ddb_state;
+boolean_t db_switch_cpu;
+long db_switch_to_cpu;
#endif
-#define NOCPU -1
-
-int ddb_cpu = NOCPU;
-
-typedef void (vector)(void);
-extern vector Xintrddb;
-
-void
-db_machine_init()
-{
-
-#ifdef MULTIPROCESSOR
- ddb_vec = idt_vec_alloc(0xf0, 0xff);
- setgate((struct gate_descriptor *)&idt[ddb_vec], &Xintrddb, 1,
- SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
-#endif
-}
+int db_active;
+db_regs_t ddb_regs;
+void kdbprinttrap(int, int);
#ifdef MULTIPROCESSOR
-
-__cpu_simple_lock_t db_lock;
-
-static int
-db_suspend_others(void)
-{
- int cpu_me = cpu_number();
- int win;
-
- if (ddb_vec == 0)
- return 1;
-
- __cpu_simple_lock(&db_lock);
- if (ddb_cpu == NOCPU)
- ddb_cpu = cpu_me;
- win = (ddb_cpu == cpu_me);
- __cpu_simple_unlock(&db_lock);
- if (win) {
- x86_ipi(ddb_vec, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED);
- }
- return win;
-}
-
-static void
-db_resume_others(void)
-{
- int i;
-
- __cpu_simple_lock(&db_lock);
- ddb_cpu = NOCPU;
- __cpu_simple_unlock(&db_lock);
-
- for (i=0; i < X86_MAXPROCS; i++) {
- struct cpu_info *ci = cpu_info[i];
- if (ci == NULL)
- continue;
- if (ci->ci_flags & CPUF_PAUSE)
- x86_atomic_clearbits_l(&ci->ci_flags, CPUF_PAUSE);
- }
-
-}
-
+void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *);
+void db_startproc_cmd(db_expr_t, int, db_expr_t, char *);
+void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *);
+void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *);
+int db_cpuid2apic(int);
#endif
/*
@@ -167,7 +106,6 @@ kdb_trap(type, code, regs)
db_regs_t *regs;
{
int s;
- db_regs_t dbreg;
switch (type) {
case T_BPTFLT: /* breakpoint */
@@ -187,11 +125,13 @@ kdb_trap(type, code, regs)
}
#ifdef MULTIPROCESSOR
- if (!db_suspend_others()) {
- ddb_suspend(regs);
- } else {
- curcpu()->ci_ddb_regs = &dbreg;
- ddb_regp = &dbreg;
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+ if (ddb_state == DDB_STATE_EXITING)
+ ddb_state = DDB_STATE_NOT_RUNNING;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ while (db_enter_ddb()) {
#endif
ddb_regs = *regs;
@@ -210,94 +150,274 @@ kdb_trap(type, code, regs)
cnpollc(FALSE);
db_active--;
splx(s);
-#ifdef MULTIPROCESSOR
- db_resume_others();
- }
-#endif
- ddb_regp = &dbreg;
*regs = ddb_regs;
+#ifdef MULTIPROCESSOR
+ if (!db_switch_cpu)
+ ddb_state = DDB_STATE_EXITING;
+ }
+#endif
return (1);
}
-void
-Debugger()
+
+#ifdef MULTIPROCESSOR
+int
+db_cpuid2apic(int id)
{
- breakpoint();
+ int apic;
+
+ for (apic = 0; apic < X86_MAXPROCS; apic++) {
+ if (cpu_info[apic] != NULL &&
+ CPU_INFO_UNIT(cpu_info[apic]) == id)
+ return (apic);
+ }
+ return (-1);
}
-#ifdef MULTIPROCESSOR
+void
+db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
+{
+ int i;
-/*
- * Called when we receive a debugger IPI (inter-processor interrupt).
- * As with trap() in trap.c, this function is called from an assembly
- * language IDT gate entry routine which prepares a suitable stack frame,
- * and restores this frame after the exception has been processed. Note
- * that the effect is as if the arguments were passed call by reference.
- */
+ for (i = 0; i < X86_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL) {
+ db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ',
+ CPU_INFO_UNIT(cpu_info[i]));
+ switch(cpu_info[i]->ci_ddb_paused) {
+ case CI_DDB_RUNNING:
+ db_printf("running\n");
+ break;
+ case CI_DDB_SHOULDSTOP:
+ db_printf("stopping\n");
+ break;
+ case CI_DDB_STOPPED:
+ db_printf("stopped\n");
+ break;
+ case CI_DDB_ENTERDDB:
+ db_printf("entering ddb\n");
+ break;
+ case CI_DDB_INDDB:
+ db_printf("ddb\n");
+ break;
+ default:
+ db_printf("? (%d)\n",
+ cpu_info[i]->ci_ddb_paused);
+ break;
+ }
+ }
+ }
+}
+
+void
+db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
+{
+ int apic;
+
+ if (have_addr) {
+ apic = db_cpuid2apic(addr);
+ if (apic >= 0 && apic < X86_MAXPROCS &&
+ cpu_info[apic] != NULL && apic != cpu_number())
+ db_startcpu(apic);
+ else
+ db_printf("Invalid cpu %d\n", (int)addr);
+ } else {
+ for (apic = 0; apic < X86_MAXPROCS; apic++) {
+ if (cpu_info[apic] != NULL && apic != cpu_number()) {
+ db_startcpu(apic);
+ }
+ }
+ }
+}
void
-ddb_ipi(struct trapframe frame)
+db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
+ int apic;
+
+ if (have_addr) {
+ apic = db_cpuid2apic(addr);
+ if (apic >= 0 && apic < X86_MAXPROCS &&
+ cpu_info[apic] != NULL && apic != cpu_number())
+ db_stopcpu(apic);
+ else
+ db_printf("Invalid cpu %d\n", (int)addr);
+ } else {
+ for (apic = 0; apic < X86_MAXPROCS; apic++) {
+ if (cpu_info[apic] != NULL && apic != cpu_number()) {
+ db_stopcpu(apic);
+ }
+ }
+ }
+}
- ddb_suspend(&frame);
+void
+db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
+{
+ int apic;
+
+ if (have_addr) {
+ apic = db_cpuid2apic(addr);
+ if (apic >= 0 && apic < X86_MAXPROCS &&
+ cpu_info[apic] != NULL && apic != cpu_number()) {
+ db_stopcpu(apic);
+ db_switch_to_cpu = apic;
+ db_switch_cpu = 1;
+ db_cmd_loop_done = 1;
+ } else {
+ db_printf("Invalid cpu %d\n", (int)addr);
+ }
+ } else {
+ db_printf("CPU not specified\n");
+ }
}
-static void
-ddb_suspend(struct trapframe *frame)
+int
+db_enter_ddb()
{
- volatile struct cpu_info *ci = curcpu();
- db_regs_t regs;
+ int s, i;
- regs = *frame;
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+
+ /* If we are first in, grab ddb and stop all other CPUs */
+ if (ddb_state == DDB_STATE_NOT_RUNNING) {
+ ddb_active_cpu = cpu_number();
+ ddb_state = DDB_STATE_RUNNING;
+ curcpu()->ci_ddb_paused = CI_DDB_INDDB;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ for (i = 0; i < X86_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL && i != cpu_number() &&
+ cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
+ cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
+ x86_send_ipi(cpu_info[i], X86_IPI_DDB);
+ }
+ }
+ return (1);
+ }
+
+ /* Leaving ddb completely. Start all other CPUs and return 0 */
+ if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
+ for (i = 0; i < X86_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL) {
+ cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
+ }
+ }
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (0);
+ }
- ci->ci_ddb_regs = &regs;
+ /* We're switching to another CPU. db_ddbproc_cmd() has made sure
+ * it is waiting for ddb, we just have to set ddb_active_cpu. */
+ if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
+ curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
+ db_switch_cpu = 0;
+ ddb_active_cpu = db_switch_to_cpu;
+ cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
+ }
- x86_atomic_setbits_l(&ci->ci_flags, CPUF_PAUSE);
+ /* Wait until we should enter ddb or resume */
+ while (ddb_active_cpu != cpu_number() &&
+ curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
+ if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
+ curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+
+ /* Busy wait without locking, we'll confirm with lock later */
+ while (ddb_active_cpu != cpu_number() &&
+ curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
+ ; /* Do nothing */
+
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+ }
- while (ci->ci_flags & CPUF_PAUSE)
- ;
- ci->ci_ddb_regs = 0;
+ /* Either enter ddb or exit */
+ if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
+ curcpu()->ci_ddb_paused = CI_DDB_INDDB;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (1);
+ } else {
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ return (0);
+ }
}
+void
+db_startcpu(int cpu)
+{
+ int s;
-extern void cpu_debug_dump(void); /* XXX */
+ if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+ cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ }
+}
void
-db_mach_cpu(addr, have_addr, count, modif)
- db_expr_t addr;
- int have_addr;
- db_expr_t count;
- char * modif;
+db_stopcpu(int cpu)
{
- struct cpu_info *ci;
- if (!have_addr) {
- cpu_debug_dump();
- return;
- }
+ int s;
- if ((addr < 0) || (addr >= X86_MAXPROCS)) {
- db_printf("%ld: cpu out of range\n", addr);
- return;
- }
- ci = cpu_info[addr];
- if (ci == NULL) {
- db_printf("cpu %ld not configured\n", addr);
- return;
- }
- if (ci != curcpu()) {
- if (!(ci->ci_flags & CPUF_PAUSE)) {
- db_printf("cpu %ld not paused\n", addr);
- return;
- }
- }
- if (ci->ci_ddb_regs == 0) {
- db_printf("cpu %ld has no saved regs\n", addr);
- return;
+ s = splhigh();
+ SIMPLE_LOCK(&ddb_mp_slock);
+ if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
+ cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
+ cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
+ x86_send_ipi(cpu_info[cpu], X86_IPI_DDB);
+ } else {
+ SIMPLE_UNLOCK(&ddb_mp_slock);
+ splx(s);
}
- db_printf("using cpu %ld", addr);
- ddb_regp = ci->ci_ddb_regs;
}
+void
+x86_ipi_db(struct cpu_info *ci)
+{
+ Debugger();
+}
+#endif /* MULTIPROCESSOR */
+
+struct db_command db_machine_command_table[] = {
+#ifdef MULTIPROCESSOR
+ { "cpuinfo", db_cpuinfo_cmd, 0, 0 },
+ { "startcpu", db_startproc_cmd, 0, 0 },
+ { "stopcpu", db_stopproc_cmd, 0, 0 },
+ { "ddbcpu", db_ddbproc_cmd, 0, 0 },
#endif
+ { (char *)0, },
+};
+
+void
+db_machine_init()
+{
+#ifdef MULTIPROCESSOR
+ int i;
+#endif
+
+ db_machine_commands_install(db_machine_command_table);
+#ifdef MULTIPROCESSOR
+ for (i = 0; i < X86_MAXPROCS; i++) {
+ if (cpu_info[i] != NULL)
+ cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
+ }
+ SIMPLE_LOCK_INIT(&ddb_mp_slock);
+#endif
+}
+
+void
+Debugger()
+{
+ breakpoint();
+}
diff --git a/sys/arch/amd64/amd64/ipifuncs.c b/sys/arch/amd64/amd64/ipifuncs.c
index fea247d36fc..82043eb2a2e 100644
--- a/sys/arch/amd64/amd64/ipifuncs.c
+++ b/sys/arch/amd64/amd64/ipifuncs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipifuncs.c,v 1.1 2004/06/25 11:03:27 art Exp $ */
+/* $OpenBSD: ipifuncs.c,v 1.2 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: ipifuncs.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*-
@@ -62,6 +62,7 @@
#include <machine/fpu.h>
#include <ddb/db_output.h>
+#include <machine/db_machdep.h>
void x86_64_ipi_halt(struct cpu_info *);
@@ -89,6 +90,7 @@ void (*ipifunc[X86_NIPI])(struct cpu_info *) =
pmap_do_tlb_shootdown,
x86_64_reload_mtrr,
gdt_reload_cpu,
+ x86_ipi_db,
};
void
diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index ddef85a0c43..9504d3112b4 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: vector.S,v 1.2 2004/06/25 11:03:27 art Exp $ */
+/* $OpenBSD: vector.S,v 1.3 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: vector.S,v 1.2 2003/05/04 23:46:41 fvdl Exp $ */
/*
@@ -319,21 +319,6 @@ IDTVEC(intr_lapic_ipi)
sti
INTRFASTEXIT
-#if defined(DDB)
-IDTVEC(intrddb)
-1:
- pushq $0
- pushq $T_BPTFLT
- INTRENTRY
- movl $0xf,%eax
- movq %rax,%cr8
- movl $0,_C_LABEL(local_apic)+LAPIC_EOI
- sti
- call _C_LABEL(ddb_ipi)
- xorl %eax,%eax
- movq %rax,%cr8
- INTRFASTEXIT
-#endif /* DDB */
#endif /* MULTIPROCESSOR */
/*
diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h
index 7c527d7d7cb..9f5d9958679 100644
--- a/sys/arch/amd64/include/cpu.h
+++ b/sys/arch/amd64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.9 2004/06/25 11:03:28 art Exp $ */
+/* $OpenBSD: cpu.h,v 1.10 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */
/*-
@@ -101,7 +101,6 @@ struct cpu_info {
int ci_want_resched;
int ci_astpending;
- struct trapframe *ci_ddb_regs;
struct x86_cache_info ci_cinfo[CAI_COUNT];
@@ -112,11 +111,16 @@ struct cpu_info {
char *ci_gdt;
+ volatile int ci_ddb_paused;
+#define CI_DDB_RUNNING 0
+#define CI_DDB_SHOULDSTOP 1
+#define CI_DDB_STOPPED 2
+#define CI_DDB_ENTERDDB 3
+#define CI_DDB_INDDB 4
+
struct x86_64_tss ci_doubleflt_tss;
- struct x86_64_tss ci_ddbipi_tss;
char *ci_doubleflt_stack;
- char *ci_ddbipi_stack;
struct evcnt ci_ipi_events[X86_NIPI];
};
diff --git a/sys/arch/amd64/include/db_machdep.h b/sys/arch/amd64/include/db_machdep.h
index c2569ee9379..9b61b0bed70 100644
--- a/sys/arch/amd64/include/db_machdep.h
+++ b/sys/arch/amd64/include/db_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_machdep.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */
+/* $OpenBSD: db_machdep.h,v 1.2 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: db_machdep.h,v 1.2 2003/04/29 17:06:04 scw Exp $ */
/*
@@ -42,14 +42,9 @@ typedef vaddr_t db_addr_t; /* address - unsigned */
typedef long db_expr_t; /* expression - signed */
typedef struct trapframe db_regs_t;
-#ifndef MULTIPROCESSOR
+
extern db_regs_t ddb_regs; /* register state */
#define DDB_REGS (&ddb_regs)
-#else
-extern db_regs_t *ddb_regp;
-#define DDB_REGS (ddb_regp)
-#define ddb_regs (*ddb_regp)
-#endif
#if defined(lint)
#define PC_REGS(regs) ((regs)->tf_rip)
@@ -126,6 +121,18 @@ void db_task_name(/* task_t */);
int kdb_trap(int, int, db_regs_t *);
+void db_machine_init(void);
+int db_enter_ddb(void);
+void db_startcpu(int cpu);
+void db_stopcpu(int cpu);
+void x86_ipi_db(struct cpu_info *);
+
+extern struct SIMPLELOCK ddb_mp_slock;
+
+#define DDB_STATE_NOT_RUNNING 0
+#define DDB_STATE_RUNNING 1
+#define DDB_STATE_EXITING 2
+
/*
* We define some of our own commands
*/
diff --git a/sys/arch/amd64/include/intrdefs.h b/sys/arch/amd64/include/intrdefs.h
index d1b46308c38..83e814015d6 100644
--- a/sys/arch/amd64/include/intrdefs.h
+++ b/sys/arch/amd64/include/intrdefs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intrdefs.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */
+/* $OpenBSD: intrdefs.h,v 1.2 2004/06/25 17:27:01 andreas Exp $ */
/* $NetBSD: intrdefs.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */
#ifndef _i386_INTRDEFS_H
@@ -81,12 +81,13 @@
#define X86_IPI_TLB 0x00000010
#define X86_IPI_MTRR 0x00000020
#define X86_IPI_GDT 0x00000040
+#define X86_IPI_DDB 0x00000080
-#define X86_NIPI 7
+#define X86_NIPI 8
#define X86_IPI_NAMES { "halt IPI", "timeset IPI", "FPU flush IPI", \
"FPU synch IPI", "TLB shootdown IPI", \
- "MTRR update IPI", "GDT update IPI" }
+ "MTRR update IPI", "GDT update IPI", "ddb IPI" }
#define IREENT_MAGIC 0x18041969