at v2.6.22-rc7 429 lines 12 kB view raw
1/* 2 * File: arch/blackfin/kernel/module.c 3 * Based on: 4 * Author: 5 * 6 * Created: 7 * Description: 8 * 9 * Modified: 10 * Copyright 2004-2006 Analog Devices Inc. 11 * 12 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, see the file COPYING, or write 26 * to the Free Software Foundation, Inc., 27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 28 */ 29 30 31#include <linux/moduleloader.h> 32#include <linux/elf.h> 33#include <linux/vmalloc.h> 34#include <linux/fs.h> 35#include <linux/string.h> 36#include <linux/kernel.h> 37#include <asm/dma.h> 38#include <asm/cacheflush.h> 39 40/* 41 * handle arithmetic relocations. 42 * See binutils/bfd/elf32-bfin.c for more details 43 */ 44#define RELOC_STACK_SIZE 100 45static uint32_t reloc_stack[RELOC_STACK_SIZE]; 46static unsigned int reloc_stack_tos; 47 48#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1) 49 50static void reloc_stack_push(uint32_t value) 51{ 52 reloc_stack[reloc_stack_tos++] = value; 53} 54 55static uint32_t reloc_stack_pop(void) 56{ 57 return reloc_stack[--reloc_stack_tos]; 58} 59 60static 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 145void *module_alloc(unsigned long size) 146{ 147 if (size == 0) 148 return NULL; 149 return vmalloc(size); 150} 151 152/* Free memory returned from module_alloc */ 153void module_free(struct module *mod, void *module_region) 154{ 155 vfree(module_region); 156} 157 158/* Transfer the section to the L1 memory */ 159int 160module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs, 161 char *secstrings, struct module *mod) 162{ 163 Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; 164 void *dest = NULL; 165 166 for (s = sechdrs; s < sechdrs_end; ++s) { 167 if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) || 168 ((strcmp(".text", secstrings + s->sh_name)==0) && 169 (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) { 170 mod->arch.text_l1 = s; 171 dest = l1_inst_sram_alloc(s->sh_size); 172 if (dest == NULL) { 173 printk(KERN_ERR 174 "module %s: L1 instruction memory allocation failed\n", 175 mod->name); 176 return -1; 177 } 178 dma_memcpy(dest, (void *)s->sh_addr, s->sh_size); 179 s->sh_flags &= ~SHF_ALLOC; 180 s->sh_addr = (unsigned long)dest; 181 } 182 if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)|| 183 ((strcmp(".data", secstrings + s->sh_name)==0) && 184 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) { 185 mod->arch.data_a_l1 = s; 186 dest = l1_data_sram_alloc(s->sh_size); 187 if (dest == NULL) { 188 printk(KERN_ERR 189 "module %s: L1 data memory allocation failed\n", 190 mod->name); 191 return -1; 192 } 193 memcpy(dest, (void *)s->sh_addr, s->sh_size); 194 s->sh_flags &= ~SHF_ALLOC; 195 s->sh_addr = (unsigned long)dest; 196 } 197 if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 || 198 ((strcmp(".bss", secstrings + s->sh_name)==0) && 199 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) { 200 mod->arch.bss_a_l1 = s; 201 dest = l1_data_sram_alloc(s->sh_size); 202 if (dest == NULL) { 203 printk(KERN_ERR 204 "module %s: L1 data memory allocation failed\n", 205 mod->name); 206 return -1; 207 } 208 memset(dest, 0, s->sh_size); 209 s->sh_flags &= ~SHF_ALLOC; 210 s->sh_addr = (unsigned long)dest; 211 } 212 if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) { 213 mod->arch.data_b_l1 = s; 214 dest = l1_data_B_sram_alloc(s->sh_size); 215 if (dest == NULL) { 216 printk(KERN_ERR 217 "module %s: L1 data memory allocation failed\n", 218 mod->name); 219 return -1; 220 } 221 memcpy(dest, (void *)s->sh_addr, s->sh_size); 222 s->sh_flags &= ~SHF_ALLOC; 223 s->sh_addr = (unsigned long)dest; 224 } 225 if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) { 226 mod->arch.bss_b_l1 = s; 227 dest = l1_data_B_sram_alloc(s->sh_size); 228 if (dest == NULL) { 229 printk(KERN_ERR 230 "module %s: L1 data memory allocation failed\n", 231 mod->name); 232 return -1; 233 } 234 memset(dest, 0, s->sh_size); 235 s->sh_flags &= ~SHF_ALLOC; 236 s->sh_addr = (unsigned long)dest; 237 } 238 } 239 return 0; 240} 241 242int 243apply_relocate(Elf_Shdr * sechdrs, const char *strtab, 244 unsigned int symindex, unsigned int relsec, struct module *me) 245{ 246 printk(KERN_ERR "module %s: .rel unsupported\n", me->name); 247 return -ENOEXEC; 248} 249 250/*************************************************************************/ 251/* FUNCTION : apply_relocate_add */ 252/* ABSTRACT : Blackfin specific relocation handling for the loadable */ 253/* modules. Modules are expected to be .o files. */ 254/* Arithmetic relocations are handled. */ 255/* We do not expect LSETUP to be split and hence is not */ 256/* handled. */ 257/* R_byte and R_byte2 are also not handled as the gas */ 258/* does not generate it. */ 259/*************************************************************************/ 260int 261apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, 262 unsigned int symindex, unsigned int relsec, 263 struct module *mod) 264{ 265 unsigned int i; 266 unsigned short tmp; 267 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 268 Elf32_Sym *sym; 269 uint32_t *location32; 270 uint16_t *location16; 271 uint32_t value; 272 273 pr_debug("Applying relocate section %u to %u\n", relsec, 274 sechdrs[relsec].sh_info); 275 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 276 /* This is where to make the change */ 277 location16 = 278 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr + 279 rel[i].r_offset); 280 location32 = (uint32_t *) location16; 281 /* This is the symbol it is referring to. Note that all 282 undefined symbols have been resolved. */ 283 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr 284 + ELF32_R_SYM(rel[i].r_info); 285 if (is_reloc_stack_empty()) { 286 value = sym->st_value; 287 } else { 288 value = reloc_stack_pop(); 289 } 290 value += rel[i].r_addend; 291 pr_debug("location is %x, value is %x type is %d \n", 292 (unsigned int) location32, value, 293 ELF32_R_TYPE(rel[i].r_info)); 294 295 switch (ELF32_R_TYPE(rel[i].r_info)) { 296 297 case R_pcrel24: 298 case R_pcrel24_jump_l: 299 /* Add the value, subtract its postition */ 300 location16 = 301 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info]. 302 sh_addr + rel[i].r_offset - 2); 303 location32 = (uint32_t *) location16; 304 value -= (uint32_t) location32; 305 value >>= 1; 306 pr_debug("value is %x, before %x-%x after %x-%x\n", value, 307 *location16, *(location16 + 1), 308 (*location16 & 0xff00) | (value >> 16 & 0x00ff), 309 value & 0xffff); 310 *location16 = 311 (*location16 & 0xff00) | (value >> 16 & 0x00ff); 312 *(location16 + 1) = value & 0xffff; 313 break; 314 case R_pcrel12_jump: 315 case R_pcrel12_jump_s: 316 value -= (uint32_t) location32; 317 value >>= 1; 318 *location16 = (value & 0xfff); 319 break; 320 case R_pcrel10: 321 value -= (uint32_t) location32; 322 value >>= 1; 323 *location16 = (value & 0x3ff); 324 break; 325 case R_luimm16: 326 pr_debug("before %x after %x\n", *location16, 327 (value & 0xffff)); 328 tmp = (value & 0xffff); 329 if((unsigned long)location16 >= L1_CODE_START) { 330 dma_memcpy(location16, &tmp, 2); 331 } else 332 *location16 = tmp; 333 break; 334 case R_huimm16: 335 pr_debug("before %x after %x\n", *location16, 336 ((value >> 16) & 0xffff)); 337 tmp = ((value >> 16) & 0xffff); 338 if((unsigned long)location16 >= L1_CODE_START) { 339 dma_memcpy(location16, &tmp, 2); 340 } else 341 *location16 = tmp; 342 break; 343 case R_rimm16: 344 *location16 = (value & 0xffff); 345 break; 346 case R_byte4_data: 347 pr_debug("before %x after %x\n", *location32, value); 348 *location32 = value; 349 break; 350 case R_push: 351 reloc_stack_push(value); 352 break; 353 case R_const: 354 reloc_stack_push(rel[i].r_addend); 355 break; 356 case R_add: 357 case R_sub: 358 case R_mult: 359 case R_div: 360 case R_mod: 361 case R_lshift: 362 case R_rshift: 363 case R_and: 364 case R_or: 365 case R_xor: 366 case R_land: 367 case R_lor: 368 case R_neg: 369 case R_comp: 370 reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod); 371 break; 372 default: 373 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 374 mod->name, ELF32_R_TYPE(rel[i].r_info)); 375 return -ENOEXEC; 376 } 377 } 378 return 0; 379} 380 381int 382module_finalize(const Elf_Ehdr * hdr, 383 const Elf_Shdr * sechdrs, struct module *mod) 384{ 385 unsigned int i, strindex = 0, symindex = 0; 386 char *secstrings; 387 388 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 389 390 for (i = 1; i < hdr->e_shnum; i++) { 391 /* Internal symbols and strings. */ 392 if (sechdrs[i].sh_type == SHT_SYMTAB) { 393 symindex = i; 394 strindex = sechdrs[i].sh_link; 395 } 396 } 397 398 for (i = 1; i < hdr->e_shnum; i++) { 399 const char *strtab = (char *)sechdrs[strindex].sh_addr; 400 unsigned int info = sechdrs[i].sh_info; 401 402 /* Not a valid relocation section? */ 403 if (info >= hdr->e_shnum) 404 continue; 405 406 if ((sechdrs[i].sh_type == SHT_RELA) && 407 ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)|| 408 ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) && 409 (hdr->e_flags & FLG_CODE_IN_L1)))) { 410 apply_relocate_add((Elf_Shdr *) sechdrs, strtab, 411 symindex, i, mod); 412 } 413 } 414 return 0; 415} 416 417void module_arch_cleanup(struct module *mod) 418{ 419 if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr)) 420 l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr); 421 if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr)) 422 l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr); 423 if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr)) 424 l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr); 425 if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr)) 426 l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr); 427 if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr)) 428 l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr); 429}