Skip to content

Commit f106f64

Browse files
roygerroyger
royger
authored and
royger
committed
xen: fix dispatching of NMIs
Currently NMIs are sent over event channels, but that defeats the purpose of NMIs since event channels can be masked. Fix this by issuing NMIs using a hypercall, which injects a NMI (vector #2) to the desired vCPU. Note that NMIs could also be triggered using the emulated local APIC, but using a hypercall is better from a performance point of view since it doesn't involve instruction decoding when not using x2APIC mode. Reported and Tested by: avg Sponsored by: Citrix Systems R&D
1 parent 0c5c403 commit f106f64

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

sys/x86/xen/xen_apic.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ static driver_filter_t xen_invlcache;
7272
static driver_filter_t xen_ipi_bitmap_handler;
7373
static driver_filter_t xen_cpustop_handler;
7474
static driver_filter_t xen_cpususpend_handler;
75-
static driver_filter_t xen_cpustophard_handler;
7675
#endif
7776

7877
/*---------------------------------- Macros ----------------------------------*/
@@ -96,7 +95,6 @@ static struct xen_ipi_handler xen_ipis[] =
9695
[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" },
9796
[IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" },
9897
[IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" },
99-
[IPI_TO_IDX(IPI_STOP_HARD)] = { xen_cpustophard_handler, "sth" },
10098
};
10199
#endif
102100

@@ -259,12 +257,52 @@ xen_pv_lapic_ipi_raw(register_t icrlo, u_int dest)
259257
XEN_APIC_UNSUPPORTED;
260258
}
261259

260+
#define PCPU_ID_GET(id, field) (pcpu_find(id)->pc_##field)
261+
static void
262+
send_nmi(int dest)
263+
{
264+
unsigned int cpu;
265+
266+
/*
267+
* NMIs are not routed over event channels, and instead delivered as on
268+
* native using the exception vector (#2). Triggering them can be done
269+
* using the local APIC, or an hypercall as a shortcut like it's done
270+
* below.
271+
*/
272+
switch(dest) {
273+
case APIC_IPI_DEST_SELF:
274+
HYPERVISOR_vcpu_op(VCPUOP_send_nmi, PCPU_GET(vcpu_id), NULL);
275+
break;
276+
case APIC_IPI_DEST_ALL:
277+
CPU_FOREACH(cpu)
278+
HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
279+
PCPU_ID_GET(cpu, vcpu_id), NULL);
280+
break;
281+
case APIC_IPI_DEST_OTHERS:
282+
CPU_FOREACH(cpu)
283+
if (cpu != PCPU_GET(cpuid))
284+
HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
285+
PCPU_ID_GET(cpu, vcpu_id), NULL);
286+
break;
287+
default:
288+
HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
289+
PCPU_ID_GET(apic_cpuid(dest), vcpu_id), NULL);
290+
break;
291+
}
292+
}
293+
#undef PCPU_ID_GET
294+
262295
static void
263296
xen_pv_lapic_ipi_vectored(u_int vector, int dest)
264297
{
265298
xen_intr_handle_t *ipi_handle;
266299
int ipi_idx, to_cpu, self;
267300

301+
if (vector >= IPI_NMI_FIRST) {
302+
send_nmi(dest);
303+
return;
304+
}
305+
268306
ipi_idx = IPI_TO_IDX(vector);
269307
if (ipi_idx >= nitems(xen_ipis))
270308
panic("IPI out of range");
@@ -522,14 +560,6 @@ xen_cpususpend_handler(void *arg)
522560
return (FILTER_HANDLED);
523561
}
524562

525-
static int
526-
xen_cpustophard_handler(void *arg)
527-
{
528-
529-
ipi_nmi_handler();
530-
return (FILTER_HANDLED);
531-
}
532-
533563
/*----------------------------- XEN PV IPI setup -----------------------------*/
534564
/*
535565
* Those functions are provided outside of the Xen PV APIC implementation

0 commit comments

Comments
 (0)