root/arch/arm64/include/asm/vdso/compat_gettimeofday.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. gettimeofday_fallback
  2. clock_gettime_fallback
  3. clock_gettime32_fallback
  4. clock_getres_fallback
  5. clock_getres32_fallback
  6. __arch_get_hw_counter
  7. __arch_get_vdso_data

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * Copyright (C) 2018 ARM Limited
   4  */
   5 #ifndef __ASM_VDSO_GETTIMEOFDAY_H
   6 #define __ASM_VDSO_GETTIMEOFDAY_H
   7 
   8 #ifndef __ASSEMBLY__
   9 
  10 #include <asm/unistd.h>
  11 #include <uapi/linux/time.h>
  12 
  13 #include <asm/vdso/compat_barrier.h>
  14 
  15 #define __VDSO_USE_SYSCALL              ULLONG_MAX
  16 
  17 #define VDSO_HAS_CLOCK_GETRES           1
  18 
  19 #define VDSO_HAS_32BIT_FALLBACK         1
  20 
  21 static __always_inline
  22 int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
  23                           struct timezone *_tz)
  24 {
  25         register struct timezone *tz asm("r1") = _tz;
  26         register struct __kernel_old_timeval *tv asm("r0") = _tv;
  27         register long ret asm ("r0");
  28         register long nr asm("r7") = __NR_compat_gettimeofday;
  29 
  30         asm volatile(
  31         "       swi #0\n"
  32         : "=r" (ret)
  33         : "r" (tv), "r" (tz), "r" (nr)
  34         : "memory");
  35 
  36         return ret;
  37 }
  38 
  39 static __always_inline
  40 long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
  41 {
  42         register struct __kernel_timespec *ts asm("r1") = _ts;
  43         register clockid_t clkid asm("r0") = _clkid;
  44         register long ret asm ("r0");
  45         register long nr asm("r7") = __NR_compat_clock_gettime64;
  46 
  47         asm volatile(
  48         "       swi #0\n"
  49         : "=r" (ret)
  50         : "r" (clkid), "r" (ts), "r" (nr)
  51         : "memory");
  52 
  53         return ret;
  54 }
  55 
  56 static __always_inline
  57 long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
  58 {
  59         register struct old_timespec32 *ts asm("r1") = _ts;
  60         register clockid_t clkid asm("r0") = _clkid;
  61         register long ret asm ("r0");
  62         register long nr asm("r7") = __NR_compat_clock_gettime;
  63 
  64         asm volatile(
  65         "       swi #0\n"
  66         : "=r" (ret)
  67         : "r" (clkid), "r" (ts), "r" (nr)
  68         : "memory");
  69 
  70         return ret;
  71 }
  72 
  73 static __always_inline
  74 int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
  75 {
  76         register struct __kernel_timespec *ts asm("r1") = _ts;
  77         register clockid_t clkid asm("r0") = _clkid;
  78         register long ret asm ("r0");
  79         register long nr asm("r7") = __NR_compat_clock_getres_time64;
  80 
  81         /* The checks below are required for ABI consistency with arm */
  82         if ((_clkid >= MAX_CLOCKS) && (_ts == NULL))
  83                 return -EINVAL;
  84 
  85         asm volatile(
  86         "       swi #0\n"
  87         : "=r" (ret)
  88         : "r" (clkid), "r" (ts), "r" (nr)
  89         : "memory");
  90 
  91         return ret;
  92 }
  93 
  94 static __always_inline
  95 int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
  96 {
  97         register struct old_timespec32 *ts asm("r1") = _ts;
  98         register clockid_t clkid asm("r0") = _clkid;
  99         register long ret asm ("r0");
 100         register long nr asm("r7") = __NR_compat_clock_getres;
 101 
 102         /* The checks below are required for ABI consistency with arm */
 103         if ((_clkid >= MAX_CLOCKS) && (_ts == NULL))
 104                 return -EINVAL;
 105 
 106         asm volatile(
 107         "       swi #0\n"
 108         : "=r" (ret)
 109         : "r" (clkid), "r" (ts), "r" (nr)
 110         : "memory");
 111 
 112         return ret;
 113 }
 114 
 115 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
 116 {
 117         u64 res;
 118 
 119         /*
 120          * clock_mode == 0 implies that vDSO are enabled otherwise
 121          * fallback on syscall.
 122          */
 123         if (clock_mode)
 124                 return __VDSO_USE_SYSCALL;
 125 
 126         /*
 127          * This isb() is required to prevent that the counter value
 128          * is speculated.
 129          */
 130         isb();
 131         asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res));
 132         /*
 133          * This isb() is required to prevent that the seq lock is
 134          * speculated.
 135          */
 136         isb();
 137 
 138         return res;
 139 }
 140 
 141 static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
 142 {
 143         const struct vdso_data *ret;
 144 
 145         /*
 146          * This simply puts &_vdso_data into ret. The reason why we don't use
 147          * `ret = _vdso_data` is that the compiler tends to optimise this in a
 148          * very suboptimal way: instead of keeping &_vdso_data in a register,
 149          * it goes through a relocation almost every time _vdso_data must be
 150          * accessed (even in subfunctions). This is both time and space
 151          * consuming: each relocation uses a word in the code section, and it
 152          * has to be loaded at runtime.
 153          *
 154          * This trick hides the assignment from the compiler. Since it cannot
 155          * track where the pointer comes from, it will only use one relocation
 156          * where __arch_get_vdso_data() is called, and then keep the result in
 157          * a register.
 158          */
 159         asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data));
 160 
 161         return ret;
 162 }
 163 
 164 #endif /* !__ASSEMBLY__ */
 165 
 166 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */

/* [<][>][^][v][top][bottom][index][help] */