aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/blackfin/kernel/module.c62
1 files changed, 34 insertions, 28 deletions
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
index 2ad805e67afc..67fc7a56c865 100644
--- a/arch/blackfin/kernel/module.c
+++ b/arch/blackfin/kernel/module.c
@@ -37,6 +37,7 @@
37#include <linux/kernel.h> 37#include <linux/kernel.h>
38#include <asm/dma.h> 38#include <asm/dma.h>
39#include <asm/cacheflush.h> 39#include <asm/cacheflush.h>
40#include <asm/uaccess.h>
40 41
41void *module_alloc(unsigned long size) 42void *module_alloc(unsigned long size)
42{ 43{
@@ -199,26 +200,23 @@ apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
199/* gas does not generate it. */ 200/* gas does not generate it. */
200/*************************************************************************/ 201/*************************************************************************/
201int 202int
202apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, 203apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
203 unsigned int symindex, unsigned int relsec, 204 unsigned int symindex, unsigned int relsec,
204 struct module *mod) 205 struct module *mod)
205{ 206{
206 unsigned int i; 207 unsigned int i;
207 unsigned short tmp;
208 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 208 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
209 Elf32_Sym *sym; 209 Elf32_Sym *sym;
210 uint32_t *location32; 210 unsigned long location, value, size;
211 uint16_t *location16;
212 uint32_t value;
213 211
214 pr_debug("applying relocate section %u to %u\n", mod->name, 212 pr_debug("applying relocate section %u to %u\n", mod->name,
215 relsec, sechdrs[relsec].sh_info); 213 relsec, sechdrs[relsec].sh_info);
214
216 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 215 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
217 /* This is where to make the change */ 216 /* This is where to make the change */
218 location16 = 217 location = sechdrs[sechdrs[relsec].sh_info].sh_addr +
219 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr + 218 rel[i].r_offset;
220 rel[i].r_offset); 219
221 location32 = (uint32_t *) location16;
222 /* This is the symbol it is referring to. Note that all 220 /* This is the symbol it is referring to. Note that all
223 undefined symbols have been resolved. */ 221 undefined symbols have been resolved. */
224 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr 222 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
@@ -227,39 +225,28 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
227 value += rel[i].r_addend; 225 value += rel[i].r_addend;
228 226
229#ifdef CONFIG_SMP 227#ifdef CONFIG_SMP
230 if ((unsigned long)location16 >= COREB_L1_DATA_A_START) { 228 if (location >= COREB_L1_DATA_A_START) {
231 pr_err("cannot relocate in L1: %u (SMP kernel)", 229 pr_err("cannot relocate in L1: %u (SMP kernel)",
232 mod->name, ELF32_R_TYPE(rel[i].r_info)); 230 mod->name, ELF32_R_TYPE(rel[i].r_info));
233 return -ENOEXEC; 231 return -ENOEXEC;
234 } 232 }
235#endif 233#endif
236 234
237 pr_debug("location is %lx, value is %x type is %d\n", 235 pr_debug("location is %lx, value is %lx type is %d\n",
238 mod->name, (unsigned long)location32, value, 236 mod->name, location, value, ELF32_R_TYPE(rel[i].r_info));
239 ELF32_R_TYPE(rel[i].r_info));
240 237
241 switch (ELF32_R_TYPE(rel[i].r_info)) { 238 switch (ELF32_R_TYPE(rel[i].r_info)) {
242 239
243 case R_BFIN_LUIMM16:
244 tmp = (value & 0xffff);
245 if ((unsigned long)location16 >= L1_CODE_START) {
246 dma_memcpy(location16, &tmp, 2);
247 } else
248 *location16 = tmp;
249 break;
250 case R_BFIN_HUIMM16: 240 case R_BFIN_HUIMM16:
251 tmp = ((value >> 16) & 0xffff); 241 value >>= 16;
252 if ((unsigned long)location16 >= L1_CODE_START) { 242 case R_BFIN_LUIMM16:
253 dma_memcpy(location16, &tmp, 2);
254 } else
255 *location16 = tmp;
256 break;
257 case R_BFIN_RIMM16: 243 case R_BFIN_RIMM16:
258 *location16 = (value & 0xffff); 244 size = 2;
259 break; 245 break;
260 case R_BFIN_BYTE4_DATA: 246 case R_BFIN_BYTE4_DATA:
261 *location32 = value; 247 size = 4;
262 break; 248 break;
249
263 case R_BFIN_PCREL24: 250 case R_BFIN_PCREL24:
264 case R_BFIN_PCREL24_JUMP_L: 251 case R_BFIN_PCREL24_JUMP_L:
265 case R_BFIN_PCREL12_JUMP: 252 case R_BFIN_PCREL12_JUMP:
@@ -268,12 +255,31 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
268 pr_err("unsupported relocation: %u (no -mlong-calls?)\n", 255 pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
269 mod->name, ELF32_R_TYPE(rel[i].r_info)); 256 mod->name, ELF32_R_TYPE(rel[i].r_info));
270 return -ENOEXEC; 257 return -ENOEXEC;
258
271 default: 259 default:
272 pr_err("unknown relocation: %u\n", mod->name, 260 pr_err("unknown relocation: %u\n", mod->name,
273 ELF32_R_TYPE(rel[i].r_info)); 261 ELF32_R_TYPE(rel[i].r_info));
274 return -ENOEXEC; 262 return -ENOEXEC;
275 } 263 }
264
265 switch (bfin_mem_access_type(location, size)) {
266 case BFIN_MEM_ACCESS_CORE:
267 case BFIN_MEM_ACCESS_CORE_ONLY:
268 memcpy((void *)location, &value, size);
269 break;
270 case BFIN_MEM_ACCESS_DMA:
271 dma_memcpy((void *)location, &value, size);
272 break;
273 case BFIN_MEM_ACCESS_ITEST:
274 isram_memcpy((void *)location, &value, size);
275 break;
276 default:
277 pr_err("invalid relocation for %#lx\n",
278 mod->name, location);
279 return -ENOEXEC;
280 }
276 } 281 }
282
277 return 0; 283 return 0;
278} 284}
279 285