2 * Copyright 2006 Andi Kleen, SUSE Labs.
3 * Subject to the GNU Public License, v.2
5 * Fast user context implementation of clock_gettime, gettimeofday, and time.
7 * The code should have no internal unresolved relocations.
8 * Check with readelf after changing.
11 /* Disable profiling for userspace code: */
12 #define DISABLE_BRANCH_PROFILING
14 #include <linux/kernel.h>
15 #include <linux/posix-timers.h>
16 #include <linux/time.h>
17 #include <linux/string.h>
18 #include <asm/vsyscall.h>
19 #include <asm/fixmap.h>
20 #include <asm/vgtod.h>
21 #include <asm/timex.h>
23 #include <asm/unistd.h>
26 #define gtod (&VVAR(vsyscall_gtod_data))
29 #define using_vclock likely(gtod->clock.vclock_mode != VCLOCK_NONE)
31 #define using_vclock 0
32 #define VCLOCK_TSC (-1)
35 notrace static cycle_t vread_tsc(void)
41 * Empirically, a fence (of type that depends on the CPU)
42 * before rdtsc is enough to ensure that rdtsc is ordered
43 * with respect to loads. The various CPU manuals are unclear
44 * as to whether rdtsc can be reordered with later loads,
45 * but no one has ever seen it happen.
48 ret = (cycle_t)vget_cycles();
50 last = VVAR(vsyscall_gtod_data).clock.cycle_last;
52 if (likely(ret >= last))
56 * GCC likes to generate cmov here, but this branch is extremely
57 * predictable (it's just a funciton of time and the likely is
58 * very likely) and there's a data dependence, so force GCC
59 * to generate a branch instead. I don't barrier() because
60 * we don't actually need a barrier, and if this function
61 * ever gets inlined it will generate worse code.
67 static notrace cycle_t vread_hpet(void)
69 return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
72 notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
75 asm("syscall" : "=a" (ret) :
76 "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
80 notrace static inline long vgetns(void)
84 if (gtod->clock.vclock_mode == VCLOCK_TSC)
87 cycles = vread_hpet();
88 v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
89 return (v * gtod->clock.mult) >> gtod->clock.shift;
92 notrace static noinline int do_realtime(struct timespec *ts)
94 unsigned long seq, ns;
96 seq = read_seqbegin(>od->lock);
97 ts->tv_sec = gtod->wall_time_sec;
98 ts->tv_nsec = gtod->wall_time_nsec;
100 } while (unlikely(read_seqretry(>od->lock, seq)));
101 timespec_add_ns(ts, ns);
105 notrace static noinline int do_monotonic(struct timespec *ts)
107 unsigned long seq, ns, secs;
109 seq = read_seqbegin(>od->lock);
110 secs = gtod->wall_time_sec;
111 ns = gtod->wall_time_nsec + vgetns();
112 secs += gtod->wall_to_monotonic.tv_sec;
113 ns += gtod->wall_to_monotonic.tv_nsec;
114 } while (unlikely(read_seqretry(>od->lock, seq)));
116 /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
117 * are all guaranteed to be nonnegative.
119 while (ns >= NSEC_PER_SEC) {
129 notrace static noinline int do_realtime_coarse(struct timespec *ts)
133 seq = read_seqbegin(>od->lock);
134 ts->tv_sec = gtod->wall_time_coarse.tv_sec;
135 ts->tv_nsec = gtod->wall_time_coarse.tv_nsec;
136 } while (unlikely(read_seqretry(>od->lock, seq)));
140 notrace static noinline int do_monotonic_coarse(struct timespec *ts)
142 unsigned long seq, ns, secs;
144 seq = read_seqbegin(>od->lock);
145 secs = gtod->wall_time_coarse.tv_sec;
146 ns = gtod->wall_time_coarse.tv_nsec;
147 secs += gtod->wall_to_monotonic.tv_sec;
148 ns += gtod->wall_to_monotonic.tv_nsec;
149 } while (unlikely(read_seqretry(>od->lock, seq)));
151 /* wall_time_nsec and wall_to_monotonic.tv_nsec are
152 * guaranteed to be between 0 and NSEC_PER_SEC.
154 if (ns >= NSEC_PER_SEC) {
164 notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
169 return do_realtime(ts);
171 case CLOCK_MONOTONIC:
173 return do_monotonic(ts);
175 case CLOCK_REALTIME_COARSE:
176 return do_realtime_coarse(ts);
177 case CLOCK_MONOTONIC_COARSE:
178 return do_monotonic_coarse(ts);
181 return vdso_fallback_gettime(clock, ts);
183 int clock_gettime(clockid_t, struct timespec *)
184 __attribute__((weak, alias("__vdso_clock_gettime")));
186 notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
190 if (likely(tv != NULL)) {
191 BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
192 offsetof(struct timespec, tv_nsec) ||
193 sizeof(*tv) != sizeof(struct timespec));
194 do_realtime((struct timespec *)tv);
197 if (unlikely(tz != NULL)) {
198 /* Avoid memcpy. Some old compilers fail to inline it */
199 tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
200 tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
204 asm("syscall" : "=a" (ret) :
205 "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
208 int gettimeofday(struct timeval *, struct timezone *)
209 __attribute__((weak, alias("__vdso_gettimeofday")));
212 * This will break when the xtime seconds get inaccurate, but that is
215 notrace time_t __vdso_time(time_t *t)
217 /* This is atomic on x86_64 so we don't need any locks. */
218 time_t result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
225 __attribute__((weak, alias("__vdso_time")));