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