Blame view
arch/x86/vdso/vdso32-setup.c
6.44 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 |
* (C) Copyright 2002 Linus Torvalds |
e6e5494cb [PATCH] vdso: ran... |
3 4 |
* Portions based on the vdso-randomization code from exec-shield: * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 8 9 10 11 12 13 14 15 |
* * This file contains the needed initializations to support sysenter. */ #include <linux/init.h> #include <linux/smp.h> #include <linux/thread_info.h> #include <linux/sched.h> #include <linux/gfp.h> #include <linux/string.h> #include <linux/elf.h> |
e6e5494cb [PATCH] vdso: ran... |
16 |
#include <linux/mm.h> |
4e950f6f0 Remove fs.h from ... |
17 |
#include <linux/err.h> |
e6e5494cb [PATCH] vdso: ran... |
18 |
#include <linux/module.h> |
4e40112c4 x86, vdso32: hand... |
19 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
20 21 22 23 24 |
#include <asm/cpufeature.h> #include <asm/msr.h> #include <asm/pgtable.h> #include <asm/unistd.h> |
d4f7a2c18 [PATCH] i386: Rel... |
25 |
#include <asm/elf.h> |
1dbf527c5 [PATCH] i386: Mak... |
26 |
#include <asm/tlbflush.h> |
6c3652efc x86 vDSO: i386 vd... |
27 |
#include <asm/vdso.h> |
af65d6484 x86 vDSO: consoli... |
28 |
#include <asm/proto.h> |
7a59ed415 x86, vdso: Add 32... |
29 30 31 |
#include <asm/fixmap.h> #include <asm/hpet.h> #include <asm/vvar.h> |
1dbf527c5 [PATCH] i386: Mak... |
32 |
|
1dbf527c5 [PATCH] i386: Mak... |
33 |
#ifdef CONFIG_COMPAT_VDSO |
b0b49f267 x86, vdso: Remove... |
34 |
#define VDSO_DEFAULT 0 |
1dbf527c5 [PATCH] i386: Mak... |
35 |
#else |
b0b49f267 x86, vdso: Remove... |
36 |
#define VDSO_DEFAULT 1 |
1dbf527c5 [PATCH] i386: Mak... |
37 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
af65d6484 x86 vDSO: consoli... |
39 40 41 |
#ifdef CONFIG_X86_64 #define vdso_enabled sysctl_vsyscall32 #define arch_setup_additional_pages syscall32_setup_pages |
fa81511bb x86-64, modify_ld... |
42 |
extern int sysctl_ldt16; |
af65d6484 x86 vDSO: consoli... |
43 44 45 |
#endif /* |
e6e5494cb [PATCH] vdso: ran... |
46 47 48 |
* Should the kernel map a VDSO page into processes and pass its * address down to glibc upon exec()? */ |
1dbf527c5 [PATCH] i386: Mak... |
49 |
unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT; |
e6e5494cb [PATCH] vdso: ran... |
50 |
|
e6e5494cb [PATCH] vdso: ran... |
51 52 53 |
static int __init vdso_setup(char *s) { vdso_enabled = simple_strtoul(s, NULL, 0); |
b0b49f267 x86, vdso: Remove... |
54 55 56 |
if (vdso_enabled > 1) pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled "); |
e6e5494cb [PATCH] vdso: ran... |
57 58 |
return 1; } |
af65d6484 x86 vDSO: consoli... |
59 60 61 62 63 64 |
/* * For consistency, the argument vdso32=[012] affects the 32-bit vDSO * behavior on both 64-bit and 32-bit kernels. * On 32-bit kernels, vdso=[012] means the same thing. */ __setup("vdso32=", vdso_setup); |
e6e5494cb [PATCH] vdso: ran... |
65 |
|
af65d6484 x86 vDSO: consoli... |
66 67 68 69 70 |
#ifdef CONFIG_X86_32 __setup_param("vdso=", vdso32_setup, vdso_setup, 0); EXPORT_SYMBOL_GPL(vdso_enabled); #endif |
1da177e4c Linux-2.6.12-rc2 |
71 |
|
4e40112c4 x86, vdso32: hand... |
72 |
static struct page **vdso32_pages; |
b67e612ce x86: Load the 32-... |
73 |
static unsigned vdso32_size; |
af65d6484 x86 vDSO: consoli... |
74 75 |
#ifdef CONFIG_X86_64 |
b6ad92d4f x86_64: vdso32 cl... |
76 |
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) |
6a52e4b1c x86_64: further c... |
77 |
#define vdso32_syscall() (boot_cpu_has(X86_FEATURE_SYSCALL32)) |
af65d6484 x86 vDSO: consoli... |
78 79 80 81 |
/* May not be __init: called during resume */ void syscall32_cpu_init(void) { |
af65d6484 x86 vDSO: consoli... |
82 83 |
/* Load these always in case some future AMD CPU supports SYSENTER from compat mode too. */ |
715c85b1f x86, cpu: Rename ... |
84 85 86 |
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); |
af65d6484 x86 vDSO: consoli... |
87 88 89 |
wrmsrl(MSR_CSTAR, ia32_cstar_target); } |
af65d6484 x86 vDSO: consoli... |
90 91 92 |
#else /* CONFIG_X86_32 */ #define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP)) |
6a52e4b1c x86_64: further c... |
93 |
#define vdso32_syscall() (0) |
af65d6484 x86 vDSO: consoli... |
94 |
|
6fe940d6c [PATCH] sep initi... |
95 |
void enable_sep_cpu(void) |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 |
{ int cpu = get_cpu(); struct tss_struct *tss = &per_cpu(init_tss, cpu); |
6fe940d6c [PATCH] sep initi... |
99 100 101 102 |
if (!boot_cpu_has(X86_FEATURE_SEP)) { put_cpu(); return; } |
a75c54f93 [PATCH] i386: i38... |
103 |
tss->x86_tss.ss1 = __KERNEL_CS; |
faca62273 x86: use generic ... |
104 |
tss->x86_tss.sp1 = sizeof(struct tss_struct) + (unsigned long) tss; |
1da177e4c Linux-2.6.12-rc2 |
105 |
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); |
faca62273 x86: use generic ... |
106 |
wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.sp1, 0); |
0aa97fb22 x86 vDSO: ia32_sy... |
107 |
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) ia32_sysenter_target, 0); |
1da177e4c Linux-2.6.12-rc2 |
108 109 |
put_cpu(); } |
af65d6484 x86 vDSO: consoli... |
110 |
#endif /* CONFIG_X86_64 */ |
a6c4e076e [PATCH] i386: cle... |
111 |
int __init sysenter_setup(void) |
1da177e4c Linux-2.6.12-rc2 |
112 |
{ |
b67e612ce x86: Load the 32-... |
113 114 |
char *vdso32_start, *vdso32_end; int npages, i; |
1da177e4c Linux-2.6.12-rc2 |
115 |
|
b67e612ce x86: Load the 32-... |
116 |
#ifdef CONFIG_COMPAT |
6a52e4b1c x86_64: further c... |
117 |
if (vdso32_syscall()) { |
b67e612ce x86: Load the 32-... |
118 119 120 121 122 123 124 125 126 |
vdso32_start = vdso32_syscall_start; vdso32_end = vdso32_syscall_end; vdso32_pages = vdso32_syscall_pages; } else #endif if (vdso32_sysenter()) { vdso32_start = vdso32_sysenter_start; vdso32_end = vdso32_sysenter_end; vdso32_pages = vdso32_sysenter_pages; |
6a52e4b1c x86_64: further c... |
127 |
} else { |
b67e612ce x86: Load the 32-... |
128 129 130 |
vdso32_start = vdso32_int80_start; vdso32_end = vdso32_int80_end; vdso32_pages = vdso32_int80_pages; |
1da177e4c Linux-2.6.12-rc2 |
131 |
} |
b67e612ce x86: Load the 32-... |
132 133 134 135 |
npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE; vdso32_size = npages << PAGE_SHIFT; for (i = 0; i < npages; i++) vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE); |
4e40112c4 x86, vdso32: hand... |
136 |
|
b67e612ce x86: Load the 32-... |
137 |
patch_vdso32(vdso32_start, vdso32_size); |
1da177e4c Linux-2.6.12-rc2 |
138 |
|
1da177e4c Linux-2.6.12-rc2 |
139 140 |
return 0; } |
e6e5494cb [PATCH] vdso: ran... |
141 |
|
e6e5494cb [PATCH] vdso: ran... |
142 |
/* Setup a VMA at program startup for the vsyscall page */ |
fc5243d98 [S390] arch_setup... |
143 |
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) |
e6e5494cb [PATCH] vdso: ran... |
144 |
{ |
e6e5494cb [PATCH] vdso: ran... |
145 146 |
struct mm_struct *mm = current->mm; unsigned long addr; |
752783c05 [PATCH] i386: In ... |
147 |
int ret = 0; |
7a59ed415 x86, vdso: Add 32... |
148 |
struct vm_area_struct *vma; |
368b69a5b x86, vdso: Fix an... |
149 |
static struct page *no_pages[] = {NULL}; |
e6e5494cb [PATCH] vdso: ran... |
150 |
|
1a21d4e09 x32: Add x32 VDSO... |
151 |
#ifdef CONFIG_X86_X32_ABI |
1a21d4e09 x32: Add x32 VDSO... |
152 |
if (test_thread_flag(TIF_X32)) |
22e842d4d x32: Fix coding s... |
153 |
return x32_setup_additional_pages(bprm, uses_interp); |
1a21d4e09 x32: Add x32 VDSO... |
154 |
#endif |
b0b49f267 x86, vdso: Remove... |
155 |
if (vdso_enabled != 1) /* Other values all mean "disabled" */ |
5de253cc5 x86 vDSO: don't m... |
156 |
return 0; |
e6e5494cb [PATCH] vdso: ran... |
157 |
down_write(&mm->mmap_sem); |
e6e5494cb [PATCH] vdso: ran... |
158 |
|
645a387ec x86, vdso: Fix si... |
159 |
addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0); |
b0b49f267 x86, vdso: Remove... |
160 161 162 |
if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; |
af65d6484 x86 vDSO: consoli... |
163 |
} |
1dbf527c5 [PATCH] i386: Mak... |
164 |
|
645a387ec x86, vdso: Fix si... |
165 |
addr += VDSO_OFFSET(VDSO_PREV_PAGES); |
f7b6eb3fa x86: Set context.... |
166 |
current->mm->context.vdso = (void *)addr; |
b0b49f267 x86, vdso: Remove... |
167 168 169 |
/* * MAYWRITE to allow gdb to COW and set breakpoints */ |
7a59ed415 x86, vdso: Add 32... |
170 171 |
ret = install_special_mapping(mm, addr, |
b67e612ce x86: Load the 32-... |
172 |
vdso32_size, |
7a59ed415 x86, vdso: Add 32... |
173 174 175 |
VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, vdso32_pages); |
b0b49f267 x86, vdso: Remove... |
176 177 178 |
if (ret) goto up_fail; |
e6e5494cb [PATCH] vdso: ran... |
179 |
|
7a59ed415 x86, vdso: Add 32... |
180 181 182 183 |
vma = _install_special_mapping(mm, addr - VDSO_OFFSET(VDSO_PREV_PAGES), VDSO_OFFSET(VDSO_PREV_PAGES), VM_READ, |
368b69a5b x86, vdso: Fix an... |
184 |
no_pages); |
7a59ed415 x86, vdso: Add 32... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto up_fail; } ret = remap_pfn_range(vma, addr - VDSO_OFFSET(VDSO_VVAR_PAGE), __pa_symbol(&__vvar_page) >> PAGE_SHIFT, PAGE_SIZE, PAGE_READONLY); if (ret) goto up_fail; #ifdef CONFIG_HPET_TIMER if (hpet_address) { ret = io_remap_pfn_range(vma, addr - VDSO_OFFSET(VDSO_HPET_PAGE), hpet_address >> PAGE_SHIFT, PAGE_SIZE, pgprot_noncached(PAGE_READONLY)); if (ret) goto up_fail; } #endif |
e6e5494cb [PATCH] vdso: ran... |
212 |
current_thread_info()->sysenter_return = |
6c3652efc x86 vDSO: i386 vd... |
213 |
VDSO32_SYMBOL(addr, SYSENTER_RETURN); |
1dbf527c5 [PATCH] i386: Mak... |
214 215 |
up_fail: |
f7b6eb3fa x86: Set context.... |
216 217 |
if (ret) current->mm->context.vdso = NULL; |
e6e5494cb [PATCH] vdso: ran... |
218 |
up_write(&mm->mmap_sem); |
1dbf527c5 [PATCH] i386: Mak... |
219 |
|
e6e5494cb [PATCH] vdso: ran... |
220 |
return ret; |
e6e5494cb [PATCH] vdso: ran... |
221 |
} |
af65d6484 x86 vDSO: consoli... |
222 |
#ifdef CONFIG_X86_64 |
d7a0380dc x86-64, mm: Initi... |
223 |
subsys_initcall(sysenter_setup); |
af65d6484 x86 vDSO: consoli... |
224 |
|
a97f52e67 x86: compat_binfm... |
225 226 227 |
#ifdef CONFIG_SYSCTL /* Register vsyscall32 into the ABI table */ #include <linux/sysctl.h> |
f07d91ede x86/vdso: Convert... |
228 |
static struct ctl_table abi_table2[] = { |
a97f52e67 x86: compat_binfm... |
229 230 231 232 233 234 235 |
{ .procname = "vsyscall32", .data = &sysctl_vsyscall32, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec }, |
fa81511bb x86-64, modify_ld... |
236 237 238 239 240 241 242 |
{ .procname = "ldt16", .data = &sysctl_ldt16, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec }, |
a97f52e67 x86: compat_binfm... |
243 244 |
{} }; |
f07d91ede x86/vdso: Convert... |
245 |
static struct ctl_table abi_root_table2[] = { |
a97f52e67 x86: compat_binfm... |
246 |
{ |
a97f52e67 x86: compat_binfm... |
247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
.procname = "abi", .mode = 0555, .child = abi_table2 }, {} }; static __init int ia32_binfmt_init(void) { register_sysctl_table(abi_root_table2); return 0; } __initcall(ia32_binfmt_init); #endif |
af65d6484 x86 vDSO: consoli... |
261 |
#else /* CONFIG_X86_32 */ |
e6e5494cb [PATCH] vdso: ran... |
262 263 264 265 266 267 |
const char *arch_vma_name(struct vm_area_struct *vma) { if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) return "[vdso]"; return NULL; } |
31db58b3a mm: arch: make ge... |
268 |
struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
e6e5494cb [PATCH] vdso: ran... |
269 270 271 |
{ return NULL; } |
83b964bbf mm: arch: make in... |
272 |
int in_gate_area(struct mm_struct *mm, unsigned long addr) |
e6e5494cb [PATCH] vdso: ran... |
273 |
{ |
b0b49f267 x86, vdso: Remove... |
274 |
return 0; |
e6e5494cb [PATCH] vdso: ran... |
275 |
} |
cae5d3903 mm: arch: rename ... |
276 |
int in_gate_area_no_mm(unsigned long addr) |
e6e5494cb [PATCH] vdso: ran... |
277 278 279 |
{ return 0; } |
af65d6484 x86 vDSO: consoli... |
280 281 |
#endif /* CONFIG_X86_64 */ |