1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2018 ARM Limited
5 #ifndef __ASM_VDSO_GETTIMEOFDAY_H
6 #define __ASM_VDSO_GETTIMEOFDAY_H
10 #include <asm/unistd.h>
11 #include <uapi/linux/time.h>
13 #include <asm/vdso/compat_barrier.h>
15 #define __VDSO_USE_SYSCALL ULLONG_MAX
17 #define VDSO_HAS_CLOCK_GETRES 1
19 #define BUILD_VDSO32 1
21 static __always_inline
22 int gettimeofday_fallback(struct __kernel_old_timeval
*_tv
,
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
;
33 : "r" (tv
), "r" (tz
), "r" (nr
)
39 static __always_inline
40 long clock_gettime_fallback(clockid_t _clkid
, struct __kernel_timespec
*_ts
)
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
;
50 : "r" (clkid
), "r" (ts
), "r" (nr
)
56 static __always_inline
57 long clock_gettime32_fallback(clockid_t _clkid
, struct old_timespec32
*_ts
)
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
;
67 : "r" (clkid
), "r" (ts
), "r" (nr
)
73 static __always_inline
74 int clock_getres_fallback(clockid_t _clkid
, struct __kernel_timespec
*_ts
)
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
;
81 /* The checks below are required for ABI consistency with arm */
82 if ((_clkid
>= MAX_CLOCKS
) && (_ts
== NULL
))
88 : "r" (clkid
), "r" (ts
), "r" (nr
)
94 static __always_inline
95 int clock_getres32_fallback(clockid_t _clkid
, struct old_timespec32
*_ts
)
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
;
102 /* The checks below are required for ABI consistency with arm */
103 if ((_clkid
>= MAX_CLOCKS
) && (_ts
== NULL
))
109 : "r" (clkid
), "r" (ts
), "r" (nr
)
115 static __always_inline u64
__arch_get_hw_counter(s32 clock_mode
)
120 * clock_mode == 0 implies that vDSO are enabled otherwise
121 * fallback on syscall.
124 return __VDSO_USE_SYSCALL
;
127 * This isb() is required to prevent that the counter value
131 asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res
));
133 * This isb() is required to prevent that the seq lock is
141 static __always_inline
const struct vdso_data
*__arch_get_vdso_data(void)
143 const struct vdso_data
*ret
;
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.
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
159 asm volatile("mov %0, %1" : "=r"(ret
) : "r"(_vdso_data
));
164 #endif /* !__ASSEMBLY__ */
166 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */