Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115840590
D46421.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D46421.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D46421: x86: Refactor kernel-mode NMI handling
Attached
Detach File
Event Timeline
Log In to Comment