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;
34 * Map the 32bit vsyscall page on demand.
36 * RED-PEN: This knows too much about high level VM.
38 * Alternative would be to generate a vma with appropriate backing options
39 * and let it be handled by generic VM.
41 int __map_syscall32(struct mm_struct
*mm
, unsigned long address
)
47 spin_lock(&mm
->page_table_lock
);
48 pmd
= pmd_alloc(mm
, pgd_offset(mm
, address
), address
);
49 if (pmd
&& (pte
= pte_alloc_map(mm
, pmd
, address
)) != NULL
) {
52 mk_pte(virt_to_page(syscall32_page
),
53 PAGE_KERNEL_VSYSCALL
));
55 /* Flush only the local CPU. Other CPUs taking a fault
56 will just end up here again */
57 __flush_tlb_one(address
);
60 spin_unlock(&mm
->page_table_lock
);
64 int map_syscall32(struct mm_struct
*mm
, unsigned long address
)
67 down_read(&mm
->mmap_sem
);
68 err
= __map_syscall32(mm
, address
);
69 up_read(&mm
->mmap_sem
);
73 static int __init
init_syscall32(void)
75 syscall32_page
= (void *)get_zeroed_page(GFP_KERNEL
);
77 panic("Cannot allocate syscall32 page");
78 SetPageReserved(virt_to_page(syscall32_page
));
79 if (use_sysenter
> 0) {
80 memcpy(syscall32_page
, syscall32_sysenter
,
81 syscall32_sysenter_end
- syscall32_sysenter
);
83 memcpy(syscall32_page
, syscall32_syscall
,
84 syscall32_syscall_end
- syscall32_syscall
);
89 __initcall(init_syscall32
);
91 /* May not be __init: called during resume */
92 void syscall32_cpu_init(void)
95 use_sysenter
= (boot_cpu_data
.x86_vendor
== X86_VENDOR_INTEL
);
97 /* Load these always in case some future AMD CPU supports
98 SYSENTER from compat mode too. */
99 checking_wrmsrl(MSR_IA32_SYSENTER_CS
, (u64
)__KERNEL_CS
);
100 checking_wrmsrl(MSR_IA32_SYSENTER_ESP
, 0ULL);
101 checking_wrmsrl(MSR_IA32_SYSENTER_EIP
, (u64
)ia32_sysenter_target
);
103 wrmsrl(MSR_CSTAR
, ia32_cstar_target
);