diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-29 21:12:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-29 21:12:23 -0400 |
commit | a591afc01d9e48affbacb365558a31e53c85af45 (patch) | |
tree | 9bb91f4eb94ec69fc4706c4944788ec5f3586063 /arch/x86/vdso/vma.c | |
parent | 820d41cf0cd0e94a5661e093821e2e5c6b36a9d8 (diff) | |
parent | 31796ac4e8f0e88f5c10f1ad6dab8f19bebe44a4 (diff) |
Merge branch 'x86-x32-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x32 support for x86-64 from Ingo Molnar:
"This tree introduces the X32 binary format and execution mode for x86:
32-bit data space binaries using 64-bit instructions and 64-bit kernel
syscalls.
This allows applications whose working set fits into a 32 bits address
space to make use of 64-bit instructions while using a 32-bit address
space with shorter pointers, more compressed data structures, etc."
Fix up trivial context conflicts in arch/x86/{Kconfig,vdso/vma.c}
* 'x86-x32-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (71 commits)
x32: Fix alignment fail in struct compat_siginfo
x32: Fix stupid ia32/x32 inversion in the siginfo format
x32: Add ptrace for x32
x32: Switch to a 64-bit clock_t
x32: Provide separate is_ia32_task() and is_x32_task() predicates
x86, mtrr: Use explicit sizing and padding for the 64-bit ioctls
x86/x32: Fix the binutils auto-detect
x32: Warn and disable rather than error if binutils too old
x32: Only clear TIF_X32 flag once
x32: Make sure TS_COMPAT is cleared for x32 tasks
fs: Remove missed ->fds_bits from cessation use of fd_set structs internally
fs: Fix close_on_exec pointer in alloc_fdtable
x32: Drop non-__vdso weak symbols from the x32 VDSO
x32: Fix coding style violations in the x32 VDSO code
x32: Add x32 VDSO support
x32: Allow x32 to be configured
x32: If configured, add x32 system calls to system call tables
x32: Handle process creation
x32: Signal-related system calls
x86: Add #ifdef CONFIG_COMPAT to <asm/sys_ia32.h>
...
Diffstat (limited to 'arch/x86/vdso/vma.c')
-rw-r--r-- | arch/x86/vdso/vma.c | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 17e18279649f..00aaf047b39f 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c | |||
@@ -24,7 +24,44 @@ extern unsigned short vdso_sync_cpuid; | |||
24 | extern struct page *vdso_pages[]; | 24 | extern struct page *vdso_pages[]; |
25 | static unsigned vdso_size; | 25 | static unsigned vdso_size; |
26 | 26 | ||
27 | static void __init patch_vdso(void *vdso, size_t len) | 27 | #ifdef CONFIG_X86_X32_ABI |
28 | extern char vdsox32_start[], vdsox32_end[]; | ||
29 | extern struct page *vdsox32_pages[]; | ||
30 | static unsigned vdsox32_size; | ||
31 | |||
32 | static void __init patch_vdsox32(void *vdso, size_t len) | ||
33 | { | ||
34 | Elf32_Ehdr *hdr = vdso; | ||
35 | Elf32_Shdr *sechdrs, *alt_sec = 0; | ||
36 | char *secstrings; | ||
37 | void *alt_data; | ||
38 | int i; | ||
39 | |||
40 | BUG_ON(len < sizeof(Elf32_Ehdr)); | ||
41 | BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); | ||
42 | |||
43 | sechdrs = (void *)hdr + hdr->e_shoff; | ||
44 | secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
45 | |||
46 | for (i = 1; i < hdr->e_shnum; i++) { | ||
47 | Elf32_Shdr *shdr = &sechdrs[i]; | ||
48 | if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) { | ||
49 | alt_sec = shdr; | ||
50 | goto found; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /* If we get here, it's probably a bug. */ | ||
55 | pr_warning("patch_vdsox32: .altinstructions not found\n"); | ||
56 | return; /* nothing to patch */ | ||
57 | |||
58 | found: | ||
59 | alt_data = (void *)hdr + alt_sec->sh_offset; | ||
60 | apply_alternatives(alt_data, alt_data + alt_sec->sh_size); | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | static void __init patch_vdso64(void *vdso, size_t len) | ||
28 | { | 65 | { |
29 | Elf64_Ehdr *hdr = vdso; | 66 | Elf64_Ehdr *hdr = vdso; |
30 | Elf64_Shdr *sechdrs, *alt_sec = 0; | 67 | Elf64_Shdr *sechdrs, *alt_sec = 0; |
@@ -47,7 +84,7 @@ static void __init patch_vdso(void *vdso, size_t len) | |||
47 | } | 84 | } |
48 | 85 | ||
49 | /* If we get here, it's probably a bug. */ | 86 | /* If we get here, it's probably a bug. */ |
50 | pr_warning("patch_vdso: .altinstructions not found\n"); | 87 | pr_warning("patch_vdso64: .altinstructions not found\n"); |
51 | return; /* nothing to patch */ | 88 | return; /* nothing to patch */ |
52 | 89 | ||
53 | found: | 90 | found: |
@@ -60,12 +97,20 @@ static int __init init_vdso(void) | |||
60 | int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; | 97 | int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; |
61 | int i; | 98 | int i; |
62 | 99 | ||
63 | patch_vdso(vdso_start, vdso_end - vdso_start); | 100 | patch_vdso64(vdso_start, vdso_end - vdso_start); |
64 | 101 | ||
65 | vdso_size = npages << PAGE_SHIFT; | 102 | vdso_size = npages << PAGE_SHIFT; |
66 | for (i = 0; i < npages; i++) | 103 | for (i = 0; i < npages; i++) |
67 | vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE); | 104 | vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE); |
68 | 105 | ||
106 | #ifdef CONFIG_X86_X32_ABI | ||
107 | patch_vdsox32(vdsox32_start, vdsox32_end - vdsox32_start); | ||
108 | npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE; | ||
109 | vdsox32_size = npages << PAGE_SHIFT; | ||
110 | for (i = 0; i < npages; i++) | ||
111 | vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE); | ||
112 | #endif | ||
113 | |||
69 | return 0; | 114 | return 0; |
70 | } | 115 | } |
71 | subsys_initcall(init_vdso); | 116 | subsys_initcall(init_vdso); |
@@ -103,7 +148,10 @@ static unsigned long vdso_addr(unsigned long start, unsigned len) | |||
103 | 148 | ||
104 | /* Setup a VMA at program startup for the vsyscall page. | 149 | /* Setup a VMA at program startup for the vsyscall page. |
105 | Not called for compat tasks */ | 150 | Not called for compat tasks */ |
106 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | 151 | static int setup_additional_pages(struct linux_binprm *bprm, |
152 | int uses_interp, | ||
153 | struct page **pages, | ||
154 | unsigned size) | ||
107 | { | 155 | { |
108 | struct mm_struct *mm = current->mm; | 156 | struct mm_struct *mm = current->mm; |
109 | unsigned long addr; | 157 | unsigned long addr; |
@@ -113,8 +161,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | |||
113 | return 0; | 161 | return 0; |
114 | 162 | ||
115 | down_write(&mm->mmap_sem); | 163 | down_write(&mm->mmap_sem); |
116 | addr = vdso_addr(mm->start_stack, vdso_size); | 164 | addr = vdso_addr(mm->start_stack, size); |
117 | addr = get_unmapped_area(NULL, addr, vdso_size, 0, 0); | 165 | addr = get_unmapped_area(NULL, addr, size, 0, 0); |
118 | if (IS_ERR_VALUE(addr)) { | 166 | if (IS_ERR_VALUE(addr)) { |
119 | ret = addr; | 167 | ret = addr; |
120 | goto up_fail; | 168 | goto up_fail; |
@@ -122,10 +170,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | |||
122 | 170 | ||
123 | current->mm->context.vdso = (void *)addr; | 171 | current->mm->context.vdso = (void *)addr; |
124 | 172 | ||
125 | ret = install_special_mapping(mm, addr, vdso_size, | 173 | ret = install_special_mapping(mm, addr, size, |
126 | VM_READ|VM_EXEC| | 174 | VM_READ|VM_EXEC| |
127 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, | 175 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, |
128 | vdso_pages); | 176 | pages); |
129 | if (ret) { | 177 | if (ret) { |
130 | current->mm->context.vdso = NULL; | 178 | current->mm->context.vdso = NULL; |
131 | goto up_fail; | 179 | goto up_fail; |
@@ -136,6 +184,20 @@ up_fail: | |||
136 | return ret; | 184 | return ret; |
137 | } | 185 | } |
138 | 186 | ||
187 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | ||
188 | { | ||
189 | return setup_additional_pages(bprm, uses_interp, vdso_pages, | ||
190 | vdso_size); | ||
191 | } | ||
192 | |||
193 | #ifdef CONFIG_X86_X32_ABI | ||
194 | int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | ||
195 | { | ||
196 | return setup_additional_pages(bprm, uses_interp, vdsox32_pages, | ||
197 | vdsox32_size); | ||
198 | } | ||
199 | #endif | ||
200 | |||
139 | static __init int vdso_setup(char *s) | 201 | static __init int vdso_setup(char *s) |
140 | { | 202 | { |
141 | vdso_enabled = simple_strtoul(s, NULL, 0); | 203 | vdso_enabled = simple_strtoul(s, NULL, 0); |