1/* 2 * linux/arch/x86_64/kernel/vsyscall.c 3 * 4 * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE 5 * 6 * Thanks to hpa@transmeta.com for some useful hint. 7 * Special thanks to Ingo Molnar for his early experience with 8 * a different vsyscall implementation for Linux/IA32 and for the name. 9 * 10 * vsyscall 1 is located at -10Mbyte, vsyscall 2 is located 11 * at virtual address -10Mbyte+1024bytes etc... There are at max 8192 12 * vsyscalls. One vsyscall can reserve more than 1 slot to avoid 13 * jumping out of line if necessary. 14 * 15 * $Id: vsyscall.c,v 1.1.1.1 2008/10/15 03:26:21 james26_jang Exp $ 16 */ 17 18/* 19 * TODO 2001-03-20: 20 * 21 * 1) make page fault handler detect faults on page1-page-last of the vsyscall 22 * virtual space, and make it increase %rip and write -ENOSYS in %rax (so 23 * we'll be able to upgrade to a new glibc without upgrading kernel after 24 * we add more vsyscalls. 25 * 2) Possibly we need a fixmap table for the vsyscalls too if we want 26 * to avoid SIGSEGV and we want to return -EFAULT from the vsyscalls as well. 27 * Can we segfault inside a "syscall"? We can fix this anytime and those fixes 28 * won't be visible for userspace. Not fixing this is a noop for correct programs, 29 * broken programs will segfault and there's no security risk until we choose to 30 * fix it. 31 * 32 * These are not urgent things that we need to address only before shipping the first 33 * production binary kernels. 34 */ 35 36#include <linux/time.h> 37#include <linux/init.h> 38#include <linux/kernel.h> 39#include <linux/mm.h> 40 41#include <asm/vsyscall.h> 42#include <asm/pgtable.h> 43#include <asm/page.h> 44#include <asm/fixmap.h> 45#include <asm/errno.h> 46#include <asm/io.h> 47#include <asm/msr.h> 48 49#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) 50 51long __vxtime_sequence[2] __section_vxtime_sequence; 52 53#undef USE_VSYSCALL 54 55#ifdef USE_VSYSCALL 56 57static inline void do_vgettimeofday(struct timeval * tv) 58{ 59 long sequence, t; 60 unsigned long sec, usec; 61 62 do { 63 sequence = __vxtime_sequence[1]; 64 rmb(); 65 66 rdtscll(t); 67 sec = __xtime.tv_sec; 68 usec = __xtime.tv_usec + 69 (__jiffies - __wall_jiffies) * (1000000 / HZ) + 70 (t - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset; 71 72 rmb(); 73 } while (sequence != __vxtime_sequence[0]); 74 75 tv->tv_sec = sec + usec / 1000000; 76 tv->tv_usec = usec % 1000000; 77} 78 79static inline void do_get_tz(struct timezone * tz) 80{ 81 long sequence; 82 83 do { 84 sequence = __vxtime_sequence[1]; 85 rmb(); 86 87 *tz = __sys_tz; 88 89 rmb(); 90 } while (sequence != __vxtime_sequence[0]); 91} 92 93static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) 94{ 95 if (tv) do_vgettimeofday(tv); 96 if (tz) do_get_tz(tz); 97 return 0; 98} 99 100#else 101 102#include <asm/unistd.h> 103 104static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) 105{ 106 int r; 107 asm volatile("syscall" 108 : "=a" (r) 109 : "0" (__NR_gettimeofday), "D" (tv), "S" (tz) 110 : "r11", "rcx","memory"); 111 return r; 112} 113 114#endif 115 116static time_t __vsyscall(1) vtime(time_t * tp) 117{ 118 struct timeval tv; 119 vgettimeofday(&tv, NULL); 120 if (tp) *tp = tv.tv_sec; 121 return tv.tv_sec; 122} 123 124static long __vsyscall(2) venosys_0(void) 125{ 126 return -ENOSYS; 127} 128 129static long __vsyscall(3) venosys_1(void) 130{ 131 return -ENOSYS; 132} 133 134static void __init map_vsyscall(void) 135{ 136 extern char __vsyscall_0; 137 unsigned long physaddr_page0 = (unsigned long) &__vsyscall_0 - __START_KERNEL_map; 138 139 __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); 140 if (hpet.address) 141 __set_fixmap(VSYSCALL_HPET, hpet.address, PAGE_KERNEL_VSYSCALL); 142} 143 144static int __init vsyscall_init(void) 145{ 146 printk("VSYSCALL: consistency checks..."); 147 if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday)) 148 panic("vgettimeofday link addr broken"); 149 if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)) 150 panic("vtime link addr broken"); 151 if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE)) 152 panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE), 153 VSYSCALL_ADDR(0)); 154 printk("passed...mapping..."); 155 map_vsyscall(); 156 printk("done.\n"); 157 158 return 0; 159} 160 161__initcall(vsyscall_init); 162