vclock_gettime.c 8.2 KB
Newer Older
1 2 3 4
/*
 * Copyright 2006 Andi Kleen, SUSE Labs.
 * Subject to the GNU Public License, v.2
 *
A
Andy Lutomirski 已提交
5
 * Fast user context implementation of clock_gettime, gettimeofday, and time.
6
 *
7 8 9
 * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
 *  sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
 *
10 11 12 13
 * The code should have no internal unresolved relocations.
 * Check with readelf after changing.
 */

14
#include <uapi/linux/time.h>
15
#include <asm/vgtod.h>
16
#include <asm/vvar.h>
17
#include <asm/unistd.h>
18
#include <asm/msr.h>
19
#include <asm/pvclock.h>
20
#include <asm/mshyperv.h>
21 22
#include <linux/math64.h>
#include <linux/time.h>
23
#include <linux/kernel.h>
24

25
#define gtod (&VVAR(vsyscall_gtod_data))
26

27 28 29 30
extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts);
extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
extern time_t __vdso_time(time_t *t);

31
#ifdef CONFIG_PARAVIRT_CLOCK
32
extern u8 pvclock_page[PAGE_SIZE]
33 34 35
	__attribute__((visibility("hidden")));
#endif

36
#ifdef CONFIG_HYPERV_TSCPAGE
37
extern u8 hvclock_page[PAGE_SIZE]
38 39 40
	__attribute__((visibility("hidden")));
#endif

41 42
#ifndef BUILD_VDSO32

43 44 45
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
	long ret;
46 47 48
	asm ("syscall" : "=a" (ret), "=m" (*ts) :
	     "0" (__NR_clock_gettime), "D" (clock), "S" (ts) :
	     "memory", "rcx", "r11");
49
	return ret;
50 51
}

52
notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
53
{
54 55
	long ret;

56 57 58
	asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) :
	     "0" (__NR_gettimeofday), "D" (tv), "S" (tz) :
	     "memory", "rcx", "r11");
59
	return ret;
60 61
}

62

63 64 65 66 67 68
#else

notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
	long ret;

69
	asm (
70
		"mov %%ebx, %%edx \n"
71
		"mov %[clock], %%ebx \n"
72 73
		"call __kernel_vsyscall \n"
		"mov %%edx, %%ebx \n"
74
		: "=a" (ret), "=m" (*ts)
75
		: "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts)
76 77 78 79 80 81 82 83
		: "memory", "edx");
	return ret;
}

notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
	long ret;

84
	asm (
85
		"mov %%ebx, %%edx \n"
86
		"mov %[tv], %%ebx \n"
87 88
		"call __kernel_vsyscall \n"
		"mov %%edx, %%ebx \n"
89
		: "=a" (ret), "=m" (*tv), "=m" (*tz)
90
		: "0" (__NR_gettimeofday), [tv] "g" (tv), "c" (tz)
91 92 93 94 95 96 97
		: "memory", "edx");
	return ret;
}

#endif

#ifdef CONFIG_PARAVIRT_CLOCK
98
static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void)
99
{
100
	return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
101 102
}

103
static notrace u64 vread_pvclock(int *mode)
104
{
105
	const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
106
	u64 ret;
107 108
	u64 last;
	u32 version;
109 110

	/*
111 112 113 114 115 116 117 118 119 120 121
	 * Note: The kernel and hypervisor must guarantee that cpu ID
	 * number maps 1:1 to per-CPU pvclock time info.
	 *
	 * Because the hypervisor is entirely unaware of guest userspace
	 * preemption, it cannot guarantee that per-CPU pvclock time
	 * info is updated if the underlying CPU changes or that that
	 * version is increased whenever underlying CPU changes.
	 *
	 * On KVM, we are guaranteed that pvti updates for any vCPU are
	 * atomic as seen by *all* vCPUs.  This is an even stronger
	 * guarantee than we get with a normal seqlock.
122
	 *
123 124
	 * On Xen, we don't appear to have that guarantee, but Xen still
	 * supplies a valid seqlock using the version field.
125
	 *
126 127 128 129
	 * We only do pvclock vdso timing at all if
	 * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
	 * mean that all vCPUs have matching pvti and that the TSC is
	 * synced, so we can just look at vCPU 0's pvti.
130
	 */
131 132

	do {
133
		version = pvclock_read_begin(pvti);
134

135 136 137 138 139
		if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
			*mode = VCLOCK_NONE;
			return 0;
		}

140
		ret = __pvclock_read_cycles(pvti, rdtsc_ordered());
141
	} while (pvclock_read_retry(pvti, version));
142

143
	/* refer to vread_tsc() comment for rationale */
144
	last = gtod->cycle_last;
145 146 147 148 149 150 151

	if (likely(ret >= last))
		return ret;

	return last;
}
#endif
152 153 154 155 156 157 158 159 160 161 162 163 164 165
#ifdef CONFIG_HYPERV_TSCPAGE
static notrace u64 vread_hvclock(int *mode)
{
	const struct ms_hyperv_tsc_page *tsc_pg =
		(const struct ms_hyperv_tsc_page *)&hvclock_page;
	u64 current_tick = hv_read_tsc_page(tsc_pg);

	if (current_tick != U64_MAX)
		return current_tick;

	*mode = VCLOCK_NONE;
	return 0;
}
#endif
166

167
notrace static u64 vread_tsc(void)
168
{
169
	u64 ret = (u64)rdtsc_ordered();
170
	u64 last = gtod->cycle_last;
171

172 173 174 175 176
	if (likely(ret >= last))
		return ret;

	/*
	 * GCC likes to generate cmov here, but this branch is extremely
177
	 * predictable (it's just a function of time and the likely is
178 179 180 181 182 183 184 185
	 * very likely) and there's a data dependence, so force GCC
	 * to generate a branch instead.  I don't barrier() because
	 * we don't actually need a barrier, and if this function
	 * ever gets inlined it will generate worse code.
	 */
	asm volatile ("");
	return last;
}
186

