Merge tag 'nfsd-5.3-1' of git://linux-nfs.org/~bfields/linux
[sfrench/cifs-2.6.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_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 */