History

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.

Marcelo Tosatti committed 9 years ago

Commit 55dd00a1 parent 6342c504 files · +112 −0Browse files

Unified · Split

4 files
  1. Documentation/virtual/kvm/hypercalls.txt +35 −0
  2. arch/x86/include/uapi/asm/kvm_para.h +9 −0
  3. arch/x86/kvm/x86.c +66 −0
  4. include/uapi/linux/kvm_para.h +2 −0
Documentation/virtual/kvm/hypercalls.txt+35−0
@@ -81,3 +81,38 @@ the vcpu to sleep until occurrence of an appropriate event. Another vcpu of the · 80 unmodified lines
8181 same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall,
8282 specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0)
8383 is used in the hypercall for future use.
84+
85+
86+6. KVM_HC_CLOCK_PAIRING
87+------------------------
88+Architecture: x86
89+Status: active
90+Purpose: Hypercall used to synchronize host and guest clocks.
91+Usage:
92+
93+a0: guest physical address where host copies
94+"struct kvm_clock_offset" structure.
95+
96+a1: clock_type, ATM only KVM_CLOCK_PAIRING_WALLCLOCK (0)
97+is 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+
113+The hypercall lets a guest compute a precise timestamp across
114+host and guest. The guest can use the returned TSC value to
115+compute the CLOCK_REALTIME for its clock, at the same instant.
116+
117+Returns KVM_EOPNOTSUPP if the host does not use TSC clocksource,
118+or if clock type is different than KVM_CLOCK_PAIRING_WALLCLOCK.
arch/x86/include/uapi/asm/kvm_para.h+9−0
@@ -50,6 +50,15 @@ struct kvm_steal_time { · 49 unmodified lines
5050 __u32 pad[11];
5151 };
5252
53+#define KVM_CLOCK_PAIRING_WALLCLOCK 0
54+struct kvm_clock_pairing {
55+ __s64 sec;
56+ __s64 nsec;
57+ __u64 tsc;
58+ __u32 flags;
59+ __u32 pad[9];
60+};
61+
5362 #define KVM_STEAL_ALIGNMENT_BITS 5
5463 #define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1)))
5564 #define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1)
arch/x86/kvm/x86.c+66−0
@@ -1142,6 +1142,7 @@ struct pvclock_gtod_data { · 1141 unmodified lines
11421142
11431143 u64 boot_ns;
11441144 u64 nsec_base;
1145+ u64 wall_time_sec;
11451146 };
11461147
11471148 static struct pvclock_gtod_data pvclock_gtod_data;
@@ -1165,6 +1166,8 @@ static void update_pvclock_gtod(struct timekeeper *tk) · 17 unmodified lines
11651166 vdata->boot_ns = boot_ns;
11661167 vdata->nsec_base = tk->tkr_mono.xtime_nsec;
11671168
1169+ vdata->wall_time_sec = tk->xtime_sec;
1170+
11681171 write_seqcount_end(&vdata->seq);
11691172 }
11701173 #endif
@@ -1626,6 +1629,28 @@ static int do_monotonic_boot(s64 *t, u64 *cycle_now) · 455 unmodified lines
16261629 return mode;
16271630 }
16281631
1632+static 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+
16291654 /* returns true if host is using tsc clocksource */
16301655 static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *cycle_now)
16311656 {
@@ -1635,6 +1660,17 @@ static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *cycle_now) · 3 unmodified lines
16351660
16361661 return do_monotonic_boot(kernel_ns, cycle_now) == VCLOCK_TSC;
16371662 }
1663+
1664+/* returns true if host is using tsc clocksource */
1665+static 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+}
16381674 #endif
16391675
16401676 /*
@@ -6112,6 +6148,33 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu) · 4471 unmodified lines
61126148 }
61136149 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
61146150
6151+static 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+
61156178 /*
61166179 * kvm_pv_kick_cpu_op: Kick a vcpu.
61176180 *
@@ -6176,6 +6239,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) · 58 unmodified lines
61766239 kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);
61776240 ret = 0;
61786241 break;
6242+ case KVM_HC_CLOCK_PAIRING:
6243+ ret = kvm_pv_clock_pairing(vcpu, a0, a1);
6244+ break;
61796245 default:
61806246 ret = -KVM_ENOSYS;
61816247 break;
include/uapi/linux/kvm_para.h+2−0
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #define KVM_EFAULT EFAULT
1515 #define KVM_E2BIG E2BIG
1616 #define KVM_EPERM EPERM
17+#define KVM_EOPNOTSUPP 95
1718
1819 #define KVM_HC_VAPIC_POLL_IRQ 1
1920 #define KVM_HC_MMU_OP 2
@@ -23,6 +24,7 @@ · 3 unmodified lines
2324 #define KVM_HC_MIPS_GET_CLOCK_FREQ 6
2425 #define KVM_HC_MIPS_EXIT_VM 7
2526 #define KVM_HC_MIPS_CONSOLE_OUTPUT 8
27+#define KVM_HC_CLOCK_PAIRING 9
2628
2729 /*
2830 * hypercalls use architecture specific

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t