/* * Derived from Linux 2.6.25 linux-2.6.25/arch/x86/kernel/vsyscall.c * Original header: * Copyright (C) 2001 Andrea Arcangeli SuSE * Copyright 2003 Andi Kleen, SuSE Labs. * * Thanks to hpa@transmeta.com for some useful hint. * Special thanks to Ingo Molnar for his early experience with * a different vsyscall implementation for Linux/IA32 and for the name. * * vsyscall 1 is located at -10Mbyte, vsyscall 2 is located * at virtual address -10Mbyte+1024bytes etc... There are at max 4 * vsyscalls. One vsyscall can reserve more than 1 slot to avoid * jumping out of line if necessary. We cannot add more with this * mechanism because older kernels won't return -ENOSYS. * If we want more than four we need a vDSO. * * Note: the concept clashes with user mode linux. If you use UML and * want per guest time just set the kernel.vsyscall64 sysctl to 0. */ #include #include #include #include #include #include #include #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) #define __syscall_clobber "r11","cx","memory" int __vsyscall(0) vgettimeofday(struct timeval *tv, struct timezone *tz) { int ret; asm volatile("syscall" : "=a" (ret) : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber ); return ret; } time_t __vsyscall(1) vtime(time_t *t) { int ret; asm volatile("syscall" : "=a" (ret) : "0" (__NR_time),"D" (t) : __syscall_clobber ); return ret; } void __init vsyscall_map(void) { extern char __vsyscall_0; unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0); /* Setup the virtual syscall fixmap entry */ __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); BUG_ON((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday)); BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); }