--- old/usr/src/uts/i86pc/io/pcplusmp/apic_common.c	Sat Mar 30 14:54:00 2019
+++ new/usr/src/uts/i86pc/io/pcplusmp/apic_common.c	Sat Mar 30 14:54:00 2019
@@ -23,7 +23,7 @@
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  */
 /*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
  * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
  */
 
@@ -808,6 +808,8 @@
 void
 apic_nmi_intr(caddr_t arg, struct regs *rp)
 {
+	nmi_action_t action = nmi_action;
+
 	if (apic_shutdown_processors) {
 		apic_disable_local_apic();
 		return;
@@ -819,18 +821,41 @@
 		return;
 	apic_num_nmis++;
 
-	if (apic_kmdb_on_nmi && psm_debugger()) {
-		debug_enter("NMI received: entering kmdb\n");
-	} else if (apic_panic_on_nmi) {
-		/* Keep panic from entering kmdb. */
-		nopanicdebug = 1;
-		panic("NMI received\n");
-	} else {
+	/*
+	 * "nmi_action" always over-rides the older way of doing this, unless we
+	 * can't actually drop into kmdb when requested.
+	 */
+	if (action == NMI_ACTION_KMDB && !psm_debugger())
+		action = NMI_ACTION_UNSET;
+
+	if (action == NMI_ACTION_UNSET) {
+		if (apic_kmdb_on_nmi && psm_debugger())
+			action = NMI_ACTION_KMDB;
+		else if (apic_panic_on_nmi)
+			action = NMI_ACTION_PANIC;
+		else
+			action = NMI_ACTION_IGNORE;
+	}
+
+	switch (action) {
+	case NMI_ACTION_IGNORE:
 		/*
 		 * prom_printf is the best shot we have of something which is
 		 * problem free from high level/NMI type of interrupts
 		 */
 		prom_printf("NMI received\n");
+		break;
+
+	case NMI_ACTION_PANIC:
+		/* Keep panic from entering kmdb. */
+		nopanicdebug = 1;
+		panic("NMI received\n");
+		break;
+
+	case NMI_ACTION_KMDB:
+	default:
+		debug_enter("NMI received: entering kmdb\n");
+		break;
 	}
 
 	lock_clear(&apic_nmi_lock);
--- old/usr/src/uts/i86pc/os/fakebop.c	Sat Mar 30 14:54:01 2019
+++ new/usr/src/uts/i86pc/os/fakebop.c	Sat Mar 30 14:54:01 2019
@@ -2915,10 +2915,8 @@
 	return (0);
 }
 
-#define	BP_MAX_STRLEN	32
-
 /*
- * Get value for given boot property
+ * Get an integer value for given boot property
  */
 int
 bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
@@ -2928,7 +2926,7 @@
 	u_longlong_t	value;
 
 	boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
-	if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
+	if (boot_prop_len < 0 || boot_prop_len >= sizeof (str) ||
 	    BOP_GETPROP(bootops, prop_name, str) < 0 ||
 	    kobj_getvalue(str, &value) == -1)
 		return (-1);
@@ -2937,4 +2935,16 @@
 		*prop_value = value;
 
 	return (0);
+}
+
+int
+bootprop_getstr(const char *prop_name, char *buf, size_t buflen)
+{
+	int boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
+
+	if (boot_prop_len < 0 || boot_prop_len >= buflen ||
+	    BOP_GETPROP(bootops, prop_name, buf) < 0)
+		return (-1);
+
+	return (0);
 }
--- old/usr/src/uts/i86pc/os/mlsetup.c	Sat Mar 30 14:54:02 2019
+++ new/usr/src/uts/i86pc/os/mlsetup.c	Sat Mar 30 14:54:02 2019
@@ -23,7 +23,7 @@
  *
  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 by Delphix. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
  */
 /*
  * Copyright (c) 2010, Intel Corporation.
@@ -61,6 +61,8 @@
 #include <sys/archsystm.h>
 #include <sys/promif.h>
 #include <sys/pci_cfgspace.h>
+#include <sys/apic.h>
+#include <sys/apic_common.h>
 #include <sys/bootvfs.h>
 #include <sys/tsc.h>
 #ifdef __xpv
@@ -79,6 +81,8 @@
 extern uint32_t cpuid_feature_edx_include;
 extern uint32_t cpuid_feature_edx_exclude;
 
+nmi_action_t nmi_action = NMI_ACTION_UNSET;
+
 /*
  * Set console mode
  */
@@ -103,6 +107,7 @@
 mlsetup(struct regs *rp)
 {
 	u_longlong_t prop_value;
+	char prop_str[BP_MAX_STRLEN];
 	extern struct classfuncs sys_classfuncs;
 	extern disp_t cpu0_disp;
 	extern char t0stack[];
@@ -149,6 +154,19 @@
 		cpuid_feature_edx_exclude = (uint32_t)prop_value;
 
 #if !defined(__xpv)
+	if (bootprop_getstr("nmi", prop_str, sizeof (prop_str)) == 0) {
+		if (strcmp(prop_str, "ignore") == 0) {
+			nmi_action = NMI_ACTION_IGNORE;
+		} else if (strcmp(prop_str, "panic") == 0) {
+			nmi_action = NMI_ACTION_PANIC;
+		} else if (strcmp(prop_str, "kmdb") == 0) {
+			nmi_action = NMI_ACTION_KMDB;
+		} else {
+			prom_printf("unix: ignoring unknown nmi=%s\n",
+			    prop_str);
+		}
+	}
+
 	/*
 	 * Check to see if KPTI has been explicitly enabled or disabled.
 	 * We have to check this before init_desctbls().
--- old/usr/src/uts/i86pc/sys/apic_common.h	Sat Mar 30 14:54:02 2019
+++ new/usr/src/uts/i86pc/sys/apic_common.h	Sat Mar 30 14:54:02 2019
@@ -23,7 +23,7 @@
  * Copyright (c) 2017 by Delphix. All rights reserved.
  */
 /*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
  */
 
 #ifndef _SYS_APIC_COMMON_H
@@ -155,7 +155,6 @@
 extern lock_t	apic_error_lock;
 
 /* Patchable global variables. */
-extern int	apic_kmdb_on_nmi;	/* 0 - no, 1 - yes enter kmdb */
 extern uint32_t	apic_divide_reg_init;	/* 0 - divide by 2 */
 
 extern apic_intrmap_ops_t *apic_vt_ops;
@@ -202,6 +201,15 @@
 extern uint32_t apic_get_localapicid(uint32_t cpuid);
 extern uchar_t apic_get_ioapicid(uchar_t ioapicindex);
 
+typedef enum nmi_action {
+	NMI_ACTION_UNSET,
+	NMI_ACTION_PANIC,
+	NMI_ACTION_IGNORE,
+	NMI_ACTION_KMDB
+} nmi_action_t;
+
+extern nmi_action_t nmi_action;
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/uts/intel/sys/bootconf.h	Sat Mar 30 14:54:03 2019
+++ new/usr/src/uts/intel/sys/bootconf.h	Sat Mar 30 14:54:03 2019
@@ -23,6 +23,7 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2019, Joyent, Inc.
  */
 
 #ifndef	_SYS_BOOTCONF_H
@@ -46,6 +47,8 @@
 extern "C" {
 #endif
 
+#define	BP_MAX_STRLEN	32
+
 /*
  * Boot property names
  */
@@ -243,6 +246,7 @@
 extern void boot_prop_finish(void);
 
 extern int bootprop_getval(const char *, u_longlong_t *);
+extern int bootprop_getstr(const char *, char *, size_t);
 
 /*
  * Back door to fakebop.c to get physical memory allocated.
