Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
reloc.c
Go to the documentation of this file.
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 */
21 static 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  ************************************************************************* */
48 rvalue 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  ************************************************************************* */
99 static const unsigned char ovf_limit[] = { 1, 2, 2 };
100 
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 */
149 static 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  ************************************************************************* */
164 void 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)
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) &
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 */