1 /* Copyright 2002,2003 Andi Kleen, SuSE Labs */
3 /* vsyscall handling for 32bit processes. Map a stub page into it
4 on demand because 32bit cannot reach the kernel's fixmaps */
7 #include <linux/string.h>
8 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/stringify.h>
12 #include <asm/proto.h>
13 #include <asm/tlbflush.h>
14 #include <asm/ia32_unistd.h>
16 /* 32bit VDSOs mapped into user space. */
17 asm(".section \".init.data\",\"aw\"\n"
18 "syscall32_syscall:\n"
19 ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n"
20 "syscall32_syscall_end:\n"
21 "syscall32_sysenter:\n"
22 ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n"
23 "syscall32_sysenter_end:\n"
26 extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
27 extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
28 extern int sysctl_vsyscall32;
31 static int use_sysenter __initdata = -1;
33 /* RED-PEN: This knows too much about high level VM */
34 /* Alternative would be to generate a vma with appropriate backing options
35 and let it be handled by generic VM */
36 int map_syscall32(struct mm_struct *mm, unsigned long address)
42 down_read(&mm->mmap_sem);
43 spin_lock(&mm->page_table_lock);
44 pmd = pmd_alloc(mm, pgd_offset(mm, address), address);
45 if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) {
48 mk_pte(virt_to_page(syscall32_page),
49 PAGE_KERNEL_VSYSCALL));
51 /* Flush only the local CPU. Other CPUs taking a fault
52 will just end up here again */
53 __flush_tlb_one(address);
56 spin_unlock(&mm->page_table_lock);
57 up_read(&mm->mmap_sem);
61 static int __init init_syscall32(void)
63 syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
65 panic("Cannot allocate syscall32 page");
66 SetPageReserved(virt_to_page(syscall32_page));
67 if (use_sysenter > 0) {
68 memcpy(syscall32_page, syscall32_sysenter,
69 syscall32_sysenter_end - syscall32_sysenter);
71 memcpy(syscall32_page, syscall32_syscall,
72 syscall32_syscall_end - syscall32_syscall);
77 __initcall(init_syscall32);
79 void __init syscall32_cpu_init(void)
82 use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
84 /* Load these always in case some future AMD CPU supports
85 SYSENTER from compat mode too. */
86 checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
87 checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL);
88 checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
90 wrmsrl(MSR_CSTAR, ia32_cstar_target);