GNU Linux-libre 4.4.289-gnu1
[releases.git] / arch / x86 / entry / vdso / vclock_gettime.c
1 /*
2  * Copyright 2006 Andi Kleen, SUSE Labs.
3  * Subject to the GNU Public License, v.2
4  *
5  * Fast user context implementation of clock_gettime, gettimeofday, and time.
6  *
7  * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
8  *  sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
9  *
10  * The code should have no internal unresolved relocations.
11  * Check with readelf after changing.
12  */
13
14 #include <uapi/linux/time.h>
15 #include <asm/vgtod.h>
16 #include <asm/vvar.h>
17 #include <asm/unistd.h>
18 #include <asm/msr.h>
19 #include <linux/math64.h>
20 #include <linux/time.h>
21
22 #define gtod (&VVAR(vsyscall_gtod_data))
23
24 extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts);
25 extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
26 extern time_t __vdso_time(time_t *t);
27
28 #ifdef CONFIG_PARAVIRT_CLOCK
29 extern u8 pvclock_page
30         __attribute__((visibility("hidden")));
31 #endif
32
33 #ifndef BUILD_VDSO32
34
35 #include <linux/kernel.h>
36 #include <asm/vsyscall.h>
37 #include <asm/fixmap.h>
38 #include <asm/pvclock.h>
39
40 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
41 {
42         long ret;
43         asm ("syscall" : "=a" (ret), "=m" (*ts) :
44              "0" (__NR_clock_gettime), "D" (clock), "S" (ts) :
45              "memory", "rcx", "r11");
46         return ret;
47 }
48
49 notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
50 {
51         long ret;
52
53         asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) :
54              "0" (__NR_gettimeofday), "D" (tv), "S" (tz) :
55              "memory", "rcx", "r11");
56         return ret;
57 }
58
59 #ifdef CONFIG_PARAVIRT_CLOCK
60
61 static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void)
62 {
63         return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
64 }
65
66 static notrace cycle_t vread_pvclock(int *mode)
67 {
68         const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
69         cycle_t ret;
70         u64 tsc, pvti_tsc;
71         u64 last, delta, pvti_system_time;
72         u32 version, pvti_tsc_to_system_mul, pvti_tsc_shift;
73
74         /*
75          * Note: The kernel and hypervisor must guarantee that cpu ID
76          * number maps 1:1 to per-CPU pvclock time info.
77          *
78          * Because the hypervisor is entirely unaware of guest userspace
79          * preemption, it cannot guarantee that per-CPU pvclock time
80          * info is updated if the underlying CPU changes or that that
81          * version is increased whenever underlying CPU changes.
82          *
83          * On KVM, we are guaranteed that pvti updates for any vCPU are
84          * atomic as seen by *all* vCPUs.  This is an even stronger
85          * guarantee than we get with a normal seqlock.
86          *
87          * On Xen, we don't appear to have that guarantee, but Xen still
88          * supplies a valid seqlock using the version field.
89
90          * We only do pvclock vdso timing at all if
91          * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
92          * mean that all vCPUs have matching pvti and that the TSC is
93          * synced, so we can just look at vCPU 0's pvti.
94          */
95
96         if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
97                 *mode = VCLOCK_NONE;
98                 return 0;
99         }
100
101         do {
102                 version = pvti->version;
103
104                 /* This is also a read barrier, so we'll read version first. */
105                 tsc = rdtsc_ordered();
106
107                 pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
108                 pvti_tsc_shift = pvti->tsc_shift;
109                 pvti_system_time = pvti->system_time;
110                 pvti_tsc = pvti->tsc_timestamp;
111
112                 /* Make sure that the version double-check is last. */
113                 smp_rmb();
114         } while (unlikely((version & 1) || version != pvti->version));
115
116         delta = tsc - pvti_tsc;
117         ret = pvti_system_time +
118                 pvclock_scale_delta(delta, pvti_tsc_to_system_mul,
119                                     pvti_tsc_shift);
120
121         /* refer to tsc.c read_tsc() comment for rationale */
122         last = gtod->cycle_last;
123
124         if (likely(ret >= last))
125                 return ret;
126
127         return last;
128 }
129 #endif
130
131 #else
132
133 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
134 {
135         long ret;
136
137         asm (
138                 "mov %%ebx, %%edx \n"
139                 "mov %[clock], %%ebx \n"
140                 "call __kernel_vsyscall \n"
141                 "mov %%edx, %%ebx \n"
142                 : "=a" (ret), "=m" (*ts)
143                 : "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts)
144                 : "memory", "edx");
145         return ret;
146 }
147
148 notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
149 {
150         long ret;
151
152         asm (
153                 "mov %%ebx, %%edx \n"
154                 "mov %[tv], %%ebx \n"
155                 "call __kernel_vsyscall \n"
156                 "mov %%edx, %%ebx \n"
157                 : "=a" (ret), "=m" (*tv), "=m" (*tz)
158                 : "0" (__NR_gettimeofday), [tv] "g" (tv), "c" (tz)
159                 : "memory", "edx");
160         return ret;
161 }
162
163 #ifdef CONFIG_PARAVIRT_CLOCK
164
165 static notrace cycle_t vread_pvclock(int *mode)
166 {
167         *mode = VCLOCK_NONE;
168         return 0;
169 }
170 #endif
171
172 #endif
173
174 notrace static cycle_t vread_tsc(void)
175 {
176         cycle_t ret = (cycle_t)rdtsc_ordered();
177         u64 last = gtod->cycle_last;
178
179         if (likely(ret >= last))
180                 return ret;
181
182         /*
183          * GCC likes to generate cmov here, but this branch is extremely
184          * predictable (it's just a funciton of time and the likely is
185          * very likely) and there's a data dependence, so force GCC
186          * to generate a branch instead.  I don't barrier() because
187          * we don't actually need a barrier, and if this function
188          * ever gets inlined it will generate worse code.
189          */
190         asm volatile ("");
191         return last;
192 }
193
194 notrace static inline u64 vgetsns(int *mode)
195 {
196         u64 v;
197         cycles_t cycles;
198
199         if (gtod->vclock_mode == VCLOCK_TSC)
200                 cycles = vread_tsc();
201 #ifdef CONFIG_PARAVIRT_CLOCK
202         else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
203                 cycles = vread_pvclock(mode);
204 #endif
205         else
206                 return 0;
207         v = (cycles - gtod->cycle_last) & gtod->mask;
208         return v * gtod->mult;
209 }
210
211 /* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
212 notrace static int __always_inline do_realtime(struct timespec *ts)
213 {
214         unsigned long seq;
215         u64 ns;
216         int mode;
217
218         do {
219                 seq = gtod_read_begin(gtod);
220                 mode = gtod->vclock_mode;
221                 ts->tv_sec = gtod->wall_time_sec;
222                 ns = gtod->wall_time_snsec;
223                 ns += vgetsns(&mode);
224                 ns >>= gtod->shift;
225         } while (unlikely(gtod_read_retry(gtod, seq)));
226
227         ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
228         ts->tv_nsec = ns;
229
230         return mode;
231 }
232
233 notrace static int __always_inline do_monotonic(struct timespec *ts)
234 {
235         unsigned long seq;
236         u64 ns;
237         int mode;
238
239         do {
240                 seq = gtod_read_begin(gtod);
241                 mode = gtod->vclock_mode;
242                 ts->tv_sec = gtod->monotonic_time_sec;
243                 ns = gtod->monotonic_time_snsec;
244                 ns += vgetsns(&mode);
245                 ns >>= gtod->shift;
246         } while (unlikely(gtod_read_retry(gtod, seq)));
247
248         ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
249         ts->tv_nsec = ns;
250
251         return mode;
252 }
253
254 notrace static void do_realtime_coarse(struct timespec *ts)
255 {
256         unsigned long seq;
257         do {
258                 seq = gtod_read_begin(gtod);
259                 ts->tv_sec = gtod->wall_time_coarse_sec;
260                 ts->tv_nsec = gtod->wall_time_coarse_nsec;
261         } while (unlikely(gtod_read_retry(gtod, seq)));
262 }
263
264 notrace static void do_monotonic_coarse(struct timespec *ts)
265 {
266         unsigned long seq;
267         do {
268                 seq = gtod_read_begin(gtod);
269                 ts->tv_sec = gtod->monotonic_time_coarse_sec;
270                 ts->tv_nsec = gtod->monotonic_time_coarse_nsec;
271         } while (unlikely(gtod_read_retry(gtod, seq)));
272 }
273
274 notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
275 {
276         switch (clock) {
277         case CLOCK_REALTIME:
278                 if (do_realtime(ts) == VCLOCK_NONE)
279                         goto fallback;
280                 break;
281         case CLOCK_MONOTONIC:
282                 if (do_monotonic(ts) == VCLOCK_NONE)
283                         goto fallback;
284                 break;
285         case CLOCK_REALTIME_COARSE:
286                 do_realtime_coarse(ts);
287                 break;
288         case CLOCK_MONOTONIC_COARSE:
289                 do_monotonic_coarse(ts);
290                 break;
291         default:
292                 goto fallback;
293         }
294
295         return 0;
296 fallback:
297         return vdso_fallback_gettime(clock, ts);
298 }
299 int clock_gettime(clockid_t, struct timespec *)
300         __attribute__((weak, alias("__vdso_clock_gettime")));
301
302 notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
303 {
304         if (likely(tv != NULL)) {
305                 if (unlikely(do_realtime((struct timespec *)tv) == VCLOCK_NONE))
306                         return vdso_fallback_gtod(tv, tz);
307                 tv->tv_usec /= 1000;
308         }
309         if (unlikely(tz != NULL)) {
310                 tz->tz_minuteswest = gtod->tz_minuteswest;
311                 tz->tz_dsttime = gtod->tz_dsttime;
312         }
313
314         return 0;
315 }
316 int gettimeofday(struct timeval *, struct timezone *)
317         __attribute__((weak, alias("__vdso_gettimeofday")));
318
319 /*
320  * This will break when the xtime seconds get inaccurate, but that is
321  * unlikely
322  */
323 notrace time_t __vdso_time(time_t *t)
324 {
325         /* This is atomic on x86 so we don't need any locks. */
326         time_t result = ACCESS_ONCE(gtod->wall_time_sec);
327
328         if (t)
329                 *t = result;
330         return result;
331 }
332 int time(time_t *t)
333         __attribute__((weak, alias("__vdso_time")));