f92752d6cbcf22f60539c095ab91729b366f075f
[linux-2.6-block.git] / arch / x86 / include / asm / vdso / gettimeofday.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Fast user context implementation of clock_gettime, gettimeofday, and time.
4  *
5  * Copyright (C) 2019 ARM Limited.
6  * Copyright 2006 Andi Kleen, SUSE Labs.
7  * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
8  *  sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
9  */
10 #ifndef __ASM_VDSO_GETTIMEOFDAY_H
11 #define __ASM_VDSO_GETTIMEOFDAY_H
12
13 #ifndef __ASSEMBLY__
14
15 #include <uapi/linux/time.h>
16 #include <asm/vgtod.h>
17 #include <asm/vvar.h>
18 #include <asm/unistd.h>
19 #include <asm/msr.h>
20 #include <asm/pvclock.h>
21 #include <asm/mshyperv.h>
22
23 #define __vdso_data (VVAR(_vdso_data))
24
25 #define VDSO_HAS_TIME 1
26
27 #define VDSO_HAS_CLOCK_GETRES 1
28
29 #ifdef CONFIG_PARAVIRT_CLOCK
30 extern u8 pvclock_page[PAGE_SIZE]
31         __attribute__((visibility("hidden")));
32 #endif
33
34 #ifdef CONFIG_HYPERV_TSCPAGE
35 extern u8 hvclock_page[PAGE_SIZE]
36         __attribute__((visibility("hidden")));
37 #endif
38
39 #ifndef BUILD_VDSO32
40
41 static __always_inline
42 long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
43 {
44         long ret;
45
46         asm ("syscall" : "=a" (ret), "=m" (*_ts) :
47              "0" (__NR_clock_gettime), "D" (_clkid), "S" (_ts) :
48              "rcx", "r11");
49
50         return ret;
51 }
52
53 static __always_inline
54 long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
55                            struct timezone *_tz)
56 {
57         long ret;
58
59         asm("syscall" : "=a" (ret) :
60             "0" (__NR_gettimeofday), "D" (_tv), "S" (_tz) : "memory");
61
62         return ret;
63 }
64
65 static __always_inline
66 long clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
67 {
68         long ret;
69
70         asm ("syscall" : "=a" (ret), "=m" (*_ts) :
71              "0" (__NR_clock_getres), "D" (_clkid), "S" (_ts) :
72              "rcx", "r11");
73
74         return ret;
75 }
76
77 #else
78
79 static __always_inline
80 long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
81 {
82         long ret;
83
84         asm (
85                 "mov %%ebx, %%edx \n"
86                 "mov %[clock], %%ebx \n"
87                 "call __kernel_vsyscall \n"
88                 "mov %%edx, %%ebx \n"
89                 : "=a" (ret), "=m" (*_ts)
90                 : "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts)
91                 : "edx");
92
93         return ret;
94 }
95
96 static __always_inline
97 long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
98                            struct timezone *_tz)
99 {
100         long ret;
101
102         asm(
103                 "mov %%ebx, %%edx \n"
104                 "mov %2, %%ebx \n"
105                 "call __kernel_vsyscall \n"
106                 "mov %%edx, %%ebx \n"
107                 : "=a" (ret)
108                 : "0" (__NR_gettimeofday), "g" (_tv), "c" (_tz)
109                 : "memory", "edx");
110
111         return ret;
112 }
113
114 static __always_inline long
115 clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
116 {
117         long ret;
118
119         asm (
120                 "mov %%ebx, %%edx \n"
121                 "mov %[clock], %%ebx \n"
122                 "call __kernel_vsyscall \n"
123                 "mov %%edx, %%ebx \n"
124                 : "=a" (ret), "=m" (*_ts)
125                 : "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts)
126                 : "edx");
127
128         return ret;
129 }
130
131 #endif
132
133 #ifdef CONFIG_PARAVIRT_CLOCK
134 static const struct pvclock_vsyscall_time_info *get_pvti0(void)
135 {
136         return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
137 }
138
139 static u64 vread_pvclock(void)
140 {
141         const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
142         u32 version;
143         u64 ret;
144
145         /*
146          * Note: The kernel and hypervisor must guarantee that cpu ID
147          * number maps 1:1 to per-CPU pvclock time info.
148          *
149          * Because the hypervisor is entirely unaware of guest userspace
150          * preemption, it cannot guarantee that per-CPU pvclock time
151          * info is updated if the underlying CPU changes or that that
152          * version is increased whenever underlying CPU changes.
153          *
154          * On KVM, we are guaranteed that pvti updates for any vCPU are
155          * atomic as seen by *all* vCPUs.  This is an even stronger
156          * guarantee than we get with a normal seqlock.
157          *
158          * On Xen, we don't appear to have that guarantee, but Xen still
159          * supplies a valid seqlock using the version field.
160          *
161          * We only do pvclock vdso timing at all if
162          * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
163          * mean that all vCPUs have matching pvti and that the TSC is
164          * synced, so we can just look at vCPU 0's pvti.
165          */
166
167         do {
168                 version = pvclock_read_begin(pvti);
169
170                 if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT)))
171                         return U64_MAX;
172
173                 ret = __pvclock_read_cycles(pvti, rdtsc_ordered());
174         } while (pvclock_read_retry(pvti, version));
175
176         return ret;
177 }
178 #endif
179
180 #ifdef CONFIG_HYPERV_TSCPAGE
181 static u64 vread_hvclock(void)
182 {
183         const struct ms_hyperv_tsc_page *tsc_pg =
184                 (const struct ms_hyperv_tsc_page *)&hvclock_page;
185
186         return hv_read_tsc_page(tsc_pg);
187 }
188 #endif
189
190 static inline u64 __arch_get_hw_counter(s32 clock_mode)
191 {
192         if (clock_mode == VCLOCK_TSC)
193                 return (u64)rdtsc_ordered();
194         /*
195          * For any memory-mapped vclock type, we need to make sure that gcc
196          * doesn't cleverly hoist a load before the mode check.  Otherwise we
197          * might end up touching the memory-mapped page even if the vclock in
198          * question isn't enabled, which will segfault.  Hence the barriers.
199          */
200 #ifdef CONFIG_PARAVIRT_CLOCK
201         if (clock_mode == VCLOCK_PVCLOCK) {
202                 barrier();
203                 return vread_pvclock();
204         }
205 #endif
206 #ifdef CONFIG_HYPERV_TSCPAGE
207         if (clock_mode == VCLOCK_HVCLOCK) {
208                 barrier();
209                 return vread_hvclock();
210         }
211 #endif
212         return U64_MAX;
213 }
214
215 static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
216 {
217         return __vdso_data;
218 }
219
220 #endif /* !__ASSEMBLY__ */
221
222 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */