Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Generic userspace implementations of gettimeofday() and similar.
0004  */
0005 #include <vdso/datapage.h>
0006 #include <vdso/helpers.h>
0007 
0008 #ifndef vdso_calc_delta
0009 /*
0010  * Default implementation which works for all sane clocksources. That
0011  * obviously excludes x86/TSC.
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     /* Add the namespace offset */
0084     sec += offs->sec;
0085     ns += offs->nsec;
0086 
0087     /*
0088      * Do this outside the loop: a race inside the loop could result
0089      * in __iter_div_u64_rem() being extremely slow.
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     /* Allows to compile the high resolution parts out */
0118     if (!__arch_vdso_hres_capable())
0119         return -1;
0120 
0121     do {
0122         /*
0123          * Open coded to handle VDSO_CLOCKMODE_TIMENS. Time namespace
0124          * enabled tasks have a special VVAR page installed which
0125          * has vd->seq set to 1 and vd->clock_mode set to
0126          * VDSO_CLOCKMODE_TIMENS. For non time namespace affected tasks
0127          * this does not affect performance because if vd->seq is
0128          * odd, i.e. a concurrent update is in progress the extra
0129          * check for vd->clock_mode is just a few extra
0130          * instructions while spin waiting for vd->seq to become
0131          * even again.
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      * Do this outside the loop: a race inside the loop could result
0156      * in __iter_div_u64_rem() being extremely slow.
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     /* Add the namespace offset */
0182     sec += offs->sec;
0183     nsec += offs->nsec;
0184 
0185     /*
0186      * Do this outside the loop: a race inside the loop could result
0187      * in __iter_div_u64_rem() being extremely slow.
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          * Open coded to handle VDSO_CLOCK_TIMENS. See comment in
0210          * do_hres().
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     /* Check for negative values or invalid clocks */
0234     if (unlikely((u32) clock >= MAX_CLOCKS))
0235         return -1;
0236 
0237     /*
0238      * Convert the clockid to a bitmask and use it to check which
0239      * clocks are handled in the VDSO directly.
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     /* For ret == 0 */
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 /* BUILD_VDSO32 */
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 /* VDSO_HAS_TIME */
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     /* Check for negative values or invalid clocks */
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      * Convert the clockid to a bitmask and use it to check which
0373      * clocks are handled in the VDSO directly.
0374      */
0375     msk = 1U << clock;
0376     if (msk & (VDSO_HRES | VDSO_RAW)) {
0377         /*
0378          * Preserves the behaviour of posix_get_hrtimer_res().
0379          */
0380         ns = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res);
0381     } else if (msk & VDSO_COARSE) {
0382         /*
0383          * Preserves the behaviour of posix_get_coarse_res().
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 /* BUILD_VDSO32 */
0441 #endif /* VDSO_HAS_CLOCK_GETRES */