@@ -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;
@@ -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;
@@ -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);