mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-13 22:25:03 +00:00
803cd75eff
This patch removes those macros that are used to perform casts Signed-off-by: Armando Uribe <x0095078@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
484 lines
14 KiB
C
484 lines
14 KiB
C
/*
|
|
* reloc.c
|
|
*
|
|
* DSP-BIOS Bridge driver support functions for TI OMAP processors.
|
|
*
|
|
* Copyright (C) 2005-2006 Texas Instruments, Inc.
|
|
*
|
|
* This package is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#include "header.h"
|
|
|
|
#if TMS32060
|
|
/* the magic symbol for the start of BSS */
|
|
static const char bsssymbol[] = { ".bss" };
|
|
#endif
|
|
|
|
#if TMS32060
|
|
#include "reloc_table_c6000.c"
|
|
#endif
|
|
|
|
#if TMS32060
|
|
/* From coff.h - ignore these relocation operations */
|
|
#define R_C60ALIGN 0x76 /* C60: Alignment info for compressor */
|
|
#define R_C60FPHEAD 0x77 /* C60: Explicit assembly directive */
|
|
#define R_C60NOCMP 0x100 /* C60: Don't compress this code scn */
|
|
#endif
|
|
|
|
/**************************************************************************
|
|
* Procedure dload_unpack
|
|
*
|
|
* Parameters:
|
|
* data pointer to storage unit containing lowest host address of
|
|
* image data
|
|
* fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
|
|
* offset Offset from LSB, 0 <= offset < BITS_PER_AU
|
|
* sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
|
|
*
|
|
* Effect:
|
|
* Extracts the specified field and returns it.
|
|
************************************************************************* */
|
|
rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, int fieldsz,
|
|
int offset, unsigned sgn)
|
|
{
|
|
register rvalue objval;
|
|
register int shift, direction;
|
|
register tgt_au_t *dp = data;
|
|
|
|
fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */
|
|
/* * collect up enough bits to contain the desired field */
|
|
if (TARGET_BIG_ENDIAN) {
|
|
dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
|
|
direction = -1;
|
|
} else
|
|
direction = 1;
|
|
objval = *dp >> offset;
|
|
shift = TGTAU_BITS - offset;
|
|
while (shift <= fieldsz) {
|
|
dp += direction;
|
|
objval += (rvalue) *dp << shift;
|
|
shift += TGTAU_BITS;
|
|
}
|
|
|
|
/* * sign or zero extend the value appropriately */
|
|
if (sgn == ROP_UNS)
|
|
objval &= (2 << fieldsz) - 1;
|
|
else {
|
|
shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz;
|
|
objval = (objval << shift) >> shift;
|
|
}
|
|
|
|
return objval;
|
|
|
|
} /* dload_unpack */
|
|
|
|
/**************************************************************************
|
|
* Procedure dload_repack
|
|
*
|
|
* Parameters:
|
|
* val Value to insert
|
|
* data Pointer to storage unit containing lowest host address of
|
|
* image data
|
|
* fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
|
|
* offset Offset from LSB, 0 <= offset < BITS_PER_AU
|
|
* sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
|
|
*
|
|
* Effect:
|
|
* Stuffs the specified value in the specified field. Returns 0 for
|
|
* success
|
|
* or 1 if the value will not fit in the specified field according to the
|
|
* specified signedness rule.
|
|
************************************************************************* */
|
|
static const unsigned char ovf_limit[] = { 1, 2, 2 };
|
|
|
|
int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data,
|
|
int fieldsz, int offset, unsigned sgn)
|
|
{
|
|
register urvalue objval, mask;
|
|
register int shift, direction;
|
|
register tgt_au_t *dp = data;
|
|
|
|
fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */
|
|
/* clip the bits */
|
|
mask = (2UL << fieldsz) - 1;
|
|
objval = (val & mask);
|
|
/* * store the bits through the specified mask */
|
|
if (TARGET_BIG_ENDIAN) {
|
|
dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
|
|
direction = -1;
|
|
} else
|
|
direction = 1;
|
|
|
|
/* insert LSBs */
|
|
*dp = (*dp & ~(mask << offset)) + (objval << offset);
|
|
shift = TGTAU_BITS - offset;
|
|
/* align mask and objval with AU boundary */
|
|
objval >>= shift;
|
|
mask >>= shift;
|
|
|
|
while (mask) {
|
|
dp += direction;
|
|
*dp = (*dp & ~mask) + objval;
|
|
objval >>= TGTAU_BITS;
|
|
mask >>= TGTAU_BITS;
|
|
}
|
|
|
|
/*
|
|
* check for overflow
|
|
*/
|
|
if (sgn) {
|
|
unsigned tmp = (val >> fieldsz) + (sgn & 0x1);
|
|
if (tmp > ovf_limit[sgn - 1])
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
} /* dload_repack */
|
|
|
|
/* lookup table for the scaling amount in a C6x instruction */
|
|
#if TMS32060
|
|
#define SCALE_BITS 4 /* there are 4 bits in the scale field */
|
|
#define SCALE_MASK 0x7 /* we really only use the bottom 3 bits */
|
|
static const u8 c60_scale[SCALE_MASK + 1] = {
|
|
1, 0, 0, 0, 1, 1, 2, 2
|
|
};
|
|
#endif
|
|
|
|
/**************************************************************************
|
|
* Procedure dload_relocate
|
|
*
|
|
* Parameters:
|
|
* data Pointer to base of image data
|
|
* rp Pointer to relocation operation
|
|
*
|
|
* Effect:
|
|
* Performs the specified relocation operation
|
|
************************************************************************* */
|
|
void dload_relocate(struct dload_state *dlthis, tgt_au_t * data,
|
|
struct reloc_record_t *rp, bool *tramps_generated,
|
|
bool second_pass)
|
|
{
|
|
rvalue val, reloc_amt, orig_val = 0;
|
|
unsigned int fieldsz = 0;
|
|
unsigned int offset = 0;
|
|
unsigned int reloc_info = 0;
|
|
unsigned int reloc_action = 0;
|
|
register int rx = 0;
|
|
rvalue *stackp = NULL;
|
|
int top;
|
|
struct local_symbol *svp = NULL;
|
|
#ifdef RFV_SCALE
|
|
unsigned int scale = 0;
|
|
#endif
|
|
struct image_packet_t *img_pkt = NULL;
|
|
|
|
/* The image packet data struct is only used during first pass
|
|
* relocation in the event that a trampoline is needed. 2nd pass
|
|
* relocation doesn't guarantee that data is coming from an
|
|
* image_packet_t structure. See cload.c, dload_data for how img_data is
|
|
* set. If that changes this needs to be updated!!! */
|
|
if (second_pass == false)
|
|
img_pkt = (struct image_packet_t *)((u8 *) data -
|
|
sizeof(struct
|
|
image_packet_t));
|
|
|
|
rx = HASH_FUNC(rp->TYPE);
|
|
while (rop_map1[rx] != rp->TYPE) {
|
|
rx = HASH_L(rop_map2[rx]);
|
|
if (rx < 0) {
|
|
#if TMS32060
|
|
switch (rp->TYPE) {
|
|
case R_C60ALIGN:
|
|
case R_C60NOCMP:
|
|
case R_C60FPHEAD:
|
|
/* Ignore these reloc types and return */
|
|
break;
|
|
default:
|
|
/* Unknown reloc type, print error and return */
|
|
dload_error(dlthis, "Bad coff operator 0x%x",
|
|
rp->TYPE);
|
|
}
|
|
#else
|
|
dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
rx = HASH_I(rop_map2[rx]);
|
|
if ((rx < (sizeof(rop_action) / sizeof(u16)))
|
|
&& (rx < (sizeof(rop_info) / sizeof(u16))) && (rx > 0)) {
|
|
reloc_action = rop_action[rx];
|
|
reloc_info = rop_info[rx];
|
|
} else {
|
|
dload_error(dlthis, "Buffer Overflow - Array Index Out "
|
|
"of Bounds");
|
|
}
|
|
|
|
/* Compute the relocation amount for the referenced symbol, if any */
|
|
reloc_amt = rp->UVAL;
|
|
if (RFV_SYM(reloc_info)) { /* relocation uses a symbol reference */
|
|
/* If this is first pass, use the module local symbol table,
|
|
* else use the trampoline symbol table. */
|
|
if (second_pass == false) {
|
|
if ((u32) rp->SYMNDX < dlthis->dfile_hdr.df_no_syms) {
|
|
/* real symbol reference */
|
|
svp = &dlthis->local_symtab[rp->SYMNDX];
|
|
reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
|
|
svp->delta : svp->value;
|
|
}
|
|
/* reloc references current section */
|
|
else if (rp->SYMNDX == -1) {
|
|
reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
|
|
dlthis->delta_runaddr :
|
|
dlthis->image_secn->run_addr;
|
|
}
|
|
}
|
|
}
|
|
/* relocation uses a symbol reference */
|
|
/* Handle stack adjustment */
|
|
val = 0;
|
|
top = RFV_STK(reloc_info);
|
|
if (top) {
|
|
top += dlthis->relstkidx - RSTK_UOP;
|
|
if (top >= STATIC_EXPR_STK_SIZE) {
|
|
dload_error(dlthis,
|
|
"Expression stack overflow in %s at offset "
|
|
FMT_UI32, dlthis->image_secn->name,
|
|
rp->vaddr + dlthis->image_offset);
|
|
return;
|
|
}
|
|
val = dlthis->relstk[dlthis->relstkidx];
|
|
dlthis->relstkidx = top;
|
|
stackp = &dlthis->relstk[top];
|
|
}
|
|
/* Derive field position and size, if we need them */
|
|
if (reloc_info & ROP_RW) { /* read or write action in our future */
|
|
fieldsz = RFV_WIDTH(reloc_action);
|
|
if (fieldsz) { /* field info from table */
|
|
offset = RFV_POSN(reloc_action);
|
|
if (TARGET_BIG_ENDIAN)
|
|
/* make sure vaddr is the lowest target
|
|
* address containing bits */
|
|
rp->vaddr += RFV_BIGOFF(reloc_info);
|
|
} else { /* field info from relocation op */
|
|
fieldsz = rp->FIELDSZ;
|
|
offset = rp->OFFSET;
|
|
if (TARGET_BIG_ENDIAN)
|
|
/* make sure vaddr is the lowest target
|
|
address containing bits */
|
|
rp->vaddr += (rp->WORDSZ - offset - fieldsz)
|
|
>> LOG_TARGET_AU_BITS;
|
|
}
|
|
data = (tgt_au_t *) ((char *)data + TADDR_TO_HOST(rp->vaddr));
|
|
/* compute lowest host location of referenced data */
|
|
#if BITS_PER_AU > TARGET_AU_BITS
|
|
/* conversion from target address to host address may lose
|
|
address bits; add loss to offset */
|
|
if (TARGET_BIG_ENDIAN) {
|
|
offset += -((rp->vaddr << LOG_TARGET_AU_BITS) +
|
|
offset + fieldsz) &
|
|
(BITS_PER_AU - TARGET_AU_BITS);
|
|
} else {
|
|
offset += (rp->vaddr << LOG_TARGET_AU_BITS) &
|
|
(BITS_PER_AU - 1);
|
|
}
|
|
#endif
|
|
#ifdef RFV_SCALE
|
|
scale = RFV_SCALE(reloc_info);
|
|
#endif
|
|
}
|
|
/* read the object value from the current image, if so ordered */
|
|
if (reloc_info & ROP_R) {
|
|
/* relocation reads current image value */
|
|
val = dload_unpack(dlthis, data, fieldsz, offset,
|
|
RFV_SIGN(reloc_info));
|
|
/* Save off the original value in case the relo overflows and
|
|
* we can trampoline it. */
|
|
orig_val = val;
|
|
|
|
#ifdef RFV_SCALE
|
|
val <<= scale;
|
|
#endif
|
|
}
|
|
/* perform the necessary arithmetic */
|
|
switch (RFV_ACTION(reloc_action)) { /* relocation actions */
|
|
case RACT_VAL:
|
|
break;
|
|
case RACT_ASGN:
|
|
val = reloc_amt;
|
|
break;
|
|
case RACT_ADD:
|
|
val += reloc_amt;
|
|
break;
|
|
case RACT_PCR:
|
|
/*-----------------------------------------------------------
|
|
* Handle special cases of jumping from absolute sections
|
|
* (special reloc type) or to absolute destination
|
|
* (symndx == -1). In either case, set the appropriate
|
|
* relocation amount to 0.
|
|
*----------------------------------------------------------- */
|
|
if (rp->SYMNDX == -1)
|
|
reloc_amt = 0;
|
|
val += reloc_amt - dlthis->delta_runaddr;
|
|
break;
|
|
case RACT_ADDISP:
|
|
val += rp->R_DISP + reloc_amt;
|
|
break;
|
|
case RACT_ASGPC:
|
|
val = dlthis->image_secn->run_addr + reloc_amt;
|
|
break;
|
|
case RACT_PLUS:
|
|
if (stackp != NULL)
|
|
val += *stackp;
|
|
break;
|
|
case RACT_SUB:
|
|
if (stackp != NULL)
|
|
val = *stackp - val;
|
|
break;
|
|
case RACT_NEG:
|
|
val = -val;
|
|
break;
|
|
case RACT_MPY:
|
|
if (stackp != NULL)
|
|
val *= *stackp;
|
|
break;
|
|
case RACT_DIV:
|
|
if (stackp != NULL)
|
|
val = *stackp / val;
|
|
break;
|
|
case RACT_MOD:
|
|
if (stackp != NULL)
|
|
val = *stackp % val;
|
|
break;
|
|
case RACT_SR:
|
|
if (val >= sizeof(rvalue) * BITS_PER_AU)
|
|
val = 0;
|
|
else if (stackp != NULL)
|
|
val = (urvalue) *stackp >> val;
|
|
break;
|
|
case RACT_ASR:
|
|
if (val >= sizeof(rvalue) * BITS_PER_AU)
|
|
val = sizeof(rvalue) * BITS_PER_AU - 1;
|
|
else if (stackp != NULL)
|
|
val = *stackp >> val;
|
|
break;
|
|
case RACT_SL:
|
|
if (val >= sizeof(rvalue) * BITS_PER_AU)
|
|
val = 0;
|
|
else if (stackp != NULL)
|
|
val = *stackp << val;
|
|
break;
|
|
case RACT_AND:
|
|
if (stackp != NULL)
|
|
val &= *stackp;
|
|
break;
|
|
case RACT_OR:
|
|
if (stackp != NULL)
|
|
val |= *stackp;
|
|
break;
|
|
case RACT_XOR:
|
|
if (stackp != NULL)
|
|
val ^= *stackp;
|
|
break;
|
|
case RACT_NOT:
|
|
val = ~val;
|
|
break;
|
|
#if TMS32060
|
|
case RACT_C6SECT:
|
|
/* actually needed address of secn containing symbol */
|
|
if (svp != NULL) {
|
|
if (rp->SYMNDX >= 0)
|
|
if (svp->secnn > 0)
|
|
reloc_amt = dlthis->ldr_sections
|
|
[svp->secnn - 1].run_addr;
|
|
}
|
|
/* !!! FALL THRU !!! */
|
|
case RACT_C6BASE:
|
|
if (dlthis->bss_run_base == 0) {
|
|
struct dynload_symbol *symp;
|
|
symp = dlthis->mysym->find_matching_symbol
|
|
(dlthis->mysym, bsssymbol);
|
|
/* lookup value of global BSS base */
|
|
if (symp)
|
|
dlthis->bss_run_base = symp->value;
|
|
else
|
|
dload_error(dlthis,
|
|
"Global BSS base referenced in %s "
|
|
"offset" FMT_UI32 " but not "
|
|
"defined",
|
|
dlthis->image_secn->name,
|
|
rp->vaddr + dlthis->image_offset);
|
|
}
|
|
reloc_amt -= dlthis->bss_run_base;
|
|
/* !!! FALL THRU !!! */
|
|
case RACT_C6DSPL:
|
|
/* scale factor determined by 3 LSBs of field */
|
|
scale = c60_scale[val & SCALE_MASK];
|
|
offset += SCALE_BITS;
|
|
fieldsz -= SCALE_BITS;
|
|
val >>= SCALE_BITS; /* ignore the scale field hereafter */
|
|
val <<= scale;
|
|
val += reloc_amt; /* do the usual relocation */
|
|
if (((1 << scale) - 1) & val)
|
|
dload_error(dlthis,
|
|
"Unaligned reference in %s offset "
|
|
FMT_UI32, dlthis->image_secn->name,
|
|
rp->vaddr + dlthis->image_offset);
|
|
break;
|
|
#endif
|
|
} /* relocation actions */
|
|
/* * Put back result as required */
|
|
if (reloc_info & ROP_W) { /* relocation writes image value */
|
|
#ifdef RFV_SCALE
|
|
val >>= scale;
|
|
#endif
|
|
if (dload_repack(dlthis, val, data, fieldsz, offset,
|
|
RFV_SIGN(reloc_info))) {
|
|
/* Check to see if this relo can be trampolined,
|
|
* but only in first phase relocation. 2nd phase
|
|
* relocation cannot trampoline. */
|
|
if ((second_pass == false) &&
|
|
(dload_tramp_avail(dlthis, rp) == true)) {
|
|
|
|
/* Before generating the trampoline, restore
|
|
* the value to its original so the 2nd pass
|
|
* relo will work. */
|
|
dload_repack(dlthis, orig_val, data, fieldsz,
|
|
offset, RFV_SIGN(reloc_info));
|
|
if (!dload_tramp_generate(dlthis,
|
|
(dlthis->image_secn -
|
|
dlthis->ldr_sections),
|
|
dlthis->image_offset,
|
|
img_pkt, rp)) {
|
|
dload_error(dlthis,
|
|
"Failed to "
|
|
"generate trampoline for "
|
|
"bit overflow");
|
|
dload_error(dlthis,
|
|
"Relocation val " FMT_UI32
|
|
" overflows %d bits in %s "
|
|
"offset " FMT_UI32, val,
|
|
fieldsz,
|
|
dlthis->image_secn->name,
|
|
dlthis->image_offset +
|
|
rp->vaddr);
|
|
} else
|
|
*tramps_generated = true;
|
|
} else {
|
|
dload_error(dlthis, "Relocation value "
|
|
FMT_UI32 " overflows %d bits in %s"
|
|
" offset " FMT_UI32, val, fieldsz,
|
|
dlthis->image_secn->name,
|
|
dlthis->image_offset + rp->vaddr);
|
|
}
|
|
}
|
|
} else if (top)
|
|
*stackp = val;
|
|
} /* reloc_value */
|