blob: f8b8ec5e63aca5e5ffcbf2de5c902c0080cf84b0 [file] [log] [blame]
Vincenzo Frascino00b26472019-06-21 10:52:29 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Generic userspace implementations of gettimeofday() and similar.
4 */
5#include <linux/compiler.h>
6#include <linux/math64.h>
7#include <linux/time.h>
8#include <linux/kernel.h>
9#include <linux/hrtimer_defs.h>
10#include <vdso/datapage.h>
11#include <vdso/helpers.h>
12
13/*
14 * The generic vDSO implementation requires that gettimeofday.h
15 * provides:
16 * - __arch_get_vdso_data(): to get the vdso datapage.
17 * - __arch_get_hw_counter(): to get the hw counter based on the
18 * clock_mode.
19 * - gettimeofday_fallback(): fallback for gettimeofday.
20 * - clock_gettime_fallback(): fallback for clock_gettime.
21 * - clock_getres_fallback(): fallback for clock_getres.
22 */
Vincenzo Frascino629fdf72019-06-21 10:52:36 +010023#ifdef ENABLE_COMPAT_VDSO
24#include <asm/vdso/compat_gettimeofday.h>
25#else
Vincenzo Frascino00b26472019-06-21 10:52:29 +010026#include <asm/vdso/gettimeofday.h>
Vincenzo Frascino629fdf72019-06-21 10:52:36 +010027#endif /* ENABLE_COMPAT_VDSO */
Vincenzo Frascino00b26472019-06-21 10:52:29 +010028
Thomas Gleixner9d90b932019-06-26 12:02:00 +020029#ifndef vdso_calc_delta
30/*
31 * Default implementation which works for all sane clocksources. That
32 * obviously excludes x86/TSC.
33 */
34static __always_inline
35u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
36{
37 return ((cycles - last) & mask) * mult;
38}
39#endif
40
Thomas Gleixner660fd042019-11-12 01:27:09 +000041#ifdef CONFIG_TIME_NS
42static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
43 struct __kernel_timespec *ts)
44{
45 const struct vdso_data *vd = __arch_get_timens_vdso_data();
46 const struct timens_offset *offs = &vdns->offset[clk];
47 const struct vdso_timestamp *vdso_ts;
48 u64 cycles, last, ns;
49 u32 seq;
50 s64 sec;
51
52 if (clk != CLOCK_MONOTONIC_RAW)
53 vd = &vd[CS_HRES_COARSE];
54 else
55 vd = &vd[CS_RAW];
56 vdso_ts = &vd->basetime[clk];
57
58 do {
59 seq = vdso_read_begin(vd);
60 cycles = __arch_get_hw_counter(vd->clock_mode);
61 ns = vdso_ts->nsec;
62 last = vd->cycle_last;
63 if (unlikely((s64)cycles < 0))
64 return -1;
65
66 ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
67 ns >>= vd->shift;
68 sec = vdso_ts->sec;
69 } while (unlikely(vdso_read_retry(vd, seq)));
70
71 /* Add the namespace offset */
72 sec += offs->sec;
73 ns += offs->nsec;
74
75 /*
76 * Do this outside the loop: a race inside the loop could result
77 * in __iter_div_u64_rem() being extremely slow.
78 */
79 ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
80 ts->tv_nsec = ns;
81
82 return 0;
83}
84#else
85static __always_inline const struct vdso_data *__arch_get_timens_vdso_data(void)
86{
87 return NULL;
88}
89
90static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
91 struct __kernel_timespec *ts)
92{
93 return -EINVAL;
94}
95#endif
96
Andrei Vaginc9665332019-11-12 01:26:51 +000097static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
Thomas Gleixner660fd042019-11-12 01:27:09 +000098 struct __kernel_timespec *ts)
Vincenzo Frascino00b26472019-06-21 10:52:29 +010099{
100 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
101 u64 cycles, last, sec, ns;
102 u32 seq;
103
104 do {
Thomas Gleixner660fd042019-11-12 01:27:09 +0000105 /*
106 * Open coded to handle VCLOCK_TIMENS. Time namespace
107 * enabled tasks have a special VVAR page installed which
108 * has vd->seq set to 1 and vd->clock_mode set to
109 * VCLOCK_TIMENS. For non time namespace affected tasks
110 * this does not affect performance because if vd->seq is
111 * odd, i.e. a concurrent update is in progress the extra
112 * check for vd->clock_mode is just a few extra
113 * instructions while spin waiting for vd->seq to become
114 * even again.
115 */
116 while (unlikely((seq = READ_ONCE(vd->seq)) & 1)) {
117 if (IS_ENABLED(CONFIG_TIME_NS) &&
118 vd->clock_mode == VCLOCK_TIMENS)
119 return do_hres_timens(vd, clk, ts);
120 cpu_relax();
121 }
122 smp_rmb();
123
Thomas Gleixner9d90b932019-06-26 12:02:00 +0200124 cycles = __arch_get_hw_counter(vd->clock_mode);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100125 ns = vdso_ts->nsec;
126 last = vd->cycle_last;
127 if (unlikely((s64)cycles < 0))
Thomas Gleixner502a5902019-07-28 15:12:53 +0200128 return -1;
Thomas Gleixner9d90b932019-06-26 12:02:00 +0200129
130 ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100131 ns >>= vd->shift;
132 sec = vdso_ts->sec;
133 } while (unlikely(vdso_read_retry(vd, seq)));
134
135 /*
136 * Do this outside the loop: a race inside the loop could result
137 * in __iter_div_u64_rem() being extremely slow.
138 */
139 ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
140 ts->tv_nsec = ns;
141
142 return 0;
143}
144
Thomas Gleixner660fd042019-11-12 01:27:09 +0000145#ifdef CONFIG_TIME_NS
146static int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk,
147 struct __kernel_timespec *ts)
148{
149 const struct vdso_data *vd = __arch_get_timens_vdso_data();
150 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
151 const struct timens_offset *offs = &vdns->offset[clk];
152 u64 nsec;
153 s64 sec;
154 s32 seq;
155
156 do {
157 seq = vdso_read_begin(vd);
158 sec = vdso_ts->sec;
159 nsec = vdso_ts->nsec;
160 } while (unlikely(vdso_read_retry(vd, seq)));
161
162 /* Add the namespace offset */
163 sec += offs->sec;
164 nsec += offs->nsec;
165
166 /*
167 * Do this outside the loop: a race inside the loop could result
168 * in __iter_div_u64_rem() being extremely slow.
169 */
170 ts->tv_sec = sec + __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec);
171 ts->tv_nsec = nsec;
172 return 0;
173}
174#else
175static int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk,
176 struct __kernel_timespec *ts)
177{
178 return -1;
179}
180#endif
181
Andrei Vaginc9665332019-11-12 01:26:51 +0000182static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk,
183 struct __kernel_timespec *ts)
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100184{
185 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
186 u32 seq;
187
188 do {
Thomas Gleixner660fd042019-11-12 01:27:09 +0000189 /*
190 * Open coded to handle VCLOCK_TIMENS. See comment in
191 * do_hres().
192 */
193 while ((seq = READ_ONCE(vd->seq)) & 1) {
194 if (IS_ENABLED(CONFIG_TIME_NS) &&
195 vd->clock_mode == VCLOCK_TIMENS)
196 return do_coarse_timens(vd, clk, ts);
197 cpu_relax();
198 }
199 smp_rmb();
200
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100201 ts->tv_sec = vdso_ts->sec;
202 ts->tv_nsec = vdso_ts->nsec;
203 } while (unlikely(vdso_read_retry(vd, seq)));
Christophe Leroy8463cf82019-12-23 14:31:07 +0000204
205 return 0;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100206}
207
208static __maybe_unused int
Thomas Gleixner502a5902019-07-28 15:12:53 +0200209__cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts)
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100210{
211 const struct vdso_data *vd = __arch_get_vdso_data();
212 u32 msk;
213
214 /* Check for negative values or invalid clocks */
215 if (unlikely((u32) clock >= MAX_CLOCKS))
Thomas Gleixner502a5902019-07-28 15:12:53 +0200216 return -1;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100217
218 /*
219 * Convert the clockid to a bitmask and use it to check which
220 * clocks are handled in the VDSO directly.
221 */
222 msk = 1U << clock;
Christophe Leroy8463cf82019-12-23 14:31:07 +0000223 if (likely(msk & VDSO_HRES))
Andrei Vaginc9665332019-11-12 01:26:51 +0000224 vd = &vd[CS_HRES_COARSE];
Christophe Leroy8463cf82019-12-23 14:31:07 +0000225 else if (msk & VDSO_COARSE)
226 return do_coarse(&vd[CS_HRES_COARSE], clock, ts);
227 else if (msk & VDSO_RAW)
Andrei Vaginc9665332019-11-12 01:26:51 +0000228 vd = &vd[CS_RAW];
229 else
230 return -1;
Christophe Leroy8463cf82019-12-23 14:31:07 +0000231
Andrei Vaginc9665332019-11-12 01:26:51 +0000232 return do_hres(vd, clock, ts);
Thomas Gleixner502a5902019-07-28 15:12:53 +0200233}
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100234
Thomas Gleixner502a5902019-07-28 15:12:53 +0200235static __maybe_unused int
236__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
237{
238 int ret = __cvdso_clock_gettime_common(clock, ts);
239
240 if (unlikely(ret))
241 return clock_gettime_fallback(clock, ts);
242 return 0;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100243}
244
Vincenzo Frascinobf279842019-08-30 14:58:56 +0100245#ifdef BUILD_VDSO32
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100246static __maybe_unused int
247__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
248{
249 struct __kernel_timespec ts;
250 int ret;
251
Thomas Gleixner502a5902019-07-28 15:12:53 +0200252 ret = __cvdso_clock_gettime_common(clock, &ts);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100253
Thomas Gleixnerc60a32e2019-07-30 11:38:50 +0200254 if (unlikely(ret))
255 return clock_gettime32_fallback(clock, res);
Thomas Gleixner502a5902019-07-28 15:12:53 +0200256
Vincenzo Frascinoa2792352019-08-30 14:58:59 +0100257 /* For ret == 0 */
258 res->tv_sec = ts.tv_sec;
259 res->tv_nsec = ts.tv_nsec;
260
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100261 return ret;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100262}
Vincenzo Frascinobf279842019-08-30 14:58:56 +0100263#endif /* BUILD_VDSO32 */
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100264
265static __maybe_unused int
266__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
267{
268 const struct vdso_data *vd = __arch_get_vdso_data();
269
270 if (likely(tv != NULL)) {
271 struct __kernel_timespec ts;
272
273 if (do_hres(&vd[CS_HRES_COARSE], CLOCK_REALTIME, &ts))
274 return gettimeofday_fallback(tv, tz);
275
276 tv->tv_sec = ts.tv_sec;
277 tv->tv_usec = (u32)ts.tv_nsec / NSEC_PER_USEC;
278 }
279
280 if (unlikely(tz != NULL)) {
Thomas Gleixner660fd042019-11-12 01:27:09 +0000281 if (IS_ENABLED(CONFIG_TIME_NS) &&
282 vd->clock_mode == VCLOCK_TIMENS)
283 vd = __arch_get_timens_vdso_data();
284
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100285 tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest;
286 tz->tz_dsttime = vd[CS_HRES_COARSE].tz_dsttime;
287 }
288
289 return 0;
290}
291
292#ifdef VDSO_HAS_TIME
Arnd Bergmann21346562019-11-05 11:10:01 +0100293static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time)
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100294{
295 const struct vdso_data *vd = __arch_get_vdso_data();
Thomas Gleixner660fd042019-11-12 01:27:09 +0000296 __kernel_old_time_t t;
297
298 if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS)
299 vd = __arch_get_timens_vdso_data();
300
301 t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100302
303 if (time)
304 *time = t;
305
306 return t;
307}
308#endif /* VDSO_HAS_TIME */
309
310#ifdef VDSO_HAS_CLOCK_GETRES
311static __maybe_unused
Thomas Gleixner502a5902019-07-28 15:12:53 +0200312int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res)
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100313{
314 const struct vdso_data *vd = __arch_get_vdso_data();
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100315 u32 msk;
Thomas Gleixner502a5902019-07-28 15:12:53 +0200316 u64 ns;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100317
318 /* Check for negative values or invalid clocks */
319 if (unlikely((u32) clock >= MAX_CLOCKS))
Thomas Gleixner502a5902019-07-28 15:12:53 +0200320 return -1;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100321
Thomas Gleixner660fd042019-11-12 01:27:09 +0000322 if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS)
323 vd = __arch_get_timens_vdso_data();
324
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100325 /*
326 * Convert the clockid to a bitmask and use it to check which
327 * clocks are handled in the VDSO directly.
328 */
329 msk = 1U << clock;
Christophe Leroycdb7c5a2019-12-23 14:31:09 +0000330 if (msk & (VDSO_HRES | VDSO_RAW)) {
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100331 /*
332 * Preserves the behaviour of posix_get_hrtimer_res().
333 */
Christophe Leroy49a101d2020-01-16 17:58:27 +0000334 ns = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100335 } else if (msk & VDSO_COARSE) {
336 /*
337 * Preserves the behaviour of posix_get_coarse_res().
338 */
339 ns = LOW_RES_NSEC;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100340 } else {
Thomas Gleixner502a5902019-07-28 15:12:53 +0200341 return -1;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100342 }
343
Thomas Gleixner1638b8f2019-10-21 12:07:15 +0200344 if (likely(res)) {
345 res->tv_sec = 0;
346 res->tv_nsec = ns;
347 }
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100348 return 0;
Thomas Gleixner502a5902019-07-28 15:12:53 +0200349}
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100350
Vincenzo Frascinoffd08732019-11-28 11:17:19 +0000351static __maybe_unused
Thomas Gleixner502a5902019-07-28 15:12:53 +0200352int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res)
353{
354 int ret = __cvdso_clock_getres_common(clock, res);
355
356 if (unlikely(ret))
357 return clock_getres_fallback(clock, res);
358 return 0;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100359}
360
Vincenzo Frascinobf279842019-08-30 14:58:56 +0100361#ifdef BUILD_VDSO32
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100362static __maybe_unused int
363__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
364{
365 struct __kernel_timespec ts;
366 int ret;
367
Thomas Gleixner502a5902019-07-28 15:12:53 +0200368 ret = __cvdso_clock_getres_common(clock, &ts);
Thomas Gleixnerc60a32e2019-07-30 11:38:50 +0200369
Thomas Gleixnerc60a32e2019-07-30 11:38:50 +0200370 if (unlikely(ret))
371 return clock_getres32_fallback(clock, res);
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100372
Vincenzo Frascinoa2792352019-08-30 14:58:59 +0100373 if (likely(res)) {
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100374 res->tv_sec = ts.tv_sec;
375 res->tv_nsec = ts.tv_nsec;
376 }
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100377 return ret;
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100378}
Vincenzo Frascinobf279842019-08-30 14:58:56 +0100379#endif /* BUILD_VDSO32 */
Vincenzo Frascino00b26472019-06-21 10:52:29 +0100380#endif /* VDSO_HAS_CLOCK_GETRES */