187
notrace static inline u64 vgetsns(int *mode)
188
{
189
	u64 v;
190
	cycles_t cycles;
191 192

	if (gtod->vclock_mode == VCLOCK_TSC)
193
		cycles = vread_tsc();
194 195 196 197 198 199 200

	/*
	 * For any memory-mapped vclock type, we need to make sure that gcc
	 * doesn't cleverly hoist a load before the mode check.  Otherwise we
	 * might end up touching the memory-mapped page even if the vclock in
	 * question isn't enabled, which will segfault.  Hence the barriers.
	 */
201
#ifdef CONFIG_PARAVIRT_CLOCK
202 203
	else if (gtod->vclock_mode == VCLOCK_PVCLOCK) {
		barrier();
204
		cycles = vread_pvclock(mode);
205
	}
206 207
#endif
#ifdef CONFIG_HYPERV_TSCPAGE
208 209
	else if (gtod->vclock_mode == VCLOCK_HVCLOCK) {
		barrier();
210
		cycles = vread_hvclock(mode);
211
	}
212
#endif
213 214
	else
		return 0;
215 216
	v = (cycles - gtod->cycle_last) & gtod->mask;
	return v * gtod->mult;
217 218
}

219 220
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
notrace static int __always_inline do_realtime(struct timespec *ts)
221
{
222 223
	unsigned long seq;
	u64 ns;
224 225
	int mode;

226
	do {
227 228
		seq = gtod_read_begin(gtod);
		mode = gtod->vclock_mode;
229
		ts->tv_sec = gtod->wall_time_sec;
230
		ns = gtod->wall_time_snsec;
231
		ns += vgetsns(&mode);
232 233 234 235 236
		ns >>= gtod->shift;
	} while (unlikely(gtod_read_retry(gtod, seq)));

	ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
	ts->tv_nsec = ns;
237 238

	return mode;
239 240
}

241
notrace static int __always_inline do_monotonic(struct timespec *ts)
242
{
243 244
	unsigned long seq;
	u64 ns;
245 246
	int mode;

247
	do {
248 249
		seq = gtod_read_begin(gtod);
		mode = gtod->vclock_mode;
250
		ts->tv_sec = gtod->monotonic_time_sec;
251
		ns = gtod->monotonic_time_snsec;
252
		ns += vgetsns(&mode);
253 254 255 256 257
		ns >>= gtod->shift;
	} while (unlikely(gtod_read_retry(gtod, seq)));

	ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
	ts->tv_nsec = ns;
258

259
	return mode;
260 261
}

262
notrace static void do_realtime_coarse(struct timespec *ts)
263 264 265
{
	unsigned long seq;
	do {
266 267 268 269
		seq = gtod_read_begin(gtod);
		ts->tv_sec = gtod->wall_time_coarse_sec;
		ts->tv_nsec = gtod->wall_time_coarse_nsec;
	} while (unlikely(gtod_read_retry(gtod, seq)));
270 271
}

272
notrace static void do_monotonic_coarse(struct timespec *ts)
273
{
274
	unsigned long seq;
275
	do {
276 277 278 279
		seq = gtod_read_begin(gtod);
		ts->tv_sec = gtod->monotonic_time_coarse_sec;
		ts->tv_nsec = gtod->monotonic_time_coarse_nsec;
	} while (unlikely(gtod_read_retry(gtod, seq)));
280 281
}

282
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
283
{
284 285
	switch (clock) {
	case CLOCK_REALTIME:
286 287
		if (do_realtime(ts) == VCLOCK_NONE)
			goto fallback;
288 289
		break;
	case CLOCK_MONOTONIC:
290 291
		if (do_monotonic(ts) == VCLOCK_NONE)
			goto fallback;
292 293
		break;
	case CLOCK_REALTIME_COARSE:
294 295
		do_realtime_coarse(ts);
		break;
296
	case CLOCK_MONOTONIC_COARSE:
297 298 299 300
		do_monotonic_coarse(ts);
		break;
	default:
		goto fallback;
301 302
	}

303
	return 0;
304 305
fallback:
	return vdso_fallback_gettime(clock, ts);
306 307 308 309
}
int clock_gettime(clockid_t, struct timespec *)
	__attribute__((weak, alias("__vdso_clock_gettime")));

310
notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
311
{
312
	if (likely(tv != NULL)) {
313 314
		if (unlikely(do_realtime((struct timespec *)tv) == VCLOCK_NONE))
			return vdso_fallback_gtod(tv, tz);
315
		tv->tv_usec /= 1000;
316
	}
317
	if (unlikely(tz != NULL)) {
318 319
		tz->tz_minuteswest = gtod->tz_minuteswest;
		tz->tz_dsttime = gtod->tz_dsttime;
320 321 322
	}

	return 0;
323 324 325
}
int gettimeofday(struct timeval *, struct timezone *)
	__attribute__((weak, alias("__vdso_gettimeofday")));
A
Andy Lutomirski 已提交
326

327 328 329 330
/*
 * This will break when the xtime seconds get inaccurate, but that is
 * unlikely
 */
A
Andy Lutomirski 已提交
331 332
notrace time_t __vdso_time(time_t *t)
{
333
	/* This is atomic on x86 so we don't need any locks. */
334
	time_t result = READ_ONCE(gtod->wall_time_sec);
A
Andy Lutomirski 已提交
335 336 337 338 339

	if (t)
		*t = result;
	return result;
}
340
time_t time(time_t *t)
A
Andy Lutomirski 已提交
341
	__attribute__((weak, alias("__vdso_time")));