1a7f71a2cSVincenzo Frascino /* SPDX-License-Identifier: GPL-2.0 */
2a7f71a2cSVincenzo Frascino /*
3a7f71a2cSVincenzo Frascino  * Copyright (C) 2018 ARM Limited
4a7f71a2cSVincenzo Frascino  */
5a7f71a2cSVincenzo Frascino #ifndef __ASM_VDSO_GETTIMEOFDAY_H
6a7f71a2cSVincenzo Frascino #define __ASM_VDSO_GETTIMEOFDAY_H
7a7f71a2cSVincenzo Frascino 
8a7f71a2cSVincenzo Frascino #ifndef __ASSEMBLY__
9a7f71a2cSVincenzo Frascino 
10002dff36SWill Deacon #include <asm/barrier.h>
11a7f71a2cSVincenzo Frascino #include <asm/unistd.h>
125340e873SVincenzo Frascino #include <asm/errno.h>
13a7f71a2cSVincenzo Frascino 
14a7f71a2cSVincenzo Frascino #include <asm/vdso/compat_barrier.h>
15a7f71a2cSVincenzo Frascino 
16a7f71a2cSVincenzo Frascino #define VDSO_HAS_CLOCK_GETRES		1
17a7f71a2cSVincenzo Frascino 
183b5584afSVincenzo Frascino #define BUILD_VDSO32			1
1933a58980SThomas Gleixner 
20a7f71a2cSVincenzo Frascino static __always_inline
gettimeofday_fallback(struct __kernel_old_timeval * _tv,struct timezone * _tz)21a7f71a2cSVincenzo Frascino int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
22a7f71a2cSVincenzo Frascino 			  struct timezone *_tz)
23a7f71a2cSVincenzo Frascino {
24a7f71a2cSVincenzo Frascino 	register struct timezone *tz asm("r1") = _tz;
25a7f71a2cSVincenzo Frascino 	register struct __kernel_old_timeval *tv asm("r0") = _tv;
26a7f71a2cSVincenzo Frascino 	register long ret asm ("r0");
27a7f71a2cSVincenzo Frascino 	register long nr asm("r7") = __NR_compat_gettimeofday;
28a7f71a2cSVincenzo Frascino 
29a7f71a2cSVincenzo Frascino 	asm volatile(
30a7f71a2cSVincenzo Frascino 	"	swi #0\n"
31a7f71a2cSVincenzo Frascino 	: "=r" (ret)
32a7f71a2cSVincenzo Frascino 	: "r" (tv), "r" (tz), "r" (nr)
33a7f71a2cSVincenzo Frascino 	: "memory");
34a7f71a2cSVincenzo Frascino 
35a7f71a2cSVincenzo Frascino 	return ret;
36a7f71a2cSVincenzo Frascino }
37a7f71a2cSVincenzo Frascino 
38a7f71a2cSVincenzo Frascino static __always_inline
clock_gettime_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)39a7f71a2cSVincenzo Frascino long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
40a7f71a2cSVincenzo Frascino {
41a7f71a2cSVincenzo Frascino 	register struct __kernel_timespec *ts asm("r1") = _ts;
42a7f71a2cSVincenzo Frascino 	register clockid_t clkid asm("r0") = _clkid;
43a7f71a2cSVincenzo Frascino 	register long ret asm ("r0");
44a7f71a2cSVincenzo Frascino 	register long nr asm("r7") = __NR_compat_clock_gettime64;
45a7f71a2cSVincenzo Frascino 
46a7f71a2cSVincenzo Frascino 	asm volatile(
47a7f71a2cSVincenzo Frascino 	"	swi #0\n"
48a7f71a2cSVincenzo Frascino 	: "=r" (ret)
49a7f71a2cSVincenzo Frascino 	: "r" (clkid), "r" (ts), "r" (nr)
50a7f71a2cSVincenzo Frascino 	: "memory");
51a7f71a2cSVincenzo Frascino 
52a7f71a2cSVincenzo Frascino 	return ret;
53a7f71a2cSVincenzo Frascino }
54a7f71a2cSVincenzo Frascino 
55a7f71a2cSVincenzo Frascino static __always_inline
clock_gettime32_fallback(clockid_t _clkid,struct old_timespec32 * _ts)5633a58980SThomas Gleixner long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
5733a58980SThomas Gleixner {
5833a58980SThomas Gleixner 	register struct old_timespec32 *ts asm("r1") = _ts;
5933a58980SThomas Gleixner 	register clockid_t clkid asm("r0") = _clkid;
6033a58980SThomas Gleixner 	register long ret asm ("r0");
6133a58980SThomas Gleixner 	register long nr asm("r7") = __NR_compat_clock_gettime;
6233a58980SThomas Gleixner 
6333a58980SThomas Gleixner 	asm volatile(
6433a58980SThomas Gleixner 	"	swi #0\n"
6533a58980SThomas Gleixner 	: "=r" (ret)
6633a58980SThomas Gleixner 	: "r" (clkid), "r" (ts), "r" (nr)
6733a58980SThomas Gleixner 	: "memory");
6833a58980SThomas Gleixner 
6933a58980SThomas Gleixner 	return ret;
7033a58980SThomas Gleixner }
7133a58980SThomas Gleixner 
7233a58980SThomas Gleixner static __always_inline
clock_getres_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)73a7f71a2cSVincenzo Frascino int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
74a7f71a2cSVincenzo Frascino {
75a7f71a2cSVincenzo Frascino 	register struct __kernel_timespec *ts asm("r1") = _ts;
76a7f71a2cSVincenzo Frascino 	register clockid_t clkid asm("r0") = _clkid;
77a7f71a2cSVincenzo Frascino 	register long ret asm ("r0");
78a7f71a2cSVincenzo Frascino 	register long nr asm("r7") = __NR_compat_clock_getres_time64;
79a7f71a2cSVincenzo Frascino 
80a7f71a2cSVincenzo Frascino 	asm volatile(
81a7f71a2cSVincenzo Frascino 	"       swi #0\n"
82a7f71a2cSVincenzo Frascino 	: "=r" (ret)
83a7f71a2cSVincenzo Frascino 	: "r" (clkid), "r" (ts), "r" (nr)
84a7f71a2cSVincenzo Frascino 	: "memory");
85a7f71a2cSVincenzo Frascino 
86a7f71a2cSVincenzo Frascino 	return ret;
87a7f71a2cSVincenzo Frascino }
88a7f71a2cSVincenzo Frascino 
8933a58980SThomas Gleixner static __always_inline
clock_getres32_fallback(clockid_t _clkid,struct old_timespec32 * _ts)9033a58980SThomas Gleixner int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
9133a58980SThomas Gleixner {
9233a58980SThomas Gleixner 	register struct old_timespec32 *ts asm("r1") = _ts;
9333a58980SThomas Gleixner 	register clockid_t clkid asm("r0") = _clkid;
9433a58980SThomas Gleixner 	register long ret asm ("r0");
9533a58980SThomas Gleixner 	register long nr asm("r7") = __NR_compat_clock_getres;
9633a58980SThomas Gleixner 
9733a58980SThomas Gleixner 	asm volatile(
9833a58980SThomas Gleixner 	"       swi #0\n"
9933a58980SThomas Gleixner 	: "=r" (ret)
10033a58980SThomas Gleixner 	: "r" (clkid), "r" (ts), "r" (nr)
10133a58980SThomas Gleixner 	: "memory");
10233a58980SThomas Gleixner 
10333a58980SThomas Gleixner 	return ret;
10433a58980SThomas Gleixner }
10533a58980SThomas Gleixner 
__arch_get_hw_counter(s32 clock_mode,const struct vdso_data * vd)1064c5a116aSThomas Gleixner static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
1074c5a116aSThomas Gleixner 						 const struct vdso_data *vd)
108a7f71a2cSVincenzo Frascino {
109a7f71a2cSVincenzo Frascino 	u64 res;
110a7f71a2cSVincenzo Frascino 
1116241c4dcSVincenzo Frascino 	/*
1125e3c6a31SThomas Gleixner 	 * Core checks for mode already, so this raced against a concurrent
1135e3c6a31SThomas Gleixner 	 * update. Return something. Core will do another round and then
1145e3c6a31SThomas Gleixner 	 * see the mode change and fallback to the syscall.
1156241c4dcSVincenzo Frascino 	 */
11697884ca8SMarc Zyngier 	if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
1175e3c6a31SThomas Gleixner 		return 0;
1186241c4dcSVincenzo Frascino 
1196241c4dcSVincenzo Frascino 	/*
1206241c4dcSVincenzo Frascino 	 * This isb() is required to prevent that the counter value
1216241c4dcSVincenzo Frascino 	 * is speculated.
1226241c4dcSVincenzo Frascino 	 */
123a7f71a2cSVincenzo Frascino 	isb();
124a7f71a2cSVincenzo Frascino 	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res));
1256241c4dcSVincenzo Frascino 	/*
1266241c4dcSVincenzo Frascino 	 * This isb() is required to prevent that the seq lock is
1276241c4dcSVincenzo Frascino 	 * speculated.
1286241c4dcSVincenzo Frascino 	 */
1296241c4dcSVincenzo Frascino 	isb();
130a7f71a2cSVincenzo Frascino 
131a7f71a2cSVincenzo Frascino 	return res;
132a7f71a2cSVincenzo Frascino }
133a7f71a2cSVincenzo Frascino 
__arch_get_vdso_data(void)134a7f71a2cSVincenzo Frascino static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
135a7f71a2cSVincenzo Frascino {
136a7f71a2cSVincenzo Frascino 	const struct vdso_data *ret;
137a7f71a2cSVincenzo Frascino 
138a7f71a2cSVincenzo Frascino 	/*
139a7f71a2cSVincenzo Frascino 	 * This simply puts &_vdso_data into ret. The reason why we don't use
140a7f71a2cSVincenzo Frascino 	 * `ret = _vdso_data` is that the compiler tends to optimise this in a
141a7f71a2cSVincenzo Frascino 	 * very suboptimal way: instead of keeping &_vdso_data in a register,
142a7f71a2cSVincenzo Frascino 	 * it goes through a relocation almost every time _vdso_data must be
143a7f71a2cSVincenzo Frascino 	 * accessed (even in subfunctions). This is both time and space
144a7f71a2cSVincenzo Frascino 	 * consuming: each relocation uses a word in the code section, and it
145a7f71a2cSVincenzo Frascino 	 * has to be loaded at runtime.
146a7f71a2cSVincenzo Frascino 	 *
147a7f71a2cSVincenzo Frascino 	 * This trick hides the assignment from the compiler. Since it cannot
148a7f71a2cSVincenzo Frascino 	 * track where the pointer comes from, it will only use one relocation
149a7f71a2cSVincenzo Frascino 	 * where __arch_get_vdso_data() is called, and then keep the result in
150a7f71a2cSVincenzo Frascino 	 * a register.
151a7f71a2cSVincenzo Frascino 	 */
152a7f71a2cSVincenzo Frascino 	asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data));
153a7f71a2cSVincenzo Frascino 
154a7f71a2cSVincenzo Frascino 	return ret;
155a7f71a2cSVincenzo Frascino }
156a7f71a2cSVincenzo Frascino 
1573503d56cSAndrei Vagin #ifdef CONFIG_TIME_NS
158*808094fcSChristophe Leroy static __always_inline
__arch_get_timens_vdso_data(const struct vdso_data * vd)159*808094fcSChristophe Leroy const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
1603503d56cSAndrei Vagin {
1613503d56cSAndrei Vagin 	const struct vdso_data *ret;
1623503d56cSAndrei Vagin 
1633503d56cSAndrei Vagin 	/* See __arch_get_vdso_data(). */
1643503d56cSAndrei Vagin 	asm volatile("mov %0, %1" : "=r"(ret) : "r"(_timens_data));
1653503d56cSAndrei Vagin 
1663503d56cSAndrei Vagin 	return ret;
1673503d56cSAndrei Vagin }
1683503d56cSAndrei Vagin #endif
1693503d56cSAndrei Vagin 
vdso_clocksource_ok(const struct vdso_data * vd)17097884ca8SMarc Zyngier static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
17197884ca8SMarc Zyngier {
17297884ca8SMarc Zyngier 	return vd->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
17397884ca8SMarc Zyngier }
17497884ca8SMarc Zyngier #define vdso_clocksource_ok	vdso_clocksource_ok
17597884ca8SMarc Zyngier 
176a7f71a2cSVincenzo Frascino #endif /* !__ASSEMBLY__ */
177a7f71a2cSVincenzo Frascino 
178a7f71a2cSVincenzo Frascino #endif /* __ASM_VDSO_GETTIMEOFDAY_H */
179