aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/vdso
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/vdso')
-rw-r--r--arch/x86/vdso/.gitignore5
-rw-r--r--arch/x86/vdso/Makefile90
-rw-r--r--arch/x86/vdso/vclock_gettime.c4
-rw-r--r--arch/x86/vdso/vdso.S3
-rw-r--r--arch/x86/vdso/vdso2c.c142
-rw-r--r--arch/x86/vdso/vdso2c.h137
-rw-r--r--arch/x86/vdso/vdso32-setup.c50
-rw-r--r--arch/x86/vdso/vdso32.S9
-rw-r--r--arch/x86/vdso/vdso32/vdso32.lds.S10
-rw-r--r--arch/x86/vdso/vdsox32.S3
-rw-r--r--arch/x86/vdso/vma.c100
11 files changed, 351 insertions, 202 deletions
diff --git a/arch/x86/vdso/.gitignore b/arch/x86/vdso/.gitignore
index 3282874bc61d..aae8ffdd5880 100644
--- a/arch/x86/vdso/.gitignore
+++ b/arch/x86/vdso/.gitignore
@@ -1,8 +1,7 @@
1vdso.lds 1vdso.lds
2vdso-syms.lds
3vdsox32.lds 2vdsox32.lds
4vdsox32-syms.lds
5vdso32-syms.lds
6vdso32-syscall-syms.lds 3vdso32-syscall-syms.lds
7vdso32-sysenter-syms.lds 4vdso32-sysenter-syms.lds
8vdso32-int80-syms.lds 5vdso32-int80-syms.lds
6vdso-image-*.c
7vdso2c
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index c580d1210ffe..895d4b16b7e3 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -24,15 +24,30 @@ vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y))
24 24
25# files to link into kernel 25# files to link into kernel
26obj-y += vma.o 26obj-y += vma.o
27obj-$(VDSO64-y) += vdso.o 27
28obj-$(VDSOX32-y) += vdsox32.o 28# vDSO images to build
29obj-$(VDSO32-y) += vdso32.o vdso32-setup.o 29vdso_img-$(VDSO64-y) += 64
30vdso_img-$(VDSOX32-y) += x32
31vdso_img-$(VDSO32-y) += 32-int80
32vdso_img-$(CONFIG_COMPAT) += 32-syscall
33vdso_img-$(VDSO32-y) += 32-sysenter
34
35obj-$(VDSO32-y) += vdso32-setup.o
30 36
31vobjs := $(foreach F,$(vobj64s),$(obj)/$F) 37vobjs := $(foreach F,$(vobj64s),$(obj)/$F)
32 38
33$(obj)/vdso.o: $(obj)/vdso.so 39$(obj)/vdso.o: $(obj)/vdso.so
34 40
35targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) 41targets += vdso.lds $(vobjs-y)
42
43# Build the vDSO image C files and link them in.
44vdso_img_objs := $(vdso_img-y:%=vdso-image-%.o)
45vdso_img_cfiles := $(vdso_img-y:%=vdso-image-%.c)
46vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg)
47obj-y += $(vdso_img_objs)
48targets += $(vdso_img_cfiles)
49targets += $(vdso_img_sodbg)
50.SECONDARY: $(vdso_img-y:%=$(obj)/vdso-image-%.c)
36 51
37export CPPFLAGS_vdso.lds += -P -C 52export CPPFLAGS_vdso.lds += -P -C
38 53
@@ -41,14 +56,18 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
41 -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \ 56 -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
42 $(DISABLE_LTO) 57 $(DISABLE_LTO)
43 58
44$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so 59$(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
45
46$(obj)/vdso.so.dbg: $(src)/vdso.lds $(vobjs) FORCE
47 $(call if_changed,vdso) 60 $(call if_changed,vdso)
48 61
49$(obj)/%.so: OBJCOPYFLAGS := -S 62hostprogs-y += vdso2c
50$(obj)/%.so: $(obj)/%.so.dbg FORCE 63
51 $(call if_changed,objcopy) 64quiet_cmd_vdso2c = VDSO2C $@
65define cmd_vdso2c
66 $(obj)/vdso2c $< $@
67endef
68
69$(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso2c FORCE
70 $(call if_changed,vdso2c)
52 71
53# 72#
54# Don't omit frame pointers for ease of userspace debugging, but do 73# Don't omit frame pointers for ease of userspace debugging, but do
@@ -68,22 +87,6 @@ CFLAGS_REMOVE_vclock_gettime.o = -pg
68CFLAGS_REMOVE_vgetcpu.o = -pg 87CFLAGS_REMOVE_vgetcpu.o = -pg
69CFLAGS_REMOVE_vvar.o = -pg 88CFLAGS_REMOVE_vvar.o = -pg
70 89
71targets += vdso-syms.lds
72obj-$(VDSO64-y) += vdso-syms.lds
73
74#
75# Match symbols in the DSO that look like VDSO*; produce a file of constants.
76#
77sed-vdsosym := -e 's/^00*/0/' \
78 -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p'
79quiet_cmd_vdsosym = VDSOSYM $@
80define cmd_vdsosym
81 $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@
82endef
83
84$(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
85 $(call if_changed,vdsosym)
86
87# 90#
88# X32 processes use x32 vDSO to access 64bit kernel data. 91# X32 processes use x32 vDSO to access 64bit kernel data.
89# 92#
@@ -94,9 +97,6 @@ $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE
94# so that it can reach 64bit address space with 64bit pointers. 97# so that it can reach 64bit address space with 64bit pointers.
95# 98#
96 99
97targets += vdsox32-syms.lds
98obj-$(VDSOX32-y) += vdsox32-syms.lds
99
100CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds) 100CPPFLAGS_vdsox32.lds = $(CPPFLAGS_vdso.lds)
101VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \ 101VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \
102 -Wl,-soname=linux-vdso.so.1 \ 102 -Wl,-soname=linux-vdso.so.1 \
@@ -113,9 +113,7 @@ quiet_cmd_x32 = X32 $@
113$(obj)/%-x32.o: $(obj)/%.o FORCE 113$(obj)/%-x32.o: $(obj)/%.o FORCE
114 $(call if_changed,x32) 114 $(call if_changed,x32)
115 115
116targets += vdsox32.so vdsox32.so.dbg vdsox32.lds $(vobjx32s-y) 116targets += vdsox32.lds $(vobjx32s-y)
117
118$(obj)/vdsox32.o: $(src)/vdsox32.S $(obj)/vdsox32.so
119 117
120$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE 118$(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
121 $(call if_changed,vdso) 119 $(call if_changed,vdso)
@@ -123,7 +121,6 @@ $(obj)/vdsox32.so.dbg: $(src)/vdsox32.lds $(vobjx32s) FORCE
123# 121#
124# Build multiple 32-bit vDSO images to choose from at boot time. 122# Build multiple 32-bit vDSO images to choose from at boot time.
125# 123#
126obj-$(VDSO32-y) += vdso32-syms.lds
127vdso32.so-$(VDSO32-y) += int80 124vdso32.so-$(VDSO32-y) += int80
128vdso32.so-$(CONFIG_COMPAT) += syscall 125vdso32.so-$(CONFIG_COMPAT) += syscall
129vdso32.so-$(VDSO32-y) += sysenter 126vdso32.so-$(VDSO32-y) += sysenter
@@ -138,10 +135,8 @@ VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1
138override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ 135override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
139 136
140targets += vdso32/vdso32.lds 137targets += vdso32/vdso32.lds
141targets += $(vdso32-images) $(vdso32-images:=.dbg)
142targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o) 138targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
143 139targets += vdso32/vclock_gettime.o
144extra-y += $(vdso32-images)
145 140
146$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%) 141$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)
147 142
@@ -166,27 +161,6 @@ $(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
166 $(obj)/vdso32/%.o 161 $(obj)/vdso32/%.o
167 $(call if_changed,vdso) 162 $(call if_changed,vdso)
168 163
169# Make vdso32-*-syms.lds from each image, and then make sure they match.
170# The only difference should be that some do not define VDSO32_SYSENTER_RETURN.
171
172targets += vdso32-syms.lds $(vdso32.so-y:%=vdso32-%-syms.lds)
173
174quiet_cmd_vdso32sym = VDSOSYM $@
175define cmd_vdso32sym
176 if LC_ALL=C sort -u $(filter-out FORCE,$^) > $(@D)/.tmp_$(@F) && \
177 $(foreach H,$(filter-out FORCE,$^),\
178 if grep -q VDSO32_SYSENTER_RETURN $H; \
179 then diff -u $(@D)/.tmp_$(@F) $H; \
180 else sed /VDSO32_SYSENTER_RETURN/d $(@D)/.tmp_$(@F) | \
181 diff -u - $H; fi &&) : ;\
182 then mv -f $(@D)/.tmp_$(@F) $@; \
183 else rm -f $(@D)/.tmp_$(@F); exit 1; \
184 fi
185endef
186
187$(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE
188 $(call if_changed,vdso32sym)
189
190# 164#
191# The DSO images are built using a special linker script. 165# The DSO images are built using a special linker script.
192# 166#
@@ -197,7 +171,7 @@ quiet_cmd_vdso = VDSO $@
197 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' 171 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
198 172
199VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ 173VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
200 $(LTO_CFLAGS) 174 -Wl,-Bsymbolic $(LTO_CFLAGS)
201GCOV_PROFILE := n 175GCOV_PROFILE := n
202 176
203# 177#
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 16d686171e9a..091554c20bc9 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -154,7 +154,7 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
154 asm( 154 asm(
155 "mov %%ebx, %%edx \n" 155 "mov %%ebx, %%edx \n"
156 "mov %2, %%ebx \n" 156 "mov %2, %%ebx \n"
157 "call VDSO32_vsyscall \n" 157 "call __kernel_vsyscall \n"
158 "mov %%edx, %%ebx \n" 158 "mov %%edx, %%ebx \n"
159 : "=a" (ret) 159 : "=a" (ret)
160 : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) 160 : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
@@ -169,7 +169,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
169 asm( 169 asm(
170 "mov %%ebx, %%edx \n" 170 "mov %%ebx, %%edx \n"
171 "mov %2, %%ebx \n" 171 "mov %2, %%ebx \n"
172 "call VDSO32_vsyscall \n" 172 "call __kernel_vsyscall \n"
173 "mov %%edx, %%ebx \n" 173 "mov %%edx, %%ebx \n"
174 : "=a" (ret) 174 : "=a" (ret)
175 : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) 175 : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
deleted file mode 100644
index be3f23b09af5..000000000000
--- a/arch/x86/vdso/vdso.S
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
new file mode 100644
index 000000000000..976e8e4ced92
--- /dev/null
+++ b/arch/x86/vdso/vdso2c.c
@@ -0,0 +1,142 @@
1#include <inttypes.h>
2#include <stdint.h>
3#include <unistd.h>
4#include <stdarg.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <fcntl.h>
9#include <err.h>
10
11#include <sys/mman.h>
12#include <sys/types.h>
13
14#include <linux/elf.h>
15#include <linux/types.h>
16
17/* Symbols that we need in vdso2c. */
18char const * const required_syms[] = {
19 "VDSO32_NOTE_MASK",
20 "VDSO32_SYSENTER_RETURN",
21 "__kernel_vsyscall",
22 "__kernel_sigreturn",
23 "__kernel_rt_sigreturn",
24};
25
26__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
27static void fail(const char *format, ...)
28{
29 va_list ap;
30 va_start(ap, format);
31 fprintf(stderr, "Error: ");
32 vfprintf(stderr, format, ap);
33 exit(1);
34 va_end(ap);
35}
36
37#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
38
39#define BITS 64
40#define GOFUNC go64
41#define Elf_Ehdr Elf64_Ehdr
42#define Elf_Shdr Elf64_Shdr
43#define Elf_Phdr Elf64_Phdr
44#define Elf_Sym Elf64_Sym
45#define Elf_Dyn Elf64_Dyn
46#include "vdso2c.h"
47#undef BITS
48#undef GOFUNC
49#undef Elf_Ehdr
50#undef Elf_Shdr
51#undef Elf_Phdr
52#undef Elf_Sym
53#undef Elf_Dyn
54
55#define BITS 32
56#define GOFUNC go32
57#define Elf_Ehdr Elf32_Ehdr
58#define Elf_Shdr Elf32_Shdr
59#define Elf_Phdr Elf32_Phdr
60#define Elf_Sym Elf32_Sym
61#define Elf_Dyn Elf32_Dyn
62#include "vdso2c.h"
63#undef BITS
64#undef GOFUNC
65#undef Elf_Ehdr
66#undef Elf_Shdr
67#undef Elf_Phdr
68#undef Elf_Sym
69#undef Elf_Dyn
70
71static int go(void *addr, size_t len, FILE *outfile, const char *name)
72{
73 Elf64_Ehdr *hdr = (Elf64_Ehdr *)addr;
74
75 if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
76 return go64(addr, len, outfile, name);
77 } else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) {
78 return go32(addr, len, outfile, name);
79 } else {
80 fprintf(stderr, "Error: unknown ELF class\n");
81 return 1;
82 }
83}
84
85int main(int argc, char **argv)
86{
87 int fd;
88 off_t len;
89 void *addr;
90 FILE *outfile;
91 int ret;
92 char *name, *tmp;
93 int namelen;
94
95 if (argc != 3) {
96 printf("Usage: vdso2c INPUT OUTPUT\n");
97 return 1;
98 }
99
100 /*
101 * Figure out the struct name. If we're writing to a .so file,
102 * generate raw output insted.
103 */
104 name = strdup(argv[2]);
105 namelen = strlen(name);
106 if (namelen >= 3 && !strcmp(name + namelen - 3, ".so")) {
107 name = NULL;
108 } else {
109 tmp = strrchr(name, '/');
110 if (tmp)
111 name = tmp + 1;
112 tmp = strchr(name, '.');
113 if (tmp)
114 *tmp = '\0';
115 for (tmp = name; *tmp; tmp++)
116 if (*tmp == '-')
117 *tmp = '_';
118 }
119
120 fd = open(argv[1], O_RDONLY);
121 if (fd == -1)
122 err(1, "%s", argv[1]);
123
124 len = lseek(fd, 0, SEEK_END);
125 if (len == (off_t)-1)
126 err(1, "lseek");
127
128 addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
129 if (addr == MAP_FAILED)
130 err(1, "mmap");
131
132 outfile = fopen(argv[2], "w");
133 if (!outfile)
134 err(1, "%s", argv[2]);
135
136 ret = go(addr, (size_t)len, outfile, name);
137
138 munmap(addr, len);
139 fclose(outfile);
140
141 return ret;
142}
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
new file mode 100644
index 000000000000..9276e5207620
--- /dev/null
+++ b/arch/x86/vdso/vdso2c.h
@@ -0,0 +1,137 @@
1/*
2 * This file is included twice from vdso2c.c. It generates code for 32-bit
3 * and 64-bit vDSOs. We need both for 64-bit builds, since 32-bit vDSOs
4 * are built for 32-bit userspace.
5 */
6
7static int GOFUNC(void *addr, size_t len, FILE *outfile, const char *name)
8{
9 int found_load = 0;
10 unsigned long load_size = -1; /* Work around bogus warning */
11 unsigned long data_size;
12 Elf_Ehdr *hdr = (Elf_Ehdr *)addr;
13 int i;
14 unsigned long j;
15 Elf_Shdr *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
16 *alt_sec = NULL;
17 Elf_Dyn *dyn = 0, *dyn_end = 0;
18 const char *secstrings;
19 uint64_t syms[NSYMS] = {};
20
21 Elf_Phdr *pt = (Elf_Phdr *)(addr + hdr->e_phoff);
22
23 /* Walk the segment table. */
24 for (i = 0; i < hdr->e_phnum; i++) {
25 if (pt[i].p_type == PT_LOAD) {
26 if (found_load)
27 fail("multiple PT_LOAD segs\n");
28
29 if (pt[i].p_offset != 0 || pt[i].p_vaddr != 0)
30 fail("PT_LOAD in wrong place\n");
31
32 if (pt[i].p_memsz != pt[i].p_filesz)
33 fail("cannot handle memsz != filesz\n");
34
35 load_size = pt[i].p_memsz;
36 found_load = 1;
37 } else if (pt[i].p_type == PT_DYNAMIC) {
38 dyn = addr + pt[i].p_offset;
39 dyn_end = addr + pt[i].p_offset + pt[i].p_memsz;
40 }
41 }
42 if (!found_load)
43 fail("no PT_LOAD seg\n");
44 data_size = (load_size + 4095) / 4096 * 4096;
45
46 /* Walk the dynamic table */
47 for (i = 0; dyn + i < dyn_end && dyn[i].d_tag != DT_NULL; i++) {
48 if (dyn[i].d_tag == DT_REL || dyn[i].d_tag == DT_RELSZ ||
49 dyn[i].d_tag == DT_RELENT || dyn[i].d_tag == DT_TEXTREL)
50 fail("vdso image contains dynamic relocations\n");
51 }
52
53 /* Walk the section table */
54 secstrings_hdr = addr + hdr->e_shoff + hdr->e_shentsize*hdr->e_shstrndx;
55 secstrings = addr + secstrings_hdr->sh_offset;
56 for (i = 0; i < hdr->e_shnum; i++) {
57 Elf_Shdr *sh = addr + hdr->e_shoff + hdr->e_shentsize * i;
58 if (sh->sh_type == SHT_SYMTAB)
59 symtab_hdr = sh;
60
61 if (!strcmp(secstrings + sh->sh_name, ".altinstructions"))
62 alt_sec = sh;
63 }
64
65 if (!symtab_hdr) {
66 fail("no symbol table\n");
67 return 1;
68 }
69
70 strtab_hdr = addr + hdr->e_shoff +
71 hdr->e_shentsize * symtab_hdr->sh_link;
72
73 /* Walk the symbol table */
74 for (i = 0; i < symtab_hdr->sh_size / symtab_hdr->sh_entsize; i++) {
75 int k;
76 Elf_Sym *sym = addr + symtab_hdr->sh_offset +
77 symtab_hdr->sh_entsize * i;
78 const char *name = addr + strtab_hdr->sh_offset + sym->st_name;
79 for (k = 0; k < NSYMS; k++) {
80 if (!strcmp(name, required_syms[k])) {
81 if (syms[k]) {
82 fail("duplicate symbol %s\n",
83 required_syms[k]);
84 }
85 syms[k] = sym->st_value;
86 }
87 }
88 }
89
90 /* Remove sections. */
91 hdr->e_shoff = 0;
92 hdr->e_shentsize = 0;
93 hdr->e_shnum = 0;
94 hdr->e_shstrndx = SHN_UNDEF;
95
96 if (!name) {
97 fwrite(addr, load_size, 1, outfile);
98 return 0;
99 }
100
101 fprintf(outfile, "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n\n");
102 fprintf(outfile, "#include <linux/linkage.h>\n");
103 fprintf(outfile, "#include <asm/page_types.h>\n");
104 fprintf(outfile, "#include <asm/vdso.h>\n");
105 fprintf(outfile, "\n");
106 fprintf(outfile,
107 "static unsigned char raw_data[%lu] __page_aligned_data = {",
108 data_size);
109 for (j = 0; j < load_size; j++) {
110 if (j % 10 == 0)
111 fprintf(outfile, "\n\t");
112 fprintf(outfile, "0x%02X, ", (int)((unsigned char *)addr)[j]);
113 }
114 fprintf(outfile, "\n};\n\n");
115
116 fprintf(outfile, "static struct page *pages[%lu];\n\n",
117 data_size / 4096);
118
119 fprintf(outfile, "const struct vdso_image %s = {\n", name);
120 fprintf(outfile, "\t.data = raw_data,\n");
121 fprintf(outfile, "\t.size = %lu,\n", data_size);
122 fprintf(outfile, "\t.pages = pages,\n");
123 if (alt_sec) {
124 fprintf(outfile, "\t.alt = %lu,\n",
125 (unsigned long)alt_sec->sh_offset);
126 fprintf(outfile, "\t.alt_len = %lu,\n",
127 (unsigned long)alt_sec->sh_size);
128 }
129 for (i = 0; i < NSYMS; i++) {
130 if (syms[i])
131 fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n",
132 required_syms[i], syms[i]);
133 }
134 fprintf(outfile, "};\n");
135
136 return 0;
137}
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 9c78d5b24874..d41460118a28 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 <asm/vdso32.h>
32 33
33#ifdef CONFIG_COMPAT_VDSO 34#ifdef CONFIG_COMPAT_VDSO
34#define VDSO_DEFAULT 0 35#define VDSO_DEFAULT 0
@@ -67,9 +68,6 @@ __setup("vdso32=", vdso32_setup);
67__setup_param("vdso=", vdso_setup, vdso32_setup, 0); 68__setup_param("vdso=", vdso_setup, vdso32_setup, 0);
68#endif 69#endif
69 70
70static struct page **vdso32_pages;
71static unsigned vdso32_size;
72
73#ifdef CONFIG_X86_64 71#ifdef CONFIG_X86_64
74 72
75#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32)) 73#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SYSENTER32))
@@ -82,34 +80,23 @@ static unsigned vdso32_size;
82 80
83#endif /* CONFIG_X86_64 */ 81#endif /* CONFIG_X86_64 */
84 82
83#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
84const struct vdso_image *selected_vdso32;
85#endif
86
85int __init sysenter_setup(void) 87int __init sysenter_setup(void)
86{ 88{
87 char *vdso32_start, *vdso32_end;
88 int npages, i;
89
90#ifdef CONFIG_COMPAT 89#ifdef CONFIG_COMPAT
91 if (vdso32_syscall()) { 90 if (vdso32_syscall())
92 vdso32_start = vdso32_syscall_start; 91 selected_vdso32 = &vdso_image_32_syscall;
93 vdso32_end = vdso32_syscall_end; 92 else
94 vdso32_pages = vdso32_syscall_pages;
95 } else
96#endif 93#endif
97 if (vdso32_sysenter()) { 94 if (vdso32_sysenter())
98 vdso32_start = vdso32_sysenter_start; 95 selected_vdso32 = &vdso_image_32_sysenter;
99 vdso32_end = vdso32_sysenter_end; 96 else
100 vdso32_pages = vdso32_sysenter_pages; 97 selected_vdso32 = &vdso_image_32_int80;
101 } else {
102 vdso32_start = vdso32_int80_start;
103 vdso32_end = vdso32_int80_end;
104 vdso32_pages = vdso32_int80_pages;
105 }
106
107 npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
108 vdso32_size = npages << PAGE_SHIFT;
109 for (i = 0; i < npages; i++)
110 vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
111 98
112 patch_vdso32(vdso32_start, vdso32_size); 99 init_vdso_image(selected_vdso32);
113 100
114 return 0; 101 return 0;
115} 102}
@@ -121,6 +108,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
121 unsigned long addr; 108 unsigned long addr;
122 int ret = 0; 109 int ret = 0;
123 struct vm_area_struct *vma; 110 struct vm_area_struct *vma;
111 unsigned long vdso32_size = selected_vdso32->size;
124 112
125#ifdef CONFIG_X86_X32_ABI 113#ifdef CONFIG_X86_X32_ABI
126 if (test_thread_flag(TIF_X32)) 114 if (test_thread_flag(TIF_X32))
@@ -140,7 +128,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
140 128
141 addr += VDSO_OFFSET(VDSO_PREV_PAGES); 129 addr += VDSO_OFFSET(VDSO_PREV_PAGES);
142 130
143 current->mm->context.vdso = (void *)addr; 131 current->mm->context.vdso = (void __user *)addr;
144 132
145 /* 133 /*
146 * MAYWRITE to allow gdb to COW and set breakpoints 134 * MAYWRITE to allow gdb to COW and set breakpoints
@@ -150,7 +138,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
150 vdso32_size, 138 vdso32_size,
151 VM_READ|VM_EXEC| 139 VM_READ|VM_EXEC|
152 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 140 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
153 vdso32_pages); 141 selected_vdso32->pages);
154 142
155 if (ret) 143 if (ret)
156 goto up_fail; 144 goto up_fail;
@@ -188,8 +176,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
188 } 176 }
189#endif 177#endif
190 178
191 current_thread_info()->sysenter_return = 179 if (selected_vdso32->sym_VDSO32_SYSENTER_RETURN)
192 VDSO32_SYMBOL(addr, SYSENTER_RETURN); 180 current_thread_info()->sysenter_return =
181 current->mm->context.vdso +
182 selected_vdso32->sym_VDSO32_SYSENTER_RETURN;
193 183
194 up_fail: 184 up_fail:
195 if (ret) 185 if (ret)
diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S
deleted file mode 100644
index 018bcd9f97b4..000000000000
--- a/arch/x86/vdso/vdso32.S
+++ /dev/null
@@ -1,9 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")
4
5#ifdef CONFIG_COMPAT
6DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
7#endif
8
9DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S
index aadb8b9994cd..f072095d6427 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/vdso/vdso32/vdso32.lds.S
@@ -38,13 +38,3 @@ VERSION
38 local: *; 38 local: *;
39 }; 39 };
40} 40}
41
42/*
43 * Symbols we define here called VDSO* get their values into vdso32-syms.h.
44 */
45VDSO32_vsyscall = __kernel_vsyscall;
46VDSO32_sigreturn = __kernel_sigreturn;
47VDSO32_rt_sigreturn = __kernel_rt_sigreturn;
48VDSO32_clock_gettime = clock_gettime;
49VDSO32_gettimeofday = gettimeofday;
50VDSO32_time = time;
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
deleted file mode 100644
index f4aa34e7f370..000000000000
--- a/arch/x86/vdso/vdsox32.S
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <asm/vdso.h>
2
3DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 8b790398ed1d..cf217626fb47 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -19,99 +19,31 @@
19#if defined(CONFIG_X86_64) 19#if defined(CONFIG_X86_64)
20unsigned int __read_mostly vdso64_enabled = 1; 20unsigned int __read_mostly vdso64_enabled = 1;
21 21
22DECLARE_VDSO_IMAGE(vdso);
23extern unsigned short vdso_sync_cpuid; 22extern unsigned short vdso_sync_cpuid;
24static unsigned vdso_size;
25
26#ifdef CONFIG_X86_X32_ABI
27DECLARE_VDSO_IMAGE(vdsox32);
28static unsigned vdsox32_size;
29#endif
30#endif 23#endif
31 24
32#if defined(CONFIG_X86_32) || defined(CONFIG_X86_X32_ABI) || \ 25void __init init_vdso_image(const struct vdso_image *image)
33 defined(CONFIG_COMPAT)
34void __init patch_vdso32(void *vdso, size_t len)
35{ 26{
36 Elf32_Ehdr *hdr = vdso;
37 Elf32_Shdr *sechdrs, *alt_sec = 0;
38 char *secstrings;
39 void *alt_data;
40 int i; 27 int i;
28 int npages = (image->size) / PAGE_SIZE;
41 29
42 BUG_ON(len < sizeof(Elf32_Ehdr)); 30 BUG_ON(image->size % PAGE_SIZE != 0);
43 BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0); 31 for (i = 0; i < npages; i++)
44 32 image->pages[i] = virt_to_page(image->data + i*PAGE_SIZE);
45 sechdrs = (void *)hdr + hdr->e_shoff;
46 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
47
48 for (i = 1; i < hdr->e_shnum; i++) {
49 Elf32_Shdr *shdr = &sechdrs[i];
50 if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
51 alt_sec = shdr;
52 goto found;
53 }
54 }
55
56 /* If we get here, it's probably a bug. */
57 pr_warning("patch_vdso32: .altinstructions not found\n");
58 return; /* nothing to patch */
59 33
60found: 34 apply_alternatives((struct alt_instr *)(image->data + image->alt),
61 alt_data = (void *)hdr + alt_sec->sh_offset; 35 (struct alt_instr *)(image->data + image->alt +
62 apply_alternatives(alt_data, alt_data + alt_sec->sh_size); 36 image->alt_len));
63} 37}
64#endif
65
66#if defined(CONFIG_X86_64)
67static void __init patch_vdso64(void *vdso, size_t len)
68{
69 Elf64_Ehdr *hdr = vdso;
70 Elf64_Shdr *sechdrs, *alt_sec = 0;
71 char *secstrings;
72 void *alt_data;
73 int i;
74 38
75 BUG_ON(len < sizeof(Elf64_Ehdr));
76 BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0);
77
78 sechdrs = (void *)hdr + hdr->e_shoff;
79 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
80
81 for (i = 1; i < hdr->e_shnum; i++) {
82 Elf64_Shdr *shdr = &sechdrs[i];
83 if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
84 alt_sec = shdr;
85 goto found;
86 }
87 }
88
89 /* If we get here, it's probably a bug. */
90 pr_warning("patch_vdso64: .altinstructions not found\n");
91 return; /* nothing to patch */
92
93found:
94 alt_data = (void *)hdr + alt_sec->sh_offset;
95 apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
96}
97 39
40#if defined(CONFIG_X86_64)
98static int __init init_vdso(void) 41static int __init init_vdso(void)
99{ 42{
100 int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE; 43 init_vdso_image(&vdso_image_64);
101 int i;
102
103 patch_vdso64(vdso_start, vdso_end - vdso_start);
104
105 vdso_size = npages << PAGE_SHIFT;
106 for (i = 0; i < npages; i++)
107 vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
108 44
109#ifdef CONFIG_X86_X32_ABI 45#ifdef CONFIG_X86_X32_ABI
110 patch_vdso32(vdsox32_start, vdsox32_end - vdsox32_start); 46 init_vdso_image(&vdso_image_x32);
111 npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
112 vdsox32_size = npages << PAGE_SHIFT;
113 for (i = 0; i < npages; i++)
114 vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE);
115#endif 47#endif
116 48
117 return 0; 49 return 0;
@@ -171,7 +103,7 @@ static int setup_additional_pages(struct linux_binprm *bprm,
171 goto up_fail; 103 goto up_fail;
172 } 104 }
173 105
174 current->mm->context.vdso = (void *)addr; 106 current->mm->context.vdso = (void __user *)addr;
175 107
176 ret = install_special_mapping(mm, addr, size, 108 ret = install_special_mapping(mm, addr, size,
177 VM_READ|VM_EXEC| 109 VM_READ|VM_EXEC|
@@ -189,15 +121,15 @@ up_fail:
189 121
190int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 122int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
191{ 123{
192 return setup_additional_pages(bprm, uses_interp, vdso_pages, 124 return setup_additional_pages(bprm, uses_interp, vdso_image_64.pages,
193 vdso_size); 125 vdso_image_64.size);
194} 126}
195 127
196#ifdef CONFIG_X86_X32_ABI 128#ifdef CONFIG_X86_X32_ABI
197int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 129int x32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
198{ 130{
199 return setup_additional_pages(bprm, uses_interp, vdsox32_pages, 131 return setup_additional_pages(bprm, uses_interp, vdso_image_x32.pages,
200 vdsox32_size); 132 vdso_image_x32.size);
201} 133}
202#endif 134#endif
203 135