summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/trap.c42
-rw-r--r--sys/i386/i386/trap.c42
-rw-r--r--sys/kern/subr_smp.c53
-rw-r--r--sys/x86/include/x86_smp.h3
-rw-r--r--sys/x86/include/x86_var.h4
-rw-r--r--sys/x86/x86/cpu_machdep.c53
-rw-r--r--sys/x86/x86/mp_x86.c35
7 files changed, 135 insertions, 97 deletions
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 8d2b399..024c1b3 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -144,14 +144,6 @@ static char *trap_msg[] = {
"DTrace pid return trap", /* 32 T_DTRACE_RET */
};
-#ifdef KDB
-static int kdb_on_nmi = 1;
-SYSCTL_INT(_machdep, OID_AUTO, kdb_on_nmi, CTLFLAG_RWTUN,
- &kdb_on_nmi, 0, "Go to KDB on NMI");
-#endif
-static int panic_on_nmi = 1;
-SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RWTUN,
- &panic_on_nmi, 0, "Panic on NMI");
static int prot_fault_translation;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RWTUN,
&prot_fault_translation, 0,
@@ -377,21 +369,7 @@ trap(struct trapframe *frame)
#ifdef DEV_ISA
case T_NMI:
- /* machine/parity/power fail/"kitchen sink" faults */
- if (isa_nmi(frame->tf_err) == 0) {
-#ifdef KDB
- /*
- * NMI can be hooked up to a pushbutton
- * for debugging.
- */
- if (kdb_on_nmi) {
- printf ("NMI ... going to debugger\n");
- kdb_trap(type, 0, frame);
- }
-#endif /* KDB */
- goto userout;
- } else if (panic_on_nmi)
- panic("NMI indicates hardware failure");
+ nmi_handle_intr(type, frame);
break;
#endif /* DEV_ISA */
@@ -563,22 +541,8 @@ trap(struct trapframe *frame)
#ifdef DEV_ISA
case T_NMI:
- /* machine/parity/power fail/"kitchen sink" faults */
- if (isa_nmi(frame->tf_err) == 0) {
-#ifdef KDB
- /*
- * NMI can be hooked up to a pushbutton
- * for debugging.
- */
- if (kdb_on_nmi) {
- printf ("NMI ... going to debugger\n");
- kdb_trap(type, 0, frame);
- }
-#endif /* KDB */
- goto out;
- } else if (panic_on_nmi == 0)
- goto out;
- /* FALLTHROUGH */
+ nmi_handle_intr(type, frame);
+ goto out;
#endif /* DEV_ISA */
}
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 3decfd43..3cf0c5a 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -158,14 +158,6 @@ static char *trap_msg[] = {
int has_f00f_bug = 0; /* Initialized so that it can be patched. */
#endif
-#ifdef KDB
-static int kdb_on_nmi = 1;
-SYSCTL_INT(_machdep, OID_AUTO, kdb_on_nmi, CTLFLAG_RWTUN,
- &kdb_on_nmi, 0, "Go to KDB on NMI");
-#endif
-static int panic_on_nmi = 1;
-SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RWTUN,
- &panic_on_nmi, 0, "Panic on NMI");
static int prot_fault_translation = 0;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
&prot_fault_translation, 0, "Select signal to deliver on protection fault");
@@ -467,21 +459,7 @@ user_trctrap_out:
}
goto userout;
#else /* !POWERFAIL_NMI */
- /* machine/parity/power fail/"kitchen sink" faults */
- if (isa_nmi(frame->tf_err) == 0) {
-#ifdef KDB
- /*
- * NMI can be hooked up to a pushbutton
- * for debugging.
- */
- if (kdb_on_nmi) {
- printf ("NMI ... going to debugger\n");
- kdb_trap(type, 0, frame);
- }
-#endif /* KDB */
- goto userout;
- } else if (panic_on_nmi)
- panic("NMI indicates hardware failure");
+ nmi_handle_intr(type, frame);
break;
#endif /* POWERFAIL_NMI */
#endif /* DEV_ISA */
@@ -730,22 +708,8 @@ kernel_trctrap:
}
goto out;
#else /* !POWERFAIL_NMI */
- /* machine/parity/power fail/"kitchen sink" faults */
- if (isa_nmi(frame->tf_err) == 0) {
-#ifdef KDB
- /*
- * NMI can be hooked up to a pushbutton
- * for debugging.
- */
- if (kdb_on_nmi) {
- printf ("NMI ... going to debugger\n");
- kdb_trap(type, 0, frame);
- }
-#endif /* KDB */
- goto out;
- } else if (panic_on_nmi == 0)
- goto out;
- /* FALLTHROUGH */
+ nmi_handle_intr(type, frame);
+ goto out;
#endif /* POWERFAIL_NMI */
#endif /* DEV_ISA */
}
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index 4f3b51d..2d1b8be 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -209,6 +209,11 @@ forward_signal(struct thread *td)
* 1: ok
*
*/
+#if defined(__amd64__) || defined(__i386__)
+#define X86 1
+#else
+#define X86 0
+#endif
static int
generic_stop_cpus(cpuset_t map, u_int type)
{
@@ -220,12 +225,11 @@ generic_stop_cpus(cpuset_t map, u_int type)
volatile cpuset_t *cpus;
KASSERT(
-#if defined(__amd64__) || defined(__i386__)
- type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND,
-#else
- type == IPI_STOP || type == IPI_STOP_HARD,
+ type == IPI_STOP || type == IPI_STOP_HARD
+#if X86
+ || type == IPI_SUSPEND
#endif
- ("%s: invalid stop type", __func__));
+ , ("%s: invalid stop type", __func__));
if (!smp_started)
return (0);
@@ -233,7 +237,7 @@ generic_stop_cpus(cpuset_t map, u_int type)
CTR2(KTR_SMP, "stop_cpus(%s) with %u type",
cpusetobj_strprint(cpusetbuf, &map), type);
-#if defined(__amd64__) || defined(__i386__)
+#if X86
/*
* When suspending, ensure there are are no IPIs in progress.
* IPIs that have been issued, but not yet delivered (e.g.
@@ -245,6 +249,9 @@ generic_stop_cpus(cpuset_t map, u_int type)
mtx_lock_spin(&smp_ipi_mtx);
#endif
+#if X86
+ if (!nmi_is_broadcast || nmi_kdb_lock == 0) {
+#endif
if (stopping_cpu != PCPU_GET(cpuid))
while (atomic_cmpset_int(&stopping_cpu, NOCPU,
PCPU_GET(cpuid)) == 0)
@@ -253,8 +260,11 @@ generic_stop_cpus(cpuset_t map, u_int type)
/* send the stop IPI to all CPUs in map */
ipi_selected(map, type);
+#if X86
+ }
+#endif
-#if defined(__amd64__) || defined(__i386__)
+#if X86
if (type == IPI_SUSPEND)
cpus = &suspended_cpus;
else
@@ -272,7 +282,7 @@ generic_stop_cpus(cpuset_t map, u_int type)
}
}
-#if defined(__amd64__) || defined(__i386__)
+#if X86
if (type == IPI_SUSPEND)
mtx_unlock_spin(&smp_ipi_mtx);
#endif
@@ -295,7 +305,7 @@ stop_cpus_hard(cpuset_t map)
return (generic_stop_cpus(map, IPI_STOP_HARD));
}
-#if defined(__amd64__) || defined(__i386__)
+#if X86
int
suspend_cpus(cpuset_t map)
{
@@ -325,20 +335,18 @@ generic_restart_cpus(cpuset_t map, u_int type)
#endif
volatile cpuset_t *cpus;
- KASSERT(
-#if defined(__amd64__) || defined(__i386__)
- type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND,
-#else
- type == IPI_STOP || type == IPI_STOP_HARD,
+ KASSERT(type == IPI_STOP || type == IPI_STOP_HARD
+#if X86
+ || type == IPI_SUSPEND
#endif
- ("%s: invalid stop type", __func__));
+ , ("%s: invalid stop type", __func__));
if (!smp_started)
- return 0;
+ return (0);
CTR1(KTR_SMP, "restart_cpus(%s)", cpusetobj_strprint(cpusetbuf, &map));
-#if defined(__amd64__) || defined(__i386__)
+#if X86
if (type == IPI_SUSPEND)
cpus = &suspended_cpus;
else
@@ -348,11 +356,17 @@ generic_restart_cpus(cpuset_t map, u_int type)
/* signal other cpus to restart */
CPU_COPY_STORE_REL(&map, &started_cpus);
+#if X86
+ if (!nmi_is_broadcast || nmi_kdb_lock == 0) {
+#endif
/* wait for each to clear its bit */
while (CPU_OVERLAP(cpus, &map))
cpu_spinwait();
+#if X86
+ }
+#endif
- return 1;
+ return (1);
}
int
@@ -362,7 +376,7 @@ restart_cpus(cpuset_t map)
return (generic_restart_cpus(map, IPI_STOP));
}
-#if defined(__amd64__) || defined(__i386__)
+#if X86
int
resume_cpus(cpuset_t map)
{
@@ -370,6 +384,7 @@ resume_cpus(cpuset_t map)
return (generic_restart_cpus(map, IPI_SUSPEND));
}
#endif
+#undef X86
/*
* All-CPU rendezvous. CPUs are signalled, all execute the setup function
diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h
index 7c906dd..84a0eba 100644
--- a/sys/x86/include/x86_smp.h
+++ b/sys/x86/include/x86_smp.h
@@ -45,6 +45,9 @@ extern u_int ipi_page;
extern u_int ipi_range;
extern u_int ipi_range_size;
+extern int nmi_kdb_lock;
+extern int nmi_is_broadcast;
+
struct cpu_info {
int cpu_present:1;
int cpu_bsp:1;
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index d04ab9b..12bc1e0 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -85,6 +85,7 @@ struct reg;
struct fpreg;
struct dbreg;
struct dumperinfo;
+struct trapframe;
/*
* The interface type of the interrupt handler entry point cannot be
@@ -107,6 +108,9 @@ bool fix_cpuid(void);
void fillw(int /*u_short*/ pat, void *base, size_t cnt);
int is_physical_memory(vm_paddr_t addr);
int isa_nmi(int cd);
+void nmi_call_kdb(u_int cpu, u_int type, struct trapframe *frame);
+void nmi_call_kdb_smp(u_int type, struct trapframe *frame);
+void nmi_handle_intr(u_int type, struct trapframe *frame);
void pagecopy(void *from, void *to);
void printcpuinfo(void);
int user_dbreg_trap(void);
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
index f07b97e..4e75402 100644
--- a/sys/x86/x86/cpu_machdep.c
+++ b/sys/x86/x86/cpu_machdep.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include "opt_inet.h"
#include "opt_isa.h"
+#include "opt_kdb.h"
#include "opt_kstack_pages.h"
#include "opt_maxmem.h"
#include "opt_mp_watchdog.h"
@@ -526,3 +527,55 @@ idle_sysctl(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
idle_sysctl, "A", "currently selected idle function");
+
+static int panic_on_nmi = 1;
+SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RWTUN,
+ &panic_on_nmi, 0,
+ "Panic on NMI");
+int nmi_is_broadcast = 1;
+SYSCTL_INT(_machdep, OID_AUTO, nmi_is_broadcast, CTLFLAG_RWTUN,
+ &nmi_is_broadcast, 0,
+ "Chipset NMI is broadcast");
+#ifdef KDB
+int kdb_on_nmi = 1;
+SYSCTL_INT(_machdep, OID_AUTO, kdb_on_nmi, CTLFLAG_RWTUN,
+ &kdb_on_nmi, 0,
+ "Go to KDB on NMI");
+#endif
+
+#ifdef DEV_ISA
+void
+nmi_call_kdb(u_int cpu, u_int type, struct trapframe *frame)
+{
+
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(frame->tf_err) == 0) {
+#ifdef KDB
+ /*
+ * NMI can be hooked up to a pushbutton for debugging.
+ */
+ if (kdb_on_nmi) {
+ printf("NMI/cpu%d ... going to debugger\n", cpu);
+ kdb_trap(type, 0, frame);
+ }
+#endif /* KDB */
+ } else if (panic_on_nmi) {
+ panic("NMI indicates hardware failure");
+ }
+}
+#endif
+
+void
+nmi_handle_intr(u_int type, struct trapframe *frame)
+{
+
+#ifdef DEV_ISA
+#ifdef SMP
+ if (nmi_is_broadcast) {
+ nmi_call_kdb_smp(type, frame);
+ return;
+ }
+#endif
+ nmi_call_kdb(PCPU_GET(cpuid), type, frame);
+#endif
+}
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
index 6ef72f9..9de5339 100644
--- a/sys/x86/x86/mp_x86.c
+++ b/sys/x86/x86/mp_x86.c
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include "opt_apic.h"
#endif
#include "opt_cpu.h"
+#include "opt_isa.h"
#include "opt_kstack_pages.h"
#include "opt_pmap.h"
#include "opt_sched.h"
@@ -140,6 +141,7 @@ int cpu_apic_ids[MAXCPU];
volatile u_int cpu_ipi_pending[MAXCPU];
static void release_aps(void *dummy);
+static void cpustop_handler_post(u_int cpu);
static int hyperthreading_allowed = 1;
SYSCTL_INT(_machdep, OID_AUTO, hyperthreading_allowed, CTLFLAG_RDTUN,
@@ -1215,6 +1217,32 @@ ipi_nmi_handler(void)
return (0);
}
+#ifdef DEV_ISA
+int nmi_kdb_lock;
+
+void
+nmi_call_kdb_smp(u_int type, struct trapframe *frame)
+{
+ int cpu;
+ bool call_post;
+
+ cpu = PCPU_GET(cpuid);
+ if (atomic_cmpset_acq_int(&nmi_kdb_lock, 0, 1)) {
+ nmi_call_kdb(cpu, type, frame);
+ call_post = false;
+ } else {
+ savectx(&stoppcbs[cpu]);
+ CPU_SET_ATOMIC(cpu, &stopped_cpus);
+ while (!atomic_cmpset_acq_int(&nmi_kdb_lock, 0, 1))
+ ia32_pause();
+ call_post = true;
+ }
+ atomic_store_rel_int(&nmi_kdb_lock, 0);
+ if (call_post)
+ cpustop_handler_post(cpu);
+}
+#endif
+
/*
* Handle an IPI_STOP by saving our current context and spinning until we
* are resumed.
@@ -1235,6 +1263,13 @@ cpustop_handler(void)
while (!CPU_ISSET(cpu, &started_cpus))
ia32_pause();
+ cpustop_handler_post(cpu);
+}
+
+static void
+cpustop_handler_post(u_int cpu)
+{
+
CPU_CLR_ATOMIC(cpu, &started_cpus);
CPU_CLR_ATOMIC(cpu, &stopped_cpus);
OpenPOWER on IntegriCloud