With the previous commit having added a KVM clock time reference to kvm_synchronize_tsc(), this patch adds a new TSC attribute KVM_VCPU_TSC_VALUE that allows for setting the TSC value in a way that is unaffected by scheduling delays. Userspace provides a struct kvm_vcpu_tsc_value consisting of a matched pair of ( guest TSC value, KVM clock value ). The TSC value that will ultimately be written is adjusted to account for the time which has elapsed since the given KVM clock time point. In order to allow userspace to retrieve an accurate time reference atomically, without being affected by scheduling delays between KVM_GET_CLOCK and KVM_GET_MSRS, the KVM_GET_DEVICE_ATTR implementation for this attribute uses get_kvmclock() internally and returns a struct kvm_vcpu_tsc_value with both values in one go. If get_kvmclock() supports the KVM_CLOCK_HOST_TSC flag, the two will be based on one and the same host TSC reading. Signed-off-by: Simon Veith <sveith@xxxxxxxxx> --- Documentation/virt/kvm/devices/vcpu.rst | 22 +++++++++++++ arch/x86/include/uapi/asm/kvm.h | 7 +++++ arch/x86/kvm/x86.c | 41 +++++++++++++++++++++++++ tools/arch/x86/include/uapi/asm/kvm.h | 7 +++++ 4 files changed, 77 insertions(+) diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst index 716aa3edae14..a9506d902b0a 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -263,3 +263,25 @@ From the destination VMM process: 7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the respective value derived in the previous step. + +4.2 ATTRIBUTE: KVM_VCPU_TSC_VALUE + +:Parameters: kvm_device_attr.addr points to a struct kvm_vcpu_tsc_value + +Returns: + + ======= ====================================== + -EFAULT Error reading/writing the provided + parameter address. + -ENXIO Attribute not supported + ======= ====================================== + +Gets or sets a matched pair of guest TSC value and KVM clock time point. + +When setting the TSC value through this attribute, a corresponding KVM clock +reference time point (as retrieved by KVM_GET_CLOCK in the clock field) must be +provided. + +The actual TSC value written will be adjusted based on the time that has +elapsed since the provided reference time point, taking TSC scaling into +account. diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 21614807a2cb..79de9e34cfa8 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -525,5 +525,12 @@ struct kvm_pmu_event_filter { /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */ #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ +#define KVM_VCPU_TSC_VALUE 1 /* attribute for the TSC value */ + +/* for KVM_VCPU_TSC_VALUE */ +struct kvm_vcpu_tsc_value { + __u64 tsc_val; + __u64 kvm_ns; +}; #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a44d083f1bf9..ed8c2729eae2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5169,6 +5169,7 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu, switch (attr->attr) { case KVM_VCPU_TSC_OFFSET: + case KVM_VCPU_TSC_VALUE: r = 0; break; default: @@ -5194,6 +5195,32 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu, break; r = 0; break; + case KVM_VCPU_TSC_VALUE: { + struct kvm_vcpu_tsc_value __user *tsc_value_arg; + struct kvm_vcpu_tsc_value tsc_value; + struct kvm_clock_data kvm_clock; + u64 host_tsc, guest_tsc, ratio, offset; + + get_kvmclock(vcpu->kvm, &kvm_clock); + if (kvm_clock.flags & KVM_CLOCK_HOST_TSC) + host_tsc = kvm_clock.host_tsc; + else + host_tsc = rdtsc(); + + ratio = vcpu->arch.l1_tsc_scaling_ratio; + offset = vcpu->arch.l1_tsc_offset; + guest_tsc = kvm_scale_tsc(host_tsc, ratio) + offset; + + tsc_value.kvm_ns = kvm_clock.clock; + tsc_value.tsc_val = guest_tsc; + + tsc_value_arg = (struct kvm_vcpu_tsc_value __user *)uaddr; + r = -EFAULT; + if (copy_to_user(tsc_value_arg, &tsc_value, sizeof(tsc_value))) + break; + r = 0; + break; + } default: r = -ENXIO; } @@ -5236,6 +5263,20 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu, r = 0; break; } + case KVM_VCPU_TSC_VALUE: { + struct kvm_vcpu_tsc_value __user *tsc_value_arg; + struct kvm_vcpu_tsc_value tsc_value; + + tsc_value_arg = (struct kvm_vcpu_tsc_value __user *)uaddr; + r = -EFAULT; + if (copy_from_user(&tsc_value, tsc_value_arg, sizeof(tsc_value))) + break; + + kvm_synchronize_tsc(vcpu, tsc_value.tsc_val, &tsc_value.kvm_ns); + + r = 0; + break; + } default: r = -ENXIO; } diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 21614807a2cb..79de9e34cfa8 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -525,5 +525,12 @@ struct kvm_pmu_event_filter { /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */ #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ +#define KVM_VCPU_TSC_VALUE 1 /* attribute for the TSC value */ + +/* for KVM_VCPU_TSC_VALUE */ +struct kvm_vcpu_tsc_value { + __u64 tsc_val; + __u64 kvm_ns; +}; #endif /* _ASM_X86_KVM_H */ -- 2.25.1 Amazon Development Center Germany GmbH Krausenstr. 38 10117 Berlin Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B Sitz: Berlin Ust-ID: DE 289 237 879