Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132960944
D19299.id54500.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D19299.id54500.diff
View Options
Index: sys/amd64/vmm/intel/vmx.c
===================================================================
--- sys/amd64/vmm/intel/vmx.c
+++ sys/amd64/vmm/intel/vmx.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2011 NetApp, Inc.
+ * Copyright (c) 2018 Joyent, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -3402,8 +3403,11 @@
struct vlapic vlapic;
struct pir_desc *pir_desc;
struct vmx *vmx;
+ uint_t pending_prio;
};
+#define VPR_PRIO_BIT(vpr) (1 << ((vpr) >> 4))
+
#define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \
do { \
VCPU_CTR2(vm, vcpuid, msg " assert %s-triggered vector %d", \
@@ -3425,7 +3429,7 @@
struct vlapic_vtx *vlapic_vtx;
struct pir_desc *pir_desc;
uint64_t mask;
- int idx, notify;
+ int idx, notify = 0;
vlapic_vtx = (struct vlapic_vtx *)vlapic;
pir_desc = vlapic_vtx->pir_desc;
@@ -3438,7 +3442,37 @@
idx = vector / 64;
mask = 1UL << (vector % 64);
atomic_set_long(&pir_desc->pir[idx], mask);
- notify = atomic_cmpset_long(&pir_desc->pending, 0, 1);
+
+ /*
+ * A notification is required whenever the 'pending' bit makes a
+ * transition from 0->1.
+ *
+ * Even if the 'pending' bit is already asserted, notification about
+ * the incoming interrupt may still be necessary. For example, if a
+ * vCPU is HLTed with a high PPR, a low priority interrupt would cause
+ * the 0->1 'pending' transition with a notification, but the vCPU
+ * would ignore the interrupt for the time being. The same vCPU would
+ * need to then be notified if a high-priority interrupt arrived which
+ * satisfied the PPR.
+ *
+ * The priorities of interrupts injected while 'pending' is asserted
+ * are tracked in a custom bitfield 'pending_prio'. Should the
+ * to-be-injected interrupt exceed the priorities already present, the
+ * notification is sent. The priorities recorded in 'pending_prio' are
+ * cleared whenever the 'pending' bit makes another 0->1 transition.
+ */
+ if (atomic_cmpset_long(&pir_desc->pending, 0, 1) != 0) {
+ notify = 1;
+ vlapic_vtx->pending_prio = 0;
+ } else {
+ const uint_t old_prio = vlapic_vtx->pending_prio;
+ const uint_t prio_bit = VPR_PRIO_BIT(vector & APIC_TPR_INT);
+
+ if ((old_prio & prio_bit) == 0 && prio_bit > old_prio) {
+ atomic_set_int(&vlapic_vtx->pending_prio, prio_bit);
+ notify = 1;
+ }
+ }
VMX_CTR_PIR(vlapic->vm, vlapic->vcpuid, pir_desc, notify, vector,
level, "vmx_set_intr_ready");
@@ -3504,14 +3538,30 @@
VCPU_CTR1(vlapic->vm, vlapic->vcpuid, "HLT with non-zero PPR %d",
lapic->ppr);
+ vpr = 0;
for (i = 3; i >= 0; i--) {
pirval = pir_desc->pir[i];
if (pirval != 0) {
vpr = (i * 64 + flsl(pirval) - 1) & APIC_TPR_INT;
- return (vpr > ppr);
+ break;
}
}
- return (0);
+ /*
+ * If the highest-priority pending interrupt falls short of the
+ * processor priority of this vCPU, ensure that 'pending_prio' does not
+ * have any stale bits which would preclude a higher-priority interrupt
+ * from incurring a notification later.
+ */
+ if (vpr <= ppr) {
+ const uint_t prio_bit = VPR_PRIO_BIT(vpr);
+ const uint_t old = vlapic_vtx->pending_prio;
+
+ if (old > prio_bit && (old & prio_bit) == 0) {
+ vlapic_vtx->pending_prio = prio_bit;
+ }
+ return (0);
+ }
+ return (1);
}
static void
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Oct 22, 2:02 PM (12 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24057816
Default Alt Text
D19299.id54500.diff (3 KB)
Attached To
Mode
D19299: bhyve can miss PIR wake-ups
Attached
Detach File
Event Timeline
Log In to Comment