0001
0002
0003
0004
0005 #include <vdso/datapage.h>
0006 #include <vdso/helpers.h>
0007
0008 #ifndef vdso_calc_delta
0009
0010
0011
0012
0013 static __always_inline
0014 u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
0015 {
0016 return ((cycles - last) & mask) * mult;
0017 }
0018 #endif
0019
0020 #ifndef vdso_shift_ns
0021 static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift)
0022 {
0023 return ns >> shift;
0024 }
0025 #endif
0026
0027 #ifndef __arch_vdso_hres_capable
0028 static inline bool __arch_vdso_hres_capable(void)
0029 {
0030 return true;
0031 }
0032 #endif
0033
0034 #ifndef vdso_clocksource_ok
0035 static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
0036 {
0037 return vd->clock_mode != VDSO_CLOCKMODE_NONE;
0038 }
0039 #endif
0040
0041 #ifndef vdso_cycles_ok
0042 static inline bool vdso_cycles_ok(u64 cycles)
0043 {
0044 return true;
0045 }
0046 #endif
0047
0048 #ifdef CONFIG_TIME_NS
0049 static __always_inline int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
0050 struct __kernel_timespec *ts)
0051 {
0052 const struct vdso_data *vd;
0053 const struct timens_offset *offs = &vdns->offset[clk];
0054 const struct vdso_timestamp *vdso_ts;
0055 u64 cycles, last, ns;
0056 u32 seq;
0057 s64 sec;
0058
0059 vd = vdns - (clk == CLOCK_MONOTONIC_RAW ? CS_RAW : CS_HRES_COARSE);
0060 vd = __arch_get_timens_vdso_data(vd);
0061 if (clk != CLOCK_MONOTONIC_RAW)
0062 vd = &vd[CS_HRES_COARSE];
0063 else
0064 vd = &vd[CS_RAW];
0065 vdso_ts = &vd->basetime[clk];
0066
0067 do {
0068 seq = vdso_read_begin(vd);
0069
0070 if (unlikely(!vdso_clocksource_ok(vd)))
0071 return -1;
0072
0073 cycles = __arch_get_hw_counter(vd->clock_mode, vd);
0074 if (unlikely(!vdso_cycles_ok(cycles)))
0075 return -1;
0076 ns = vdso_ts->nsec;
0077 last = vd->cycle_last;
0078 ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
0079 ns = vdso_shift_ns(ns, vd->shift);
0080 sec = vdso_ts->sec;
0081 } while (unlikely(vdso_read_retry(vd, seq)));
0082
0083
0084 sec += offs->sec;
0085 ns += offs->nsec;
0086
0087
0088
0089
0090
0091 ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
0092 ts->tv_nsec = ns;
0093
0094 return 0;
0095 }
0096 #else
0097 static __always_inline
0098 const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
0099 {
0100 return NULL;
0101 }
0102
0103 static __always_inline int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
0104 struct __kernel_timespec *ts)
0105 {
0106 return -EINVAL;
0107 }
0108 #endif
0109
0110 static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
0111 struct __kernel_timespec *ts)
0112 {
0113 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
0114 u64 cycles, last, sec, ns;
0115 u32 seq;
0116
0117
0118 if (!__arch_vdso_hres_capable())
0119 return -1;
0120
0121 do {
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133 while (unlikely((seq = READ_ONCE(vd->seq)) & 1)) {
0134 if (IS_ENABLED(CONFIG_TIME_NS) &&
0135 vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
0136 return do_hres_timens(vd, clk, ts);
0137 cpu_relax();
0138 }
0139 smp_rmb();
0140
0141 if (unlikely(!vdso_clocksource_ok(vd)))
0142 return -1;
0143
0144 cycles = __arch_get_hw_counter(vd->clock_mode, vd);
0145 if (unlikely(!vdso_cycles_ok(cycles)))
0146 return -1;
0147 ns = vdso_ts->nsec;
0148 last = vd->cycle_last;
0149 ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
0150 ns = vdso_shift_ns(ns, vd->shift);
0151 sec = vdso_ts->sec;
0152 } while (unlikely(vdso_read_retry(vd, seq)));
0153
0154
0155
0156
0157
0158 ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
0159 ts->tv_nsec = ns;
0160
0161 return 0;
0162 }
0163
0164 #ifdef CONFIG_TIME_NS
0165 static __always_inline int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk,
0166 struct __kernel_timespec *ts)
0167 {
0168 const struct vdso_data *vd = __arch_get_timens_vdso_data(vdns);
0169 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
0170 const struct timens_offset *offs = &vdns->offset[clk];
0171 u64 nsec;
0172 s64 sec;
0173 s32 seq;
0174
0175 do {
0176 seq = vdso_read_begin(vd);
0177 sec = vdso_ts->sec;
0178 nsec = vdso_ts->nsec;
0179 } while (unlikely(vdso_read_retry(vd, seq)));
0180
0181
0182 sec += offs->sec;
0183 nsec += offs->nsec;
0184
0185
0186
0187
0188
0189 ts->tv_sec = sec + __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec);
0190 ts->tv_nsec = nsec;
0191 return 0;
0192 }
0193 #else
0194 static __always_inline int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk,
0195 struct __kernel_timespec *ts)
0196 {
0197 return -1;
0198 }
0199 #endif
0200
0201 static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk,
0202 struct __kernel_timespec *ts)
0203 {
0204 const struct vdso_timestamp *vdso_ts = &vd->basetime[clk];
0205 u32 seq;
0206
0207 do {
0208
0209
0210
0211
0212 while ((seq = READ_ONCE(vd->seq)) & 1) {
0213 if (IS_ENABLED(CONFIG_TIME_NS) &&
0214 vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
0215 return do_coarse_timens(vd, clk, ts);
0216 cpu_relax();
0217 }
0218 smp_rmb();
0219
0220 ts->tv_sec = vdso_ts->sec;
0221 ts->tv_nsec = vdso_ts->nsec;
0222 } while (unlikely(vdso_read_retry(vd, seq)));
0223
0224 return 0;
0225 }
0226
0227 static __always_inline int
0228 __cvdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock,
0229 struct __kernel_timespec *ts)
0230 {
0231 u32 msk;
0232
0233
0234 if (unlikely((u32) clock >= MAX_CLOCKS))
0235 return -1;
0236
0237
0238
0239
0240
0241 msk = 1U << clock;
0242 if (likely(msk & VDSO_HRES))
0243 vd = &vd[CS_HRES_COARSE];
0244 else if (msk & VDSO_COARSE)
0245 return do_coarse(&vd[CS_HRES_COARSE], clock, ts);
0246 else if (msk & VDSO_RAW)
0247 vd = &vd[CS_RAW];
0248 else
0249 return -1;
0250
0251 return do_hres(vd, clock, ts);
0252 }
0253
0254 static __maybe_unused int
0255 __cvdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock,
0256 struct __kernel_timespec *ts)
0257 {
0258 int ret = __cvdso_clock_gettime_common(vd, clock, ts);
0259
0260 if (unlikely(ret))
0261 return clock_gettime_fallback(clock, ts);
0262 return 0;
0263 }
0264
0265 static __maybe_unused int
0266 __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
0267 {
0268 return __cvdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts);
0269 }
0270
0271 #ifdef BUILD_VDSO32
0272 static __maybe_unused int
0273 __cvdso_clock_gettime32_data(const struct vdso_data *vd, clockid_t clock,
0274 struct old_timespec32 *res)
0275 {
0276 struct __kernel_timespec ts;
0277 int ret;
0278
0279 ret = __cvdso_clock_gettime_common(vd, clock, &ts);
0280
0281 if (unlikely(ret))
0282 return clock_gettime32_fallback(clock, res);
0283
0284
0285 res->tv_sec = ts.tv_sec;
0286 res->tv_nsec = ts.tv_nsec;
0287
0288 return ret;
0289 }
0290
0291 static __maybe_unused int
0292 __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
0293 {
0294 return __cvdso_clock_gettime32_data(__arch_get_vdso_data(), clock, res);
0295 }
0296 #endif
0297
0298 static __maybe_unused int
0299 __cvdso_gettimeofday_data(const struct vdso_data *vd,
0300 struct __kernel_old_timeval *tv, struct timezone *tz)
0301 {
0302
0303 if (likely(tv != NULL)) {
0304 struct __kernel_timespec ts;
0305
0306 if (do_hres(&vd[CS_HRES_COARSE], CLOCK_REALTIME, &ts))
0307 return gettimeofday_fallback(tv, tz);
0308
0309 tv->tv_sec = ts.tv_sec;
0310 tv->tv_usec = (u32)ts.tv_nsec / NSEC_PER_USEC;
0311 }
0312
0313 if (unlikely(tz != NULL)) {
0314 if (IS_ENABLED(CONFIG_TIME_NS) &&
0315 vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
0316 vd = __arch_get_timens_vdso_data(vd);
0317
0318 tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest;
0319 tz->tz_dsttime = vd[CS_HRES_COARSE].tz_dsttime;
0320 }
0321
0322 return 0;
0323 }
0324
0325 static __maybe_unused int
0326 __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
0327 {
0328 return __cvdso_gettimeofday_data(__arch_get_vdso_data(), tv, tz);
0329 }
0330
0331 #ifdef VDSO_HAS_TIME
0332 static __maybe_unused __kernel_old_time_t
0333 __cvdso_time_data(const struct vdso_data *vd, __kernel_old_time_t *time)
0334 {
0335 __kernel_old_time_t t;
0336
0337 if (IS_ENABLED(CONFIG_TIME_NS) &&
0338 vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
0339 vd = __arch_get_timens_vdso_data(vd);
0340
0341 t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec);
0342
0343 if (time)
0344 *time = t;
0345
0346 return t;
0347 }
0348
0349 static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time)
0350 {
0351 return __cvdso_time_data(__arch_get_vdso_data(), time);
0352 }
0353 #endif
0354
0355 #ifdef VDSO_HAS_CLOCK_GETRES
0356 static __maybe_unused
0357 int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock,
0358 struct __kernel_timespec *res)
0359 {
0360 u32 msk;
0361 u64 ns;
0362
0363
0364 if (unlikely((u32) clock >= MAX_CLOCKS))
0365 return -1;
0366
0367 if (IS_ENABLED(CONFIG_TIME_NS) &&
0368 vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
0369 vd = __arch_get_timens_vdso_data(vd);
0370
0371
0372
0373
0374
0375 msk = 1U << clock;
0376 if (msk & (VDSO_HRES | VDSO_RAW)) {
0377
0378
0379
0380 ns = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res);
0381 } else if (msk & VDSO_COARSE) {
0382
0383
0384
0385 ns = LOW_RES_NSEC;
0386 } else {
0387 return -1;
0388 }
0389
0390 if (likely(res)) {
0391 res->tv_sec = 0;
0392 res->tv_nsec = ns;
0393 }
0394 return 0;
0395 }
0396
0397 static __maybe_unused
0398 int __cvdso_clock_getres_data(const struct vdso_data *vd, clockid_t clock,
0399 struct __kernel_timespec *res)
0400 {
0401 int ret = __cvdso_clock_getres_common(vd, clock, res);
0402
0403 if (unlikely(ret))
0404 return clock_getres_fallback(clock, res);
0405 return 0;
0406 }
0407
0408 static __maybe_unused
0409 int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res)
0410 {
0411 return __cvdso_clock_getres_data(__arch_get_vdso_data(), clock, res);
0412 }
0413
0414 #ifdef BUILD_VDSO32
0415 static __maybe_unused int
0416 __cvdso_clock_getres_time32_data(const struct vdso_data *vd, clockid_t clock,
0417 struct old_timespec32 *res)
0418 {
0419 struct __kernel_timespec ts;
0420 int ret;
0421
0422 ret = __cvdso_clock_getres_common(vd, clock, &ts);
0423
0424 if (unlikely(ret))
0425 return clock_getres32_fallback(clock, res);
0426
0427 if (likely(res)) {
0428 res->tv_sec = ts.tv_sec;
0429 res->tv_nsec = ts.tv_nsec;
0430 }
0431 return ret;
0432 }
0433
0434 static __maybe_unused int
0435 __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
0436 {
0437 return __cvdso_clock_getres_time32_data(__arch_get_vdso_data(),
0438 clock, res);
0439 }
0440 #endif
0441 #endif