diff options
Diffstat (limited to 'arch/blackfin/kernel/module.c')
-rw-r--r-- | arch/blackfin/kernel/module.c | 152 |
1 files changed, 18 insertions, 134 deletions
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c index e1bebc80a5bf..1bd7f2d018a8 100644 --- a/arch/blackfin/kernel/module.c +++ b/arch/blackfin/kernel/module.c | |||
@@ -37,111 +37,6 @@ | |||
37 | #include <asm/dma.h> | 37 | #include <asm/dma.h> |
38 | #include <asm/cacheflush.h> | 38 | #include <asm/cacheflush.h> |
39 | 39 | ||
40 | /* | ||
41 | * handle arithmetic relocations. | ||
42 | * See binutils/bfd/elf32-bfin.c for more details | ||
43 | */ | ||
44 | #define RELOC_STACK_SIZE 100 | ||
45 | static uint32_t reloc_stack[RELOC_STACK_SIZE]; | ||
46 | static unsigned int reloc_stack_tos; | ||
47 | |||
48 | #define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1) | ||
49 | |||
50 | static void reloc_stack_push(uint32_t value) | ||
51 | { | ||
52 | reloc_stack[reloc_stack_tos++] = value; | ||
53 | } | ||
54 | |||
55 | static uint32_t reloc_stack_pop(void) | ||
56 | { | ||
57 | return reloc_stack[--reloc_stack_tos]; | ||
58 | } | ||
59 | |||
60 | static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod) | ||
61 | { | ||
62 | uint32_t value; | ||
63 | |||
64 | switch (oper) { | ||
65 | case R_add: | ||
66 | value = reloc_stack[reloc_stack_tos - 2] + | ||
67 | reloc_stack[reloc_stack_tos - 1]; | ||
68 | reloc_stack_tos -= 2; | ||
69 | break; | ||
70 | case R_sub: | ||
71 | value = reloc_stack[reloc_stack_tos - 2] - | ||
72 | reloc_stack[reloc_stack_tos - 1]; | ||
73 | reloc_stack_tos -= 2; | ||
74 | break; | ||
75 | case R_mult: | ||
76 | value = reloc_stack[reloc_stack_tos - 2] * | ||
77 | reloc_stack[reloc_stack_tos - 1]; | ||
78 | reloc_stack_tos -= 2; | ||
79 | break; | ||
80 | case R_div: | ||
81 | value = reloc_stack[reloc_stack_tos - 2] / | ||
82 | reloc_stack[reloc_stack_tos - 1]; | ||
83 | reloc_stack_tos -= 2; | ||
84 | break; | ||
85 | case R_mod: | ||
86 | value = reloc_stack[reloc_stack_tos - 2] % | ||
87 | reloc_stack[reloc_stack_tos - 1]; | ||
88 | reloc_stack_tos -= 2; | ||
89 | break; | ||
90 | case R_lshift: | ||
91 | value = reloc_stack[reloc_stack_tos - 2] << | ||
92 | reloc_stack[reloc_stack_tos - 1]; | ||
93 | reloc_stack_tos -= 2; | ||
94 | break; | ||
95 | case R_rshift: | ||
96 | value = reloc_stack[reloc_stack_tos - 2] >> | ||
97 | reloc_stack[reloc_stack_tos - 1]; | ||
98 | reloc_stack_tos -= 2; | ||
99 | break; | ||
100 | case R_and: | ||
101 | value = reloc_stack[reloc_stack_tos - 2] & | ||
102 | reloc_stack[reloc_stack_tos - 1]; | ||
103 | reloc_stack_tos -= 2; | ||
104 | break; | ||
105 | case R_or: | ||
106 | value = reloc_stack[reloc_stack_tos - 2] | | ||
107 | reloc_stack[reloc_stack_tos - 1]; | ||
108 | reloc_stack_tos -= 2; | ||
109 | break; | ||
110 | case R_xor: | ||
111 | value = reloc_stack[reloc_stack_tos - 2] ^ | ||
112 | reloc_stack[reloc_stack_tos - 1]; | ||
113 | reloc_stack_tos -= 2; | ||
114 | break; | ||
115 | case R_land: | ||
116 | value = reloc_stack[reloc_stack_tos - 2] && | ||
117 | reloc_stack[reloc_stack_tos - 1]; | ||
118 | reloc_stack_tos -= 2; | ||
119 | break; | ||
120 | case R_lor: | ||
121 | value = reloc_stack[reloc_stack_tos - 2] || | ||
122 | reloc_stack[reloc_stack_tos - 1]; | ||
123 | reloc_stack_tos -= 2; | ||
124 | break; | ||
125 | case R_neg: | ||
126 | value = -reloc_stack[reloc_stack_tos - 1]; | ||
127 | reloc_stack_tos--; | ||
128 | break; | ||
129 | case R_comp: | ||
130 | value = ~reloc_stack[reloc_stack_tos - 1]; | ||
131 | reloc_stack_tos -= 1; | ||
132 | break; | ||
133 | default: | ||
134 | printk(KERN_WARNING "module %s: unhandled reloction\n", | ||
135 | mod->name); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* now push the new value back on stack */ | ||
140 | reloc_stack_push(value); | ||
141 | |||
142 | return value; | ||
143 | } | ||
144 | |||
145 | void *module_alloc(unsigned long size) | 40 | void *module_alloc(unsigned long size) |
146 | { | 41 | { |
147 | if (size == 0) | 42 | if (size == 0) |
@@ -334,16 +229,18 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, | |||
334 | undefined symbols have been resolved. */ | 229 | undefined symbols have been resolved. */ |
335 | sym = (Elf32_Sym *) sechdrs[symindex].sh_addr | 230 | sym = (Elf32_Sym *) sechdrs[symindex].sh_addr |
336 | + ELF32_R_SYM(rel[i].r_info); | 231 | + ELF32_R_SYM(rel[i].r_info); |
337 | if (is_reloc_stack_empty()) { | 232 | value = sym->st_value; |
338 | value = sym->st_value; | ||
339 | } else { | ||
340 | value = reloc_stack_pop(); | ||
341 | } | ||
342 | value += rel[i].r_addend; | 233 | value += rel[i].r_addend; |
343 | pr_debug("location is %x, value is %x type is %d \n", | 234 | pr_debug("location is %x, value is %x type is %d \n", |
344 | (unsigned int) location32, value, | 235 | (unsigned int) location32, value, |
345 | ELF32_R_TYPE(rel[i].r_info)); | 236 | ELF32_R_TYPE(rel[i].r_info)); |
346 | 237 | #ifdef CONFIG_SMP | |
238 | if ((unsigned long)location16 >= COREB_L1_DATA_A_START) { | ||
239 | printk(KERN_ERR "module %s: cannot relocate in L1: %u (SMP kernel)", | ||
240 | mod->name, ELF32_R_TYPE(rel[i].r_info)); | ||
241 | return -ENOEXEC; | ||
242 | } | ||
243 | #endif | ||
347 | switch (ELF32_R_TYPE(rel[i].r_info)) { | 244 | switch (ELF32_R_TYPE(rel[i].r_info)) { |
348 | 245 | ||
349 | case R_pcrel24: | 246 | case R_pcrel24: |
@@ -355,6 +252,12 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, | |||
355 | location32 = (uint32_t *) location16; | 252 | location32 = (uint32_t *) location16; |
356 | value -= (uint32_t) location32; | 253 | value -= (uint32_t) location32; |
357 | value >>= 1; | 254 | value >>= 1; |
255 | if ((value & 0xFF000000) != 0 && | ||
256 | (value & 0xFF000000) != 0xFF000000) { | ||
257 | printk(KERN_ERR "module %s: relocation overflow\n", | ||
258 | mod->name); | ||
259 | return -ENOEXEC; | ||
260 | } | ||
358 | pr_debug("value is %x, before %x-%x after %x-%x\n", value, | 261 | pr_debug("value is %x, before %x-%x after %x-%x\n", value, |
359 | *location16, *(location16 + 1), | 262 | *location16, *(location16 + 1), |
360 | (*location16 & 0xff00) | (value >> 16 & 0x00ff), | 263 | (*location16 & 0xff00) | (value >> 16 & 0x00ff), |
@@ -399,28 +302,6 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, | |||
399 | pr_debug("before %x after %x\n", *location32, value); | 302 | pr_debug("before %x after %x\n", *location32, value); |
400 | *location32 = value; | 303 | *location32 = value; |
401 | break; | 304 | break; |
402 | case R_push: | ||
403 | reloc_stack_push(value); | ||
404 | break; | ||
405 | case R_const: | ||
406 | reloc_stack_push(rel[i].r_addend); | ||
407 | break; | ||
408 | case R_add: | ||
409 | case R_sub: | ||
410 | case R_mult: | ||
411 | case R_div: | ||
412 | case R_mod: | ||
413 | case R_lshift: | ||
414 | case R_rshift: | ||
415 | case R_and: | ||
416 | case R_or: | ||
417 | case R_xor: | ||
418 | case R_land: | ||
419 | case R_lor: | ||
420 | case R_neg: | ||
421 | case R_comp: | ||
422 | reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod); | ||
423 | break; | ||
424 | default: | 305 | default: |
425 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | 306 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", |
426 | mod->name, ELF32_R_TYPE(rel[i].r_info)); | 307 | mod->name, ELF32_R_TYPE(rel[i].r_info)); |
@@ -436,6 +317,7 @@ module_finalize(const Elf_Ehdr * hdr, | |||
436 | { | 317 | { |
437 | unsigned int i, strindex = 0, symindex = 0; | 318 | unsigned int i, strindex = 0, symindex = 0; |
438 | char *secstrings; | 319 | char *secstrings; |
320 | long err = 0; | ||
439 | 321 | ||
440 | secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 322 | secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
441 | 323 | ||
@@ -460,8 +342,10 @@ module_finalize(const Elf_Ehdr * hdr, | |||
460 | (strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) || | 342 | (strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) || |
461 | ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) && | 343 | ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) && |
462 | (hdr->e_flags & (EF_BFIN_CODE_IN_L1|EF_BFIN_CODE_IN_L2))))) { | 344 | (hdr->e_flags & (EF_BFIN_CODE_IN_L1|EF_BFIN_CODE_IN_L2))))) { |
463 | apply_relocate_add((Elf_Shdr *) sechdrs, strtab, | 345 | err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab, |
464 | symindex, i, mod); | 346 | symindex, i, mod); |
347 | if (err < 0) | ||
348 | return -ENOEXEC; | ||
465 | } | 349 | } |
466 | } | 350 | } |
467 | return 0; | 351 | return 0; |