aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2017-01-24 12:09:39 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2017-02-07 12:16:45 -0500
commit55dd00a73a518281bc846dc5de1a718349431eb2 (patch)
tree13c912f125578744049bf28902e26e5e30b57b66
parent6342c50ad12e8ce0736e722184a7dbdea4a3477f (diff)
KVM: x86: add KVM_HC_CLOCK_PAIRING hypercall
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@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--Documentation/virtual/kvm/hypercalls.txt35
-rw-r--r--arch/x86/include/uapi/asm/kvm_para.h9
-rw-r--r--arch/x86/kvm/x86.c66
-rw-r--r--include/uapi/linux/kvm_para.h2
4 files changed, 112 insertions, 0 deletions
diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
index c8d040e27046..feaaa634f154 100644
--- a/Documentation/virtual/kvm/hypercalls.txt
+++ b/Documentation/virtual/kvm/hypercalls.txt
@@ -81,3 +81,38 @@ the vcpu to sleep until occurrence of an appropriate event. Another vcpu of the
81same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall, 81same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall,
82specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0) 82specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0)
83is used in the hypercall for future use. 83is used in the hypercall for future use.
84
85
866. KVM_HC_CLOCK_PAIRING
87------------------------
88Architecture: x86
89Status: active
90Purpose: Hypercall used to synchronize host and guest clocks.
91Usage:
92
93a0: guest physical address where host copies
94"struct kvm_clock_offset" structure.
95
96a1: clock_type, ATM only KVM_CLOCK_PAIRING_WALLCLOCK (0)
97is supported (corresponding to the host's CLOCK_REALTIME clock).
98
99 struct kvm_clock_pairing {
100 __s64 sec;
101 __s64 nsec;
102 __u64 tsc;
103 __u32 flags;
104 __u32 pad[9];
105 };
106
107 Where:
108 * sec: seconds from clock_type clock.
109 * nsec: nanoseconds from clock_type clock.
110 * tsc: guest TSC value used to calculate sec/nsec pair
111 * flags: flags, unused (0) at the moment.
112
113The hypercall lets a guest compute a precise timestamp across
114host and guest. The guest can use the returned TSC value to
115compute the CLOCK_REALTIME for its clock, at the same instant.
116
117Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource,
118or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK.
diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
index 1421a6585126..cff0bb6556f8 100644
--- a/arch/x86/include/uapi/asm/kvm_para.h
+++ b/arch/x86/include/uapi/asm/kvm_para.h
@@ -50,6 +50,15 @@ struct kvm_steal_time {
50 __u32 pad[11]; 50 __u32 pad[11];
51}; 51};
52 52
53#define KVM_CLOCK_PAIRING_WALLCLOCK 0
54struct kvm_clock_pairing {
55 __s64 sec;
56 __s64 nsec;
57 __u64 tsc;
58 __u32 flags;
59 __u32 pad[9];
60};
61
53#define KVM_STEAL_ALIGNMENT_BITS 5 62#define KVM_STEAL_ALIGNMENT_BITS 5
54#define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1))) 63#define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1)))
55#define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1) 64#define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4fd4d4f35caf..09e5d31dac98 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1142,6 +1142,7 @@ struct pvclock_gtod_data {
1142 1142
1143 u64 boot_ns; 1143 u64 boot_ns;
1144 u64 nsec_base; 1144 u64 nsec_base;
1145 u64 wall_time_sec;
1145}; 1146};
1146 1147
1147static struct pvclock_gtod_data pvclock_gtod_data; 1148static struct pvclock_gtod_data pvclock_gtod_data;
@@ -1165,6 +1166,8 @@ static void update_pvclock_gtod(struct timekeeper *tk)
1165 vdata->boot_ns = boot_ns; 1166 vdata->boot_ns = boot_ns;
1166 vdata->nsec_base = tk->tkr_mono.xtime_nsec; 1167 vdata->nsec_base = tk->tkr_mono.xtime_nsec;
1167 1168
1169 vdata->wall_time_sec = tk->xtime_sec;
1170
1168 write_seqcount_end(&vdata->seq); 1171 write_seqcount_end(&vdata->seq);
1169} 1172}
1170#endif 1173#endif
@@ -1626,6 +1629,28 @@ static int do_monotonic_boot(s64 *t, u64 *cycle_now)
1626 return mode; 1629 return mode;
1627} 1630}
1628 1631
1632static int do_realtime(struct timespec *ts, u64 *cycle_now)
1633{
1634 struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
1635 unsigned long seq;
1636 int mode;
1637 u64 ns;
1638
1639 do {
1640 seq = read_seqcount_begin(&gtod->seq);
1641 mode = gtod->clock.vclock_mode;
1642 ts->tv_sec = gtod->wall_time_sec;
1643 ns = gtod->nsec_base;
1644 ns += vgettsc(cycle_now);
1645 ns >>= gtod->clock.shift;
1646 } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
1647
1648 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
1649 ts->tv_nsec = ns;
1650
1651 return mode;
1652}
1653
1629/* returns true if host is using tsc clocksource */ 1654/* returns true if host is using tsc clocksource */
1630static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *cycle_now) 1655static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *cycle_now)
1631{ 1656{
@@ -1635,6 +1660,17 @@ static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *cycle_now)
1635 1660
1636 return do_monotonic_boot(kernel_ns, cycle_now) == VCLOCK_TSC; 1661 return do_monotonic_boot(kernel_ns, cycle_now) == VCLOCK_TSC;
1637} 1662}
1663
1664/* returns true if host is using tsc clocksource */
1665static bool kvm_get_walltime_and_clockread(struct timespec *ts,
1666 u64 *cycle_now)
1667{
1668 /* checked again under seqlock below */
1669 if (pvclock_gtod_data.clock.vclock_mode != VCLOCK_TSC)
1670 return false;
1671
1672 return do_realtime(ts, cycle_now) == VCLOCK_TSC;
1673}
1638#endif 1674#endif
1639 1675
1640/* 1676/*
@@ -6112,6 +6148,33 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
6112} 6148}
6113EXPORT_SYMBOL_GPL(kvm_emulate_halt); 6149EXPORT_SYMBOL_GPL(kvm_emulate_halt);
6114 6150
6151static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr,
6152 unsigned long clock_type)
6153{
6154 struct kvm_clock_pairing clock_pairing;
6155 struct timespec ts;
6156 cycle_t cycle;
6157 int ret;
6158
6159 if (clock_type != KVM_CLOCK_PAIRING_WALLCLOCK)
6160 return -KVM_EOPNOTSUPP;
6161
6162 if (kvm_get_walltime_and_clockread(&ts, &cycle) == false)
6163 return -KVM_EOPNOTSUPP;
6164
6165 clock_pairing.sec = ts.tv_sec;
6166 clock_pairing.nsec = ts.tv_nsec;
6167 clock_pairing.tsc = kvm_read_l1_tsc(vcpu, cycle);
6168 clock_pairing.flags = 0;
6169
6170 ret = 0;
6171 if (kvm_write_guest(vcpu->kvm, paddr, &clock_pairing,
6172 sizeof(struct kvm_clock_pairing)))
6173 ret = -KVM_EFAULT;
6174
6175 return ret;
6176}
6177
6115/* 6178/*
6116 * kvm_pv_kick_cpu_op: Kick a vcpu. 6179 * kvm_pv_kick_cpu_op: Kick a vcpu.
6117 * 6180 *
@@ -6176,6 +6239,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
6176 kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1); 6239 kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);
6177 ret = 0; 6240 ret = 0;
6178 break; 6241 break;
6242 case KVM_HC_CLOCK_PAIRING:
6243 ret = kvm_pv_clock_pairing(vcpu, a0, a1);
6244 break;
6179 default: 6245 default:
6180 ret = -KVM_ENOSYS; 6246 ret = -KVM_ENOSYS;
6181 break; 6247 break;
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index bf6cd7d5cac2..fed506aeff62 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -14,6 +14,7 @@
14#define KVM_EFAULT EFAULT 14#define KVM_EFAULT EFAULT
15#define KVM_E2BIG E2BIG 15#define KVM_E2BIG E2BIG
16#define KVM_EPERM EPERM 16#define KVM_EPERM EPERM
17#define KVM_EOPNOTSUPP 95
17 18
18#define KVM_HC_VAPIC_POLL_IRQ 1 19#define KVM_HC_VAPIC_POLL_IRQ 1
19#define KVM_HC_MMU_OP 2 20#define KVM_HC_MMU_OP 2
@@ -23,6 +24,7 @@
23#define KVM_HC_MIPS_GET_CLOCK_FREQ 6 24#define KVM_HC_MIPS_GET_CLOCK_FREQ 6
24#define KVM_HC_MIPS_EXIT_VM 7 25#define KVM_HC_MIPS_EXIT_VM 7
25#define KVM_HC_MIPS_CONSOLE_OUTPUT 8 26#define KVM_HC_MIPS_CONSOLE_OUTPUT 8
27#define KVM_HC_CLOCK_PAIRING 9
26 28
27/* 29/*
28 * hypercalls use architecture specific 30 * hypercalls use architecture specific