diff options
-rw-r--r-- | arch/i386/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/i386/kernel/sysenter.c | 158 | ||||
-rw-r--r-- | arch/i386/mm/pgtable.c | 6 | ||||
-rw-r--r-- | include/asm-i386/elf.h | 28 | ||||
-rw-r--r-- | include/asm-i386/fixmap.h | 8 | ||||
-rw-r--r-- | include/linux/elf.h | 17 |
6 files changed, 178 insertions, 43 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index c61c6b67e856..e901952dff37 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S | |||
@@ -305,16 +305,12 @@ sysenter_past_esp: | |||
305 | pushl $(__USER_CS) | 305 | pushl $(__USER_CS) |
306 | CFI_ADJUST_CFA_OFFSET 4 | 306 | CFI_ADJUST_CFA_OFFSET 4 |
307 | /*CFI_REL_OFFSET cs, 0*/ | 307 | /*CFI_REL_OFFSET cs, 0*/ |
308 | #ifndef CONFIG_COMPAT_VDSO | ||
309 | /* | 308 | /* |
310 | * Push current_thread_info()->sysenter_return to the stack. | 309 | * Push current_thread_info()->sysenter_return to the stack. |
311 | * A tiny bit of offset fixup is necessary - 4*4 means the 4 words | 310 | * A tiny bit of offset fixup is necessary - 4*4 means the 4 words |
312 | * pushed above; +8 corresponds to copy_thread's esp0 setting. | 311 | * pushed above; +8 corresponds to copy_thread's esp0 setting. |
313 | */ | 312 | */ |
314 | pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) | 313 | pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) |
315 | #else | ||
316 | pushl $SYSENTER_RETURN | ||
317 | #endif | ||
318 | CFI_ADJUST_CFA_OFFSET 4 | 314 | CFI_ADJUST_CFA_OFFSET 4 |
319 | CFI_REL_OFFSET eip, 0 | 315 | CFI_REL_OFFSET eip, 0 |
320 | 316 | ||
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c index 13ca54a85a1c..e5a958379ac9 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/msr.h> | 22 | #include <asm/msr.h> |
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/unistd.h> | 24 | #include <asm/unistd.h> |
25 | #include <asm/elf.h> | ||
25 | 26 | ||
26 | /* | 27 | /* |
27 | * Should the kernel map a VDSO page into processes and pass its | 28 | * Should the kernel map a VDSO page into processes and pass its |
@@ -46,6 +47,129 @@ __setup("vdso=", vdso_setup); | |||
46 | 47 | ||
47 | extern asmlinkage void sysenter_entry(void); | 48 | extern asmlinkage void sysenter_entry(void); |
48 | 49 | ||
50 | #ifdef CONFIG_COMPAT_VDSO | ||
51 | static __init void reloc_symtab(Elf32_Ehdr *ehdr, | ||
52 | unsigned offset, unsigned size) | ||
53 | { | ||
54 | Elf32_Sym *sym = (void *)ehdr + offset; | ||
55 | unsigned nsym = size / sizeof(*sym); | ||
56 | unsigned i; | ||
57 | |||
58 | for(i = 0; i < nsym; i++, sym++) { | ||
59 | if (sym->st_shndx == SHN_UNDEF || | ||
60 | sym->st_shndx == SHN_ABS) | ||
61 | continue; /* skip */ | ||
62 | |||
63 | if (sym->st_shndx > SHN_LORESERVE) { | ||
64 | printk(KERN_INFO "VDSO: unexpected st_shndx %x\n", | ||
65 | sym->st_shndx); | ||
66 | continue; | ||
67 | } | ||
68 | |||
69 | switch(ELF_ST_TYPE(sym->st_info)) { | ||
70 | case STT_OBJECT: | ||
71 | case STT_FUNC: | ||
72 | case STT_SECTION: | ||
73 | case STT_FILE: | ||
74 | sym->st_value += VDSO_HIGH_BASE; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset) | ||
80 | { | ||
81 | Elf32_Dyn *dyn = (void *)ehdr + offset; | ||
82 | |||
83 | for(; dyn->d_tag != DT_NULL; dyn++) | ||
84 | switch(dyn->d_tag) { | ||
85 | case DT_PLTGOT: | ||
86 | case DT_HASH: | ||
87 | case DT_STRTAB: | ||
88 | case DT_SYMTAB: | ||
89 | case DT_RELA: | ||
90 | case DT_INIT: | ||
91 | case DT_FINI: | ||
92 | case DT_REL: | ||
93 | case DT_DEBUG: | ||
94 | case DT_JMPREL: | ||
95 | case DT_VERSYM: | ||
96 | case DT_VERDEF: | ||
97 | case DT_VERNEED: | ||
98 | case DT_ADDRRNGLO ... DT_ADDRRNGHI: | ||
99 | /* definitely pointers needing relocation */ | ||
100 | dyn->d_un.d_ptr += VDSO_HIGH_BASE; | ||
101 | break; | ||
102 | |||
103 | case DT_ENCODING ... OLD_DT_LOOS-1: | ||
104 | case DT_LOOS ... DT_HIOS-1: | ||
105 | /* Tags above DT_ENCODING are pointers if | ||
106 | they're even */ | ||
107 | if (dyn->d_tag >= DT_ENCODING && | ||
108 | (dyn->d_tag & 1) == 0) | ||
109 | dyn->d_un.d_ptr += VDSO_HIGH_BASE; | ||
110 | break; | ||
111 | |||
112 | case DT_VERDEFNUM: | ||
113 | case DT_VERNEEDNUM: | ||
114 | case DT_FLAGS_1: | ||
115 | case DT_RELACOUNT: | ||
116 | case DT_RELCOUNT: | ||
117 | case DT_VALRNGLO ... DT_VALRNGHI: | ||
118 | /* definitely not pointers */ | ||
119 | break; | ||
120 | |||
121 | case OLD_DT_LOOS ... DT_LOOS-1: | ||
122 | case DT_HIOS ... DT_VALRNGLO-1: | ||
123 | default: | ||
124 | if (dyn->d_tag > DT_ENCODING) | ||
125 | printk(KERN_INFO "VDSO: unexpected DT_tag %x\n", | ||
126 | dyn->d_tag); | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static __init void relocate_vdso(Elf32_Ehdr *ehdr) | ||
132 | { | ||
133 | Elf32_Phdr *phdr; | ||
134 | Elf32_Shdr *shdr; | ||
135 | int i; | ||
136 | |||
137 | BUG_ON(memcmp(ehdr->e_ident, ELFMAG, 4) != 0 || | ||
138 | !elf_check_arch(ehdr) || | ||
139 | ehdr->e_type != ET_DYN); | ||
140 | |||
141 | ehdr->e_entry += VDSO_HIGH_BASE; | ||
142 | |||
143 | /* rebase phdrs */ | ||
144 | phdr = (void *)ehdr + ehdr->e_phoff; | ||
145 | for (i = 0; i < ehdr->e_phnum; i++) { | ||
146 | phdr[i].p_vaddr += VDSO_HIGH_BASE; | ||
147 | |||
148 | /* relocate dynamic stuff */ | ||
149 | if (phdr[i].p_type == PT_DYNAMIC) | ||
150 | reloc_dyn(ehdr, phdr[i].p_offset); | ||
151 | } | ||
152 | |||
153 | /* rebase sections */ | ||
154 | shdr = (void *)ehdr + ehdr->e_shoff; | ||
155 | for(i = 0; i < ehdr->e_shnum; i++) { | ||
156 | if (!(shdr[i].sh_flags & SHF_ALLOC)) | ||
157 | continue; | ||
158 | |||
159 | shdr[i].sh_addr += VDSO_HIGH_BASE; | ||
160 | |||
161 | if (shdr[i].sh_type == SHT_SYMTAB || | ||
162 | shdr[i].sh_type == SHT_DYNSYM) | ||
163 | reloc_symtab(ehdr, shdr[i].sh_offset, | ||
164 | shdr[i].sh_size); | ||
165 | } | ||
166 | } | ||
167 | #else | ||
168 | static inline void relocate_vdso(Elf32_Ehdr *ehdr) | ||
169 | { | ||
170 | } | ||
171 | #endif /* COMPAT_VDSO */ | ||
172 | |||
49 | void enable_sep_cpu(void) | 173 | void enable_sep_cpu(void) |
50 | { | 174 | { |
51 | int cpu = get_cpu(); | 175 | int cpu = get_cpu(); |
@@ -75,6 +199,9 @@ static struct page *syscall_pages[1]; | |||
75 | int __init sysenter_setup(void) | 199 | int __init sysenter_setup(void) |
76 | { | 200 | { |
77 | void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); | 201 | void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); |
202 | const void *vsyscall; | ||
203 | size_t vsyscall_len; | ||
204 | |||
78 | syscall_pages[0] = virt_to_page(syscall_page); | 205 | syscall_pages[0] = virt_to_page(syscall_page); |
79 | 206 | ||
80 | #ifdef CONFIG_COMPAT_VDSO | 207 | #ifdef CONFIG_COMPAT_VDSO |
@@ -83,23 +210,23 @@ int __init sysenter_setup(void) | |||
83 | #endif | 210 | #endif |
84 | 211 | ||
85 | if (!boot_cpu_has(X86_FEATURE_SEP)) { | 212 | if (!boot_cpu_has(X86_FEATURE_SEP)) { |
86 | memcpy(syscall_page, | 213 | vsyscall = &vsyscall_int80_start; |
87 | &vsyscall_int80_start, | 214 | vsyscall_len = &vsyscall_int80_end - &vsyscall_int80_start; |
88 | &vsyscall_int80_end - &vsyscall_int80_start); | 215 | } else { |
89 | return 0; | 216 | vsyscall = &vsyscall_sysenter_start; |
217 | vsyscall_len = &vsyscall_sysenter_end - &vsyscall_sysenter_start; | ||
90 | } | 218 | } |
91 | 219 | ||
92 | memcpy(syscall_page, | 220 | memcpy(syscall_page, vsyscall, vsyscall_len); |
93 | &vsyscall_sysenter_start, | 221 | relocate_vdso(syscall_page); |
94 | &vsyscall_sysenter_end - &vsyscall_sysenter_start); | ||
95 | 222 | ||
96 | return 0; | 223 | return 0; |
97 | } | 224 | } |
98 | 225 | ||
99 | #ifndef CONFIG_COMPAT_VDSO | ||
100 | /* Defined in vsyscall-sysenter.S */ | 226 | /* Defined in vsyscall-sysenter.S */ |
101 | extern void SYSENTER_RETURN; | 227 | extern void SYSENTER_RETURN; |
102 | 228 | ||
229 | #ifdef __HAVE_ARCH_GATE_AREA | ||
103 | /* Setup a VMA at program startup for the vsyscall page */ | 230 | /* Setup a VMA at program startup for the vsyscall page */ |
104 | int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) | 231 | int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) |
105 | { | 232 | { |
@@ -159,4 +286,17 @@ int in_gate_area_no_task(unsigned long addr) | |||
159 | { | 286 | { |
160 | return 0; | 287 | return 0; |
161 | } | 288 | } |
162 | #endif | 289 | #else /* !__HAVE_ARCH_GATE_AREA */ |
290 | int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) | ||
291 | { | ||
292 | /* | ||
293 | * If not creating userspace VMA, simply set vdso to point to | ||
294 | * fixmap page. | ||
295 | */ | ||
296 | current->mm->context.vdso = (void *)VDSO_HIGH_BASE; | ||
297 | current_thread_info()->sysenter_return = | ||
298 | (void *)VDSO_SYM(&SYSENTER_RETURN); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | #endif /* __HAVE_ARCH_GATE_AREA */ | ||
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index fa0cfbd551e1..99c09edc3dbb 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c | |||
@@ -144,10 +144,8 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) | |||
144 | } | 144 | } |
145 | 145 | ||
146 | static int fixmaps; | 146 | static int fixmaps; |
147 | #ifndef CONFIG_COMPAT_VDSO | ||
148 | unsigned long __FIXADDR_TOP = 0xfffff000; | 147 | unsigned long __FIXADDR_TOP = 0xfffff000; |
149 | EXPORT_SYMBOL(__FIXADDR_TOP); | 148 | EXPORT_SYMBOL(__FIXADDR_TOP); |
150 | #endif | ||
151 | 149 | ||
152 | void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) | 150 | void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) |
153 | { | 151 | { |
@@ -173,12 +171,8 @@ void reserve_top_address(unsigned long reserve) | |||
173 | BUG_ON(fixmaps > 0); | 171 | BUG_ON(fixmaps > 0); |
174 | printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", | 172 | printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", |
175 | (int)-reserve); | 173 | (int)-reserve); |
176 | #ifdef CONFIG_COMPAT_VDSO | ||
177 | BUG_ON(reserve != 0); | ||
178 | #else | ||
179 | __FIXADDR_TOP = -reserve - PAGE_SIZE; | 174 | __FIXADDR_TOP = -reserve - PAGE_SIZE; |
180 | __VMALLOC_RESERVE += reserve; | 175 | __VMALLOC_RESERVE += reserve; |
181 | #endif | ||
182 | } | 176 | } |
183 | 177 | ||
184 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | 178 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) |
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index 952b3ee3c9bb..d304ab4161ff 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h | |||
@@ -133,39 +133,31 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct | |||
133 | #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs) | 133 | #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs) |
134 | 134 | ||
135 | #define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO)) | 135 | #define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO)) |
136 | #define VDSO_BASE ((unsigned long)current->mm->context.vdso) | 136 | #define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) |
137 | 137 | #define VDSO_PRELINK 0 | |
138 | #ifdef CONFIG_COMPAT_VDSO | ||
139 | # define VDSO_COMPAT_BASE VDSO_HIGH_BASE | ||
140 | # define VDSO_PRELINK VDSO_HIGH_BASE | ||
141 | #else | ||
142 | # define VDSO_COMPAT_BASE VDSO_BASE | ||
143 | # define VDSO_PRELINK 0 | ||
144 | #endif | ||
145 | 138 | ||
146 | #define VDSO_SYM(x) \ | 139 | #define VDSO_SYM(x) \ |
147 | (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK) | 140 | (VDSO_CURRENT_BASE + (unsigned long)(x) - VDSO_PRELINK) |
148 | 141 | ||
149 | #define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE) | 142 | #define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE) |
150 | #define VDSO_EHDR ((const struct elfhdr *) VDSO_COMPAT_BASE) | 143 | #define VDSO_EHDR ((const struct elfhdr *) VDSO_CURRENT_BASE) |
151 | 144 | ||
152 | extern void __kernel_vsyscall; | 145 | extern void __kernel_vsyscall; |
153 | 146 | ||
154 | #define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall) | 147 | #define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall) |
155 | 148 | ||
156 | #ifndef CONFIG_COMPAT_VDSO | ||
157 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
158 | struct linux_binprm; | 149 | struct linux_binprm; |
150 | |||
151 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
159 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | 152 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, |
160 | int executable_stack); | 153 | int executable_stack); |
161 | #endif | ||
162 | 154 | ||
163 | extern unsigned int vdso_enabled; | 155 | extern unsigned int vdso_enabled; |
164 | 156 | ||
165 | #define ARCH_DLINFO \ | 157 | #define ARCH_DLINFO \ |
166 | do if (vdso_enabled) { \ | 158 | do if (vdso_enabled) { \ |
167 | NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ | 159 | NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ |
168 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \ | 160 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ |
169 | } while (0) | 161 | } while (0) |
170 | 162 | ||
171 | #endif | 163 | #endif |
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h index 3e9f610c35df..e5651b2a585a 100644 --- a/include/asm-i386/fixmap.h +++ b/include/asm-i386/fixmap.h | |||
@@ -19,13 +19,9 @@ | |||
19 | * Leave one empty page between vmalloc'ed areas and | 19 | * Leave one empty page between vmalloc'ed areas and |
20 | * the start of the fixmap. | 20 | * the start of the fixmap. |
21 | */ | 21 | */ |
22 | #ifndef CONFIG_COMPAT_VDSO | ||
23 | extern unsigned long __FIXADDR_TOP; | 22 | extern unsigned long __FIXADDR_TOP; |
24 | #else | 23 | #define FIXADDR_USER_START __fix_to_virt(FIX_VDSO) |
25 | #define __FIXADDR_TOP 0xfffff000 | 24 | #define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1) |
26 | #define FIXADDR_USER_START __fix_to_virt(FIX_VDSO) | ||
27 | #define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1) | ||
28 | #endif | ||
29 | 25 | ||
30 | #ifndef __ASSEMBLY__ | 26 | #ifndef __ASSEMBLY__ |
31 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
diff --git a/include/linux/elf.h b/include/linux/elf.h index 60713e6ea297..8b17ffe222c4 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
@@ -83,6 +83,23 @@ typedef __s64 Elf64_Sxword; | |||
83 | #define DT_DEBUG 21 | 83 | #define DT_DEBUG 21 |
84 | #define DT_TEXTREL 22 | 84 | #define DT_TEXTREL 22 |
85 | #define DT_JMPREL 23 | 85 | #define DT_JMPREL 23 |
86 | #define DT_ENCODING 32 | ||
87 | #define OLD_DT_LOOS 0x60000000 | ||
88 | #define DT_LOOS 0x6000000d | ||
89 | #define DT_HIOS 0x6ffff000 | ||
90 | #define DT_VALRNGLO 0x6ffffd00 | ||
91 | #define DT_VALRNGHI 0x6ffffdff | ||
92 | #define DT_ADDRRNGLO 0x6ffffe00 | ||
93 | #define DT_ADDRRNGHI 0x6ffffeff | ||
94 | #define DT_VERSYM 0x6ffffff0 | ||
95 | #define DT_RELACOUNT 0x6ffffff9 | ||
96 | #define DT_RELCOUNT 0x6ffffffa | ||
97 | #define DT_FLAGS_1 0x6ffffffb | ||
98 | #define DT_VERDEF 0x6ffffffc | ||
99 | #define DT_VERDEFNUM 0x6ffffffd | ||
100 | #define DT_VERNEED 0x6ffffffe | ||
101 | #define DT_VERNEEDNUM 0x6fffffff | ||
102 | #define OLD_DT_HIOS 0x6fffffff | ||
86 | #define DT_LOPROC 0x70000000 | 103 | #define DT_LOPROC 0x70000000 |
87 | #define DT_HIPROC 0x7fffffff | 104 | #define DT_HIPROC 0x7fffffff |
88 | 105 | ||