tracing: profile likely and unlikely annotations
[linux-2.6.git] / arch / x86 / kernel / vsyscall_64.c
1 /*
2  *  Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
3  *  Copyright 2003 Andi Kleen, SuSE Labs.
4  *
5  *  Thanks to hpa@transmeta.com for some useful hint.
6  *  Special thanks to Ingo Molnar for his early experience with
7  *  a different vsyscall implementation for Linux/IA32 and for the name.
8  *
9  *  vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
10  *  at virtual address -10Mbyte+1024bytes etc... There are at max 4
11  *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
12  *  jumping out of line if necessary. We cannot add more with this
13  *  mechanism because older kernels won't return -ENOSYS.
14  *  If we want more than four we need a vDSO.
15  *
16  *  Note: the concept clashes with user mode linux. If you use UML and
17  *  want per guest time just set the kernel.vsyscall64 sysctl to 0.
18  */
19
20 /* Protect userspace from profiling */
21 #ifdef CONFIG_TRACE_UNLIKELY_PROFILE
22 # undef likely
23 # undef unlikely
24 # define likely(x)              likely_notrace(x)
25 # define unlikely(x)            unlikely_notrace(x)
26 #endif
27
28 #include <linux/time.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/timer.h>
32 #include <linux/seqlock.h>
33 #include <linux/jiffies.h>
34 #include <linux/sysctl.h>
35 #include <linux/clocksource.h>
36 #include <linux/getcpu.h>
37 #include <linux/cpu.h>
38 #include <linux/smp.h>
39 #include <linux/notifier.h>
40
41 #include <asm/vsyscall.h>
42 #include <asm/pgtable.h>
43 #include <asm/page.h>
44 #include <asm/unistd.h>
45 #include <asm/fixmap.h>
46 #include <asm/errno.h>
47 #include <asm/io.h>
48 #include <asm/segment.h>
49 #include <asm/desc.h>
50 #include <asm/topology.h>
51 #include <asm/vgtod.h>
52
53 #define __vsyscall(nr) \
54                 __attribute__ ((unused, __section__(".vsyscall_" #nr))) notrace
55 #define __syscall_clobber "r11","cx","memory"
56
57 /*
58  * vsyscall_gtod_data contains data that is :
59  * - readonly from vsyscalls
60  * - written by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
61  * Try to keep this structure as small as possible to avoid cache line ping pongs
62  */
63 int __vgetcpu_mode __section_vgetcpu_mode;
64
65 struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
66 {
67         .lock = SEQLOCK_UNLOCKED,
68         .sysctl_enabled = 1,
69 };
70
71 void update_vsyscall_tz(void)
72 {
73         unsigned long flags;
74
75         write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
76         /* sys_tz has changed */
77         vsyscall_gtod_data.sys_tz = sys_tz;
78         write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
79 }
80
81 void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
82 {
83         unsigned long flags;
84
85         write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
86         /* copy vsyscall data */
87         vsyscall_gtod_data.clock.vread = clock->vread;
88         vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
89         vsyscall_gtod_data.clock.mask = clock->mask;
90         vsyscall_gtod_data.clock.mult = clock->mult;
91         vsyscall_gtod_data.clock.shift = clock->shift;
92         vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
93         vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
94         vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
95         write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
96 }
97
98 /* RED-PEN may want to readd seq locking, but then the variable should be
99  * write-once.
100  */
101 static __always_inline void do_get_tz(struct timezone * tz)
102 {
103         *tz = __vsyscall_gtod_data.sys_tz;
104 }
105
106 static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
107 {
108         int ret;
109         asm volatile("syscall"
110                 : "=a" (ret)
111                 : "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
112                 : __syscall_clobber );
113         return ret;
114 }
115
116 static __always_inline long time_syscall(long *t)
117 {
118         long secs;
119         asm volatile("syscall"
120                 : "=a" (secs)
121                 : "0" (__NR_time),"D" (t) : __syscall_clobber);
122         return secs;
123 }
124
125 static __always_inline void do_vgettimeofday(struct timeval * tv)
126 {
127         cycle_t now, base, mask, cycle_delta;
128         unsigned seq;
129         unsigned long mult, shift, nsec;
130         cycle_t (*vread)(void);
131         do {
132                 seq = read_seqbegin(&__vsyscall_gtod_data.lock);
133
134                 vread = __vsyscall_gtod_data.clock.vread;
135                 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) {
136                         gettimeofday(tv,NULL);
137                         return;
138                 }
139                 now = vread();
140                 base = __vsyscall_gtod_data.clock.cycle_last;
141                 mask = __vsyscall_gtod_data.clock.mask;
142                 mult = __vsyscall_gtod_data.clock.mult;
143                 shift = __vsyscall_gtod_data.clock.shift;
144
145                 tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
146                 nsec = __vsyscall_gtod_data.wall_time_nsec;
147         } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
148
149         /* calculate interval: */
150         cycle_delta = (now - base) & mask;
151         /* convert to nsecs: */
152         nsec += (cycle_delta * mult) >> shift;
153
154         while (nsec >= NSEC_PER_SEC) {
155                 tv->tv_sec += 1;
156                 nsec -= NSEC_PER_SEC;
157         }
158         tv->tv_usec = nsec / NSEC_PER_USEC;
159 }
160
161 int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
162 {
163         if (tv)
164                 do_vgettimeofday(tv);
165         if (tz)
166                 do_get_tz(tz);
167         return 0;
168 }
169
170 /* This will break when the xtime seconds get inaccurate, but that is
171  * unlikely */
172 time_t __vsyscall(1) vtime(time_t *t)
173 {
174         struct timeval tv;
175         time_t result;
176         if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
177                 return time_syscall(t);
178
179         vgettimeofday(&tv, NULL);
180         result = tv.tv_sec;
181         if (t)
182                 *t = result;
183         return result;
184 }
185
186 /* Fast way to get current CPU and node.
187    This helps to do per node and per CPU caches in user space.
188    The result is not guaranteed without CPU affinity, but usually
189    works out because the scheduler tries to keep a thread on the same
190    CPU.
191
192    tcache must point to a two element sized long array.
193    All arguments can be NULL. */
194 long __vsyscall(2)
195 vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
196 {
197         unsigned int p;
198         unsigned long j = 0;
199
200         /* Fast cache - only recompute value once per jiffies and avoid
201            relatively costly rdtscp/cpuid otherwise.
202            This works because the scheduler usually keeps the process
203            on the same CPU and this syscall doesn't guarantee its
204            results anyways.
205            We do this here because otherwise user space would do it on
206            its own in a likely inferior way (no access to jiffies).
207            If you don't like it pass NULL. */
208         if (tcache && tcache->blob[0] == (j = __jiffies)) {
209                 p = tcache->blob[1];
210         } else if (__vgetcpu_mode == VGETCPU_RDTSCP) {
211                 /* Load per CPU data from RDTSCP */
212                 native_read_tscp(&p);
213         } else {
214                 /* Load per CPU data from GDT */
215                 asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
216         }
217         if (tcache) {
218                 tcache->blob[0] = j;
219                 tcache->blob[1] = p;
220         }
221         if (cpu)
222                 *cpu = p & 0xfff;
223         if (node)
224                 *node = p >> 12;
225         return 0;
226 }
227
228 static long __vsyscall(3) venosys_1(void)
229 {
230         return -ENOSYS;
231 }
232
233 #ifdef CONFIG_SYSCTL
234
235 static int
236 vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
237                        void __user *buffer, size_t *lenp, loff_t *ppos)
238 {
239         return proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
240 }
241
242 static ctl_table kernel_table2[] = {
243         { .procname = "vsyscall64",
244           .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int),
245           .mode = 0644,
246           .proc_handler = vsyscall_sysctl_change },
247         {}
248 };
249
250 static ctl_table kernel_root_table2[] = {
251         { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555,
252           .child = kernel_table2 },
253         {}
254 };
255 #endif
256
257 /* Assume __initcall executes before all user space. Hopefully kmod
258    doesn't violate that. We'll find out if it does. */
259 static void __cpuinit vsyscall_set_cpu(int cpu)
260 {
261         unsigned long d;
262         unsigned long node = 0;
263 #ifdef CONFIG_NUMA
264         node = cpu_to_node(cpu);
265 #endif
266         if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP))
267                 write_rdtscp_aux((node << 12) | cpu);
268
269         /* Store cpu number in limit so that it can be loaded quickly
270            in user space in vgetcpu.
271            12 bits for the CPU and 8 bits for the node. */
272         d = 0x0f40000000000ULL;
273         d |= cpu;
274         d |= (node & 0xf) << 12;
275         d |= (node >> 4) << 48;
276         write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
277 }
278
279 static void __cpuinit cpu_vsyscall_init(void *arg)
280 {
281         /* preemption should be already off */
282         vsyscall_set_cpu(raw_smp_processor_id());
283 }
284
285 static int __cpuinit
286 cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
287 {
288         long cpu = (long)arg;
289         if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
290                 smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 1);
291         return NOTIFY_DONE;
292 }
293
294 void __init map_vsyscall(void)
295 {
296         extern char __vsyscall_0;
297         unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
298
299         /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */
300         __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
301 }
302
303 static int __init vsyscall_init(void)
304 {
305         BUG_ON(((unsigned long) &vgettimeofday !=
306                         VSYSCALL_ADDR(__NR_vgettimeofday)));
307         BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime));
308         BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)));
309         BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu));
310 #ifdef CONFIG_SYSCTL
311         register_sysctl_table(kernel_root_table2);
312 #endif
313         on_each_cpu(cpu_vsyscall_init, NULL, 1);
314         hotcpu_notifier(cpu_vsyscall_notifier, 0);
315         return 0;
316 }
317
318 __initcall(vsyscall_init);