[PATCH v2 08/11] KVM: x86/xen: Use 32-bit atomics if vCPU's evtchn_pending_sel isn't aligned

0 views
Skip to first unread message

David Woodhouse

unread,
5:48 AM (7 hours ago) 5:48 AM
to sea...@google.com, pbon...@redhat.com, dw...@amazon.co.uk, pa...@xen.org, joao.m....@oracle.com, boris.o...@oracle.com, ankur....@oracle.com, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, h...@zytor.com, x...@kernel.org, syzbot+208f7f...@syzkaller.appspotmail.com, syzkall...@googlegroups.com, suryasai...@gmail.com, l...@intel.com, k...@vger.kernel.org, linux-...@vger.kernel.org
From: Sean Christopherson <sea...@google.com>

When propagating pending Xen events from KVM's "cache" to the guest-visible
structure, use two 32-bit atomic operations to do the bitwise-OR into the
guest-controlled structure if the structure isn't 64-bit aligned, i.e. if
the guest registered its vcpu_info in 32-bit mode and then switched to
64-bit mode, in which case using a 64-bit atomic OR will generate a
split-lock #AC (if enabled).

Opportunistically isolate the clearing of the bits from KVM's cache, as
that structure is KVM-controlled, i.e. is guaranteed to be 64-bit aligned.
This will allow dropping the open-coded inline asm blobs in the future.

[dwmw2: Cast to u64 before shifting; evtchn_pending_sel is unsigned long,
so >> 32 is undefined on 32-bit even though the branch is
unreachable there]

Fixes: 14243b387137 ("KVM: x86/xen: Add KVM_IRQ_ROUTING_XEN_EVTCHN and event channel delivery")
Reported-by: sashi...@kernel.org
Closes: https://lore.kernel.org/all/2026060419355...@smtp.kernel.org
Reported-by: kernel test robot <l...@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202608071502...@intel.com/
Signed-off-by: Sean Christopherson <sea...@google.com>
Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/x86/kvm/xen.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index c935651906ec..419b07fdaa3a 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -663,13 +663,28 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v)
if (kvm_xen_has_64bit_shinfo(v->kvm)) {
struct vcpu_info *vi = gpc->khva;

- asm volatile(LOCK_PREFIX "orq %0, %1\n"
- "notq %0\n"
- LOCK_PREFIX "andq %0, %2\n"
- : "=r" (evtchn_pending_sel),
- "+m" (vi->evtchn_pending_sel),
- "+m" (v->arch.xen.evtchn_pending_sel)
- : "0" (evtchn_pending_sel));
+ if (IS_ALIGNED((unsigned long)&vi->evtchn_pending_sel, sizeof(u64)))
+ asm volatile(LOCK_PREFIX "orq %[src], %[dst]\n"
+ : [dst] "+m" (vi->evtchn_pending_sel)
+ : [src] "r" (evtchn_pending_sel));
+ else
+ /*
+ * The cast keeps the shift well-defined on 32-bit,
+ * where evtchn_pending_sel is 32 bits wide and this
+ * branch is unreachable anyway (this is inside
+ * kvm_xen_has_64bit_shinfo(), which is gated on
+ * IS_ENABLED(CONFIG_64BIT)).
+ */
+ asm volatile(LOCK_PREFIX "orl %[src_lo], %[dst_lo]\n"
+ LOCK_PREFIX "orl %[src_hi], %[dst_hi]\n"
+ : [dst_lo] "+m" (vi->evtchn_pending_sel),
+ [dst_hi] "+m" (*(((u32 *)&vi->evtchn_pending_sel) + 1))
+ : [src_lo] "r" ((u32)evtchn_pending_sel),
+ [src_hi] "r" ((u32)((u64)evtchn_pending_sel >> 32)));
+
+ asm volatile(LOCK_PREFIX "andq %1, %0\n"
+ : "+m" (v->arch.xen.evtchn_pending_sel)
+ : "r" (~evtchn_pending_sel));
WRITE_ONCE(vi->evtchn_upcall_pending, 1);
} else {
u32 evtchn_pending_sel32 = evtchn_pending_sel;
--
2.55.0

Reply all
Reply to author
Forward
0 new messages