arm64: vdso32: Code clean up
[linux-2.6-microblaze.git] / arch / arm64 / include / asm / vdso / compat_gettimeofday.h
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_HAS_CLOCK_GETRES           1
16
17 #define BUILD_VDSO32                    1
18
19 static __always_inline
20 int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
21                           struct timezone *_tz)
22 {
23         register struct timezone *tz asm("r1") = _tz;
24         register struct __kernel_old_timeval *tv asm("r0") = _tv;
25         register long ret asm ("r0");
26         register long nr asm("r7") = __NR_compat_gettimeofday;
27
28         asm volatile(
29         "       swi #0\n"
30         : "=r" (ret)
31         : "r" (tv), "r" (tz), "r" (nr)
32         : "memory");
33
34         return ret;
35 }
36
37 static __always_inline
38 long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
39 {
40         register struct __kernel_timespec *ts asm("r1") = _ts;
41         register clockid_t clkid asm("r0") = _clkid;
42         register long ret asm ("r0");
43         register long nr asm("r7") = __NR_compat_clock_gettime64;
44
45         asm volatile(
46         "       swi #0\n"
47         : "=r" (ret)
48         : "r" (clkid), "r" (ts), "r" (nr)
49         : "memory");
50
51         return ret;
52 }
53
54 static __always_inline
55 long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
56 {
57         register struct old_timespec32 *ts asm("r1") = _ts;
58         register clockid_t clkid asm("r0") = _clkid;
59         register long ret asm ("r0");
60         register long nr asm("r7") = __NR_compat_clock_gettime;
61
62         asm volatile(
63         "       swi #0\n"
64         : "=r" (ret)
65         : "r" (clkid), "r" (ts), "r" (nr)
66         : "memory");
67
68         return ret;
69 }
70
71 static __always_inline
72 int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
73 {
74         register struct __kernel_timespec *ts asm("r1") = _ts;
75         register clockid_t clkid asm("r0") = _clkid;
76         register long ret asm ("r0");
77         register long nr asm("r7") = __NR_compat_clock_getres_time64;
78
79         asm volatile(
80         "       swi #0\n"
81         : "=r" (ret)
82         : "r" (clkid), "r" (ts), "r" (nr)
83         : "memory");
84
85         return ret;
86 }
87
88 static __always_inline
89 int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
90 {
91         register struct old_timespec32 *ts asm("r1") = _ts;
92         register clockid_t clkid asm("r0") = _clkid;
93         register long ret asm ("r0");
94         register long nr asm("r7") = __NR_compat_clock_getres;
95
96         asm volatile(
97         "       swi #0\n"
98         : "=r" (ret)
99         : "r" (clkid), "r" (ts), "r" (nr)
100         : "memory");
101
102         return ret;
103 }
104
105 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
106 {
107         u64 res;
108
109         /*
110          * Core checks for mode already, so this raced against a concurrent
111          * update. Return something. Core will do another round and then
112          * see the mode change and fallback to the syscall.
113          */
114         if (clock_mode == VDSO_CLOCKMODE_NONE)
115                 return 0;
116
117         /*
118          * This isb() is required to prevent that the counter value
119          * is speculated.
120          */
121         isb();
122         asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res));
123         /*
124          * This isb() is required to prevent that the seq lock is
125          * speculated.
126          */
127         isb();
128
129         return res;
130 }
131
132 static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
133 {
134         const struct vdso_data *ret;
135
136         /*
137          * This simply puts &_vdso_data into ret. The reason why we don't use
138          * `ret = _vdso_data` is that the compiler tends to optimise this in a
139          * very suboptimal way: instead of keeping &_vdso_data in a register,
140          * it goes through a relocation almost every time _vdso_data must be
141          * accessed (even in subfunctions). This is both time and space
142          * consuming: each relocation uses a word in the code section, and it
143          * has to be loaded at runtime.
144          *
145          * This trick hides the assignment from the compiler. Since it cannot
146          * track where the pointer comes from, it will only use one relocation
147          * where __arch_get_vdso_data() is called, and then keep the result in
148          * a register.
149          */
150         asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data));
151
152         return ret;
153 }
154
155 #endif /* !__ASSEMBLY__ */
156
157 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */