summaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-10-25 13:36:19 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-25 13:36:19 -0400
commitcaf539cd1087f7c36b9c4df271575e9aee49fde5 (patch)
treeead06508c7fc91d86b0c0d302abd43110f32a056 /arch/sparc
parent44adbac8f7217040be97928cd19998259d9d4418 (diff)
sparc: Fix VDSO build with older binutils.
Older versions of bintutils do not allow symbol math across different segments on sparc: ==================== Assembler messages: 99: Error: operation combines symbols in different segments ==================== This is controlled by whether or not DIFF_EXPR_OK is defined in gas/config/tc-*.h and for sparc this was not the case until mid-2017. So we have to patch between %stick and %tick another way. Do what powerpc does and emit two versions of the relevant functions, one using %tick and one using %stick, and patch the symbols in the dynamic symbol table. Fixes: 2f6c9bf31a0b ("sparc: Improve VDSO instruction patching.") Reported-by: Meelis Roos <mroos@linux.ee> Tested-by: Meelis Roos <mroos@linux.ee> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/vdso.h2
-rw-r--r--arch/sparc/vdso/vclock_gettime.c149
-rw-r--r--arch/sparc/vdso/vdso-layout.lds.S3
-rw-r--r--arch/sparc/vdso/vdso.lds.S2
-rw-r--r--arch/sparc/vdso/vdso2c.h17
-rw-r--r--arch/sparc/vdso/vdso32/vdso32.lds.S2
-rw-r--r--arch/sparc/vdso/vma.c222
7 files changed, 335 insertions, 62 deletions
diff --git a/arch/sparc/include/asm/vdso.h b/arch/sparc/include/asm/vdso.h
index 56836eb01787..59e79d35cd73 100644
--- a/arch/sparc/include/asm/vdso.h
+++ b/arch/sparc/include/asm/vdso.h
@@ -9,8 +9,6 @@ struct vdso_image {
9 void *data; 9 void *data;
10 unsigned long size; /* Always a multiple of PAGE_SIZE */ 10 unsigned long size; /* Always a multiple of PAGE_SIZE */
11 11
12 unsigned long tick_patch, tick_patch_len;
13
14 long sym_vvar_start; /* Negative offset to the vvar area */ 12 long sym_vvar_start; /* Negative offset to the vvar area */
15}; 13};
16 14
diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c
index 7b539ceebe13..55662c3b4513 100644
--- a/arch/sparc/vdso/vclock_gettime.c
+++ b/arch/sparc/vdso/vclock_gettime.c
@@ -90,16 +90,15 @@ notrace static __always_inline u64 vread_tick(void)
90{ 90{
91 u64 ret; 91 u64 ret;
92 92
93 __asm__ __volatile__("1:\n\t" 93 __asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
94 "rd %%tick, %0\n\t" 94 return ret;
95 ".pushsection .tick_patch, \"a\"\n\t" 95}
96 ".word 1b - ., 1f - .\n\t" 96
97 ".popsection\n\t" 97notrace static __always_inline u64 vread_tick_stick(void)
98 ".pushsection .tick_patch_replacement, \"ax\"\n\t" 98{
99 "1:\n\t" 99 u64 ret;
100 "rd %%asr24, %0\n\t" 100
101 ".popsection\n" 101 __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret));
102 : "=r" (ret));
103 return ret; 102 return ret;
104} 103}
105#else 104#else
@@ -107,16 +106,18 @@ notrace static __always_inline u64 vread_tick(void)
107{ 106{
108 register unsigned long long ret asm("o4"); 107 register unsigned long long ret asm("o4");
109 108
110 __asm__ __volatile__("1:\n\t" 109 __asm__ __volatile__("rd %%tick, %L0\n\t"
111 "rd %%tick, %L0\n\t" 110 "srlx %L0, 32, %H0"
112 "srlx %L0, 32, %H0\n\t" 111 : "=r" (ret));
113 ".pushsection .tick_patch, \"a\"\n\t" 112 return ret;
114 ".word 1b - ., 1f - .\n\t" 113}
115 ".popsection\n\t" 114
116 ".pushsection .tick_patch_replacement, \"ax\"\n\t" 115notrace static __always_inline u64 vread_tick_stick(void)
117 "1:\n\t" 116{
118 "rd %%asr24, %L0\n\t" 117 register unsigned long long ret asm("o4");
119 ".popsection\n" 118
119 __asm__ __volatile__("rd %%asr24, %L0\n\t"
120 "srlx %L0, 32, %H0"
120 : "=r" (ret)); 121 : "=r" (ret));
121 return ret; 122 return ret;
122} 123}
@@ -132,6 +133,16 @@ notrace static __always_inline u64 vgetsns(struct vvar_data *vvar)
132 return v * vvar->clock.mult; 133 return v * vvar->clock.mult;
133} 134}
134 135
136notrace static __always_inline u64 vgetsns_stick(struct vvar_data *vvar)
137{
138 u64 v;
139 u64 cycles;
140
141 cycles = vread_tick_stick();
142 v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask;
143 return v * vvar->clock.mult;
144}
145
135notrace static __always_inline int do_realtime(struct vvar_data *vvar, 146notrace static __always_inline int do_realtime(struct vvar_data *vvar,
136 struct timespec *ts) 147 struct timespec *ts)
137{ 148{
@@ -152,6 +163,26 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar,
152 return 0; 163 return 0;
153} 164}
154 165
166notrace static __always_inline int do_realtime_stick(struct vvar_data *vvar,
167 struct timespec *ts)
168{
169 unsigned long seq;
170 u64 ns;
171
172 do {
173 seq = vvar_read_begin(vvar);
174 ts->tv_sec = vvar->wall_time_sec;
175 ns = vvar->wall_time_snsec;
176 ns += vgetsns_stick(vvar);
177 ns >>= vvar->clock.shift;
178 } while (unlikely(vvar_read_retry(vvar, seq)));
179
180 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
181 ts->tv_nsec = ns;
182
183 return 0;
184}
185
155notrace static __always_inline int do_monotonic(struct vvar_data *vvar, 186notrace static __always_inline int do_monotonic(struct vvar_data *vvar,
156 struct timespec *ts) 187 struct timespec *ts)
157{ 188{
@@ -172,6 +203,26 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar,
172 return 0; 203 return 0;
173} 204}
174 205
206notrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar,
207 struct timespec *ts)
208{
209 unsigned long seq;
210 u64 ns;
211
212 do {
213 seq = vvar_read_begin(vvar);
214 ts->tv_sec = vvar->monotonic_time_sec;
215 ns = vvar->monotonic_time_snsec;
216 ns += vgetsns_stick(vvar);
217 ns >>= vvar->clock.shift;
218 } while (unlikely(vvar_read_retry(vvar, seq)));
219
220 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
221 ts->tv_nsec = ns;
222
223 return 0;
224}
225
175notrace static int do_realtime_coarse(struct vvar_data *vvar, 226notrace static int do_realtime_coarse(struct vvar_data *vvar,
176 struct timespec *ts) 227 struct timespec *ts)
177{ 228{
@@ -228,6 +279,31 @@ clock_gettime(clockid_t, struct timespec *)
228 __attribute__((weak, alias("__vdso_clock_gettime"))); 279 __attribute__((weak, alias("__vdso_clock_gettime")));
229 280
230notrace int 281notrace int
282__vdso_clock_gettime_stick(clockid_t clock, struct timespec *ts)
283{
284 struct vvar_data *vvd = get_vvar_data();
285
286 switch (clock) {
287 case CLOCK_REALTIME:
288 if (unlikely(vvd->vclock_mode == VCLOCK_NONE))
289 break;
290 return do_realtime_stick(vvd, ts);
291 case CLOCK_MONOTONIC:
292 if (unlikely(vvd->vclock_mode == VCLOCK_NONE))
293 break;
294 return do_monotonic_stick(vvd, ts);
295 case CLOCK_REALTIME_COARSE:
296 return do_realtime_coarse(vvd, ts);
297 case CLOCK_MONOTONIC_COARSE:
298 return do_monotonic_coarse(vvd, ts);
299 }
300 /*
301 * Unknown clock ID ? Fall back to the syscall.
302 */
303 return vdso_fallback_gettime(clock, ts);
304}
305
306notrace int
231__vdso_gettimeofday(struct timeval *tv, struct timezone *tz) 307__vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
232{ 308{
233 struct vvar_data *vvd = get_vvar_data(); 309 struct vvar_data *vvd = get_vvar_data();
@@ -262,3 +338,36 @@ __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
262int 338int
263gettimeofday(struct timeval *, struct timezone *) 339gettimeofday(struct timeval *, struct timezone *)
264 __attribute__((weak, alias("__vdso_gettimeofday"))); 340 __attribute__((weak, alias("__vdso_gettimeofday")));
341
342notrace int
343__vdso_gettimeofday_stick(struct timeval *tv, struct timezone *tz)
344{
345 struct vvar_data *vvd = get_vvar_data();
346
347 if (likely(vvd->vclock_mode != VCLOCK_NONE)) {
348 if (likely(tv != NULL)) {
349 union tstv_t {
350 struct timespec ts;
351 struct timeval tv;
352 } *tstv = (union tstv_t *) tv;
353 do_realtime_stick(vvd, &tstv->ts);
354 /*
355 * Assign before dividing to ensure that the division is
356 * done in the type of tv_usec, not tv_nsec.
357 *
358 * There cannot be > 1 billion usec in a second:
359 * do_realtime() has already distributed such overflow
360 * into tv_sec. So we can assign it to an int safely.
361 */
362 tstv->tv.tv_usec = tstv->ts.tv_nsec;
363 tstv->tv.tv_usec /= 1000;
364 }
365 if (unlikely(tz != NULL)) {
366 /* Avoid memcpy. Some old compilers fail to inline it */
367 tz->tz_minuteswest = vvd->tz_minuteswest;
368 tz->tz_dsttime = vvd->tz_dsttime;
369 }
370 return 0;
371 }
372 return vdso_fallback_gettimeofday(tv, tz);
373}
diff --git a/arch/sparc/vdso/vdso-layout.lds.S b/arch/sparc/vdso/vdso-layout.lds.S
index ed36d49e1617..d31e57e8a3bb 100644
--- a/arch/sparc/vdso/vdso-layout.lds.S
+++ b/arch/sparc/vdso/vdso-layout.lds.S
@@ -73,9 +73,6 @@ SECTIONS
73 73
74 .text : { *(.text*) } :text =0x90909090, 74 .text : { *(.text*) } :text =0x90909090,
75 75
76 .tick_patch : { *(.tick_patch) } :text
77 .tick_patch_insns : { *(.tick_patch_insns) } :text
78
79 /DISCARD/ : { 76 /DISCARD/ : {
80 *(.discard) 77 *(.discard)
81 *(.discard.*) 78 *(.discard.*)
diff --git a/arch/sparc/vdso/vdso.lds.S b/arch/sparc/vdso/vdso.lds.S
index f3caa29a331c..629ab6900df7 100644
--- a/arch/sparc/vdso/vdso.lds.S
+++ b/arch/sparc/vdso/vdso.lds.S
@@ -18,8 +18,10 @@ VERSION {
18 global: 18 global:
19 clock_gettime; 19 clock_gettime;
20 __vdso_clock_gettime; 20 __vdso_clock_gettime;
21 __vdso_clock_gettime_stick;
21 gettimeofday; 22 gettimeofday;
22 __vdso_gettimeofday; 23 __vdso_gettimeofday;
24 __vdso_gettimeofday_stick;
23 local: *; 25 local: *;
24 }; 26 };
25} 27}
diff --git a/arch/sparc/vdso/vdso2c.h b/arch/sparc/vdso/vdso2c.h
index 4df005cf98c0..60d69acc748f 100644
--- a/arch/sparc/vdso/vdso2c.h
+++ b/arch/sparc/vdso/vdso2c.h
@@ -17,11 +17,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
17 unsigned long mapping_size; 17 unsigned long mapping_size;
18 int i; 18 int i;
19 unsigned long j; 19 unsigned long j;
20 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, 20 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr;
21 *patch_sec = NULL;
22 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; 21 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;
23 ELF(Dyn) *dyn = 0, *dyn_end = 0; 22 ELF(Dyn) *dyn = 0, *dyn_end = 0;
24 const char *secstrings;
25 INT_BITS syms[NSYMS] = {}; 23 INT_BITS syms[NSYMS] = {};
26 24
27 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff)); 25 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff));
@@ -64,18 +62,11 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
64 } 62 }
65 63
66 /* Walk the section table */ 64 /* Walk the section table */
67 secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) +
68 GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx);
69 secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset);
70 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) { 65 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) {
71 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) + 66 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) +
72 GET_BE(&hdr->e_shentsize) * i; 67 GET_BE(&hdr->e_shentsize) * i;
73 if (GET_BE(&sh->sh_type) == SHT_SYMTAB) 68 if (GET_BE(&sh->sh_type) == SHT_SYMTAB)
74 symtab_hdr = sh; 69 symtab_hdr = sh;
75
76 if (!strcmp(secstrings + GET_BE(&sh->sh_name),
77 ".tick_patch"))
78 patch_sec = sh;
79 } 70 }
80 71
81 if (!symtab_hdr) 72 if (!symtab_hdr)
@@ -142,12 +133,6 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
142 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); 133 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name);
143 fprintf(outfile, "\t.data = raw_data,\n"); 134 fprintf(outfile, "\t.data = raw_data,\n");
144 fprintf(outfile, "\t.size = %lu,\n", mapping_size); 135 fprintf(outfile, "\t.size = %lu,\n", mapping_size);
145 if (patch_sec) {
146 fprintf(outfile, "\t.tick_patch = %lu,\n",
147 (unsigned long)GET_BE(&patch_sec->sh_offset));
148 fprintf(outfile, "\t.tick_patch_len = %lu,\n",
149 (unsigned long)GET_BE(&patch_sec->sh_size));
150 }
151 for (i = 0; i < NSYMS; i++) { 136 for (i = 0; i < NSYMS; i++) {
152 if (required_syms[i].export && syms[i]) 137 if (required_syms[i].export && syms[i])
153 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n", 138 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
diff --git a/arch/sparc/vdso/vdso32/vdso32.lds.S b/arch/sparc/vdso/vdso32/vdso32.lds.S
index 53575ee154c4..218930fdff03 100644
--- a/arch/sparc/vdso/vdso32/vdso32.lds.S
+++ b/arch/sparc/vdso/vdso32/vdso32.lds.S
@@ -17,8 +17,10 @@ VERSION {
17 global: 17 global:
18 clock_gettime; 18 clock_gettime;
19 __vdso_clock_gettime; 19 __vdso_clock_gettime;
20 __vdso_clock_gettime_stick;
20 gettimeofday; 21 gettimeofday;
21 __vdso_gettimeofday; 22 __vdso_gettimeofday;
23 __vdso_gettimeofday_stick;
22 local: *; 24 local: *;
23 }; 25 };
24} 26}
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c
index 8874a27d8adc..154fe8adc090 100644
--- a/arch/sparc/vdso/vma.c
+++ b/arch/sparc/vdso/vma.c
@@ -42,24 +42,201 @@ static struct vm_special_mapping vdso_mapping32 = {
42 42
43struct vvar_data *vvar_data; 43struct vvar_data *vvar_data;
44 44
45struct tick_patch_entry { 45struct vdso_elfinfo32 {
46 s32 orig, repl; 46 Elf32_Ehdr *hdr;
47 Elf32_Sym *dynsym;
48 unsigned long dynsymsize;
49 const char *dynstr;
50 unsigned long text;
47}; 51};
48 52
49static void stick_patch(const struct vdso_image *image) 53struct vdso_elfinfo64 {
54 Elf64_Ehdr *hdr;
55 Elf64_Sym *dynsym;
56 unsigned long dynsymsize;
57 const char *dynstr;
58 unsigned long text;
59};
60
61struct vdso_elfinfo {
62 union {
63 struct vdso_elfinfo32 elf32;
64 struct vdso_elfinfo64 elf64;
65 } u;
66};
67
68static void *one_section64(struct vdso_elfinfo64 *e, const char *name,
69 unsigned long *size)
70{
71 const char *snames;
72 Elf64_Shdr *shdrs;
73 unsigned int i;
74
75 shdrs = (void *)e->hdr + e->hdr->e_shoff;
76 snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
77 for (i = 1; i < e->hdr->e_shnum; i++) {
78 if (!strcmp(snames+shdrs[i].sh_name, name)) {
79 if (size)
80 *size = shdrs[i].sh_size;
81 return (void *)e->hdr + shdrs[i].sh_offset;
82 }
83 }
84 return NULL;
85}
86
87static int find_sections64(const struct vdso_image *image, struct vdso_elfinfo *_e)
88{
89 struct vdso_elfinfo64 *e = &_e->u.elf64;
90
91 e->hdr = image->data;
92 e->dynsym = one_section64(e, ".dynsym", &e->dynsymsize);
93 e->dynstr = one_section64(e, ".dynstr", NULL);
94
95 if (!e->dynsym || !e->dynstr) {
96 pr_err("VDSO64: Missing symbol sections.\n");
97 return -ENODEV;
98 }
99 return 0;
100}
101
102static Elf64_Sym *find_sym64(const struct vdso_elfinfo64 *e, const char *name)
103{
104 unsigned int i;
105
106 for (i = 0; i < (e->dynsymsize / sizeof(Elf64_Sym)); i++) {
107 Elf64_Sym *s = &e->dynsym[i];
108 if (s->st_name == 0)
109 continue;
110 if (!strcmp(e->dynstr + s->st_name, name))
111 return s;
112 }
113 return NULL;
114}
115
116static int patchsym64(struct vdso_elfinfo *_e, const char *orig,
117 const char *new)
118{
119 struct vdso_elfinfo64 *e = &_e->u.elf64;
120 Elf64_Sym *osym = find_sym64(e, orig);
121 Elf64_Sym *nsym = find_sym64(e, new);
122
123 if (!nsym || !osym) {
124 pr_err("VDSO64: Missing symbols.\n");
125 return -ENODEV;
126 }
127 osym->st_value = nsym->st_value;
128 osym->st_size = nsym->st_size;
129 osym->st_info = nsym->st_info;
130 osym->st_other = nsym->st_other;
131 osym->st_shndx = nsym->st_shndx;
132
133 return 0;
134}
135
136static void *one_section32(struct vdso_elfinfo32 *e, const char *name,
137 unsigned long *size)
138{
139 const char *snames;
140 Elf32_Shdr *shdrs;
141 unsigned int i;
142
143 shdrs = (void *)e->hdr + e->hdr->e_shoff;
144 snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
145 for (i = 1; i < e->hdr->e_shnum; i++) {
146 if (!strcmp(snames+shdrs[i].sh_name, name)) {
147 if (size)
148 *size = shdrs[i].sh_size;
149 return (void *)e->hdr + shdrs[i].sh_offset;
150 }
151 }
152 return NULL;
153}
154
155static int find_sections32(const struct vdso_image *image, struct vdso_elfinfo *_e)
156{
157 struct vdso_elfinfo32 *e = &_e->u.elf32;
158
159 e->hdr = image->data;
160 e->dynsym = one_section32(e, ".dynsym", &e->dynsymsize);
161 e->dynstr = one_section32(e, ".dynstr", NULL);
162
163 if (!e->dynsym || !e->dynstr) {
164 pr_err("VDSO32: Missing symbol sections.\n");
165 return -ENODEV;
166 }
167 return 0;
168}
169
170static Elf32_Sym *find_sym32(const struct vdso_elfinfo32 *e, const char *name)
50{ 171{
51 struct tick_patch_entry *p, *p_end; 172 unsigned int i;
173
174 for (i = 0; i < (e->dynsymsize / sizeof(Elf32_Sym)); i++) {
175 Elf32_Sym *s = &e->dynsym[i];
176 if (s->st_name == 0)
177 continue;
178 if (!strcmp(e->dynstr + s->st_name, name))
179 return s;
180 }
181 return NULL;
182}
52 183
53 p = image->data + image->tick_patch; 184static int patchsym32(struct vdso_elfinfo *_e, const char *orig,
54 p_end = (void *)p + image->tick_patch_len; 185 const char *new)
55 while (p < p_end) { 186{
56 u32 *instr = (void *)&p->orig + p->orig; 187 struct vdso_elfinfo32 *e = &_e->u.elf32;
57 u32 *repl = (void *)&p->repl + p->repl; 188 Elf32_Sym *osym = find_sym32(e, orig);
189 Elf32_Sym *nsym = find_sym32(e, new);
58 190
59 *instr = *repl; 191 if (!nsym || !osym) {
60 flushi(instr); 192 pr_err("VDSO32: Missing symbols.\n");
61 p++; 193 return -ENODEV;
62 } 194 }
195 osym->st_value = nsym->st_value;
196 osym->st_size = nsym->st_size;
197 osym->st_info = nsym->st_info;
198 osym->st_other = nsym->st_other;
199 osym->st_shndx = nsym->st_shndx;
200
201 return 0;
202}
203
204static int find_sections(const struct vdso_image *image, struct vdso_elfinfo *e,
205 bool elf64)
206{
207 if (elf64)
208 return find_sections64(image, e);
209 else
210 return find_sections32(image, e);
211}
212
213static int patch_one_symbol(struct vdso_elfinfo *e, const char *orig,
214 const char *new_target, bool elf64)
215{
216 if (elf64)
217 return patchsym64(e, orig, new_target);
218 else
219 return patchsym32(e, orig, new_target);
220}
221
222static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, bool elf64)
223{
224 int err;
225
226 err = find_sections(image, e, elf64);
227 if (err)
228 return err;
229
230 err = patch_one_symbol(e,
231 "__vdso_gettimeofday",
232 "__vdso_gettimeofday_stick", elf64);
233 if (err)
234 return err;
235
236 return patch_one_symbol(e,
237 "__vdso_clock_gettime",
238 "__vdso_clock_gettime_stick", elf64);
239 return 0;
63} 240}
64 241
65/* 242/*
@@ -67,13 +244,19 @@ static void stick_patch(const struct vdso_image *image)
67 * kernel image. 244 * kernel image.
68 */ 245 */
69int __init init_vdso_image(const struct vdso_image *image, 246int __init init_vdso_image(const struct vdso_image *image,
70 struct vm_special_mapping *vdso_mapping) 247 struct vm_special_mapping *vdso_mapping, bool elf64)
71{ 248{
72 int i; 249 int cnpages = (image->size) / PAGE_SIZE;
73 struct page *dp, **dpp = NULL; 250 struct page *dp, **dpp = NULL;
74 int dnpages = 0;
75 struct page *cp, **cpp = NULL; 251 struct page *cp, **cpp = NULL;
76 int cnpages = (image->size) / PAGE_SIZE; 252 struct vdso_elfinfo ei;
253 int i, dnpages = 0;
254
255 if (tlb_type != spitfire) {
256 int err = stick_patch(image, &ei, elf64);
257 if (err)
258 return err;
259 }
77 260
78 /* 261 /*
79 * First, the vdso text. This is initialied data, an integral number of 262 * First, the vdso text. This is initialied data, an integral number of
@@ -88,9 +271,6 @@ int __init init_vdso_image(const struct vdso_image *image,
88 if (!cpp) 271 if (!cpp)
89 goto oom; 272 goto oom;
90 273
91 if (tlb_type != spitfire)
92 stick_patch(image);
93
94 for (i = 0; i < cnpages; i++) { 274 for (i = 0; i < cnpages; i++) {
95 cp = alloc_page(GFP_KERNEL); 275 cp = alloc_page(GFP_KERNEL);
96 if (!cp) 276 if (!cp)
@@ -153,13 +333,13 @@ static int __init init_vdso(void)
153{ 333{
154 int err = 0; 334 int err = 0;
155#ifdef CONFIG_SPARC64 335#ifdef CONFIG_SPARC64
156 err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64); 336 err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64, true);
157 if (err) 337 if (err)
158 return err; 338 return err;
159#endif 339#endif
160 340
161#ifdef CONFIG_COMPAT 341#ifdef CONFIG_COMPAT
162 err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32); 342 err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32, false);
163#endif 343#endif
164 return err; 344 return err;
165 345