upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / arch / i386 / kernel / sysenter.c
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 #include <linux/mman.h>
17
18 #include <asm/cpufeature.h>
19 #include <asm/msr.h>
20 #include <asm/pgtable.h>
21 #include <asm/unistd.h>
22
23 extern asmlinkage void sysenter_entry(void);
24
25 void enable_sep_cpu(void *info)
26 {
27         int cpu = get_cpu();
28         struct tss_struct *tss = &per_cpu(init_tss, cpu);
29
30         tss->ss1 = __KERNEL_CS;
31         tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
32         wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
33         wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
34         wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
35         put_cpu();      
36 }
37
38 /*
39  * These symbols are defined by vsyscall.o to mark the bounds
40  * of the ELF DSO images included therein.
41  */
42 extern const char vsyscall_int80_start, vsyscall_int80_end;
43 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
44
45 struct page *sysenter_page;
46
47 static int __init sysenter_setup(void)
48 {
49         void *page = (void *)get_zeroed_page(GFP_ATOMIC);
50
51         sysenter_page = virt_to_page(page);
52
53         if (1 || (!boot_cpu_has(X86_FEATURE_SEP))) {
54                 memcpy(page,
55                        &vsyscall_int80_start,
56                        &vsyscall_int80_end - &vsyscall_int80_start);
57                 return 0;
58         }
59
60         memcpy(page,
61                &vsyscall_sysenter_start,
62                &vsyscall_sysenter_end - &vsyscall_sysenter_start);
63
64         on_each_cpu(enable_sep_cpu, NULL, 1, 1);
65         return 0;
66 }
67
68 __initcall(sysenter_setup);
69
70 extern void SYSENTER_RETURN_OFFSET;
71
72 unsigned int vdso_enabled = 1;
73
74 /*
75  * This is called from binfmt_elf, we create the special vma for the
76  * vDSO and insert it into the mm struct tree.
77  */
78 int arch_setup_additional_pages(struct linux_binprm *bprm,
79                                 int executable_stack)
80 {
81         struct thread_info *ti = current_thread_info();
82         unsigned long addr, len;
83         int err;
84
85         current->mm->context.vdso = NULL;
86         if (unlikely(!vdso_enabled) || unlikely(!sysenter_page))
87                 return 0;
88
89         /*
90          * Map the vDSO (it will be randomized):
91          */
92         down_write(&current->mm->mmap_sem);
93         len = PAGE_SIZE > ELF_EXEC_PAGESIZE ? PAGE_SIZE : ELF_EXEC_PAGESIZE;
94         addr = get_unmapped_area_prot(NULL, 0, len, 0,
95                                       MAP_PRIVATE, PROT_READ | PROT_EXEC);
96         if (unlikely(addr & ~PAGE_MASK)) {
97                 up_write(&current->mm->mmap_sem);
98                 return addr;
99         }
100         get_page(sysenter_page);
101         err = install_special_mapping(current->mm, addr, len,
102                                       VM_DONTEXPAND | VM_READ | VM_EXEC |
103                                       VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
104                                       PAGE_READONLY_EXEC,
105                                       &sysenter_page, 1);
106         if (likely(err == 0)) {
107                 current->mm->context.vdso = (void *)addr;
108                 ti->sysenter_return = &SYSENTER_RETURN_OFFSET + addr;
109         }
110         up_write(&current->mm->mmap_sem);
111         return err;
112 }
113
114 int in_gate_area_no_task(unsigned long addr)
115 {
116         return 0;
117 }
118
119 int in_gate_area(struct task_struct *task, unsigned long addr)
120 {
121         return 0;
122 }
123
124 struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
125 {
126         return NULL;
127 }
128
129 static int __init vdso_setup(char *str)
130 {
131         vdso_enabled = simple_strtoul(str, NULL, 0);
132         return 1;
133 }
134 __setup("vdso=", vdso_setup);
135