xref: /linux/lib/vdso/gettimeofday.c (revision fb61bdb27fd730c393a8bddbda2401c37a919667)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Generic userspace implementations of gettimeofday() and similar.
4  */
5 #include <vdso/datapage.h>
6 #include <vdso/helpers.h>
7 
8 /* Bring in default accessors */
9 #include <vdso/vsyscall.h>
10 
11 #ifndef vdso_calc_ns
12 
13 #ifdef VDSO_DELTA_NOMASK
14 # define VDSO_DELTA_MASK(vd)	ULLONG_MAX
15 #else
16 # define VDSO_DELTA_MASK(vd)	(vd->mask)
17 #endif
18 
19 #ifdef CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT
20 static __always_inline bool vdso_delta_ok(const struct vdso_clock *vc, u64 delta)
21 {
22 	return delta < vc->max_cycles;
23 }
24 #else
25 static __always_inline bool vdso_delta_ok(const struct vdso_clock *vc, u64 delta)
26 {
27 	return true;
28 }
29 #endif
30 
31 #ifndef vdso_shift_ns
32 static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift)
33 {
34 	return ns >> shift;
35 }
36 #endif
37 
38 /*
39  * Default implementation which works for all sane clocksources. That
40  * obviously excludes x86/TSC.
41  */
42 static __always_inline u64 vdso_calc_ns(const struct vdso_clock *vc, u64 cycles, u64 base)
43 {
44 	u64 delta = (cycles - vc->cycle_last) & VDSO_DELTA_MASK(vc);
45 
46 	if (likely(vdso_delta_ok(vc, delta)))
47 		return vdso_shift_ns((delta * vc->mult) + base, vc->shift);
48 
49 	return mul_u64_u32_add_u64_shr(delta, vc->mult, base, vc->shift);
50 }
51 #endif /* vdso_calc_ns */
52 
53 #ifndef __arch_vdso_hres_capable
54 static inline bool __arch_vdso_hres_capable(void)
55 {
56 	return true;
57 }
58 #endif
59 
60 #ifndef vdso_clocksource_ok
61 static inline bool vdso_clocksource_ok(const struct vdso_clock *vc)
62 {
63 	return vc->clock_mode != VDSO_CLOCKMODE_NONE;
64 }
65 #endif
66 
67 #ifndef vdso_cycles_ok
68 static inline bool vdso_cycles_ok(u64 cycles)
69 {
70 	return true;
71 }
72 #endif
73 
74 #ifdef CONFIG_TIME_NS
75 
76 #ifdef CONFIG_GENERIC_VDSO_DATA_STORE
77 static __always_inline
78 const struct vdso_time_data *__arch_get_vdso_u_timens_data(const struct vdso_time_data *vd)
79 {
80 	return (void *)vd + PAGE_SIZE;
81 }
82 #endif /* CONFIG_GENERIC_VDSO_DATA_STORE */
83 
84 static __always_inline
85 bool do_hres_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns,
86 		    clockid_t clk, struct __kernel_timespec *ts)
87 {
88 	const struct vdso_time_data *vd = __arch_get_vdso_u_timens_data(vdns);
89 	const struct timens_offset *offs = &vcns->offset[clk];
90 	const struct vdso_clock *vc = vd->clock_data;
91 	const struct vdso_timestamp *vdso_ts;
92 	u64 cycles, ns;
93 	u32 seq;
94 	s64 sec;
95 
96 	if (clk != CLOCK_MONOTONIC_RAW)
97 		vc = &vc[CS_HRES_COARSE];
98 	else
99 		vc = &vc[CS_RAW];
100 	vdso_ts = &vc->basetime[clk];
101 
102 	do {
103 		seq = vdso_read_begin(vc);
104 
105 		if (unlikely(!vdso_clocksource_ok(vc)))
106 			return false;
107 
108 		cycles = __arch_get_hw_counter(vc->clock_mode, vd);
109 		if (unlikely(!vdso_cycles_ok(cycles)))
110 			return false;
111 		ns = vdso_calc_ns(vc, cycles, vdso_ts->nsec);
112 		sec = vdso_ts->sec;
113 	} while (unlikely(vdso_read_retry(vc, seq)));
114 
115 	/* Add the namespace offset */
116 	sec += offs->sec;
117 	ns += offs->nsec;
118 
119 	/*
120 	 * Do this outside the loop: a race inside the loop could result
121 	 * in __iter_div_u64_rem() being extremely slow.
122 	 */
123 	ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
124 	ts->tv_nsec = ns;
125 
126 	return true;
127 }
128 #else
129 static __always_inline
130 const struct vdso_time_data *__arch_get_vdso_u_timens_data(const struct vdso_time_data *vd)
131 {
132 	return NULL;
133 }
134 
135 static __always_inline
136 bool do_hres_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns,
137 		    clockid_t clk, struct __kernel_timespec *ts)
138 {
139 	return false;
140 }
141 #endif
142 
143 static __always_inline
144 bool do_hres(const struct vdso_time_data *vd, const struct vdso_clock *vc,
145 	     clockid_t clk, struct __kernel_timespec *ts)
146 {
147 	const struct vdso_timestamp *vdso_ts = &vc->basetime[clk];
148 	u64 cycles, sec, ns;
149 	u32 seq;
150 
151 	/* Allows to compile the high resolution parts out */
152 	if (!__arch_vdso_hres_capable())
153 		return false;
154 
155 	do {
156 		/*
157 		 * Open coded function vdso_read_begin() to handle
158 		 * VDSO_CLOCKMODE_TIMENS. Time namespace enabled tasks have a
159 		 * special VVAR page installed which has vc->seq set to 1 and
160 		 * vc->clock_mode set to VDSO_CLOCKMODE_TIMENS. For non time
161 		 * namespace affected tasks this does not affect performance
162 		 * because if vc->seq is odd, i.e. a concurrent update is in
163 		 * progress the extra check for vc->clock_mode is just a few
164 		 * extra instructions while spin waiting for vc->seq to become
165 		 * even again.
166 		 */
167 		while (unlikely((seq = READ_ONCE(vc->seq)) & 1)) {
168 			if (IS_ENABLED(CONFIG_TIME_NS) &&
169 			    vc->clock_mode == VDSO_CLOCKMODE_TIMENS)
170 				return do_hres_timens(vd, vc, clk, ts);
171 			cpu_relax();
172 		}
173 		smp_rmb();
174 
175 		if (unlikely(!vdso_clocksource_ok(vc)))
176 			return false;
177 
178 		cycles = __arch_get_hw_counter(vc->clock_mode, vd);
179 		if (unlikely(!vdso_cycles_ok(cycles)))
180 			return false;
181 		ns = vdso_calc_ns(vc, cycles, vdso_ts->nsec);
182 		sec = vdso_ts->sec;
183 	} while (unlikely(vdso_read_retry(vc, seq)));
184 
185 	/*
186 	 * Do this outside the loop: a race inside the loop could result
187 	 * in __iter_div_u64_rem() being extremely slow.
188 	 */
189 	ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
190 	ts->tv_nsec = ns;
191 
192 	return true;
193 }
194 
195 #ifdef CONFIG_TIME_NS
196 static __always_inline
197 bool do_coarse_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns,
198 		      clockid_t clk, struct __kernel_timespec *ts)
199 {
200 	const struct vdso_time_data *vd = __arch_get_vdso_u_timens_data(vdns);
201 	const struct timens_offset *offs = &vcns->offset[clk];
202 	const struct vdso_clock *vc = vd->clock_data;
203 	const struct vdso_timestamp *vdso_ts;
204 	u64 nsec;
205 	s64 sec;
206 	s32 seq;
207 
208 	vdso_ts = &vc->basetime[clk];
209 
210 	do {
211 		seq = vdso_read_begin(vc);
212 		sec = vdso_ts->sec;
213 		nsec = vdso_ts->nsec;
214 	} while (unlikely(vdso_read_retry(vc, seq)));
215 
216 	/* Add the namespace offset */
217 	sec += offs->sec;
218 	nsec += offs->nsec;
219 
220 	/*
221 	 * Do this outside the loop: a race inside the loop could result
222 	 * in __iter_div_u64_rem() being extremely slow.
223 	 */
224 	ts->tv_sec = sec + __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec);
225 	ts->tv_nsec = nsec;
226 	return true;
227 }
228 #else
229 static __always_inline
230 bool do_coarse_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns,
231 		      clockid_t clk, struct __kernel_timespec *ts)
232 {
233 	return false;
234 }
235 #endif
236 
237 static __always_inline
238 bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
239 	       clockid_t clk, struct __kernel_timespec *ts)
240 {
241 	const struct vdso_timestamp *vdso_ts = &vc->basetime[clk];
242 	u32 seq;
243 
244 	do {
245 		/*
246 		 * Open coded function vdso_read_begin() to handle
247 		 * VDSO_CLOCK_TIMENS. See comment in do_hres().
248 		 */
249 		while ((seq = READ_ONCE(vc->seq)) & 1) {
250 			if (IS_ENABLED(CONFIG_TIME_NS) &&
251 			    vc->clock_mode == VDSO_CLOCKMODE_TIMENS)
252 				return do_coarse_timens(vd, vc, clk, ts);
253 			cpu_relax();
254 		}
255 		smp_rmb();
256 
257 		ts->tv_sec = vdso_ts->sec;
258 		ts->tv_nsec = vdso_ts->nsec;
259 	} while (unlikely(vdso_read_retry(vc, seq)));
260 
261 	return true;
262 }
263 
264 static __always_inline bool
265 __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
266 			     struct __kernel_timespec *ts)
267 {
268 	const struct vdso_clock *vc = vd->clock_data;
269 	u32 msk;
270 
271 	/* Check for negative values or invalid clocks */
272 	if (unlikely((u32) clock >= MAX_CLOCKS))
273 		return false;
274 
275 	/*
276 	 * Convert the clockid to a bitmask and use it to check which
277 	 * clocks are handled in the VDSO directly.
278 	 */
279 	msk = 1U << clock;
280 	if (likely(msk & VDSO_HRES))
281 		vc = &vc[CS_HRES_COARSE];
282 	else if (msk & VDSO_COARSE)
283 		return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
284 	else if (msk & VDSO_RAW)
285 		vc = &vc[CS_RAW];
286 	else
287 		return false;
288 
289 	return do_hres(vd, vc, clock, ts);
290 }
291 
292 static __maybe_unused int
293 __cvdso_clock_gettime_data(const struct vdso_time_data *vd, clockid_t clock,
294 			   struct __kernel_timespec *ts)
295 {
296 	bool ok;
297 
298 	ok = __cvdso_clock_gettime_common(vd, clock, ts);
299 
300 	if (unlikely(!ok))
301 		return clock_gettime_fallback(clock, ts);
302 	return 0;
303 }
304 
305 static __maybe_unused int
306 __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
307 {
308 	return __cvdso_clock_gettime_data(__arch_get_vdso_u_time_data(), clock, ts);
309 }
310 
311 #ifdef BUILD_VDSO32
312 static __maybe_unused int
313 __cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock,
314 			     struct old_timespec32 *res)
315 {
316 	struct __kernel_timespec ts;
317 	bool ok;
318 
319 	ok = __cvdso_clock_gettime_common(vd, clock, &ts);
320 
321 	if (unlikely(!ok))
322 		return clock_gettime32_fallback(clock, res);
323 
324 	/* For ok == true */
325 	res->tv_sec = ts.tv_sec;
326 	res->tv_nsec = ts.tv_nsec;
327 
328 	return 0;
329 }
330 
331 static __maybe_unused int
332 __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
333 {
334 	return __cvdso_clock_gettime32_data(__arch_get_vdso_u_time_data(), clock, res);
335 }
336 #endif /* BUILD_VDSO32 */
337 
338 static __maybe_unused int
339 __cvdso_gettimeofday_data(const struct vdso_time_data *vd,
340 			  struct __kernel_old_timeval *tv, struct timezone *tz)
341 {
342 	const struct vdso_clock *vc = vd->clock_data;
343 
344 	if (likely(tv != NULL)) {
345 		struct __kernel_timespec ts;
346 
347 		if (!do_hres(vd, &vc[CS_HRES_COARSE], CLOCK_REALTIME, &ts))
348 			return gettimeofday_fallback(tv, tz);
349 
350 		tv->tv_sec = ts.tv_sec;
351 		tv->tv_usec = (u32)ts.tv_nsec / NSEC_PER_USEC;
352 	}
353 
354 	if (unlikely(tz != NULL)) {
355 		if (IS_ENABLED(CONFIG_TIME_NS) &&
356 		    vc->clock_mode == VDSO_CLOCKMODE_TIMENS)
357 			vd = __arch_get_vdso_u_timens_data(vd);
358 
359 		tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest;
360 		tz->tz_dsttime = vd[CS_HRES_COARSE].tz_dsttime;
361 	}
362 
363 	return 0;
364 }
365 
366 static __maybe_unused int
367 __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
368 {
369 	return __cvdso_gettimeofday_data(__arch_get_vdso_u_time_data(), tv, tz);
370 }
371 
372 #ifdef VDSO_HAS_TIME
373 static __maybe_unused __kernel_old_time_t
374 __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time)
375 {
376 	const struct vdso_clock *vc = vd->clock_data;
377 	__kernel_old_time_t t;
378 
379 	if (IS_ENABLED(CONFIG_TIME_NS) &&
380 	    vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
381 		vd = __arch_get_vdso_u_timens_data(vd);
382 		vc = vd->clock_data;
383 	}
384 
385 	t = READ_ONCE(vc[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec);
386 
387 	if (time)
388 		*time = t;
389 
390 	return t;
391 }
392 
393 static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time)
394 {
395 	return __cvdso_time_data(__arch_get_vdso_u_time_data(), time);
396 }
397 #endif /* VDSO_HAS_TIME */
398 
399 #ifdef VDSO_HAS_CLOCK_GETRES
400 static __maybe_unused
401 bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t clock,
402 				 struct __kernel_timespec *res)
403 {
404 	const struct vdso_clock *vc = vd->clock_data;
405 	u32 msk;
406 	u64 ns;
407 
408 	/* Check for negative values or invalid clocks */
409 	if (unlikely((u32) clock >= MAX_CLOCKS))
410 		return false;
411 
412 	if (IS_ENABLED(CONFIG_TIME_NS) &&
413 	    vc->clock_mode == VDSO_CLOCKMODE_TIMENS)
414 		vd = __arch_get_vdso_u_timens_data(vd);
415 
416 	/*
417 	 * Convert the clockid to a bitmask and use it to check which
418 	 * clocks are handled in the VDSO directly.
419 	 */
420 	msk = 1U << clock;
421 	if (msk & (VDSO_HRES | VDSO_RAW)) {
422 		/*
423 		 * Preserves the behaviour of posix_get_hrtimer_res().
424 		 */
425 		ns = READ_ONCE(vd->hrtimer_res);
426 	} else if (msk & VDSO_COARSE) {
427 		/*
428 		 * Preserves the behaviour of posix_get_coarse_res().
429 		 */
430 		ns = LOW_RES_NSEC;
431 	} else {
432 		return false;
433 	}
434 
435 	if (likely(res)) {
436 		res->tv_sec = 0;
437 		res->tv_nsec = ns;
438 	}
439 	return true;
440 }
441 
442 static __maybe_unused
443 int __cvdso_clock_getres_data(const struct vdso_time_data *vd, clockid_t clock,
444 			      struct __kernel_timespec *res)
445 {
446 	bool ok;
447 
448 	ok =  __cvdso_clock_getres_common(vd, clock, res);
449 
450 	if (unlikely(!ok))
451 		return clock_getres_fallback(clock, res);
452 	return 0;
453 }
454 
455 static __maybe_unused
456 int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res)
457 {
458 	return __cvdso_clock_getres_data(__arch_get_vdso_u_time_data(), clock, res);
459 }
460 
461 #ifdef BUILD_VDSO32
462 static __maybe_unused int
463 __cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t clock,
464 				 struct old_timespec32 *res)
465 {
466 	struct __kernel_timespec ts;
467 	bool ok;
468 
469 	ok = __cvdso_clock_getres_common(vd, clock, &ts);
470 
471 	if (unlikely(!ok))
472 		return clock_getres32_fallback(clock, res);
473 
474 	if (likely(res)) {
475 		res->tv_sec = ts.tv_sec;
476 		res->tv_nsec = ts.tv_nsec;
477 	}
478 	return 0;
479 }
480 
481 static __maybe_unused int
482 __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
483 {
484 	return __cvdso_clock_getres_time32_data(__arch_get_vdso_u_time_data(),
485 						clock, res);
486 }
487 #endif /* BUILD_VDSO32 */
488 #endif /* VDSO_HAS_CLOCK_GETRES */
489