| 62 | | return vmalloc(size); |
|---|
| | 102 | |
|---|
| | 103 | ptr = alloc_phys(size); |
|---|
| | 104 | if (ptr) |
|---|
| | 105 | return ptr; |
|---|
| | 106 | |
|---|
| | 107 | /* try to allocate contiguos chunk of memory not spanning 256Mb |
|---|
| | 108 | range, so all jump instructions can work */ |
|---|
| | 109 | addr = VMALLOC_START; |
|---|
| | 110 | while (addr < VMALLOC_END) { |
|---|
| | 111 | unsigned end = ALIGN(addr + 1, 1u << 28); |
|---|
| | 112 | |
|---|
| | 113 | if (addr + size <= end) { |
|---|
| | 114 | struct vm_struct *area |
|---|
| | 115 | = __get_vm_area(size, VM_ALLOC, addr, end); |
|---|
| | 116 | |
|---|
| | 117 | if (area) |
|---|
| | 118 | return __vmalloc_area( |
|---|
| | 119 | area, GFP_KERNEL, PAGE_KERNEL); |
|---|
| | 120 | } |
|---|
| | 121 | addr = end; |
|---|
| | 122 | } |
|---|
| | 123 | return NULL; |
|---|
| | 157 | /* Get the potential trampolines size required of the init and |
|---|
| | 158 | non-init sections */ |
|---|
| | 159 | static unsigned get_plt_size(const Elf32_Ehdr *hdr, |
|---|
| | 160 | const Elf32_Shdr *sechdrs, |
|---|
| | 161 | const char *secstrings, |
|---|
| | 162 | unsigned symindex, |
|---|
| | 163 | int is_init) |
|---|
| | 164 | { |
|---|
| | 165 | unsigned long ret = 0; |
|---|
| | 166 | unsigned i, j; |
|---|
| | 167 | Elf_Sym *syms; |
|---|
| | 168 | |
|---|
| | 169 | /* Everything marked ALLOC (this includes the exported symbols) */ |
|---|
| | 170 | for (i = 1; i < hdr->e_shnum; ++i) { |
|---|
| | 171 | unsigned int info = sechdrs[i].sh_info; |
|---|
| | 172 | |
|---|
| | 173 | if (sechdrs[i].sh_type != SHT_REL |
|---|
| | 174 | && sechdrs[i].sh_type != SHT_RELA) |
|---|
| | 175 | continue; |
|---|
| | 176 | |
|---|
| | 177 | /* Not a valid relocation section? */ |
|---|
| | 178 | if (info >= hdr->e_shnum) |
|---|
| | 179 | continue; |
|---|
| | 180 | |
|---|
| | 181 | /* Don't bother with non-allocated sections */ |
|---|
| | 182 | if (!(sechdrs[info].sh_flags & SHF_ALLOC)) |
|---|
| | 183 | continue; |
|---|
| | 184 | |
|---|
| | 185 | /* If it's called *.init*, and we're not init, we're |
|---|
| | 186 | not interested */ |
|---|
| | 187 | if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) |
|---|
| | 188 | != is_init) |
|---|
| | 189 | continue; |
|---|
| | 190 | |
|---|
| | 191 | syms = (Elf_Sym *) sechdrs[symindex].sh_addr; |
|---|
| | 192 | if (sechdrs[i].sh_type == SHT_REL) { |
|---|
| | 193 | Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; |
|---|
| | 194 | unsigned size = sechdrs[i].sh_size / sizeof(*rel); |
|---|
| | 195 | |
|---|
| | 196 | for (j = 0; j < size; ++j) { |
|---|
| | 197 | Elf_Sym *sym; |
|---|
| | 198 | |
|---|
| | 199 | if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) |
|---|
| | 200 | continue; |
|---|
| | 201 | sym = syms + ELF_MIPS_R_SYM(rel[j]); |
|---|
| | 202 | if (!is_init && sym->st_shndx != SHN_UNDEF) |
|---|
| | 203 | continue; |
|---|
| | 204 | |
|---|
| | 205 | ret += sizeof(unsigned[4]); |
|---|
| | 206 | } |
|---|
| | 207 | } else { |
|---|
| | 208 | Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; |
|---|
| | 209 | unsigned size = sechdrs[i].sh_size / sizeof(*rela); |
|---|
| | 210 | |
|---|
| | 211 | for (j = 0; j < size; ++j) { |
|---|
| | 212 | Elf_Sym *sym; |
|---|
| | 213 | |
|---|
| | 214 | if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) |
|---|
| | 215 | continue; |
|---|
| | 216 | sym = syms + ELF_MIPS_R_SYM(rela[j]); |
|---|
| | 217 | if (!is_init && sym->st_shndx != SHN_UNDEF) |
|---|
| | 218 | continue; |
|---|
| | 219 | |
|---|
| | 220 | ret += sizeof(unsigned[4]); |
|---|
| | 221 | } |
|---|
| | 222 | } |
|---|
| | 223 | |
|---|
| | 224 | } |
|---|
| | 225 | |
|---|
| | 226 | return ret; |
|---|
| | 227 | } |
|---|
| | 228 | |
|---|
| | 229 | int module_relayout(Elf32_Ehdr *hdr, |
|---|
| | 230 | Elf32_Shdr *sechdrs, |
|---|
| | 231 | char *secstrings, |
|---|
| | 232 | unsigned symindex, |
|---|
| | 233 | struct module *me) |
|---|
| | 234 | { |
|---|
| | 235 | unsigned core_plt_size = get_plt_size( |
|---|
| | 236 | hdr, sechdrs, secstrings, symindex, 0); |
|---|
| | 237 | unsigned init_plt_size = get_plt_size( |
|---|
| | 238 | hdr, sechdrs, secstrings, symindex, 1); |
|---|
| | 239 | |
|---|
| | 240 | if (core_plt_size > 0) |
|---|
| | 241 | me->core_size = PAGE_ALIGN(me->core_size); |
|---|
| | 242 | me->arch.core_plt_offset = me->core_size; |
|---|
| | 243 | me->core_size = me->core_size + core_plt_size; |
|---|
| | 244 | |
|---|
| | 245 | me->arch.init_plt_offset = me->init_size; |
|---|
| | 246 | me->init_size = me->init_size + init_plt_size; |
|---|
| | 247 | |
|---|
| | 248 | return 0; |
|---|
| | 249 | } |
|---|
| | 250 | |
|---|
| | 267 | return 0; |
|---|
| | 268 | } |
|---|
| | 269 | |
|---|
| | 270 | static Elf_Addr add_plt_entry_to(unsigned *plt_offset, |
|---|
| | 271 | void *start, unsigned size, Elf_Addr v) |
|---|
| | 272 | { |
|---|
| | 273 | unsigned *tramp = start + *plt_offset; |
|---|
| | 274 | if (*plt_offset == size) return 0; |
|---|
| | 275 | |
|---|
| | 276 | *plt_offset += sizeof(unsigned[4]); |
|---|
| | 277 | |
|---|
| | 278 | /* adjust carry for addiu */ |
|---|
| | 279 | if (v & 0x00008000) |
|---|
| | 280 | v += 0x10000; |
|---|
| | 281 | |
|---|
| | 282 | tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ |
|---|
| | 283 | tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ |
|---|
| | 284 | tramp[2] = 0x03200008; /* jr t9 */ |
|---|
| | 285 | tramp[3] = 0x00000000; /* nop */ |
|---|
| | 286 | |
|---|
| | 287 | return (Elf_Addr) tramp; |
|---|
| | 288 | } |
|---|
| | 289 | |
|---|
| | 290 | static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) |
|---|
| | 291 | { |
|---|
| | 292 | if (location >= me->module_core |
|---|
| | 293 | && location < me->module_core + me->core_size) { |
|---|
| | 294 | return add_plt_entry_to(&me->arch.core_plt_offset, |
|---|
| | 295 | me->module_core, me->core_size, v); |
|---|
| | 296 | } else if (location > me->module_init |
|---|
| | 297 | && location < me->module_init + me->init_size) { |
|---|
| | 298 | return add_plt_entry_to(&me->arch.init_plt_offset, |
|---|
| | 299 | me->module_init, me->init_size, v); |
|---|
| | 300 | } else { |
|---|
| | 301 | printk(KERN_ERR "module %s: " |
|---|
| | 302 | "relocation to unknown segment %u\n", |
|---|
| | 303 | me->name, v); |
|---|
| | 304 | } |
|---|