Add a hypercall to retrieve the host realtime clock and the TSC value used to calculate that clock read. Used to implement clock synchronization between host and guest. Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> --- Documentation/virtual/kvm/hypercalls.txt | 33 ++++++++++++++++++++++++ arch/x86/include/uapi/asm/kvm_para.h | 9 ++++++ arch/x86/kvm/x86.c | 41 +++++++++++++++++++++++++++++++ include/uapi/linux/kvm_para.h | 3 ++ 4 files changed, 86 insertions(+) v2: improve documentation (Radim) change hypercall name to KVM_HC_CLOCK_PAIRING (Radim) increase padding size Index: kvm-ptpdriver/arch/x86/include/uapi/asm/kvm_para.h =================================================================== --- kvm-ptpdriver.orig/arch/x86/include/uapi/asm/kvm_para.h 2017-01-13 16:43:11.947240575 -0200 +++ kvm-ptpdriver/arch/x86/include/uapi/asm/kvm_para.h 2017-01-13 16:43:25.038258187 -0200 @@ -50,6 +50,15 @@ __u32 pad[11]; }; +#define KVM_CLOCK_PAIRING_WALLCLOCK 0 +struct kvm_clock_offset { + __s64 sec; + __s64 nsec; + __u64 tsc; + __u32 flags; + __u32 pad[9]; +}; + #define KVM_STEAL_ALIGNMENT_BITS 5 #define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1))) #define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1) Index: kvm-ptpdriver/Documentation/virtual/kvm/hypercalls.txt =================================================================== --- kvm-ptpdriver.orig/Documentation/virtual/kvm/hypercalls.txt 2017-01-13 16:43:11.947240575 -0200 +++ kvm-ptpdriver/Documentation/virtual/kvm/hypercalls.txt 2017-01-13 16:43:25.038258187 -0200 @@ -81,3 +81,36 @@ same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall, specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0) is used in the hypercall for future use. + + +6. KVM_HC_CLOCK_PAIRING +------------------------ +Architecture: x86 +Status: active +Purpose: Hypercall used to synchronize host and guest clocks. +Usage: + +a0: guest physical address where host copies +"struct kvm_clock_offset" structure. + +a1: clock_type, ATM only KVM_CLOCK_PAIRING_WALLCLOCK (0) +is supported (hosts CLOCK_REALTIME clock). + + struct kvm_clock_offset { + __s64 sec; + __s64 nsec; + __u64 tsc; + __u32 flags; + __u32 pad[9]; + }; + + Where: + * sec: seconds from clock_type clock. + * nsec: nanoseconds from clock_type clock. + * tsc: TSC value used to calculate sec/nsec pair + (this hypercall only works when host uses TSC clocksource). + * flags: flags, unused (0) at the moment. + +Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource, +or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK. + Index: kvm-ptpdriver/arch/x86/kvm/x86.c =================================================================== --- kvm-ptpdriver.orig/arch/x86/kvm/x86.c 2017-01-13 16:43:20.898252596 -0200 +++ kvm-ptpdriver/arch/x86/kvm/x86.c 2017-01-13 16:43:25.041258191 -0200 @@ -6119,6 +6119,44 @@ } EXPORT_SYMBOL_GPL(kvm_emulate_halt); +static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr, + unsigned long clock_type) +{ + struct kvm_clock_offset *clock_offset; + struct timespec ts; + cycle_t cycle; + int ret; + + if (clock_type != KVM_CLOCK_PAIRING_WALLCLOCK) + return -KVM_EOPNOTSUPP; + + if (pvclock_gtod_data.clock.vclock_mode != VCLOCK_TSC) + return -KVM_EOPNOTSUPP; + + clock_offset = kzalloc(sizeof(struct kvm_clock_offset), GFP_KERNEL); + if (clock_offset == NULL) + return -KVM_ENOMEM; + + if (kvm_get_walltime_and_clockread(&ts, &cycle) == false) { + kfree(clock_offset); + return -KVM_EOPNOTSUPP; + } + + clock_offset->sec = ts.tv_sec; + clock_offset->nsec = ts.tv_nsec; + clock_offset->tsc = kvm_read_l1_tsc(vcpu, cycle); + clock_offset->flags = 0; + + ret = 0; + if (kvm_write_guest(vcpu->kvm, paddr, clock_offset, + sizeof(struct kvm_clock_offset))) + ret = -KVM_EFAULT; + + kfree(clock_offset); + + return ret; +} + /* * kvm_pv_kick_cpu_op: Kick a vcpu. * @@ -6183,6 +6221,9 @@ kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1); ret = 0; break; + case KVM_HC_CLOCK_PAIRING: + ret = kvm_pv_clock_pairing(vcpu, a0, a1); + break; default: ret = -KVM_ENOSYS; break; Index: kvm-ptpdriver/include/uapi/linux/kvm_para.h =================================================================== --- kvm-ptpdriver.orig/include/uapi/linux/kvm_para.h 2017-01-13 16:43:11.947240575 -0200 +++ kvm-ptpdriver/include/uapi/linux/kvm_para.h 2017-01-13 16:43:25.042258192 -0200 @@ -14,6 +14,8 @@ #define KVM_EFAULT EFAULT #define KVM_E2BIG E2BIG #define KVM_EPERM EPERM +#define KVM_EOPNOTSUPP EOPNOTSUPP +#define KVM_ENOMEM ENOMEM #define KVM_HC_VAPIC_POLL_IRQ 1 #define KVM_HC_MMU_OP 2 @@ -23,6 +25,7 @@ #define KVM_HC_MIPS_GET_CLOCK_FREQ 6 #define KVM_HC_MIPS_EXIT_VM 7 #define KVM_HC_MIPS_CONSOLE_OUTPUT 8 +#define KVM_HC_CLOCK_PAIRING 9 /* * hypercalls use architecture specific -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html