4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
20 /* the magic symbol for the start of BSS */
21 static const char bsssymbol[] = { ".bss" };
25 #include "reloc_table_c6000.c"
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 */
35 /**************************************************************************
36 * Procedure dload_unpack
39 * data pointer to storage unit containing lowest host address of
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)
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)
51 register rvalue objval;
52 register int shift, direction;
53 register tgt_au_t *dp = data;
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;
62 objval = *dp >> offset;
63 shift = TGTAU_BITS - offset;
64 while (shift <= fieldsz) {
66 objval += (rvalue) *dp << shift;
70 /* * sign or zero extend the value appropriately */
72 objval &= (2 << fieldsz) - 1;
74 shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz;
75 objval = (objval << shift) >> shift;
82 /**************************************************************************
83 * Procedure dload_repack
87 * data Pointer to storage unit containing lowest host address of
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)
94 * Stuffs the specified value in the specified field. Returns 0 for
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 };
101 int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t *data,
102 int fieldsz, int offset, unsigned sgn)
104 register urvalue objval, mask;
105 register int shift, direction;
106 register tgt_au_t *dp = data;
108 fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */
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;
120 *dp = (*dp & ~(mask << offset)) + (objval << offset);
121 shift = TGTAU_BITS - offset;
122 /* align mask and objval with AU boundary */
128 *dp = (*dp & ~mask) + objval;
129 objval >>= TGTAU_BITS;
137 unsigned tmp = (val >> fieldsz) + (sgn & 0x1);
138 if (tmp > ovf_limit[sgn - 1])
145 /* lookup table for the scaling amount in a C6x instruction */
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
154 /**************************************************************************
155 * Procedure dload_relocate
158 * data Pointer to base of image data
159 * rp Pointer to relocation operation
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,
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;
174 rvalue *stackp = NULL;
176 struct local_symbol *svp = NULL;
178 unsigned int scale = 0;
180 struct image_packet_t *img_pkt = NULL;
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 -
192 rx = HASH_FUNC(rp->TYPE);
193 while (rop_map1[rx] != rp->TYPE) {
194 rx = HASH_L(rop_map2[rx]);
201 /* Ignore these reloc types and return */
204 /* Unknown reloc type, print error and return */
205 dload_error(dlthis, "Bad coff operator 0x%x",
209 dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE);
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];
220 dload_error(dlthis, "Buffer Overflow - Array Index Out "
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;
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;
244 /* relocation uses a symbol reference */
245 /* Handle stack adjustment */
247 top = RFV_STK(reloc_info);
249 top += dlthis->relstkidx - RSTK_UOP;
250 if (top >= STATIC_EXPR_STK_SIZE) {
252 "Expression stack overflow in %s at offset "
253 FMT_UI32, dlthis->image_secn->name,
254 rp->vaddr + dlthis->image_offset);
257 val = dlthis->relstk[dlthis->relstkidx];
258 dlthis->relstkidx = top;
259 stackp = &dlthis->relstk[top];
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;
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;
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) +
287 (BITS_PER_AU - TARGET_AU_BITS);
289 offset += (rp->vaddr << LOG_TARGET_AU_BITS) &
294 scale = RFV_SCALE(reloc_info);
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. */
310 /* perform the necessary arithmetic */
311 switch (RFV_ACTION(reloc_action)) { /* relocation actions */
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)
329 val += reloc_amt - dlthis->delta_runaddr;
332 val += rp->R_DISP + reloc_amt;
335 val = dlthis->image_secn->run_addr + reloc_amt;
361 if (val >= sizeof(rvalue) * BITS_PER_AU)
363 else if (stackp != NULL)
364 val = (urvalue) *stackp >> val;
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;
373 if (val >= sizeof(rvalue) * BITS_PER_AU)
375 else if (stackp != NULL)
376 val = *stackp << val;
395 /* actually needed address of secn containing symbol */
399 reloc_amt = dlthis->ldr_sections
400 [svp->secnn - 1].run_addr;
402 /* !!! FALL THRU !!! */
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 */
410 dlthis->bss_run_base = symp->value;
413 "Global BSS base referenced in %s "
414 "offset" FMT_UI32 " but not "
416 dlthis->image_secn->name,
417 rp->vaddr + dlthis->image_offset);
419 reloc_amt -= dlthis->bss_run_base;
420 /* !!! FALL THRU !!! */
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 */
428 val += reloc_amt; /* do the usual relocation */
429 if (((1 << scale) - 1) & val)
431 "Unaligned reference in %s offset "
432 FMT_UI32, dlthis->image_secn->name,
433 rp->vaddr + dlthis->image_offset);
436 } /* relocation actions */
437 /* * Put back result as required */
438 if (reloc_info & ROP_W) { /* relocation writes image value */
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)) {
450 /* Before generating the trampoline, restore
451 * the value to its original so the 2nd pass
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,
462 "generate trampoline for "
465 "Relocation val " FMT_UI32
466 " overflows %d bits in %s "
467 "offset " FMT_UI32, val,
469 dlthis->image_secn->name,
470 dlthis->image_offset +
473 *tramps_generated = true;
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);