From: Paul Durrant <[email protected]>

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 <[email protected]>
---
Cc: Sean Christopherson <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: [email protected]

v10:
 - New in this version.
---
 arch/x86/kvm/xen.c | 36 +++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 9351b32cfcba..3aa452a71890 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -623,10 +623,20 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct 
kvm_xen_hvm_attr *data)
                if (!IS_ENABLED(CONFIG_64BIT) && data->u.long_mode) {
                        r = -EINVAL;
                } else {
+                       bool lm = !!data->u.long_mode;
+
                        mutex_lock(&kvm->arch.xen.xen_lock);
-                       kvm->arch.xen.long_mode = !!data->u.long_mode;
+                       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.
+                                */
+                               r = kvm->arch.xen.shinfo_cache.active ?
+                                       kvm_xen_shared_info_init(kvm) : 0;
+                       }
                        mutex_unlock(&kvm->arch.xen.xen_lock);
-                       r = 0;
                }
                break;
 
@@ -648,9 +658,6 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct 
kvm_xen_hvm_attr *data)
 
                srcu_read_unlock(&kvm->srcu, idx);
 
-               if (!r && kvm->arch.xen.shinfo_cache.active)
-                       r = kvm_xen_shared_info_init(kvm);
-
                mutex_unlock(&kvm->arch.xen.xen_lock);
                break;
        }
@@ -1101,9 +1108,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
-- 
2.39.2


Reply via email to