Page MenuHomeFreeBSD

D46421.diff
No OneTemporary

D46421.diff

diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -230,38 +230,22 @@
VM_CNT_INC(v_trap);
type = frame->tf_trapno;
-#ifdef SMP
- /* Handler for NMI IPIs used for stopping CPUs. */
- if (type == T_NMI && ipi_nmi_handler() == 0)
- return;
-#endif
-
#ifdef KDB
if (kdb_active) {
kdb_reenter();
return;
}
#endif
+ if (type == T_NMI) {
+ nmi_handle_intr(frame);
+ return;
+ }
if (type == T_RESERVED) {
trap_fatal(frame, 0);
return;
}
- if (type == T_NMI) {
-#ifdef HWPMC_HOOKS
- /*
- * CPU PMCs interrupt using an NMI. If the PMC module is
- * active, pass the 'rip' value to the PMC module's interrupt
- * handler. A non-zero return value from the handler means that
- * the NMI was consumed by it and we can return immediately.
- */
- if (pmc_intr != NULL &&
- (*pmc_intr)(frame) != 0)
- return;
-#endif
- }
-
if ((frame->tf_rflags & PSL_I) == 0) {
/*
* Buggy application or kernel code has disabled
@@ -392,10 +376,6 @@
signo = SIGFPE;
break;
- case T_NMI:
- nmi_handle_intr(type, frame);
- return;
-
case T_OFLOW: /* integer overflow fault */
ucode = FPE_INTOVF;
signo = SIGFPE;
@@ -619,10 +599,6 @@
return;
#endif
break;
-
- case T_NMI:
- nmi_handle_intr(type, frame);
- return;
}
trap_fatal(frame, 0);
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -237,12 +237,6 @@
KASSERT((read_eflags() & PSL_I) == 0,
("trap: interrupts enabled, type %d frame %p", type, frame));
-#ifdef SMP
- /* Handler for NMI IPIs used for stopping CPUs. */
- if (type == T_NMI && ipi_nmi_handler() == 0)
- return;
-#endif /* SMP */
-
#ifdef KDB
if (kdb_active) {
kdb_reenter();
@@ -251,24 +245,14 @@
#endif
trap_check_kstack();
- if (type == T_RESERVED) {
- trap_fatal(frame, 0);
+ if (type == T_NMI) {
+ nmi_handle_intr(frame);
return;
}
- if (type == T_NMI) {
-#ifdef HWPMC_HOOKS
- /*
- * CPU PMCs interrupt using an NMI so we check for that first.
- * If the HWPMC module is active, 'pmc_hook' will point to
- * the function to be called. A non-zero return value from the
- * hook means that the NMI was consumed by it and that we can
- * return immediately.
- */
- if (pmc_intr != NULL &&
- (*pmc_intr)(frame) != 0)
- return;
-#endif
+ if (type == T_RESERVED) {
+ trap_fatal(frame, 0);
+ return;
}
if (type == T_MCHK) {
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -148,7 +148,9 @@
void zenbleed_check_and_apply(bool all_cpus);
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 nmi_register_handler(int (*handler)(struct trapframe *));
+void nmi_remove_handler(int (*handler)(struct trapframe *));
+void nmi_handle_intr(struct trapframe *frame);
void pagecopy(void *from, void *to);
void printcpuinfo(void);
int pti_get_default(void);
diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c
--- a/sys/x86/x86/cpu_machdep.c
+++ b/sys/x86/x86/cpu_machdep.c
@@ -76,6 +76,7 @@
#include <machine/cputypes.h>
#include <machine/specialreg.h>
#include <machine/md_var.h>
+#include <machine/trap.h>
#include <machine/tss.h>
#ifdef SMP
#include <machine/smp.h>
@@ -885,17 +886,105 @@
panic("NMI");
}
+/*
+ * Dynamically registered NMI handlers.
+ */
+struct nmi_handler {
+ int running;
+ int (*func)(struct trapframe *);
+ struct nmi_handler *next;
+};
+static struct nmi_handler *nmi_handlers_head = NULL;
+MALLOC_DEFINE(M_NMI, "NMI handlers",
+ "List entries for dynamically registered NMI handlers");
+
void
-nmi_handle_intr(u_int type, struct trapframe *frame)
+nmi_register_handler(int (*handler)(struct trapframe *))
{
+ struct nmi_handler *hp;
+ int (*hpf)(struct trapframe *);
+
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&nmi_handlers_head);
+ while (hp != NULL) {
+ hpf = hp->func;
+ MPASS(hpf != handler);
+ if (hpf == NULL &&
+ atomic_cmpset_ptr((volatile uintptr_t *)&hp->func,
+ (uintptr_t)NULL, (uintptr_t)handler) != 0) {
+ hp->running = 0;
+ return;
+ }
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&hp->next);
+ }
+ hp = malloc(sizeof(struct nmi_handler), M_NMI, M_WAITOK | M_ZERO);
+ hp->func = handler;
+ hp->next = nmi_handlers_head;
+ while (atomic_fcmpset_rel_ptr(
+ (volatile uintptr_t *)&nmi_handlers_head,
+ (uintptr_t *)&hp->next, (uintptr_t)hp) == 0)
+ ;
+}
+void
+nmi_remove_handler(int (*handler)(struct trapframe *))
+{
+ struct nmi_handler *hp;
+
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&nmi_handlers_head);
+ while (hp != NULL) {
+ if (hp->func == handler) {
+ hp->func = NULL;
+ /* Wait for the handler to exit before returning. */
+ while (atomic_load_int(&hp->running) != 0)
+ cpu_spinwait();
+ return;
+ }
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&hp->next);
+ }
+
+ panic("%s: attempting to remove an unregistered NMI handler %p\n",
+ __func__, handler);
+}
+
+void
+nmi_handle_intr(struct trapframe *frame)
+{
+ int (*func)(struct trapframe *);
+ struct nmi_handler *hp;
+ bool handled;
+
+#ifdef SMP
+ /* Handler for NMI IPIs used for stopping CPUs. */
+ if (ipi_nmi_handler() == 0)
+ return;
+#endif
+ handled = false;
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&nmi_handlers_head);
+ while (hp != NULL) {
+ func = hp->func;
+ if (func != NULL) {
+ atomic_add_int(&hp->running, 1);
+ if (func(frame) != 0)
+ handled = true;
+ atomic_subtract_int(&hp->running, 1);
+ }
+ hp = (struct nmi_handler *)atomic_load_acq_ptr(
+ (uintptr_t *)&hp->next);
+ }
+ if (handled)
+ return;
#ifdef SMP
if (nmi_is_broadcast) {
- nmi_call_kdb_smp(type, frame);
+ nmi_call_kdb_smp(T_NMI, frame);
return;
}
#endif
- nmi_call_kdb(PCPU_GET(cpuid), type, frame);
+ nmi_call_kdb(PCPU_GET(cpuid), T_NMI, frame);
}
static int hw_ibrs_active;

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 30, 10:04 AM (4 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17855744
Default Alt Text
D46421.diff (6 KB)

Event Timeline