]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/i386/kernel/sysenter.c | |
3 | * | |
4 | * (C) Copyright 2002 Linus Torvalds | |
5 | * | |
6 | * This file contains the needed initializations to support sysenter. | |
7 | */ | |
8 | ||
9 | #include <linux/init.h> | |
10 | #include <linux/smp.h> | |
11 | #include <linux/thread_info.h> | |
12 | #include <linux/sched.h> | |
13 | #include <linux/gfp.h> | |
14 | #include <linux/string.h> | |
15 | #include <linux/elf.h> | |
16 | ||
17 | #include <asm/cpufeature.h> | |
18 | #include <asm/msr.h> | |
19 | #include <asm/pgtable.h> | |
20 | #include <asm/unistd.h> | |
21 | ||
22 | extern asmlinkage void sysenter_entry(void); | |
23 | ||
24 | void enable_sep_cpu(void *info) | |
25 | { | |
26 | int cpu = get_cpu(); | |
27 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | |
28 | ||
29 | tss->ss1 = __KERNEL_CS; | |
30 | tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; | |
31 | wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); | |
32 | wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0); | |
33 | wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0); | |
34 | put_cpu(); | |
35 | } | |
36 | ||
37 | /* | |
38 | * These symbols are defined by vsyscall.o to mark the bounds | |
39 | * of the ELF DSO images included therein. | |
40 | */ | |
41 | extern const char vsyscall_int80_start, vsyscall_int80_end; | |
42 | extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; | |
43 | ||
44 | static int __init sysenter_setup(void) | |
45 | { | |
46 | void *page = (void *)get_zeroed_page(GFP_ATOMIC); | |
47 | ||
48 | __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC); | |
49 | ||
50 | if (!boot_cpu_has(X86_FEATURE_SEP)) { | |
51 | memcpy(page, | |
52 | &vsyscall_int80_start, | |
53 | &vsyscall_int80_end - &vsyscall_int80_start); | |
54 | return 0; | |
55 | } | |
56 | ||
57 | memcpy(page, | |
58 | &vsyscall_sysenter_start, | |
59 | &vsyscall_sysenter_end - &vsyscall_sysenter_start); | |
60 | ||
61 | on_each_cpu(enable_sep_cpu, NULL, 1, 1); | |
62 | return 0; | |
63 | } | |
64 | ||
65 | __initcall(sysenter_setup); |