svn commit: r308438 - in stable/11/sys: amd64/amd64 i386/i386 kern x86/include x86/x86

Konstantin Belousov kib at FreeBSD.org
Tue Nov 8 09:51:57 UTC 2016


Author: kib
Date: Tue Nov  8 09:51:55 2016
New Revision: 308438
URL: https://svnweb.freebsd.org/changeset/base/308438

Log:
  MFC r307866:
  Handle broadcast NMIs.
  
  MFC r307880:
  Follow-up to r307866.
  
  MFC r308030:
  Use correct cpu id in the banner.

Modified:
  stable/11/sys/amd64/amd64/trap.c
  stable/11/sys/i386/i386/trap.c
  stable/11/sys/kern/subr_smp.c
  stable/11/sys/x86/include/x86_smp.h
  stable/11/sys/x86/include/x86_var.h
  stable/11/sys/x86/x86/cpu_machdep.c
  stable/11/sys/x86/x86/mp_x86.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/amd64/amd64/trap.c
==============================================================================
--- stable/11/sys/amd64/amd64/trap.c	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/amd64/amd64/trap.c	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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 */
 		}
 

Modified: stable/11/sys/i386/i386/trap.c
==============================================================================
--- stable/11/sys/i386/i386/trap.c	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/i386/i386/trap.c	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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 */
 		}

Modified: stable/11/sys/kern/subr_smp.c
==============================================================================
--- stable/11/sys/kern/subr_smp.c	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/kern/subr_smp.c	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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 ty
 	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 ty
 	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 ty
 		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 ty
 
 	/* 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 ty
 		}
 	}
 
-#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
 #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
 	/* 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 

Modified: stable/11/sys/x86/include/x86_smp.h
==============================================================================
--- stable/11/sys/x86/include/x86_smp.h	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/x86/include/x86_smp.h	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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;

Modified: stable/11/sys/x86/include/x86_var.h
==============================================================================
--- stable/11/sys/x86/include/x86_var.h	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/x86/include/x86_var.h	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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);

Modified: stable/11/sys/x86/x86/cpu_machdep.c
==============================================================================
--- stable/11/sys/x86/x86/cpu_machdep.c	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/x86/x86/cpu_machdep.c	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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
+}

Modified: stable/11/sys/x86/x86/mp_x86.c
==============================================================================
--- stable/11/sys/x86/x86/mp_x86.c	Tue Nov  8 08:09:48 2016	(r308437)
+++ stable/11/sys/x86/x86/mp_x86.c	Tue Nov  8 09:51:55 2016	(r308438)
@@ -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);
 


More information about the svn-src-all mailing list