aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-03-20 18:01:21 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-03-20 18:19:14 -0400
commitb67e612cef1e5964efc6fa99fb7ad3d31c4db01a (patch)
treec037de472a7e20c143dc3ca05e3f9327dc917d09
parent4e40112c4ff6a577dd06d92b2a54cdf06265bf74 (diff)
x86: Load the 32-bit vdso in place, just like the 64-bit vdsos
This replaces a decent amount of incomprehensible and buggy code with much more straightforward code. It also brings the 32-bit vdso more in line with the 64-bit vdsos, so maybe someday they can share even more code. This wastes a small amount of kernel .data and .text space, but it avoids a couple of allocations on startup, so it should be more or less a wash memory-wise. Signed-off-by: Andy Lutomirski <luto@amacapital.net> Cc: Stefani Seibold <stefani@seibold.net> Link: http://lkml.kernel.org/r/b8093933fad09ce181edb08a61dcd5d2592e9814.1395352498.git.luto@amacapital.net Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/include/asm/vdso.h8
-rw-r--r--arch/x86/vdso/vdso.S22
-rw-r--r--arch/x86/vdso/vdso32-setup.c50
-rw-r--r--arch/x86/vdso/vdso32.S21
-rw-r--r--arch/x86/vdso/vdso_image.h30
-rw-r--r--arch/x86/vdso/vdsox32.S22
-rw-r--r--arch/x86/vdso/vma.c8
7 files changed, 70 insertions, 91 deletions
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index bde435998f3a..0301d78bb910 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -25,14 +25,6 @@ extern const char VDSO32_PRELINK[];
25extern void __user __kernel_sigreturn; 25extern void __user __kernel_sigreturn;
26extern void __user __kernel_rt_sigreturn; 26extern void __user __kernel_rt_sigreturn;
27 27
28/*
29 * These symbols are defined by vdso32.S to mark the bounds
30 * of the ELF DSO images included therein.
31 */
32extern const char vdso32_int80_start, vdso32_int80_end;
33extern const char vdso32_syscall_start, vdso32_syscall_end;
34extern const char vdso32_sysenter_start, vdso32_sysenter_end;
35
36void __init patch_vdso32(void *vdso, size_t len); 28void __init patch_vdso32(void *vdso, size_t len);
37 29
38#endif /* _ASM_X86_VDSO_H */ 30#endif /* _ASM_X86_VDSO_H */
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
index 1e13eb8c9656..c749d15da2e9 100644
--- a/arch/x86/vdso/vdso.S
+++ b/arch/x86/vdso/vdso.S
@@ -1,21 +1,3 @@
1#include <asm/page_types.h> 1#include "vdso_image.h"
2#include <linux/linkage.h>
3 2
4__PAGE_ALIGNED_DATA 3DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
5
6 .globl vdso_start, vdso_end
7 .align PAGE_SIZE
8vdso_start:
9 .incbin "arch/x86/vdso/vdso.so"
10vdso_end:
11 .align PAGE_SIZE /* extra data here leaks to userspace. */
12
13.previous
14
15 .globl vdso_pages
16 .bss
17 .align 8
18 .type vdso_pages, @object
19vdso_pages:
20 .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
21 .size vdso_pages, .-vdso_pages
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 5b4aaefb6b42..b45528ee8e19 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -29,6 +29,7 @@
29#include <asm/fixmap.h> 29#include <asm/fixmap.h>
30#include <asm/hpet.h> 30#include <asm/hpet.h>
31#include <asm/vvar.h> 31#include <asm/vvar.h>
32#include "vdso_image.h"
32 33
33#ifdef CONFIG_COMPAT_VDSO 34#ifdef CONFIG_COMPAT_VDSO
34#define VDSO_DEFAULT 0 35#define VDSO_DEFAULT 0
@@ -41,6 +42,12 @@
41#define arch_setup_additional_pages syscall32_setup_pages 42#define arch_setup_additional_pages syscall32_setup_pages
42#endif 43#endif
43 44
45DECLARE_VDSO_IMAGE(vdso32_int80);
46#ifdef CONFIG_COMPAT
47DECLARE_VDSO_IMAGE(vdso32_syscall);
48#endif
49DECLARE_VDSO_IMAGE(vdso32_sysenter);
50
44/* 51/*
45 * Should the kernel map a VDSO page into processes and pass its 52 * Should the kernel map a VDSO page into processes and pass its
46 * address down to glibc upon exec()? 53 * address down to glibc upon exec()?
@@ -71,7 +78,7 @@ EXPORT_SYMBOL_GPL(vdso_enabled);
71#endif 78#endif
72 79
73static struct page **vdso32_pages; 80static struct page **vdso32_pages;
74static unsigned int vdso32_size; 81static unsigned vdso32_size;
75 82
76#ifdef CONFIG_X86_64 83#ifdef CONFIG_X86_64
77 84
@@ -117,31 +124,32 @@ void enable_sep_cpu(void)
117 124
118int __init sysenter_setup(void) 125int __init sysenter_setup(void)
119{ 126{
120 void *vdso_pages; 127 char *vdso32_start, *vdso32_end;
121 const void *vdso; 128 int npages, i;
122 size_t vdso_len;
123 unsigned int i;
124 129
130#ifdef CONFIG_COMPAT
125 if (vdso32_syscall()) { 131 if (vdso32_syscall()) {
126 vdso = &vdso32_syscall_start; 132 vdso32_start = vdso32_syscall_start;
127 vdso_len = &vdso32_syscall_end - &vdso32_syscall_start; 133 vdso32_end = vdso32_syscall_end;
128 } else if (vdso32_sysenter()){ 134 vdso32_pages = vdso32_syscall_pages;
129 vdso = &vdso32_sysenter_start; 135 } else
130 vdso_len = &vdso32_sysenter_end - &vdso32_sysenter_start; 136#endif
137 if (vdso32_sysenter()) {
138 vdso32_start = vdso32_sysenter_start;
139 vdso32_end = vdso32_sysenter_end;
140 vdso32_pages = vdso32_sysenter_pages;
131 } else { 141 } else {
132 vdso = &vdso32_int80_start; 142 vdso32_start = vdso32_int80_start;
133 vdso_len = &vdso32_int80_end - &vdso32_int80_start; 143 vdso32_end = vdso32_int80_end;
144 vdso32_pages = vdso32_int80_pages;
134 } 145 }
135 146
136 vdso32_size = (vdso_len + PAGE_SIZE - 1) / PAGE_SIZE; 147 npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
137 vdso32_pages = kmalloc(sizeof(*vdso32_pages) * vdso32_size, GFP_ATOMIC); 148 vdso32_size = npages << PAGE_SHIFT;
138 vdso_pages = kmalloc(VDSO_OFFSET(vdso32_size), GFP_ATOMIC); 149 for (i = 0; i < npages; i++)
139 150 vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
140 for(i = 0; i != vdso32_size; ++i)
141 vdso32_pages[i] = virt_to_page(vdso_pages + VDSO_OFFSET(i));
142 151
143 memcpy(vdso_pages, vdso, vdso_len); 152 patch_vdso32(vdso32_start, vdso32_size);
144 patch_vdso32(vdso_pages, vdso_len);
145 153
146 return 0; 154 return 0;
147} 155}
@@ -177,7 +185,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
177 */ 185 */
178 ret = install_special_mapping(mm, 186 ret = install_special_mapping(mm,
179 addr, 187 addr,
180 VDSO_OFFSET(vdso32_size), 188 vdso32_size,
181 VM_READ|VM_EXEC| 189 VM_READ|VM_EXEC|
182 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 190 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
183 vdso32_pages); 191 vdso32_pages);
diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S
index 2ce5f82c333b..cfa6adda110b 100644
--- a/arch/x86/vdso/vdso32.S
+++ b/arch/x86/vdso/vdso32.S
@@ -1,22 +1,9 @@
1#include <linux/init.h> 1#include "vdso_image.h"
2 2
3__INITDATA 3DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")
4 4
5 .globl vdso32_int80_start, vdso32_int80_end
6vdso32_int80_start:
7 .incbin "arch/x86/vdso/vdso32-int80.so"
8vdso32_int80_end:
9
10 .globl vdso32_syscall_start, vdso32_syscall_end
11vdso32_syscall_start:
12#ifdef CONFIG_COMPAT 5#ifdef CONFIG_COMPAT
13 .incbin "arch/x86/vdso/vdso32-syscall.so" 6DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
14#endif 7#endif
15vdso32_syscall_end:
16
17 .globl vdso32_sysenter_start, vdso32_sysenter_end
18vdso32_sysenter_start:
19 .incbin "arch/x86/vdso/vdso32-sysenter.so"
20vdso32_sysenter_end:
21 8
22__FINIT 9DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
diff --git a/arch/x86/vdso/vdso_image.h b/arch/x86/vdso/vdso_image.h
new file mode 100644
index 000000000000..1baa6bc517bf
--- /dev/null
+++ b/arch/x86/vdso/vdso_image.h
@@ -0,0 +1,30 @@
1#ifndef _VDSO_IMAGE_H
2#define _VDSO_IMAGE_H
3
4#include <asm/page_types.h>
5#include <linux/linkage.h>
6
7#define DEFINE_VDSO_IMAGE(symname, filename) \
8__PAGE_ALIGNED_DATA ; \
9 .globl symname##_start, symname##_end ; \
10 .align PAGE_SIZE ; \
11 symname##_start: ; \
12 .incbin filename ; \
13 symname##_end: ; \
14 .align PAGE_SIZE /* extra data here leaks to userspace. */ ; \
15 \
16.previous ; \
17 \
18 .globl symname##_pages ; \
19 .bss ; \
20 .align 8 ; \
21 .type symname##_pages, @object ; \
22 symname##_pages: ; \
23 .zero (symname##_end - symname##_start + PAGE_SIZE - 1) / PAGE_SIZE * (BITS_PER_LONG / 8) ; \
24 .size symname##_pages, .-symname##_pages
25
26#define DECLARE_VDSO_IMAGE(symname) \
27 extern char symname##_start[], symname##_end[]; \
28 extern struct page *symname##_pages[]
29
30#endif /* _VDSO_IMAGE_H */
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
index 295f1c7543d8..19a692778650 100644
--- a/arch/x86/vdso/vdsox32.S
+++ b/arch/x86/vdso/vdsox32.S
@@ -1,21 +1,3 @@
1#include <asm/page_types.h> 1#include "vdso_image.h"
2#include <linux/linkage.h>
3 2
4__PAGE_ALIGNED_DATA 3DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
5
6 .globl vdsox32_start, vdsox32_end
7 .align PAGE_SIZE
8vdsox32_start:
9 .incbin "arch/x86/vdso/vdsox32.so"
10vdsox32_end:
11 .align PAGE_SIZE /* extra data here leaks to userspace. */
12
13.previous
14
15 .globl vdsox32_pages
16 .bss
17 .align 8
18 .type vdsox32_pages, @object
19vdsox32_pages:
20 .zero (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
21 .size vdsox32_pages, .-vdsox32_pages
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 7345bc9a1af6..6db0bbd876fd 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -15,19 +15,17 @@
15#include <asm/proto.h> 15#include <asm/proto.h>
16#include <asm/vdso.h> 16#include <asm/vdso.h>
17#include <asm/page.h> 17#include <asm/page.h>
18#include "vdso_image.h"
18 19
19#if defined(CONFIG_X86_64) 20#if defined(CONFIG_X86_64)
20unsigned int __read_mostly vdso_enabled = 1; 21unsigned int __read_mostly vdso_enabled = 1;
21 22
22extern char vdso_start[], vdso_end[]; 23DECLARE_VDSO_IMAGE(vdso);
23extern unsigned short vdso_sync_cpuid; 24extern unsigned short vdso_sync_cpuid;
24
25extern struct page *vdso_pages[];
26static unsigned vdso_size; 25static unsigned vdso_size;
27 26
28#ifdef CONFIG_X86_X32_ABI 27#ifdef CONFIG_X86_X32_ABI
29extern char vdsox32_start[], vdsox32_end[]; 28DECLARE_VDSO_IMAGE(vdsox32);
30extern struct page *vdsox32_pages[];
31static unsigned vdsox32_size; 29static unsigned vdsox32_size;
32#endif 30#endif
33#endif 31#endif