1/* 2 * reloc.c 3 * 4 * DSP-BIOS Bridge driver support functions for TI OMAP processors. 5 * 6 * Copyright (C) 2005-2006 Texas Instruments, Inc. 7 * 8 * This package is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 15 */ 16 17#include "header.h" 18 19#if TMS32060 20/* the magic symbol for the start of BSS */ 21static const char bsssymbol[] = { ".bss" }; 22#endif 23 24#if TMS32060 25#include "reloc_table_c6000.c" 26#endif 27 28#if TMS32060 29/* From coff.h - ignore these relocation operations */ 30#define R_C60ALIGN 0x76 /* C60: Alignment info for compressor */ 31#define R_C60FPHEAD 0x77 /* C60: Explicit assembly directive */ 32#define R_C60NOCMP 0x100 /* C60: Don't compress this code scn */ 33#endif 34 35/************************************************************************** 36 * Procedure dload_unpack 37 * 38 * Parameters: 39 * data pointer to storage unit containing lowest host address of 40 * image data 41 * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU 42 * offset Offset from LSB, 0 <= offset < BITS_PER_AU 43 * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) 44 * 45 * Effect: 46 * Extracts the specified field and returns it. 47 ************************************************************************* */ 48rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, int fieldsz, 49 int offset, unsigned sgn) 50{ 51 register rvalue objval; 52 register int shift, direction; 53 register tgt_au_t *dp = data; 54 55 fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */ 56 /* * collect up enough bits to contain the desired field */ 57 if (TARGET_BIG_ENDIAN) { 58 dp += (fieldsz + offset) >> LOG_TGTAU_BITS; 59 direction = -1; 60 } else 61 direction = 1; 62 objval = *dp >> offset; 63 shift = TGTAU_BITS - offset; 64 while (shift <= fieldsz) { 65 dp += direction; 66 objval += (rvalue) *dp << shift; 67 shift += TGTAU_BITS; 68 } 69 70 /* * sign or zero extend the value appropriately */ 71 if (sgn == ROP_UNS) 72 objval &= (2 << fieldsz) - 1; 73 else { 74 shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz; 75 objval = (objval << shift) >> shift; 76 } 77 78 return objval; 79 80} /* dload_unpack */ 81 82/************************************************************************** 83 * Procedure dload_repack 84 * 85 * Parameters: 86 * val Value to insert 87 * data Pointer to storage unit containing lowest host address of 88 * image data 89 * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU 90 * offset Offset from LSB, 0 <= offset < BITS_PER_AU 91 * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) 92 * 93 * Effect: 94 * Stuffs the specified value in the specified field. Returns 0 for 95 * success 96 * or 1 if the value will not fit in the specified field according to the 97 * specified signedness rule. 98 ************************************************************************* */ 99static const unsigned char ovf_limit[] = { 1, 2, 2 }; 100 101int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data, 102 int fieldsz, int offset, unsigned sgn) 103{ 104 register urvalue objval, mask; 105 register int shift, direction; 106 register tgt_au_t *dp = data; 107 108 fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */ 109 /* clip the bits */ 110 mask = (2UL << fieldsz) - 1; 111 objval = (val & mask); 112 /* * store the bits through the specified mask */ 113 if (TARGET_BIG_ENDIAN) { 114 dp += (fieldsz + offset) >> LOG_TGTAU_BITS; 115 direction = -1; 116 } else 117 direction = 1; 118 119 /* insert LSBs */ 120 *dp = (*dp & ~(mask << offset)) + (objval << offset); 121 shift = TGTAU_BITS - offset; 122 /* align mask and objval with AU boundary */ 123 objval >>= shift; 124 mask >>= shift; 125 126 while (mask) { 127 dp += direction; 128 *dp = (*dp & ~mask) + objval; 129 objval >>= TGTAU_BITS; 130 mask >>= TGTAU_BITS; 131 } 132 133 /* 134 * check for overflow 135 */ 136 if (sgn) { 137 unsigned tmp = (val >> fieldsz) + (sgn & 0x1); 138 if (tmp > ovf_limit[sgn - 1]) 139 return 1; 140 } 141 return 0; 142 143} /* dload_repack */ 144 145/* lookup table for the scaling amount in a C6x instruction */ 146#if TMS32060 147#define SCALE_BITS 4 /* there are 4 bits in the scale field */ 148#define SCALE_MASK 0x7 /* we really only use the bottom 3 bits */ 149static const u8 c60_scale[SCALE_MASK + 1] = { 150 1, 0, 0, 0, 1, 1, 2, 2 151}; 152#endif 153 154/************************************************************************** 155 * Procedure dload_relocate 156 * 157 * Parameters: 158 * data Pointer to base of image data 159 * rp Pointer to relocation operation 160 * 161 * Effect: 162 * Performs the specified relocation operation 163 ************************************************************************* */ 164void dload_relocate(struct dload_state *dlthis, tgt_au_t * data, 165 struct reloc_record_t *rp, bool *tramps_generated, 166 bool second_pass) 167{ 168 rvalue val, reloc_amt, orig_val = 0; 169 unsigned int fieldsz = 0; 170 unsigned int offset = 0; 171 unsigned int reloc_info = 0; 172 unsigned int reloc_action = 0; 173 register int rx = 0; 174 rvalue *stackp = NULL; 175 int top; 176 struct local_symbol *svp = NULL; 177#ifdef RFV_SCALE 178 unsigned int scale = 0; 179#endif 180 struct image_packet_t *img_pkt = NULL; 181 182 /* The image packet data struct is only used during first pass 183 * relocation in the event that a trampoline is needed. 2nd pass 184 * relocation doesn't guarantee that data is coming from an 185 * image_packet_t structure. See cload.c, dload_data for how img_data is 186 * set. If that changes this needs to be updated!!! */ 187 if (second_pass == false) 188 img_pkt = (struct image_packet_t *)((u8 *) data - 189 sizeof(struct 190 image_packet_t)); 191 192 rx = HASH_FUNC(rp->TYPE); 193 while (rop_map1[rx] != rp->TYPE) { 194 rx = HASH_L(rop_map2[rx]); 195 if (rx < 0) { 196#if TMS32060 197 switch (rp->TYPE) { 198 case R_C60ALIGN: 199 case R_C60NOCMP: 200 case R_C60FPHEAD: 201 /* Ignore these reloc types and return */ 202 break; 203 default: 204 /* Unknown reloc type, print error and return */ 205 dload_error(dlthis, "Bad coff operator 0x%x", 206 rp->TYPE); 207 } 208#else 209 dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE); 210#endif 211 return; 212 } 213 } 214 rx = HASH_I(rop_map2[rx]); 215 if ((rx < (sizeof(rop_action) / sizeof(u16))) 216 && (rx < (sizeof(rop_info) / sizeof(u16))) && (rx > 0)) { 217 reloc_action = rop_action[rx]; 218 reloc_info = rop_info[rx]; 219 } else { 220 dload_error(dlthis, "Buffer Overflow - Array Index Out " 221 "of Bounds"); 222 } 223 224 /* Compute the relocation amount for the referenced symbol, if any */ 225 reloc_amt = rp->UVAL; 226 if (RFV_SYM(reloc_info)) { /* relocation uses a symbol reference */ 227 /* If this is first pass, use the module local symbol table, 228 * else use the trampoline symbol table. */ 229 if (second_pass == false) { 230 if ((u32) rp->SYMNDX < dlthis->dfile_hdr.df_no_syms) { 231 /* real symbol reference */ 232 svp = &dlthis->local_symtab[rp->SYMNDX]; 233 reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? 234 svp->delta : svp->value; 235 } 236 /* reloc references current section */ 237 else if (rp->SYMNDX == -1) { 238 reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? 239 dlthis->delta_runaddr : 240 dlthis->image_secn->run_addr; 241 } 242 } 243 } 244 /* relocation uses a symbol reference */ 245 /* Handle stack adjustment */ 246 val = 0; 247 top = RFV_STK(reloc_info); 248 if (top) { 249 top += dlthis->relstkidx - RSTK_UOP; 250 if (top >= STATIC_EXPR_STK_SIZE) { 251 dload_error(dlthis, 252 "Expression stack overflow in %s at offset " 253 FMT_UI32, dlthis->image_secn->name, 254 rp->vaddr + dlthis->image_offset); 255 return; 256 } 257 val = dlthis->relstk[dlthis->relstkidx]; 258 dlthis->relstkidx = top; 259 stackp = &dlthis->relstk[top]; 260 } 261 /* Derive field position and size, if we need them */ 262 if (reloc_info & ROP_RW) { /* read or write action in our future */ 263 fieldsz = RFV_WIDTH(reloc_action); 264 if (fieldsz) { /* field info from table */ 265 offset = RFV_POSN(reloc_action); 266 if (TARGET_BIG_ENDIAN) 267 /* make sure vaddr is the lowest target 268 * address containing bits */ 269 rp->vaddr += RFV_BIGOFF(reloc_info); 270 } else { /* field info from relocation op */ 271 fieldsz = rp->FIELDSZ; 272 offset = rp->OFFSET; 273 if (TARGET_BIG_ENDIAN) 274 /* make sure vaddr is the lowest target 275 address containing bits */ 276 rp->vaddr += (rp->WORDSZ - offset - fieldsz) 277 >> LOG_TARGET_AU_BITS; 278 } 279 data = (tgt_au_t *) ((char *)data + TADDR_TO_HOST(rp->vaddr)); 280 /* compute lowest host location of referenced data */ 281#if BITS_PER_AU > TARGET_AU_BITS 282 /* conversion from target address to host address may lose 283 address bits; add loss to offset */ 284 if (TARGET_BIG_ENDIAN) { 285 offset += -((rp->vaddr << LOG_TARGET_AU_BITS) + 286 offset + fieldsz) & 287 (BITS_PER_AU - TARGET_AU_BITS); 288 } else { 289 offset += (rp->vaddr << LOG_TARGET_AU_BITS) & 290 (BITS_PER_AU - 1); 291 } 292#endif 293#ifdef RFV_SCALE 294 scale = RFV_SCALE(reloc_info); 295#endif 296 } 297 /* read the object value from the current image, if so ordered */ 298 if (reloc_info & ROP_R) { 299 /* relocation reads current image value */ 300 val = dload_unpack(dlthis, data, fieldsz, offset, 301 RFV_SIGN(reloc_info)); 302 /* Save off the original value in case the relo overflows and 303 * we can trampoline it. */ 304 orig_val = val; 305 306#ifdef RFV_SCALE 307 val <<= scale; 308#endif 309 } 310 /* perform the necessary arithmetic */ 311 switch (RFV_ACTION(reloc_action)) { /* relocation actions */ 312 case RACT_VAL: 313 break; 314 case RACT_ASGN: 315 val = reloc_amt; 316 break; 317 case RACT_ADD: 318 val += reloc_amt; 319 break; 320 case RACT_PCR: 321 /*----------------------------------------------------------- 322 * Handle special cases of jumping from absolute sections 323 * (special reloc type) or to absolute destination 324 * (symndx == -1). In either case, set the appropriate 325 * relocation amount to 0. 326 *----------------------------------------------------------- */ 327 if (rp->SYMNDX == -1) 328 reloc_amt = 0; 329 val += reloc_amt - dlthis->delta_runaddr; 330 break; 331 case RACT_ADDISP: 332 val += rp->R_DISP + reloc_amt; 333 break; 334 case RACT_ASGPC: 335 val = dlthis->image_secn->run_addr + reloc_amt; 336 break; 337 case RACT_PLUS: 338 if (stackp != NULL) 339 val += *stackp; 340 break; 341 case RACT_SUB: 342 if (stackp != NULL) 343 val = *stackp - val; 344 break; 345 case RACT_NEG: 346 val = -val; 347 break; 348 case RACT_MPY: 349 if (stackp != NULL) 350 val *= *stackp; 351 break; 352 case RACT_DIV: 353 if (stackp != NULL) 354 val = *stackp / val; 355 break; 356 case RACT_MOD: 357 if (stackp != NULL) 358 val = *stackp % val; 359 break; 360 case RACT_SR: 361 if (val >= sizeof(rvalue) * BITS_PER_AU) 362 val = 0; 363 else if (stackp != NULL) 364 val = (urvalue) *stackp >> val; 365 break; 366 case RACT_ASR: 367 if (val >= sizeof(rvalue) * BITS_PER_AU) 368 val = sizeof(rvalue) * BITS_PER_AU - 1; 369 else if (stackp != NULL) 370 val = *stackp >> val; 371 break; 372 case RACT_SL: 373 if (val >= sizeof(rvalue) * BITS_PER_AU) 374 val = 0; 375 else if (stackp != NULL) 376 val = *stackp << val; 377 break; 378 case RACT_AND: 379 if (stackp != NULL) 380 val &= *stackp; 381 break; 382 case RACT_OR: 383 if (stackp != NULL) 384 val |= *stackp; 385 break; 386 case RACT_XOR: 387 if (stackp != NULL) 388 val ^= *stackp; 389 break; 390 case RACT_NOT: 391 val = ~val; 392 break; 393#if TMS32060 394 case RACT_C6SECT: 395 /* actually needed address of secn containing symbol */ 396 if (svp != NULL) { 397 if (rp->SYMNDX >= 0) 398 if (svp->secnn > 0) 399 reloc_amt = dlthis->ldr_sections 400 [svp->secnn - 1].run_addr; 401 } 402 /* !!! FALL THRU !!! */ 403 case RACT_C6BASE: 404 if (dlthis->bss_run_base == 0) { 405 struct dynload_symbol *symp; 406 symp = dlthis->mysym->find_matching_symbol 407 (dlthis->mysym, bsssymbol); 408 /* lookup value of global BSS base */ 409 if (symp) 410 dlthis->bss_run_base = symp->value; 411 else 412 dload_error(dlthis, 413 "Global BSS base referenced in %s " 414 "offset" FMT_UI32 " but not " 415 "defined", 416 dlthis->image_secn->name, 417 rp->vaddr + dlthis->image_offset); 418 } 419 reloc_amt -= dlthis->bss_run_base; 420 /* !!! FALL THRU !!! */ 421 case RACT_C6DSPL: 422 /* scale factor determined by 3 LSBs of field */ 423 scale = c60_scale[val & SCALE_MASK]; 424 offset += SCALE_BITS; 425 fieldsz -= SCALE_BITS; 426 val >>= SCALE_BITS; /* ignore the scale field hereafter */ 427 val <<= scale; 428 val += reloc_amt; /* do the usual relocation */ 429 if (((1 << scale) - 1) & val) 430 dload_error(dlthis, 431 "Unaligned reference in %s offset " 432 FMT_UI32, dlthis->image_secn->name, 433 rp->vaddr + dlthis->image_offset); 434 break; 435#endif 436 } /* relocation actions */ 437 /* * Put back result as required */ 438 if (reloc_info & ROP_W) { /* relocation writes image value */ 439#ifdef RFV_SCALE 440 val >>= scale; 441#endif 442 if (dload_repack(dlthis, val, data, fieldsz, offset, 443 RFV_SIGN(reloc_info))) { 444 /* Check to see if this relo can be trampolined, 445 * but only in first phase relocation. 2nd phase 446 * relocation cannot trampoline. */ 447 if ((second_pass == false) && 448 (dload_tramp_avail(dlthis, rp) == true)) { 449 450 /* Before generating the trampoline, restore 451 * the value to its original so the 2nd pass 452 * relo will work. */ 453 dload_repack(dlthis, orig_val, data, fieldsz, 454 offset, RFV_SIGN(reloc_info)); 455 if (!dload_tramp_generate(dlthis, 456 (dlthis->image_secn - 457 dlthis->ldr_sections), 458 dlthis->image_offset, 459 img_pkt, rp)) { 460 dload_error(dlthis, 461 "Failed to " 462 "generate trampoline for " 463 "bit overflow"); 464 dload_error(dlthis, 465 "Relocation val " FMT_UI32 466 " overflows %d bits in %s " 467 "offset " FMT_UI32, val, 468 fieldsz, 469 dlthis->image_secn->name, 470 dlthis->image_offset + 471 rp->vaddr); 472 } else 473 *tramps_generated = true; 474 } else { 475 dload_error(dlthis, "Relocation value " 476 FMT_UI32 " overflows %d bits in %s" 477 " offset " FMT_UI32, val, fieldsz, 478 dlthis->image_secn->name, 479 dlthis->image_offset + rp->vaddr); 480 } 481 } 482 } else if (top) 483 *stackp = val; 484} /* reloc_value */ 485