From: Sean Christopherson 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: sashiko-bot@kernel.org Closes: https://lore.kernel.org/all/20260604193554.1BA311F00893@smtp.kernel.org Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202608071502.rYOi3Pg8-lkp@intel.com/ Signed-off-by: Sean Christopherson Signed-off-by: David Woodhouse --- 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