]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: x86/xen: setup pvclock updates
authorJoao Martins <joao.m.martins@oracle.com>
Fri, 1 Feb 2019 18:01:45 +0000 (13:01 -0500)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Wed, 9 Dec 2020 20:57:52 +0000 (20:57 +0000)
This means when we set shared_info page GPA, and request a master
clock update. This will trigger all vcpus to update their respective
shared pvclock data with guests. We follow a similar approach
as Hyper-V and KVM and adjust it accordingly.

Note however that Xen differs a little on how pvclock pages are set up.
Specifically KVM assumes 4KiB page alignment and pvclock data starts in
the beginning of the page. Whereas Xen you can place that information
anywhere in the page.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/kvm/x86.c
arch/x86/kvm/xen.c
arch/x86/kvm/xen.h

index 4a960629687cd383273e24b108108ec3c32635cb..e9191dfffbbb3c35a341409b42db9fd02fd87dee 100644 (file)
@@ -2719,6 +2719,8 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 
        if (vcpu->pv_time_enabled)
                kvm_setup_pvclock_page(v);
+       if (ka->xen.shinfo)
+               kvm_xen_setup_pvclock_page(v);
        if (v == kvm_get_vcpu(v->kvm, 0))
                kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock);
        return 0;
index 5b3e1022225fb91dce45e98b0819be547261f3dd..b5be2f6be87ed0e836a8c9bb5c067a968d1314a8 100644 (file)
@@ -55,9 +55,68 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
        if (ret)
                return ret;
 
+       kvm_make_all_cpus_request(kvm, KVM_REQ_MASTERCLOCK_UPDATE);
+
        return 0;
 }
 
+void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
+{
+       struct kvm_vcpu_arch *vcpu = &v->arch;
+       struct pvclock_vcpu_time_info *guest_hv_clock;
+       unsigned int offset;
+       void *hva;
+       int idx;
+
+       if (v->vcpu_id >= MAX_VIRT_CPUS)
+               return;
+
+       BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
+       BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
+       BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info));
+       BUILD_BUG_ON(offsetof(struct vcpu_info, time) !=
+                    offsetof(struct compat_vcpu_info, time));
+
+       idx = srcu_read_lock(&v->kvm->srcu);
+       hva = READ_ONCE(v->kvm->arch.xen.shinfo);
+       if (!hva)
+               goto out;
+
+       offset = v->vcpu_id * sizeof(struct vcpu_info);
+       offset += offsetof(struct vcpu_info, time);
+
+       guest_hv_clock = hva + offset;
+
+       if (guest_hv_clock->version & 1)
+               ++guest_hv_clock->version;  /* first time write, random junk */
+
+       vcpu->hv_clock.version = guest_hv_clock->version + 1;
+       guest_hv_clock->version = vcpu->hv_clock.version;
+
+       smp_wmb();
+
+       /* retain PVCLOCK_GUEST_STOPPED if set in guest copy */
+       vcpu->hv_clock.flags |= (guest_hv_clock->flags & PVCLOCK_GUEST_STOPPED);
+
+       if (vcpu->pvclock_set_guest_stopped_request) {
+               vcpu->hv_clock.flags |= PVCLOCK_GUEST_STOPPED;
+               vcpu->pvclock_set_guest_stopped_request = false;
+       }
+
+       trace_kvm_pvclock_update(v->vcpu_id, &vcpu->hv_clock);
+
+       *guest_hv_clock = vcpu->hv_clock;
+
+       smp_wmb();
+
+       vcpu->hv_clock.version++;
+
+       guest_hv_clock->version = vcpu->hv_clock.version;
+
+ out:
+       srcu_read_unlock(&v->kvm->srcu, idx);
+}
+
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 {
        int r = -ENOENT;
index cd3c52b62068912348bfc956966ff52205778807..950a364f5b22abea7c37a4ece24e0e7487f8c84e 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef __ARCH_X86_KVM_XEN_H__
 #define __ARCH_X86_KVM_XEN_H__
 
+void kvm_xen_setup_pvclock_page(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hypercall(struct kvm_vcpu *vcpu);