diff options
author | Andreas Gunnarsson <andreas@cvs.openbsd.org> | 2004-06-25 17:27:02 +0000 |
---|---|---|
committer | Andreas Gunnarsson <andreas@cvs.openbsd.org> | 2004-06-25 17:27:02 +0000 |
commit | e7a05a23ee68d06836bb6b72fdca8a3512cae3d0 (patch) | |
tree | a3122fd61114e8d5d90eb2004b5211f6245ee34e /sys | |
parent | 13fc92a79fdc61156f083e7caab5dfe8b28c87a3 (diff) |
'machine cpuinfo' and 'machine ddbcpu' in ddb for amd64
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/db_interface.c | 404 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/ipifuncs.c | 4 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/vector.S | 17 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 12 | ||||
-rw-r--r-- | sys/arch/amd64/include/db_machdep.h | 21 | ||||
-rw-r--r-- | sys/arch/amd64/include/intrdefs.h | 7 |
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 = ®s; + /* 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 |