Pull sparc fix from David Miller: "Build regression fix" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc: Fix VDSO build with older binutils.
Unified · Split
| @@ -9,8 +9,6 @@ struct vdso_image { · 8 unmodified lines | ||
| 9 | 9 | void *data; |
| 10 | 10 | unsigned long size; /* Always a multiple of PAGE_SIZE */ |
| 11 | 11 | |
| 12 | − unsigned long tick_patch, tick_patch_len; | |
| 13 | − | |
| 14 | 12 | long sym_vvar_start; /* Negative offset to the vvar area */ |
| 15 | 13 | }; |
| 16 | 14 | |
| @@ -90,16 +90,15 @@ notrace static __always_inline u64 vread_tick(void) · 89 unmodified lines | ||
| 90 | 90 | { |
| 91 | 91 | u64 ret; |
| 92 | 92 | |
| 93 | − __asm__ __volatile__("1:\n\t" | |
| 94 | − "rd %%tick, %0\n\t" | |
| 95 | − ".pushsection .tick_patch, \"a\"\n\t" | |
| 96 | − ".word 1b - ., 1f - .\n\t" | |
| 97 | − ".popsection\n\t" | |
| 98 | − ".pushsection .tick_patch_replacement, \"ax\"\n\t" | |
| 99 | − "1:\n\t" | |
| 100 | − "rd %%asr24, %0\n\t" | |
| 101 | − ".popsection\n" | |
| 102 | − : "=r" (ret)); | |
| 93 | + __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); | |
| 94 | + return ret; | |
| 95 | +} | |
| 96 | + | |
| 97 | +notrace static __always_inline u64 vread_tick_stick(void) | |
| 98 | +{ | |
| 99 | + u64 ret; | |
| 100 | + | |
| 101 | + __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret)); | |
| 103 | 102 | return ret; |
| 104 | 103 | } |
| 105 | 104 | #else |
| @@ -107,16 +106,18 @@ notrace static __always_inline u64 vread_tick(void) · 1 unmodified line | ||
| 107 | 106 | { |
| 108 | 107 | register unsigned long long ret asm("o4"); |
| 109 | 108 | |
| 110 | − __asm__ __volatile__("1:\n\t" | |
| 111 | − "rd %%tick, %L0\n\t" | |
| 112 | − "srlx %L0, 32, %H0\n\t" | |
| 113 | − ".pushsection .tick_patch, \"a\"\n\t" | |
| 114 | − ".word 1b - ., 1f - .\n\t" | |
| 115 | − ".popsection\n\t" | |
| 116 | − ".pushsection .tick_patch_replacement, \"ax\"\n\t" | |
| 117 | − "1:\n\t" | |
| 118 | − "rd %%asr24, %L0\n\t" | |
| 119 | − ".popsection\n" | |
| 109 | + __asm__ __volatile__("rd %%tick, %L0\n\t" | |
| 110 | + "srlx %L0, 32, %H0" | |
| 111 | + : "=r" (ret)); | |
| 112 | + return ret; | |
| 113 | +} | |
| 114 | + | |
| 115 | +notrace static __always_inline u64 vread_tick_stick(void) | |
| 116 | +{ | |
| 117 | + register unsigned long long ret asm("o4"); | |
| 118 | + | |
| 119 | + __asm__ __volatile__("rd %%asr24, %L0\n\t" | |
| 120 | + "srlx %L0, 32, %H0" | |
| 120 | 121 | : "=r" (ret)); |
| 121 | 122 | return ret; |
| 122 | 123 | } |
| @@ -132,6 +133,16 @@ notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) · 9 unmodified lines | ||
| 132 | 133 | return v * vvar->clock.mult; |
| 133 | 134 | } |
| 134 | 135 | |
| 136 | +notrace 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 | + | |
| 135 | 146 | notrace static __always_inline int do_realtime(struct vvar_data *vvar, |
| 136 | 147 | struct timespec *ts) |
| 137 | 148 | { |
| @@ -152,6 +163,26 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar, · 14 unmodified lines | ||
| 152 | 163 | return 0; |
| 153 | 164 | } |
| 154 | 165 | |
| 166 | +notrace 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 | + | |
| 155 | 186 | notrace static __always_inline int do_monotonic(struct vvar_data *vvar, |
| 156 | 187 | struct timespec *ts) |
| 157 | 188 | { |
| @@ -172,6 +203,26 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar, · 14 unmodified lines | ||
| 172 | 203 | return 0; |
| 173 | 204 | } |
| 174 | 205 | |
| 206 | +notrace 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 | + | |
| 175 | 226 | notrace static int do_realtime_coarse(struct vvar_data *vvar, |
| 176 | 227 | struct timespec *ts) |
| 177 | 228 | { |
| @@ -227,6 +278,31 @@ int · 49 unmodified lines | ||
| 227 | 278 | clock_gettime(clockid_t, struct timespec *) |
| 228 | 279 | __attribute__((weak, alias("__vdso_clock_gettime"))); |
| 229 | 280 | |
| 281 | +notrace 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 | + | |
| 230 | 306 | notrace int |
| 231 | 307 | __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) |
| 232 | 308 | { |
| @@ -262,3 +338,36 @@ __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) · 29 unmodified lines | ||
| 262 | 338 | int |
| 263 | 339 | gettimeofday(struct timeval *, struct timezone *) |
| 264 | 340 | __attribute__((weak, alias("__vdso_gettimeofday"))); |
| 341 | + | |
| 342 | +notrace 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 | +} | |
| @@ -73,9 +73,6 @@ SECTIONS · 72 unmodified lines | ||
| 73 | 73 | |
| 74 | 74 | .text : { *(.text*) } :text =0x90909090, |
| 75 | 75 | |
| 76 | − .tick_patch : { *(.tick_patch) } :text | |
| 77 | − .tick_patch_insns : { *(.tick_patch_insns) } :text | |
| 78 | − | |
| 79 | 76 | /DISCARD/ : { |
| 80 | 77 | *(.discard) |
| 81 | 78 | *(.discard.*) |
| @@ -18,8 +18,10 @@ VERSION { · 17 unmodified lines | ||
| 18 | 18 | global: |
| 19 | 19 | clock_gettime; |
| 20 | 20 | __vdso_clock_gettime; |
| 21 | + __vdso_clock_gettime_stick; | |
| 21 | 22 | gettimeofday; |
| 22 | 23 | __vdso_gettimeofday; |
| 24 | + __vdso_gettimeofday_stick; | |
| 23 | 25 | local: *; |
| 24 | 26 | }; |
| 25 | 27 | } |
| @@ -17,11 +17,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, · 16 unmodified lines | ||
| 17 | 17 | unsigned long mapping_size; |
| 18 | 18 | int i; |
| 19 | 19 | unsigned long j; |
| 20 | − ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, | |
| 21 | − *patch_sec = NULL; | |
| 20 | + ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr; | |
| 22 | 21 | ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; |
| 23 | 22 | ELF(Dyn) *dyn = 0, *dyn_end = 0; |
| 24 | − const char *secstrings; | |
| 25 | 23 | INT_BITS syms[NSYMS] = {}; |
| 26 | 24 | |
| 27 | 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, · 36 unmodified lines | ||
| 64 | 62 | } |
| 65 | 63 | |
| 66 | 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 | 65 | for (i = 0; i < GET_BE(&hdr->e_shnum); i++) { |
| 71 | 66 | ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) + |
| 72 | 67 | GET_BE(&hdr->e_shentsize) * i; |
| 73 | 68 | if (GET_BE(&sh->sh_type) == SHT_SYMTAB) |
| 74 | 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 | 72 | if (!symtab_hdr) |
| @@ -142,12 +133,6 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, · 60 unmodified lines | ||
| 142 | 133 | fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); |
| 143 | 134 | fprintf(outfile, "\t.data = raw_data,\n"); |
| 144 | 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 | 136 | for (i = 0; i < NSYMS; i++) { |
| 152 | 137 | if (required_syms[i].export && syms[i]) |
| 153 | 138 | fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n", |
| @@ -17,8 +17,10 @@ VERSION { · 16 unmodified lines | ||
| 17 | 17 | global: |
| 18 | 18 | clock_gettime; |
| 19 | 19 | __vdso_clock_gettime; |
| 20 | + __vdso_clock_gettime_stick; | |
| 20 | 21 | gettimeofday; |
| 21 | 22 | __vdso_gettimeofday; |
| 23 | + __vdso_gettimeofday_stick; | |
| 22 | 24 | local: *; |
| 23 | 25 | }; |
| 24 | 26 | } |
| @@ -42,24 +42,201 @@ static struct vm_special_mapping vdso_mapping32 = { · 41 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | struct vvar_data *vvar_data; |
| 44 | 44 | |
| 45 | −struct tick_patch_entry { | |
| 46 | − s32 orig, repl; | |
| 45 | +struct vdso_elfinfo32 { | |
| 46 | + Elf32_Ehdr *hdr; | |
| 47 | + Elf32_Sym *dynsym; | |
| 48 | + unsigned long dynsymsize; | |
| 49 | + const char *dynstr; | |
| 50 | + unsigned long text; | |
| 47 | 51 | }; |
| 48 | 52 | |
| 49 | −static void stick_patch(const struct vdso_image *image) | |
| 53 | +struct vdso_elfinfo64 { | |
| 54 | + Elf64_Ehdr *hdr; | |
| 55 | + Elf64_Sym *dynsym; | |
| 56 | + unsigned long dynsymsize; | |
| 57 | + const char *dynstr; | |
| 58 | + unsigned long text; | |
| 59 | +}; | |
| 60 | + | |
| 61 | +struct vdso_elfinfo { | |
| 62 | + union { | |
| 63 | + struct vdso_elfinfo32 elf32; | |
| 64 | + struct vdso_elfinfo64 elf64; | |
| 65 | + } u; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +static 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 | + | |
| 87 | +static 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 | + | |
| 102 | +static 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 | + | |
| 116 | +static 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 | + | |
| 136 | +static 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 | + | |
| 155 | +static 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 | + | |
| 170 | +static 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; | |
| 54 | − p_end = (void *)p + image->tick_patch_len; | |
| 55 | − while (p < p_end) { | |
| 56 | − u32 *instr = (void *)&p->orig + p->orig; | |
| 57 | − u32 *repl = (void *)&p->repl + p->repl; | |
| 184 | +static int patchsym32(struct vdso_elfinfo *_e, const char *orig, | |
| 185 | + const char *new) | |
| 186 | +{ | |
| 187 | + struct vdso_elfinfo32 *e = &_e->u.elf32; | |
| 188 | + Elf32_Sym *osym = find_sym32(e, orig); | |
| 189 | + Elf32_Sym *nsym = find_sym32(e, new); | |
| 58 | 190 | |
| 59 | − *instr = *repl; | |
| 60 | − flushi(instr); | |
| 61 | − p++; | |
| 191 | + if (!nsym || !osym) { | |
| 192 | + pr_err("VDSO32: Missing symbols.\n"); | |
| 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 | + | |
| 204 | +static 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 | + | |
| 213 | +static 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 | + | |
| 222 | +static 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) · 1 unmodified line | ||
| 67 | 244 | * kernel image. |
| 68 | 245 | */ |
| 69 | 246 | int __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 | 250 | struct page *dp, **dpp = NULL; |
| 74 | − int dnpages = 0; | |
| 75 | 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 | 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, · 8 unmodified lines | ||
| 88 | 271 | if (!cpp) |
| 89 | 272 | goto oom; |
| 90 | 273 | |
| 91 | − if (tlb_type != spitfire) | |
| 92 | − stick_patch(image); | |
| 93 | − | |
| 94 | 274 | for (i = 0; i < cnpages; i++) { |
| 95 | 275 | cp = alloc_page(GFP_KERNEL); |
| 96 | 276 | if (!cp) |
| @@ -153,13 +333,13 @@ static int __init init_vdso(void) · 56 unmodified lines | ||
| 153 | 333 | { |
| 154 | 334 | int err = 0; |
| 155 | 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 | 337 | if (err) |
| 158 | 338 | return err; |
| 159 | 339 | #endif |
| 160 | 340 | |
| 161 | 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 | 343 | #endif |
| 164 | 344 | return err; |
| 165 | 345 | |