x86, vdso: Remove compat vdso support
[deliverable/linux.git] / arch / x86 / vdso / vdso32-setup.c
1 /*
2 * (C) Copyright 2002 Linus Torvalds
3 * Portions based on the vdso-randomization code from exec-shield:
4 * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
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/mm.h>
17 #include <linux/err.h>
18 #include <linux/module.h>
19
20 #include <asm/cpufeature.h>
21 #include <asm/msr.h>
22 #include <asm/pgtable.h>
23 #include <asm/unistd.h>
24 #include <asm/elf.h>
25 #include <asm/tlbflush.h>
26 #include <asm/vdso.h>
27 #include <asm/proto.h>
28
29 #ifdef CONFIG_COMPAT_VDSO
30 #define VDSO_DEFAULT 0
31 #else
32 #define VDSO_DEFAULT 1
33 #endif
34
35 #ifdef CONFIG_X86_64
36 #define vdso_enabled sysctl_vsyscall32
37 #define arch_setup_additional_pages syscall32_setup_pages
38 #endif
39
40 /*
41 * Should the kernel map a VDSO page into processes and pass its
42 * address down to glibc upon exec()?
43 */
44 unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT;
45
46 static int __init vdso_setup(char *s)
47 {
48 vdso_enabled = simple_strtoul(s, NULL, 0);
49
50 if (vdso_enabled > 1)
51 pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
52
53 return 1;
54 }
55
56 /*
57 * For consistency, the argument vdso32=[012] affects the 32-bit vDSO
58 * behavior on both 64-bit and 32-bit kernels.
59 * On 32-bit kernels, vdso=[012] means the same thing.
60 */
61 __setup("vdso32=", vdso_setup);
62
63 #ifdef CONFIG_X86_32
64 __setup_param("vdso=", vdso32_setup, vdso_setup, 0);
65
66 EXPORT_SYMBOL_GPL(vdso_enabled);
67 #endif
68
69 static struct page *vdso32_pages[1];
70
71 #ifdef CONFIG_X86_64
72
73 #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32))
74 #define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32))
75
76 /* May not be __init: called during resume */
77 void syscall32_cpu_init(void)
78 {
79 /* Load these always in case some future AMD CPU supports
80 SYSENTER from compat mode too. */
81 wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
82 wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
83 wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
84
85 wrmsrl(MSR_CSTAR, ia32_cstar_target);
86 }
87
88 #else /* CONFIG_X86_32 */
89
90 #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP))
91 #define vdso32_syscall() (0)
92
93 void enable_sep_cpu(void)
94 {
95 int cpu = get_cpu();
96 struct tss_struct *tss = &per_cpu(init_tss, cpu);
97
98 if (!boot_cpu_has(X86_FEATURE_SEP)) {
99 put_cpu();
100 return;
101 }
102
103 tss->x86_tss.ss1 = __KERNEL_CS;
104 tss->x86_tss.sp1 = sizeof(struct tss_struct) + (unsigned long) tss;
105 wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
106 wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0);
107 wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0);
108 put_cpu();
109 }
110
111 #endif /* CONFIG_X86_64 */
112
113 int __init sysenter_setup(void)
114 {
115 void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
116 const void *vsyscall;
117 size_t vsyscall_len;
118
119 vdso32_pages[0] = virt_to_page(syscall_page);
120
121 if (vdso32_syscall()) {
122 vsyscall = &vdso32_syscall_start;
123 vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
124 } else if (vdso32_sysenter()){
125 vsyscall = &vdso32_sysenter_start;
126 vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
127 } else {
128 vsyscall = &vdso32_int80_start;
129 vsyscall_len = &vdso32_int80_end - &vdso32_int80_start;
130 }
131
132 memcpy(syscall_page, vsyscall, vsyscall_len);
133
134 return 0;
135 }
136
137 /* Setup a VMA at program startup for the vsyscall page */
138 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
139 {
140 struct mm_struct *mm = current->mm;
141 unsigned long addr;
142 int ret = 0;
143
144 #ifdef CONFIG_X86_X32_ABI
145 if (test_thread_flag(TIF_X32))
146 return x32_setup_additional_pages(bprm, uses_interp);
147 #endif
148
149 if (vdso_enabled != 1) /* Other values all mean "disabled" */
150 return 0;
151
152 down_write(&mm->mmap_sem);
153
154 addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
155 if (IS_ERR_VALUE(addr)) {
156 ret = addr;
157 goto up_fail;
158 }
159
160 current->mm->context.vdso = (void *)addr;
161
162 /*
163 * MAYWRITE to allow gdb to COW and set breakpoints
164 */
165 ret = install_special_mapping(mm, addr, PAGE_SIZE,
166 VM_READ|VM_EXEC|
167 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
168 vdso32_pages);
169
170 if (ret)
171 goto up_fail;
172
173 current_thread_info()->sysenter_return =
174 VDSO32_SYMBOL(addr, SYSENTER_RETURN);
175
176 up_fail:
177 if (ret)
178 current->mm->context.vdso = NULL;
179
180 up_write(&mm->mmap_sem);
181
182 return ret;
183 }
184
185 #ifdef CONFIG_X86_64
186
187 subsys_initcall(sysenter_setup);
188
189 #ifdef CONFIG_SYSCTL
190 /* Register vsyscall32 into the ABI table */
191 #include <linux/sysctl.h>
192
193 static struct ctl_table abi_table2[] = {
194 {
195 .procname = "vsyscall32",
196 .data = &sysctl_vsyscall32,
197 .maxlen = sizeof(int),
198 .mode = 0644,
199 .proc_handler = proc_dointvec
200 },
201 {}
202 };
203
204 static struct ctl_table abi_root_table2[] = {
205 {
206 .procname = "abi",
207 .mode = 0555,
208 .child = abi_table2
209 },
210 {}
211 };
212
213 static __init int ia32_binfmt_init(void)
214 {
215 register_sysctl_table(abi_root_table2);
216 return 0;
217 }
218 __initcall(ia32_binfmt_init);
219 #endif
220
221 #else /* CONFIG_X86_32 */
222
223 const char *arch_vma_name(struct vm_area_struct *vma)
224 {
225 if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
226 return "[vdso]";
227 return NULL;
228 }
229
230 struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
231 {
232 return NULL;
233 }
234
235 int in_gate_area(struct mm_struct *mm, unsigned long addr)
236 {
237 return 0;
238 }
239
240 int in_gate_area_no_mm(unsigned long addr)
241 {
242 return 0;
243 }
244
245 #endif /* CONFIG_X86_64 */
This page took 0.110746 seconds and 5 git commands to generate.