summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_kdb.c
diff options
context:
space:
mode:
authordwhite <dwhite@FreeBSD.org>2005-04-30 20:01:00 +0000
committerdwhite <dwhite@FreeBSD.org>2005-04-30 20:01:00 +0000
commitc8fa8099674d921d50dae72e3a58ef66ac9c7fbc (patch)
treeb1d1d16a2806520655c3bf213640cc3b5593de38 /sys/kern/subr_kdb.c
parentebe4b8304d164a842cc96bcc863c9321a37f57ff (diff)
downloadFreeBSD-src-c8fa8099674d921d50dae72e3a58ef66ac9c7fbc.zip
FreeBSD-src-c8fa8099674d921d50dae72e3a58ef66ac9c7fbc.tar.gz
Implement an alternate method to stop CPUs when entering DDB. Normally we use
a regular IPI vector, but this vector is blocked when interrupts are disabled. With "options KDB_STOP_NMI" and debug.kdb.stop_cpus_with_nmi set, KDB will send an NMI to each CPU instead. The code also has a context-stuffing feature which helps ddb extract the state of processes running on the stopped CPUs. KDB_STOP_NMI is only useful with SMP and complains if SMP is not defined. This feature only applies to i386 and amd64 at the moment, but could be used on other architectures with the appropriate MD bits. Submitted by: ups
Diffstat (limited to 'sys/kern/subr_kdb.c')
-rw-r--r--sys/kern/subr_kdb.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c
index 54274db..5726a84 100644
--- a/sys/kern/subr_kdb.c
+++ b/sys/kern/subr_kdb.c
@@ -40,6 +40,18 @@ __FBSDID("$FreeBSD$");
#include <machine/kdb.h>
#include <machine/pcb.h>
+#ifdef KDB_STOP_NMI
+#include <machine/smp.h>
+#endif
+
+/*
+ * KDB_STOP_NMI requires SMP to pick up the right dependencies
+ * (And isn't useful on UP anyway)
+ */
+#if defined(KDB_STOP_NMI) && !defined(SMP)
+#error "options KDB_STOP_NMI" requires "options SMP"
+#endif
+
int kdb_active = 0;
void *kdb_jmpbufp = NULL;
struct kdb_dbbe *kdb_dbbe = NULL;
@@ -77,6 +89,19 @@ static int kdb_stop_cpus = 1;
SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus, CTLTYPE_INT | CTLFLAG_RW,
&kdb_stop_cpus, 0, "");
TUNABLE_INT("debug.kdb.stop_cpus", &kdb_stop_cpus);
+
+#ifdef KDB_STOP_NMI
+/*
+ * Provide an alternate method of stopping other CPUs. If another CPU has
+ * disabled interrupts the conventional STOP IPI will be blocked. This
+ * NMI-based stop should get through in that case.
+ */
+static int kdb_stop_cpus_with_nmi = 0;
+SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus_with_nmi, CTLTYPE_INT | CTLFLAG_RW,
+ &kdb_stop_cpus_with_nmi, 0, "");
+TUNABLE_INT("debug.kdb.stop_cpus_with_nmi", &kdb_stop_cpus_with_nmi);
+#endif /* KDB_STOP_NMI */
+
#endif
static int
@@ -308,9 +333,27 @@ kdb_reenter(void)
struct pcb *
kdb_thr_ctx(struct thread *thr)
+#ifdef KDB_STOP_NMI
+{
+ u_int cpuid;
+ struct pcpu *pc;
+
+ if (thr == curthread)
+ return &kdb_pcb;
+
+ SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
+ cpuid = pc->pc_cpuid;
+ if (pc->pc_curthread == thr && (atomic_load_acq_int(&stopped_cpus) & (1 << cpuid)))
+ return &stoppcbs[cpuid];
+ }
+
+ return thr->td_pcb;
+}
+#else
{
return ((thr == curthread) ? &kdb_pcb : thr->td_pcb);
}
+#endif /* KDB_STOP_NMI */
struct thread *
kdb_thr_first(void)
@@ -407,7 +450,14 @@ kdb_trap(int type, int code, struct trapframe *tf)
#ifdef SMP
if ((did_stop_cpus = kdb_stop_cpus) != 0)
+ {
+#ifdef KDB_STOP_NMI
+ if(kdb_stop_cpus_with_nmi)
+ stop_cpus_nmi(PCPU_GET(other_cpus));
+ else
+#endif /* KDB_STOP_NMI */
stop_cpus(PCPU_GET(other_cpus));
+ }
#endif
kdb_frame = tf;
OpenPOWER on IntegriCloud