diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/blackfin/kernel/module.c | 62 |
1 files changed, 34 insertions, 28 deletions
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c index 2ad805e67af..67fc7a56c86 100644 --- a/arch/blackfin/kernel/module.c +++ b/arch/blackfin/kernel/module.c @@ -37,6 +37,7 @@ #include <linux/kernel.h> #include <asm/dma.h> #include <asm/cacheflush.h> +#include <asm/uaccess.h> void *module_alloc(unsigned long size) { @@ -199,26 +200,23 @@ apply_relocate(Elf_Shdr * sechdrs, const char *strtab, /* gas does not generate it. */ /*************************************************************************/ int -apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, +apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *mod) { unsigned int i; - unsigned short tmp; Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; - uint32_t *location32; - uint16_t *location16; - uint32_t value; + unsigned long location, value, size; pr_debug("applying relocate section %u to %u\n", mod->name, relsec, sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location16 = - (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr + - rel[i].r_offset); - location32 = (uint32_t *) location16; + location = sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *) sechdrs[symindex].sh_addr @@ -227,39 +225,28 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, value += rel[i].r_addend; #ifdef CONFIG_SMP - if ((unsigned long)location16 >= COREB_L1_DATA_A_START) { + if (location >= COREB_L1_DATA_A_START) { pr_err("cannot relocate in L1: %u (SMP kernel)", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } #endif - pr_debug("location is %lx, value is %x type is %d\n", - mod->name, (unsigned long)location32, value, - ELF32_R_TYPE(rel[i].r_info)); + pr_debug("location is %lx, value is %lx type is %d\n", + mod->name, location, value, ELF32_R_TYPE(rel[i].r_info)); switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_BFIN_LUIMM16: - tmp = (value & 0xffff); - if ((unsigned long)location16 >= L1_CODE_START) { - dma_memcpy(location16, &tmp, 2); - } else - *location16 = tmp; - break; case R_BFIN_HUIMM16: - tmp = ((value >> 16) & 0xffff); - if ((unsigned long)location16 >= L1_CODE_START) { - dma_memcpy(location16, &tmp, 2); - } else - *location16 = tmp; - break; + value >>= 16; + case R_BFIN_LUIMM16: case R_BFIN_RIMM16: - *location16 = (value & 0xffff); + size = 2; break; case R_BFIN_BYTE4_DATA: - *location32 = value; + size = 4; break; + case R_BFIN_PCREL24: case R_BFIN_PCREL24_JUMP_L: case R_BFIN_PCREL12_JUMP: @@ -268,12 +255,31 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, pr_err("unsupported relocation: %u (no -mlong-calls?)\n", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; + default: pr_err("unknown relocation: %u\n", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } + + switch (bfin_mem_access_type(location, size)) { + case BFIN_MEM_ACCESS_CORE: + case BFIN_MEM_ACCESS_CORE_ONLY: + memcpy((void *)location, &value, size); + break; + case BFIN_MEM_ACCESS_DMA: + dma_memcpy((void *)location, &value, size); + break; + case BFIN_MEM_ACCESS_ITEST: + isram_memcpy((void *)location, &value, size); + break; + default: + pr_err("invalid relocation for %#lx\n", + mod->name, location); + return -ENOEXEC; + } } + return 0; } |