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
);