diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/kernel/module.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/kernel/module.c')
-rw-r--r-- | arch/arm/kernel/module.c | 187 |
1 files changed, 108 insertions, 79 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 6b4605893f1e..016d6a0830a3 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
25 | #include <asm/smp_plat.h> | ||
25 | #include <asm/unwind.h> | 26 | #include <asm/unwind.h> |
26 | 27 | ||
27 | #ifdef CONFIG_XIP_KERNEL | 28 | #ifdef CONFIG_XIP_KERNEL |
@@ -38,17 +39,9 @@ | |||
38 | #ifdef CONFIG_MMU | 39 | #ifdef CONFIG_MMU |
39 | void *module_alloc(unsigned long size) | 40 | void *module_alloc(unsigned long size) |
40 | { | 41 | { |
41 | struct vm_struct *area; | 42 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, |
42 | 43 | GFP_KERNEL, PAGE_KERNEL_EXEC, -1, | |
43 | size = PAGE_ALIGN(size); | 44 | __builtin_return_address(0)); |
44 | if (!size) | ||
45 | return NULL; | ||
46 | |||
47 | area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); | ||
48 | if (!area) | ||
49 | return NULL; | ||
50 | |||
51 | return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); | ||
52 | } | 45 | } |
53 | #else /* CONFIG_MMU */ | 46 | #else /* CONFIG_MMU */ |
54 | void *module_alloc(unsigned long size) | 47 | void *module_alloc(unsigned long size) |
@@ -67,24 +60,6 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, | |||
67 | char *secstrings, | 60 | char *secstrings, |
68 | struct module *mod) | 61 | struct module *mod) |
69 | { | 62 | { |
70 | #ifdef CONFIG_ARM_UNWIND | ||
71 | Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; | ||
72 | |||
73 | for (s = sechdrs; s < sechdrs_end; s++) { | ||
74 | if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0) | ||
75 | mod->arch.unw_sec_init = s; | ||
76 | else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0) | ||
77 | mod->arch.unw_sec_devinit = s; | ||
78 | else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0) | ||
79 | mod->arch.unw_sec_core = s; | ||
80 | else if (strcmp(".init.text", secstrings + s->sh_name) == 0) | ||
81 | mod->arch.sec_init_text = s; | ||
82 | else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0) | ||
83 | mod->arch.sec_devinit_text = s; | ||
84 | else if (strcmp(".text", secstrings + s->sh_name) == 0) | ||
85 | mod->arch.sec_core_text = s; | ||
86 | } | ||
87 | #endif | ||
88 | return 0; | 63 | return 0; |
89 | } | 64 | } |
90 | 65 | ||
@@ -101,6 +76,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
101 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { | 76 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { |
102 | unsigned long loc; | 77 | unsigned long loc; |
103 | Elf32_Sym *sym; | 78 | Elf32_Sym *sym; |
79 | const char *symname; | ||
104 | s32 offset; | 80 | s32 offset; |
105 | #ifdef CONFIG_THUMB2_KERNEL | 81 | #ifdef CONFIG_THUMB2_KERNEL |
106 | u32 upper, lower, sign, j1, j2; | 82 | u32 upper, lower, sign, j1, j2; |
@@ -108,18 +84,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
108 | 84 | ||
109 | offset = ELF32_R_SYM(rel->r_info); | 85 | offset = ELF32_R_SYM(rel->r_info); |
110 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { | 86 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { |
111 | printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n", | 87 | pr_err("%s: section %u reloc %u: bad relocation sym offset\n", |
112 | module->name, relindex, i); | 88 | module->name, relindex, i); |
113 | return -ENOEXEC; | 89 | return -ENOEXEC; |
114 | } | 90 | } |
115 | 91 | ||
116 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; | 92 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; |
93 | symname = strtab + sym->st_name; | ||
117 | 94 | ||
118 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { | 95 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { |
119 | printk(KERN_ERR "%s: out of bounds relocation, " | 96 | pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n", |
120 | "section %d reloc %d offset %d size %d\n", | 97 | module->name, relindex, i, symname, |
121 | module->name, relindex, i, rel->r_offset, | 98 | rel->r_offset, dstsec->sh_size); |
122 | dstsec->sh_size); | ||
123 | return -ENOEXEC; | 99 | return -ENOEXEC; |
124 | } | 100 | } |
125 | 101 | ||
@@ -145,10 +121,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
145 | if (offset & 3 || | 121 | if (offset & 3 || |
146 | offset <= (s32)0xfe000000 || | 122 | offset <= (s32)0xfe000000 || |
147 | offset >= (s32)0x02000000) { | 123 | offset >= (s32)0x02000000) { |
148 | printk(KERN_ERR | 124 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
149 | "%s: relocation out of range, section " | 125 | module->name, relindex, i, symname, |
150 | "%d reloc %d sym '%s'\n", module->name, | 126 | ELF32_R_TYPE(rel->r_info), loc, |
151 | relindex, i, strtab + sym->st_name); | 127 | sym->st_value); |
152 | return -ENOEXEC; | 128 | return -ENOEXEC; |
153 | } | 129 | } |
154 | 130 | ||
@@ -217,14 +193,23 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
217 | offset -= 0x02000000; | 193 | offset -= 0x02000000; |
218 | offset += sym->st_value - loc; | 194 | offset += sym->st_value - loc; |
219 | 195 | ||
220 | /* only Thumb addresses allowed (no interworking) */ | 196 | /* |
221 | if (!(offset & 1) || | 197 | * For function symbols, only Thumb addresses are |
198 | * allowed (no interworking). | ||
199 | * | ||
200 | * For non-function symbols, the destination | ||
201 | * has no specific ARM/Thumb disposition, so | ||
202 | * the branch is resolved under the assumption | ||
203 | * that interworking is not required. | ||
204 | */ | ||
205 | if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC && | ||
206 | !(offset & 1)) || | ||
222 | offset <= (s32)0xff000000 || | 207 | offset <= (s32)0xff000000 || |
223 | offset >= (s32)0x01000000) { | 208 | offset >= (s32)0x01000000) { |
224 | printk(KERN_ERR | 209 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
225 | "%s: relocation out of range, section " | 210 | module->name, relindex, i, symname, |
226 | "%d reloc %d sym '%s'\n", module->name, | 211 | ELF32_R_TYPE(rel->r_info), loc, |
227 | relindex, i, strtab + sym->st_name); | 212 | sym->st_value); |
228 | return -ENOEXEC; | 213 | return -ENOEXEC; |
229 | } | 214 | } |
230 | 215 | ||
@@ -289,50 +274,94 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, | |||
289 | return -ENOEXEC; | 274 | return -ENOEXEC; |
290 | } | 275 | } |
291 | 276 | ||
292 | #ifdef CONFIG_ARM_UNWIND | 277 | struct mod_unwind_map { |
293 | static void register_unwind_tables(struct module *mod) | 278 | const Elf_Shdr *unw_sec; |
294 | { | 279 | const Elf_Shdr *txt_sec; |
295 | if (mod->arch.unw_sec_init && mod->arch.sec_init_text) | 280 | }; |
296 | mod->arch.unwind_init = | ||
297 | unwind_table_add(mod->arch.unw_sec_init->sh_addr, | ||
298 | mod->arch.unw_sec_init->sh_size, | ||
299 | mod->arch.sec_init_text->sh_addr, | ||
300 | mod->arch.sec_init_text->sh_size); | ||
301 | if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text) | ||
302 | mod->arch.unwind_devinit = | ||
303 | unwind_table_add(mod->arch.unw_sec_devinit->sh_addr, | ||
304 | mod->arch.unw_sec_devinit->sh_size, | ||
305 | mod->arch.sec_devinit_text->sh_addr, | ||
306 | mod->arch.sec_devinit_text->sh_size); | ||
307 | if (mod->arch.unw_sec_core && mod->arch.sec_core_text) | ||
308 | mod->arch.unwind_core = | ||
309 | unwind_table_add(mod->arch.unw_sec_core->sh_addr, | ||
310 | mod->arch.unw_sec_core->sh_size, | ||
311 | mod->arch.sec_core_text->sh_addr, | ||
312 | mod->arch.sec_core_text->sh_size); | ||
313 | } | ||
314 | 281 | ||
315 | static void unregister_unwind_tables(struct module *mod) | 282 | static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, |
283 | const Elf_Shdr *sechdrs, const char *name) | ||
316 | { | 284 | { |
317 | unwind_table_del(mod->arch.unwind_init); | 285 | const Elf_Shdr *s, *se; |
318 | unwind_table_del(mod->arch.unwind_devinit); | 286 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
319 | unwind_table_del(mod->arch.unwind_core); | 287 | |
288 | for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) | ||
289 | if (strcmp(name, secstrs + s->sh_name) == 0) | ||
290 | return s; | ||
291 | |||
292 | return NULL; | ||
320 | } | 293 | } |
321 | #else | ||
322 | static inline void register_unwind_tables(struct module *mod) { } | ||
323 | static inline void unregister_unwind_tables(struct module *mod) { } | ||
324 | #endif | ||
325 | 294 | ||
326 | int | 295 | extern void fixup_pv_table(const void *, unsigned long); |
327 | module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | 296 | extern void fixup_smp(const void *, unsigned long); |
328 | struct module *module) | 297 | |
298 | int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
299 | struct module *mod) | ||
329 | { | 300 | { |
330 | register_unwind_tables(module); | 301 | const Elf_Shdr *s = NULL; |
302 | #ifdef CONFIG_ARM_UNWIND | ||
303 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
304 | const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; | ||
305 | struct mod_unwind_map maps[ARM_SEC_MAX]; | ||
306 | int i; | ||
307 | |||
308 | memset(maps, 0, sizeof(maps)); | ||
309 | |||
310 | for (s = sechdrs; s < sechdrs_end; s++) { | ||
311 | const char *secname = secstrs + s->sh_name; | ||
312 | |||
313 | if (!(s->sh_flags & SHF_ALLOC)) | ||
314 | continue; | ||
315 | |||
316 | if (strcmp(".ARM.exidx.init.text", secname) == 0) | ||
317 | maps[ARM_SEC_INIT].unw_sec = s; | ||
318 | else if (strcmp(".ARM.exidx.devinit.text", secname) == 0) | ||
319 | maps[ARM_SEC_DEVINIT].unw_sec = s; | ||
320 | else if (strcmp(".ARM.exidx", secname) == 0) | ||
321 | maps[ARM_SEC_CORE].unw_sec = s; | ||
322 | else if (strcmp(".ARM.exidx.exit.text", secname) == 0) | ||
323 | maps[ARM_SEC_EXIT].unw_sec = s; | ||
324 | else if (strcmp(".ARM.exidx.devexit.text", secname) == 0) | ||
325 | maps[ARM_SEC_DEVEXIT].unw_sec = s; | ||
326 | else if (strcmp(".init.text", secname) == 0) | ||
327 | maps[ARM_SEC_INIT].txt_sec = s; | ||
328 | else if (strcmp(".devinit.text", secname) == 0) | ||
329 | maps[ARM_SEC_DEVINIT].txt_sec = s; | ||
330 | else if (strcmp(".text", secname) == 0) | ||
331 | maps[ARM_SEC_CORE].txt_sec = s; | ||
332 | else if (strcmp(".exit.text", secname) == 0) | ||
333 | maps[ARM_SEC_EXIT].txt_sec = s; | ||
334 | else if (strcmp(".devexit.text", secname) == 0) | ||
335 | maps[ARM_SEC_DEVEXIT].txt_sec = s; | ||
336 | } | ||
337 | |||
338 | for (i = 0; i < ARM_SEC_MAX; i++) | ||
339 | if (maps[i].unw_sec && maps[i].txt_sec) | ||
340 | mod->arch.unwind[i] = | ||
341 | unwind_table_add(maps[i].unw_sec->sh_addr, | ||
342 | maps[i].unw_sec->sh_size, | ||
343 | maps[i].txt_sec->sh_addr, | ||
344 | maps[i].txt_sec->sh_size); | ||
345 | #endif | ||
346 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
347 | s = find_mod_section(hdr, sechdrs, ".pv_table"); | ||
348 | if (s) | ||
349 | fixup_pv_table((void *)s->sh_addr, s->sh_size); | ||
350 | #endif | ||
351 | s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); | ||
352 | if (s && !is_smp()) | ||
353 | fixup_smp((void *)s->sh_addr, s->sh_size); | ||
331 | return 0; | 354 | return 0; |
332 | } | 355 | } |
333 | 356 | ||
334 | void | 357 | void |
335 | module_arch_cleanup(struct module *mod) | 358 | module_arch_cleanup(struct module *mod) |
336 | { | 359 | { |
337 | unregister_unwind_tables(mod); | 360 | #ifdef CONFIG_ARM_UNWIND |
361 | int i; | ||
362 | |||
363 | for (i = 0; i < ARM_SEC_MAX; i++) | ||
364 | if (mod->arch.unwind[i]) | ||
365 | unwind_table_del(mod->arch.unwind[i]); | ||
366 | #endif | ||
338 | } | 367 | } |