• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/tidspbridge/dynload/
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