KVM: x86/xen: re-initialize shared_info if guest (32/64-bit) mode is set
authorPaul Durrant <pdurrant@amazon.com>
Thu, 15 Feb 2024 15:29:06 +0000 (15:29 +0000)
committerSean Christopherson <seanjc@google.com>
Tue, 20 Feb 2024 15:37:48 +0000 (07:37 -0800)
If the shared_info PFN cache has already been initialized then the content
of the shared_info page needs to be re-initialized whenever the guest
mode is (re)set.
Setting the guest mode is either done explicitly by the VMM via the
KVM_XEN_ATTR_TYPE_LONG_MODE attribute, or implicitly when the guest writes
the MSR to set up the hypercall page.

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
Link: https://lore.kernel.org/r/20240215152916.1158-12-paul@xen.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/xen.c

index 031e98d88ba22ea9e2f1238d3e43fccd32e2dc72..52edf676c471277620ab0e06e194c31b50bb107d 100644 (file)
@@ -625,8 +625,16 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                } else {
                        mutex_lock(&kvm->arch.xen.xen_lock);
                        kvm->arch.xen.long_mode = !!data->u.long_mode;
+
+                       /*
+                        * Re-initialize shared_info to put the wallclock in the
+                        * correct place. Whilst it's not necessary to do this
+                        * unless the mode is actually changed, it does no harm
+                        * to make the call anyway.
+                        */
+                       r = kvm->arch.xen.shinfo_cache.active ?
+                               kvm_xen_shared_info_init(kvm) : 0;
                        mutex_unlock(&kvm->arch.xen.xen_lock);
-                       r = 0;
                }
                break;
 
@@ -1101,9 +1109,24 @@ int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data)
        u32 page_num = data & ~PAGE_MASK;
        u64 page_addr = data & PAGE_MASK;
        bool lm = is_long_mode(vcpu);
+       int r = 0;
+
+       mutex_lock(&kvm->arch.xen.xen_lock);
+       if (kvm->arch.xen.long_mode != lm) {
+               kvm->arch.xen.long_mode = lm;
+
+               /*
+                * Re-initialize shared_info to put the wallclock in the
+                * correct place.
+                */
+               if (kvm->arch.xen.shinfo_cache.active &&
+                   kvm_xen_shared_info_init(kvm))
+                       r = 1;
+       }
+       mutex_unlock(&kvm->arch.xen.xen_lock);
 
-       /* Latch long_mode for shared_info pages etc. */
-       vcpu->kvm->arch.xen.long_mode = lm;
+       if (r)
+               return r;
 
        /*
         * If Xen hypercall intercept is enabled, fill the hypercall