diff mbox

[PATCHv2,04/18] DSPBRIDGE: Implemented Trampoline support for dynamic loader

Message ID 1261016163-11091-5-git-send-email-omar.ramirez@ti.com (mailing list archive)
State Awaiting Upstream, archived
Headers show

Commit Message

omar ramirez Dec. 17, 2009, 2:15 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/dsp/bridge/Makefile b/drivers/dsp/bridge/Makefile
index e10a2da..cb6d1ce 100644
--- a/drivers/dsp/bridge/Makefile
+++ b/drivers/dsp/bridge/Makefile
@@ -14,7 +14,8 @@  libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/wcd.o \
 librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \
 		rmgr/proc.o rmgr/pwr.o rmgr/rmm.o rmgr/strm.o rmgr/dspdrv.o \
 		rmgr/nldr.o rmgr/drv_interface.o
-libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o
+libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o \
+		 dynload/tramp.o
 libhw = hw/hw_prcm.o hw/hw_dspssC64P.o hw/hw_mmu.o hw/hw_mbox.o
 
 bridgedriver-objs = $(libgen) $(libservices) $(libwmd) $(libpmgr) $(librmgr) \
diff --git a/drivers/dsp/bridge/dynload/cload.c b/drivers/dsp/bridge/dynload/cload.c
index 4fead55..505fcdf 100644
--- a/drivers/dsp/bridge/dynload/cload.c
+++ b/drivers/dsp/bridge/dynload/cload.c
@@ -191,6 +191,8 @@  int Dynamic_Load_Module(struct Dynamic_Loader_Stream *module,
 		symbol_table_free(&dl_state);
 		section_table_free(&dl_state);
 		string_table_free(&dl_state);
+		dload_tramp_cleanup(&dl_state);
+
 
 		if (dl_state.dload_errcount) {
 			Dynamic_Unload_Module(dl_state.myhandle, syms, alloc,
@@ -489,10 +491,14 @@  static void allocate_sections(struct dload_state *dlthis)
 		DL_ERROR("Arg 3 (alloc) required but NULL", 0);
 		return;
 	}
-	/* allocate space for the module handle, which we will
-	 *	keep for unload purposes */
-	siz = dlthis->dfile_hdr.df_target_scns *
-	      sizeof(struct LDR_SECTION_INFO) + MY_HANDLE_SIZE;
+	/*
+	 * allocate space for the module handle, which we will keep for unload
+	 * purposes include an additional section store for an auto-generated
+	 * trampoline section in case we need it.
+	 */
+	siz = (dlthis->dfile_hdr.df_target_scns + 1) *
+		sizeof(struct LDR_SECTION_INFO) + MY_HANDLE_SIZE;
+
 	hndl = (struct my_handle *)dlthis->mysym->Allocate(dlthis->mysym, siz);
 	if (!hndl) {		/* not enough storage */
 		DL_ERROR(E_ALLOC, siz);
@@ -587,7 +593,7 @@  static void section_table_free(struct dload_state *dlthis)
  * big unsorted array.  We just read that array into memory in bulk.
  ************************************************************************/
 static const char S_STRINGTBL[] = { "string table" };
-void dload_strings(struct dload_state *dlthis, boolean sec_names_only)
+void dload_strings(struct dload_state *dlthis, bool sec_names_only)
 {
 	u32 ssiz;
 	char *strbuf;
@@ -707,11 +713,16 @@  static void dload_symbols(struct dload_state *dlthis)
 	if (s_count == 0)
 		return;
 
-	/* We keep a local symbol table for all of the symbols in the input.
+	/*
+	 * We keep a local symbol table for all of the symbols in the input.
 	 * This table contains only section & value info, as we do not have
 	 * to do any name processing for locals.  We reuse this storage
 	 * as a temporary for .dllview record construction.
-	 * Allocate storage for the whole table.*/
+	 * Allocate storage for the whole table.  Add 1 to the section count
+	 * in case a trampoline section is auto-generated as well as the
+	 * size of the trampoline section name so DLLView doens't get lost.
+	 */
+
 	siz = s_count * sizeof(struct Local_Symbol);
 	dsiz = DBG_HDR_SIZE +
 		(sizeof(struct dll_sect) * dlthis->allocated_secn_count) +
@@ -790,6 +801,12 @@  static void dload_symbols(struct dload_state *dlthis)
 					goto loop_cont;
 				}
 				val = delta = symp->value;
+#ifdef ENABLE_TRAMP_DEBUG
+				dload_syms_error(dlthis->mysym,
+						"===> ext sym [%s] at %x",
+						sname, val);
+#endif
+
 				goto loop_cont;
 			}
 			/* symbol defined by this module */
@@ -1045,9 +1062,11 @@  loopexit:
 #define MY_RELOC_BUF_SIZ 8
 /* careful! exists at the same time as the image buffer*/
 static int relocate_packet(struct dload_state *dlthis,
-			   struct image_packet_t *ipacket, u32 *checks)
+				struct image_packet_t *ipacket,
+				u32 *checks, bool *tramps_generated)
 {
 	u32 rnum;
+	*tramps_generated = false;
 
 	rnum = ipacket->i_num_relocs;
 	do {			/* all relocs */
@@ -1068,11 +1087,21 @@  static int relocate_packet(struct dload_state *dlthis,
 		*checks += dload_checksum(rp, siz);
 		do {
 			/* perform the relocation operation */
-			dload_relocate(dlthis, (TgtAU_t *) ipacket->i_bits, rp);
+			dload_relocate(dlthis, (TgtAU_t *) ipacket->i_bits, rp,
+					tramps_generated, false);
 			rp += 1;
 			rnum -= 1;
 		} while ((rinbuf -= 1) > 0);
 	} while (rnum > 0);	/* all relocs */
+	/* If trampoline(s) were generated, we need to do an update of the
+	 * trampoline copy of the packet since a 2nd phase relo will be done
+	 * later.  */
+	if (*tramps_generated == true) {
+		dload_tramp_pkt_udpate(dlthis,
+				(dlthis->image_secn - dlthis->ldr_sections),
+				dlthis->image_offset, ipacket);
+	}
+
 	return 1;
 }				/* dload_read_reloc */
 
@@ -1097,7 +1126,7 @@  static void dload_data(struct dload_state *dlthis)
 	struct doff_scnhdr_t *sptr = dlthis->sect_hdrs;
 	struct LDR_SECTION_INFO *lptr = dlthis->ldr_sections;
 #ifdef OPT_ZERO_COPY_LOADER
-	boolean bZeroCopy = false;
+	bool bZeroCopy = false;
 #endif
 	u8 *pDest;
 
@@ -1107,7 +1136,7 @@  static void dload_data(struct dload_state *dlthis)
 	} ibuf;
 
 	/* Indicates whether CINIT processing has occurred */
-	boolean cinit_processed = false;
+	bool cinit_processed = false;
 
 	/* Loop through the sections and load them one at a time.
 	 */
@@ -1132,6 +1161,8 @@  static void dload_data(struct dload_state *dlthis)
 
 				s32 ipsize;
 				u32 checks;
+				bool  tramp_generated = false;
+
 				/* get the fixed header bits */
 				if (dlthis->strm->read_buffer(dlthis->strm,
 				    &ibuf.ipacket, IPH_SIZE) != IPH_SIZE) {
@@ -1203,33 +1234,44 @@  static void dload_data(struct dload_state *dlthis)
 				if (ibuf.ipacket.i_num_relocs) {
 					dlthis->image_offset = image_offset;
 					if (!relocate_packet(dlthis,
-					    &ibuf.ipacket, &checks))
+					    &ibuf.ipacket, &checks,
+					    &tramp_generated))
 						return;	/* serious error */
 				}
 				if (~checks)
 					DL_ERROR(E_CHECKSUM, IMAGEPAK);
-				/* stuff the result into target memory */
-				if (DLOAD_SECT_TYPE(sptr) == DLOAD_CINIT) {
-					cload_cinit(dlthis, &ibuf.ipacket);
-					cinit_processed = true;
-				} else {
+				/* Only write the result to the target if no
+				  * trampoline was generated.  Otherwise it
+				  *will be done during trampoline finalize.  */
+
+				if (tramp_generated == false) {
+
+					/* stuff the result into target
+					 * memory */
+					if (DLOAD_SECT_TYPE(sptr) ==
+					    DLOAD_CINIT) {
+						cload_cinit(dlthis,
+							&ibuf.ipacket);
+						cinit_processed = true;
+					} else {
 #ifdef OPT_ZERO_COPY_LOADER
-				    if (!bZeroCopy) {
+						if (!bZeroCopy) {
 #endif
-
-					if (!dlthis->myio->writemem
-					   (dlthis->myio, ibuf.bufr,
-					   lptr->load_addr + image_offset, lptr,
-					   BYTE_TO_HOST
-					   (ibuf.ipacket.i_packet_size))) {
-						DL_ERROR(
-						"Write to " FMT_UI32 " failed",
-						lptr->load_addr + image_offset);
-					}
+						if (!dlthis->myio->writemem
+						(dlthis->myio, ibuf.bufr,
+						lptr->load_addr + image_offset,
+						lptr, BYTE_TO_HOST
+						(ibuf.ipacket.i_packet_size))) {
+							DL_ERROR(
+							"Write to " FMT_UI32
+							" failed",
+							lptr->load_addr +
+							image_offset);
+						}
 #ifdef OPT_ZERO_COPY_LOADER
-				}
+					}
 #endif
-
+					}
 				}
 				image_offset +=
 				      BYTE_TO_TADDR(ibuf.ipacket.i_packet_size);
@@ -1281,6 +1323,12 @@  loop_cont:
 		sptr += 1;
 		lptr += 1;
 	}			/* load sections */
+
+	/*  Finalize any trampolines that were created during the load  */
+	if (dload_tramp_finalize(dlthis) == 0) {
+		DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32
+			") failed", dlthis->tramp.tramp_sect_next_addr);
+    }
 }				/* dload_data */
 
 /*************************************************************************
@@ -1526,6 +1574,16 @@  static void init_module_handle(struct dload_state *dlthis)
 	hndl = dlthis->myhandle;
 	if (!hndl)
 		return;		/* must be errors detected, so forget it */
+
+	/*  Store the section count  */
+	hndl->secn_count = dlthis->allocated_secn_count;
+
+	/*  If a trampoline section was created, add it in  */
+	if (dlthis->tramp.tramp_sect_next_addr != 0)
+		hndl->secn_count += 1;
+
+	hndl->secn_count = hndl->secn_count << 1;
+
 	hndl->secn_count = dlthis->allocated_secn_count << 1;
 #ifndef TARGET_ENDIANNESS
 	if (dlthis->big_e_target)
@@ -1603,10 +1661,30 @@  static void init_module_handle(struct dload_state *dlthis)
 		dbsec += 1;
 		asecs += 1;
 	}
+
+	/*  If a trampoline section was created go ahead and add its info  */
+	if (dlthis->tramp.tramp_sect_next_addr != 0) {
+		dbmod->num_sects++;
+		dbsec->sect_load_adr = asecs->load_addr;
+		dbsec->sect_run_adr = asecs->run_addr;
+		dbsec++;
+		asecs++;
+	}
+
 	/* now cram in the names */
 	cp = copy_tgt_strings(dbsec, dlthis->str_head,
 			      dlthis->debug_string_size);
 
+
+	/* If a trampoline section was created, add its name so DLLView
+	 * can show the user the section info.  */
+	if (dlthis->tramp.tramp_sect_next_addr != 0) {
+		cp = copy_tgt_strings(cp,
+			dlthis->tramp.final_string_table,
+			strlen(dlthis->tramp.final_string_table) + 1);
+	}
+
+
 	/* round off the size of the debug record, and remember same */
 	hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod);
 	*cp = 0;		/* strictly to make our test harness happy */
@@ -1713,7 +1791,9 @@  int Dynamic_Unload_Module(DLOAD_mhandle mhandle,
 	if (!syms)
 		return 1;
 	syms->Purge_Symbol_Table(syms, (unsigned) hndl);
-	 /* Deallocate target memory for sections */
+	 /* Deallocate target memory for sections
+	  * NOTE: The trampoline section, if created, gets deleted here, too */
+
 	asecs = hndl->secns;
 	if (alloc)
 		for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0;
diff --git a/drivers/dsp/bridge/dynload/dload_internal.h b/drivers/dsp/bridge/dynload/dload_internal.h
index 78f5058..65d1f47 100644
--- a/drivers/dsp/bridge/dynload/dload_internal.h
+++ b/drivers/dsp/bridge/dynload/dload_internal.h
@@ -120,7 +120,103 @@  struct Local_Symbol {
 	s32 delta;	/* Original value in input file */
 	s16 secnn;		/* section number */
 	s16 sclass;		/* symbol class */
-} ;
+};
+
+
+/*
+ * Trampoline data structures
+ */
+#define TRAMP_NO_GEN_AVAIL              65535
+#define TRAMP_SYM_PREFIX                "__$dbTR__"
+#define TRAMP_SECT_NAME                 ".dbTR"
+#define TRAMP_SYM_PREFIX_LEN            9  /*  MUST MATCH THE LENGTH ABOVE!! */
+#define TRAMP_SYM_HEX_ASCII_LEN         9  /*  Includes NULL termination  */
+
+#define GET_CONTAINER(ptr, type, field) ((type *)((unsigned long)ptr -\
+				(unsigned long)(&((type *)0)->field)))
+#ifndef FIELD_OFFSET
+#define FIELD_OFFSET(type, field)       ((unsigned long)(&((type *)0)->field))
+#endif
+
+
+/*
+    The trampoline code for the target is located in a table called
+    "tramp_gen_info" with is indexed by looking up the index in the table
+    "tramp_map".  The tramp_map index is acquired using the target
+    HASH_FUNC on the relocation type that caused the trampoline.  Each
+    trampoline code table entry MUST follow this format:
+
+    |----------------------------------------------|
+    |  tramp_gen_code_hdr                          |
+    |----------------------------------------------|
+    |  Trampoline image code                       |
+    |  (the raw instruction code for the target)   |
+    |----------------------------------------------|
+    |  Relocation entries for the image code       |
+    |----------------------------------------------|
+
+    This is very similar to how image data is laid out in the DOFF file
+    itself.
+*/
+struct tramp_gen_code_hdr {
+	u32		tramp_code_size;    /*  in BYTES  */
+	u32		num_relos;
+	u32		relo_offset;   /*  in BYTES  */
+};
+
+struct tramp_img_pkt {
+	struct tramp_img_pkt	*next;    /*  MUST BE FIRST  */
+	u32		base;
+	struct tramp_gen_code_hdr	hdr;
+	u8		payload[VARIABLE_SIZE];
+};
+
+struct tramp_img_dup_relo {
+	struct tramp_img_dup_relo	*next;
+	struct reloc_record_t	relo;
+};
+
+struct tramp_img_dup_pkt {
+	struct tramp_img_dup_pkt  *next;    /*  MUST BE FIRST  */
+	s16		secnn;
+	u32		offset;
+	struct image_packet_t                img_pkt;
+	struct tramp_img_dup_relo            *relo_chain;
+
+	/*  PAYLOAD OF IMG PKT FOLLOWS  */
+};
+
+struct tramp_sym {
+	struct tramp_sym	*next;    /*  MUST BE FIRST  */
+	u32		index;
+	u32		str_index;
+	struct Local_Symbol sym_info;
+};
+
+struct tramp_string {
+	struct tramp_string	*next;    /*  MUST BE FIRST  */
+	u32	index;
+	char    str[VARIABLE_SIZE];    /*  NULL terminated  */
+};
+
+struct tramp_info {
+	u32		tramp_sect_next_addr;
+	struct LDR_SECTION_INFO	sect_info;
+
+	struct tramp_sym		*symbol_head;
+	struct tramp_sym		*symbol_tail;
+	u32		tramp_sym_next_index;
+	struct	Local_Symbol		*final_sym_table;
+
+	struct tramp_string                *string_head;
+	struct tramp_string                *string_tail;
+	u32		tramp_string_next_index;
+	u32		tramp_string_size;
+	char		*final_string_table;
+
+	struct tramp_img_pkt		*tramp_pkts;
+	struct tramp_img_dup_pkt	*dup_pkts;
+};
 
 /*
  * States of the .cinit state machine
@@ -187,6 +283,8 @@  struct dload_state {
 	struct doff_filehdr_t dfile_hdr;	/* DOFF file header structure */
 	struct doff_verify_rec_t verify;	/* Verify record */
 
+	struct tramp_info tramp;	/* Trampoline data, if needed  */
+
 	int relstkidx;		/* index into relocation value stack */
 	/* relocation value stack used in relexp.c */
 	RVALUE relstk[STATIC_EXPR_STK_SIZE];
@@ -206,7 +304,7 @@  extern void dload_error(struct dload_state *dlthis, const char *errtxt, ...);
 extern void dload_syms_error(struct Dynamic_Loader_Sym *syms,
 			     const char *errtxt, ...);
 extern void dload_headers(struct dload_state *dlthis);
-extern void dload_strings(struct dload_state *dlthis, boolean sec_names_only);
+extern void dload_strings(struct dload_state *dlthis, bool sec_names_only);
 extern void dload_sections(struct dload_state *dlthis);
 extern void dload_reorder(void *data, int dsiz, u32 map);
 extern u32 dload_checksum(void *data, unsigned siz);
@@ -226,7 +324,8 @@  extern uint32_t dload_reverse_checksum_16(void *data, unsigned siz);
  * exported by reloc.c
  */
 extern void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
-			   struct reloc_record_t *rp);
+			struct reloc_record_t *rp, bool *tramps_generated,
+			bool second_pass);
 
 extern RVALUE dload_unpack(struct dload_state *dlthis, TgtAU_t *data,
 			   int fieldsz, int offset, unsigned sgn);
@@ -234,4 +333,24 @@  extern RVALUE dload_unpack(struct dload_state *dlthis, TgtAU_t *data,
 extern int dload_repack(struct dload_state *dlthis, RVALUE val, TgtAU_t *data,
 			int fieldsz, int offset, unsigned sgn);
 
+
+/*
+ * exported by tramp.c
+ */
+extern bool dload_tramp_avail(struct dload_state *dlthis,
+			struct reloc_record_t *rp);
+
+int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
+			u32 image_offset, struct image_packet_t *ipacket,
+			struct reloc_record_t *rp);
+
+extern int dload_tramp_pkt_udpate(struct dload_state *dlthis,
+			s16 secnn, u32 image_offset,
+			struct image_packet_t *ipacket);
+
+extern int dload_tramp_finalize(struct dload_state *dlthis);
+
+extern void dload_tramp_cleanup(struct dload_state *dlthis);
+
+
 #endif				/* __DLOAD_INTERNAL__ */
diff --git a/drivers/dsp/bridge/dynload/reloc.c b/drivers/dsp/bridge/dynload/reloc.c
index 54e460e..d4457c5 100644
--- a/drivers/dsp/bridge/dynload/reloc.c
+++ b/drivers/dsp/bridge/dynload/reloc.c
@@ -163,10 +163,10 @@  static const u8 C60_Scale[SCALE_MASK+1] = {
  *	Performs the specified relocation operation
  **************************************************************************/
 void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
-		    struct reloc_record_t *rp)
+			struct reloc_record_t *rp, bool *tramps_genereted,
+			bool second_pass)
 {
-	RVALUE val = 0;
-	RVALUE reloc_amt = 0;
+	RVALUE val, reloc_amt, orig_val = 0;
 	unsigned int fieldsz = 0;
 	unsigned int offset = 0;
 	unsigned int reloc_info = 0;
@@ -178,6 +178,17 @@  void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
 #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 i_bits 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->r_type);
 	while (rop_map1[rx] != rp->r_type) {
@@ -211,16 +222,22 @@  void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
 	/* Compute the relocation amount for the referenced symbol, if any */
 	reloc_amt = rp->r_uval;
 	if (RFV_SYM(reloc_info)) {	/* relocation uses a symbol reference */
-		if ((u32)rp->r_symndx < dlthis->dfile_hdr.df_no_syms) {
-			/* real symbol reference */
-			svp = &dlthis->local_symtab[rp->r_symndx];
-			reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
-				    svp->delta : svp->value;
+		/* If this is first pass, use the module local symbol table,
+		  * else use the trampoline symbol table.  */
+	       if (second_pass == false) {
+			if ((u32)rp->r_symndx < dlthis->dfile_hdr.df_no_syms) {
+				/* real symbol reference */
+				svp = &dlthis->local_symtab[rp->r_symndx];
+				reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
+					    svp->delta : svp->value;
+			}
+			/* reloc references current section */
+			else if (rp->r_symndx == -1) {
+				reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
+				dlthis->delta_runaddr :
+				dlthis->image_secn->run_addr;
+			}
 		}
-		/* reloc references current section */
-		else if (rp->r_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;
@@ -277,6 +294,10 @@  void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
 	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
@@ -414,10 +435,38 @@  void dload_relocate(struct dload_state *dlthis, TgtAU_t *data,
 #endif
 		if (dload_repack(dlthis, val, data, fieldsz, offset,
 		   RFV_SIGN(reloc_info))) {
-			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->r_vaddr);
+			/* 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 value "
+					   FMT_UI32 " overflows %d bits in %s "
+					   "offset " FMT_UI32, val, fieldsz,
+					   dlthis->image_secn->name,
+					   dlthis->image_offset + rp->r_vaddr);
+				} else
+					*tramps_genereted = 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->r_vaddr);
+			}
 		}
 	} else if (top)
 		*stackp = val;
diff --git a/drivers/dsp/bridge/dynload/tramp.c b/drivers/dsp/bridge/dynload/tramp.c
new file mode 100644
index 0000000..8c725c7
--- /dev/null
+++ b/drivers/dsp/bridge/dynload/tramp.c
@@ -0,0 +1,1110 @@ 
+/*
+ *  Copyright 2009 by Texas Instruments Incorporated.
+ *  All rights reserved. Property of Texas Instruments Incorporated.
+ *  Restricted rights to use, duplicate or disclose this code are
+ *  granted through contract.
+ *
+ *  @(#) DSP/BIOS Bridge
+ */
+#include "header.h"
+
+#if TMS32060
+#include "tramp_table_c6000.c"
+#endif
+
+#define MAX_RELOS_PER_PASS	4
+
+/*
+ * Function:	priv_tramp_sect_tgt_alloc
+ * Description: Allocate target memory for the trampoline section.  The
+ *	  target mem size is easily obtained as the next available address.
+ */
+static int priv_tramp_sect_tgt_alloc(struct dload_state *dlthis)
+{
+	int ret_val = 0;
+	struct LDR_SECTION_INFO	*sect_info;
+
+	/*  Populate the trampoline loader section and allocate it on the
+	 * target.  The section name is ALWAYS the first string in the final
+	 * string table for trampolines.  The trampoline section is always
+	 * 1 beyond the total number of allocated sections.  */
+	sect_info = &dlthis->ldr_sections[dlthis->allocated_secn_count];
+
+	sect_info->name = dlthis->tramp.final_string_table;
+	sect_info->size = dlthis->tramp.tramp_sect_next_addr;
+	sect_info->context = 0;
+	sect_info->type =
+		(4 << 8) | DLOAD_TEXT | DS_ALLOCATE_MASK | DS_DOWNLOAD_MASK;
+	sect_info->page = 0;
+	sect_info->run_addr = 0;
+	sect_info->load_addr = 0;
+	ret_val = dlthis->myalloc->Allocate(dlthis->myalloc,
+			sect_info, DS_ALIGNMENT(sect_info->type));
+
+	if (ret_val == 0)
+		dload_error(dlthis, "Failed to allocate target memory for"
+							" trampoline");
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_h2a
+ * Description: Helper function to convert a hex value to its ASCII
+ *	  representation.  Used for trampoline symbol name generation.
+ */
+static u8 priv_h2a(u8 value)
+{
+	if (value > 0xF)
+		return 0xFF;
+
+	if (value <= 9)
+		value += 0x30;
+	else
+		value += 0x37;
+
+	return value;
+}
+
+/*
+ * Function:	priv_tramp_sym_gen_name
+ * Description: Generate a trampoline symbol name (ASCII) using the value
+ *	  of the symbol.  This places the new name into the user buffer.
+ *	  The name is fixed in length and of the form: __$dbTR__xxxxxxxx
+ *	  (where "xxxxxxxx" is the hex value.
+ */
+static void priv_tramp_sym_gen_name(u32 value, char *dst)
+{
+	u32 i;
+	volatile char *prefix = TRAMP_SYM_PREFIX;
+	volatile char *dst_local = dst;
+	u8 tmp;
+
+	/*  Clear out the destination, including the ending NULL  */
+	for (i = 0; i < (TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN); i++)
+		*(dst_local + i) = 0;
+
+	/*  Copy the prefix to start  */
+	for (i = 0; i < strlen(TRAMP_SYM_PREFIX); i++) {
+		*dst_local = *(prefix + i);
+		dst_local++;
+	}
+
+	/*  Now convert the value passed in to a string equiv of the hex  */
+	for (i = 0; i < sizeof(value); i++) {
+#ifndef _BIG_ENDIAN
+		tmp = *(((u8 *)&value) + (sizeof(value) - 1) - i);
+		*dst_local = priv_h2a((tmp & 0xF0) >> 4);
+		dst_local++;
+		*dst_local = priv_h2a(tmp & 0x0F);
+		dst_local++;
+#else
+		tmp = *(((u8 *)&value) + i);
+		*dst_local = priv_h2a((tmp & 0xF0) >> 4);
+		dst_local++;
+		*dst_local = priv_h2a(tmp & 0x0F);
+		dst_local++;
+#endif
+	}
+
+	/*  NULL terminate  */
+	*dst_local = 0;
+}
+
+/*
+ * Function:	priv_tramp_string_create
+ * Description: Create a new string specific to the trampoline loading and add
+ *	  it to the trampoline string list.  This list contains the
+ *	  trampoline section name and trampoline point symbols.
+ */
+static struct tramp_string *priv_tramp_string_create(struct dload_state *dlthis,
+	  u32 str_len, char *str)
+{
+	struct tramp_string *new_string = NULL;
+	u32 i;
+
+	/*  Create a new string object with the specified size.  */
+	new_string = (struct tramp_string *)dlthis->mysym->Allocate(
+		dlthis->mysym, (sizeof(struct tramp_string) + str_len + 1));
+	if (new_string != NULL) {
+		/*  Clear the string first.  This ensures the ending NULL is
+		 * present and the optimizer won't touch it.  */
+		for (i = 0; i < (sizeof(struct tramp_string) + str_len + 1);
+				i++)
+			*((u8 *)new_string + i) = 0;
+
+		/*  Add this string to our virtual table by assigning it the
+		 * next index and pushing it to the tail of the list.  */
+		new_string->index = dlthis->tramp.tramp_string_next_index;
+		dlthis->tramp.tramp_string_next_index++;
+		dlthis->tramp.tramp_string_size += str_len + 1;
+
+		new_string->next = NULL;
+		if (dlthis->tramp.string_head == NULL)
+			dlthis->tramp.string_head = new_string;
+		else
+			dlthis->tramp.string_tail->next = new_string;
+
+		dlthis->tramp.string_tail = new_string;
+
+		/*  Copy the string over to the new object  */
+		for (i = 0; i < str_len; i++)
+			new_string->str[i] = str[i];
+	}
+
+	return new_string;
+}
+
+/*
+ * Function:	priv_tramp_string_find
+ * Description: Walk the trampoline string list and find a match for the
+ *	  provided string.  If not match is found, NULL is returned.
+ */
+static struct tramp_string *priv_tramp_string_find(struct dload_state *dlthis,
+								char *str)
+{
+	struct tramp_string *cur_str = NULL;
+	struct tramp_string *ret_val = NULL;
+	u32 i;
+	u32 str_len = strlen(str);
+
+	for (cur_str = dlthis->tramp.string_head;
+		 (ret_val == NULL) && (cur_str != NULL);
+		 cur_str = cur_str->next) {
+		/*  If the string lengths aren't equal, don't bother
+		 * comparing  */
+		if (str_len != strlen(cur_str->str))
+			continue;
+
+		/*  Walk the strings until one of them ends  */
+		for (i = 0; i < str_len; i++) {
+			/*  If they don't match in the current position then
+			 * break out now, no sense in continuing to look at
+			 * this string.  */
+			if (str[i] != cur_str->str[i])
+				break;
+		}
+
+		if (i == str_len)
+			ret_val = cur_str;
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_string_tbl_finalize
+ * Description: Flatten the trampoline string list into a table of NULL
+ *	  terminated strings.  This is the same format of string table
+ *	  as used by the COFF/DOFF file.
+ */
+static int priv_string_tbl_finalize(struct dload_state *dlthis)
+{
+	int ret_val = 0;
+	struct tramp_string *cur_string;
+	char *cur_loc;
+	char *tmp;
+
+	/*  Allocate enough space for all strings that have been created.  The
+	 * table is simply all strings concatenated together will NULL
+	 * endings.  */
+	dlthis->tramp.final_string_table =
+		(char *)dlthis->mysym->Allocate(dlthis->mysym,
+					dlthis->tramp.tramp_string_size);
+	if (dlthis->tramp.final_string_table != NULL) {
+		/*  We got our buffer, walk the list and release the nodes as*
+		 * we go  */
+		cur_loc = dlthis->tramp.final_string_table;
+		cur_string = dlthis->tramp.string_head;
+		while (cur_string != NULL) {
+			/*  Move the head/tail pointers  */
+			dlthis->tramp.string_head = cur_string->next;
+			if (dlthis->tramp.string_tail == cur_string)
+				dlthis->tramp.string_tail = NULL;
+
+			/*  Copy the string contents  */
+			for (tmp = cur_string->str;
+				 *tmp != '\0';
+				 tmp++, cur_loc++)
+				*cur_loc = *tmp;
+
+			/*  Pick up the NULL termination since it was missed by
+			 * breaking using it to end the above loop.  */
+			*cur_loc = '\0';
+			cur_loc++;
+
+			/*  Free the string node, we don't need it any more. */
+			dlthis->mysym->Deallocate(dlthis->mysym, cur_string);
+
+			/*  Move our pointer to the next one  */
+			cur_string = dlthis->tramp.string_head;
+		}
+
+		/*  Update our return value to success  */
+		ret_val = 1;
+	} else
+		dload_error(dlthis, "Failed to allocate trampoline "
+						"string table");
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_tramp_sect_alloc
+ * Description: Virtually allocate space from the trampoline section.  This
+ *	  function returns the next offset within the trampoline section
+ *	  that is available and moved the next available offset by the
+ *	  requested size.  NO TARGET ALLOCATION IS DONE AT THIS TIME.
+ */
+static u32 priv_tramp_sect_alloc(struct dload_state *dlthis, u32 tramp_size)
+{
+	u32 ret_val;
+
+	/*  If the next available address is 0, this is our first allocation.
+	 * Create a section name string to go into the string table .  */
+	if (dlthis->tramp.tramp_sect_next_addr == 0) {
+		dload_syms_error(dlthis->mysym, "*** WARNING ***  created "
+			"dynamic TRAMPOLINE section for module %s",
+			dlthis->str_head);
+	}
+
+	/*  Reserve space for the new trampoline  */
+	ret_val = dlthis->tramp.tramp_sect_next_addr;
+	dlthis->tramp.tramp_sect_next_addr += tramp_size;
+	return ret_val;
+}
+
+/*
+ * Function:	priv_tramp_sym_create
+ * Description: Allocate and create a new trampoline specific symbol and add
+ *	  it to the trampoline symbol list.  These symbols will include
+ *	  trampoline points as well as the external symbols they
+ *	  reference.
+ */
+static struct tramp_sym *priv_tramp_sym_create(struct dload_state *dlthis,
+			u32 str_index, struct Local_Symbol *tmp_sym)
+{
+	struct tramp_sym	*new_sym = NULL;
+	u32 i;
+
+	/*  Allocate new space for the symbol in the symbol table.  */
+	new_sym = (struct tramp_sym *)dlthis->mysym->Allocate(dlthis->mysym,
+						   sizeof(struct tramp_sym));
+	if (new_sym != NULL) {
+		for (i = 0; i != sizeof(struct tramp_sym); i++)
+			*((char *)new_sym + i) = 0;
+
+		/*  Assign this symbol the next symbol index for easier
+		 * reference later during relocation.  */
+		new_sym->index = dlthis->tramp.tramp_sym_next_index;
+		dlthis->tramp.tramp_sym_next_index++;
+
+		/*  Populate the symbol information.  At this point any
+		 * trampoline symbols will be the offset location, not the
+		 * final.  Copy over the symbol info to start, then be sure to
+		 * get the string index from the trampoline string table.  */
+		new_sym->sym_info = *tmp_sym;
+		new_sym->str_index = str_index;
+
+		/*  Push the new symbol to the tail of the symbol table list  */
+		new_sym->next = NULL;
+		if (dlthis->tramp.symbol_head == NULL)
+			dlthis->tramp.symbol_head = new_sym;
+		else
+			dlthis->tramp.symbol_tail->next = new_sym;
+
+		dlthis->tramp.symbol_tail = new_sym;
+	}
+
+	return new_sym;
+}
+
+/*
+ * Function:	priv_tramp_sym_get
+ * Description: Search for the symbol with the matching string index (from
+ *	  the trampoline string table) and return the trampoline
+ *	  symbol object, if found.  Otherwise return NULL.
+ */
+static struct tramp_sym *priv_tramp_sym_get(struct dload_state *dlthis,
+						 u32 string_index)
+{
+	struct tramp_sym *sym_found = NULL;
+
+	/*  Walk the symbol table list and search vs. the string index  */
+	for (sym_found = dlthis->tramp.symbol_head;
+		 sym_found != NULL;
+		 sym_found = sym_found->next) {
+		if (sym_found->str_index == string_index)
+			break;
+	}
+
+	return sym_found;
+}
+
+/*
+ * Function:	priv_tramp_sym_find
+ * Description: Search for a trampoline symbol based on the string name of
+ *	  the symbol.  Return the symbol object, if found, otherwise
+ *	  return NULL.
+ */
+static struct tramp_sym *priv_tramp_sym_find(struct dload_state *dlthis,
+							char *string)
+{
+	struct tramp_sym *sym_found = NULL;
+	struct tramp_string *str_found = NULL;
+
+	/*  First, search for the string, then search for the sym based on the
+		string index.  */
+	str_found = priv_tramp_string_find(dlthis, string);
+	if (str_found != NULL)
+		sym_found = priv_tramp_sym_get(dlthis, str_found->index);
+
+	return sym_found;
+}
+
+/*
+ * Function:	priv_tramp_sym_finalize
+ * Description: Allocate a flat symbol table for the trampoline section,
+ *	  put each trampoline symbol into the table, adjust the
+ *	  symbol value based on the section address on the target and
+ *	  free the trampoline symbol list nodes.
+ */
+static int priv_tramp_sym_finalize(struct dload_state *dlthis)
+{
+	int ret_val = 0;
+	struct tramp_sym *cur_sym;
+	struct LDR_SECTION_INFO *tramp_sect =
+		&dlthis->ldr_sections[dlthis->allocated_secn_count];
+	struct Local_Symbol *new_sym;
+
+	/*  Allocate a table to hold a flattened version of all symbols
+	 * created.  */
+	dlthis->tramp.final_sym_table =
+		(struct Local_Symbol *)dlthis->mysym->Allocate(
+			dlthis->mysym, (sizeof(struct Local_Symbol) *
+			dlthis->tramp.tramp_sym_next_index));
+	if (dlthis->tramp.final_sym_table != NULL) {
+		/*  Walk the list of all symbols, copy it over to the flattened
+		 * table. After it has been copied, the node can be freed as
+		 * it is no longer needed.  */
+		new_sym = dlthis->tramp.final_sym_table;
+		cur_sym = dlthis->tramp.symbol_head;
+		while (cur_sym != NULL) {
+			/*  Pop it off the list  */
+			dlthis->tramp.symbol_head = cur_sym->next;
+			if (cur_sym == dlthis->tramp.symbol_tail)
+				dlthis->tramp.symbol_tail = NULL;
+
+			/*  Copy the symbol contents into the flat table  */
+			*new_sym = cur_sym->sym_info;
+
+			/*  Now finaize the symbol.  If it is in the tramp
+			 * section, we need to adjust for the section start.
+			 * If it is external then we don't need to adjust at
+			 * all.
+			 * NOTE: THIS CODE ASSUMES THAT THE TRAMPOLINE IS
+			 * REFERENCED LIKE A CALL TO AN EXTERNAL SO VALUE AND
+			 * DELTA ARE THE SAME.  SEE THE FUNCTION dload_symbols
+			 * WHERE DN_UNDEF IS HANDLED FOR MORE REFERENCE.  */
+			if (new_sym->secnn < 0) {
+				new_sym->value += tramp_sect->load_addr;
+				new_sym->delta = new_sym->value;
+			}
+
+			/*  Let go of the symbol node  */
+			dlthis->mysym->Deallocate(dlthis->mysym, cur_sym);
+
+			/*  Move to the next node  */
+			cur_sym = dlthis->tramp.symbol_head;
+			new_sym++;
+		}
+
+		ret_val = 1;
+	} else
+		dload_error(dlthis, "Failed to alloc trampoline sym table");
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_tgt_img_gen
+ * Description: Allocate storage for and copy the target specific image data
+ *	and fix up its relocations for the new external symbol.  If
+ *	a trampoline image packet was successfully created it is added
+ *	to the trampoline list.
+ */
+static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base,
+		u32 gen_index, struct tramp_sym *new_ext_sym)
+{
+	struct tramp_img_pkt *new_img_pkt = NULL;
+	u32 i;
+	u32 pkt_size = tramp_img_pkt_size_get();
+	u8 *gen_tbl_entry;
+	u8 *pkt_data;
+	struct reloc_record_t *cur_relo;
+	int ret_val = 0;
+
+	/*  Allocate a new image packet and set it up.  */
+	new_img_pkt =
+		(struct tramp_img_pkt *)dlthis->mysym->Allocate(dlthis->mysym,
+								 pkt_size);
+	if (new_img_pkt != NULL) {
+		/*  Save the base, this is where it goes in the section  */
+		new_img_pkt->base = base;
+
+		/*  Copy over the image data and relos from the target table */
+		pkt_data = (u8 *)&new_img_pkt->hdr;
+		gen_tbl_entry = (u8 *)&tramp_gen_info[gen_index];
+		for (i = 0; i < pkt_size; i++) {
+			*pkt_data = *gen_tbl_entry;
+			pkt_data++;
+			gen_tbl_entry++;
+		}
+
+		/*  Update the relocations to point to the external symbol  */
+		cur_relo =
+			(struct reloc_record_t *)((u8 *)&new_img_pkt->hdr +
+					   new_img_pkt->hdr.relo_offset);
+		for (i = 0; i < new_img_pkt->hdr.num_relos; i++)
+			cur_relo[i].r_symndx = new_ext_sym->index;
+
+		/*  Add it to the trampoline list.  */
+		new_img_pkt->next = dlthis->tramp.tramp_pkts;
+		dlthis->tramp.tramp_pkts = new_img_pkt;
+
+		ret_val = 1;
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_pkt_relo
+ * Description: Take the provided image data and the collection of relocations
+ *	  for it and perform the relocations.  Note that all relocations
+ *	  at this stage are considered SECOND PASS since the original
+ *	  image has already been processed in the first pass.  This means
+ *	  TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really
+ *	  the first (and only) relocation that will be performed on them.
+ */
+static int priv_pkt_relo(struct dload_state *dlthis, TgtAU_t *data,
+			 struct reloc_record_t *rp[], u32 relo_count)
+{
+	int ret_val = 1;
+	u32 i;
+	bool tmp;
+
+	/*  Walk through all of the relos and process them.  This function is
+	 * the equivalent of relocate_packet() from cload.c, but specialized
+	 * for trampolines and 2nd phase relocations.  */
+	for (i = 0; i < relo_count; i++)
+		dload_relocate(dlthis, data, rp[i], &tmp, true);
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_tramp_pkt_finalize
+ * Description: Walk the list of all trampoline packets and finalize them.
+ *	  Each trampoline image packet will be relocated now that the
+ *	  trampoline section has been allocated on the target.  Once
+ *	  all of the relocations are done the trampoline image data
+ *	  is written into target memory and the trampoline packet
+ *	  is freed: it is no longer needed after this point.
+ */
+static int priv_tramp_pkt_finalize(struct dload_state *dlthis)
+{
+	int ret_val = 1;
+	struct tramp_img_pkt *cur_pkt = NULL;
+	struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
+	u32 relos_done;
+	u32 i;
+	struct reloc_record_t *cur_relo;
+	struct LDR_SECTION_INFO *sect_info =
+		&dlthis->ldr_sections[dlthis->allocated_secn_count];
+
+	/*  Walk the list of trampoline packets and relocate each packet.  This
+	 * function is the trampoline equivalent of dload_data() from
+	 * cload.c.  */
+	cur_pkt = dlthis->tramp.tramp_pkts;
+	while ((ret_val != 0) && (cur_pkt != NULL)) {
+		/*  Remove the pkt from the list  */
+		dlthis->tramp.tramp_pkts = cur_pkt->next;
+
+		/*  Setup section and image offset information for the relo  */
+		dlthis->image_secn = sect_info;
+		dlthis->image_offset = cur_pkt->base;
+		dlthis->delta_runaddr = sect_info->run_addr;
+
+		/*  Walk through all relos for the packet  */
+		relos_done = 0;
+		cur_relo = (struct reloc_record_t *)((u8 *)&cur_pkt->hdr +
+						  cur_pkt->hdr.relo_offset);
+		while (relos_done < cur_pkt->hdr.num_relos) {
+#ifdef ENABLE_TRAMP_DEBUG
+			dload_syms_error(dlthis->mysym,
+				 "===> Trampoline %x branches to %x",
+				 sect_info->run_addr + dlthis->image_offset,
+				 dlthis->tramp.
+				 final_sym_table[cur_relo->r_symndx].value);
+#endif
+
+			for (i = 0;
+				 ((i < MAX_RELOS_PER_PASS) &&
+				  ((i + relos_done) < cur_pkt->hdr.num_relos));
+				 i++)
+				relos[i] = cur_relo + i;
+
+			/*  Do the actual relo  */
+			ret_val = priv_pkt_relo(dlthis,
+						(TgtAU_t *)&cur_pkt->payload,
+						relos, i);
+			if (ret_val == 0) {
+				dload_error(dlthis,
+				"Relocation of trampoline pkt at %x failed",
+				cur_pkt->base + sect_info->run_addr);
+				break;
+			}
+
+			relos_done += i;
+			cur_relo += i;
+		}
+
+		/*  Make sure we didn't hit a problem  */
+		if (ret_val != 0) {
+			/*  Relos are done for the packet, write it to the
+			 * target  */
+			ret_val = dlthis->myio->writemem(dlthis->myio,
+					   &cur_pkt->payload,
+					   sect_info->load_addr + cur_pkt->base
+					   , sect_info, BYTE_TO_HOST(
+					   cur_pkt->hdr.tramp_code_size));
+			if (ret_val == 0) {
+				dload_error(dlthis,
+					"Write to " FMT_UI32 " failed",
+					sect_info->load_addr + cur_pkt->base);
+			}
+
+			/*  Done with the pkt, let it go  */
+			dlthis->mysym->Deallocate(dlthis->mysym, cur_pkt);
+
+			/*  Get the next packet to process  */
+			cur_pkt = dlthis->tramp.tramp_pkts;
+		}
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_dup_pkt_finalize
+ * Description: Walk the list of duplicate image packets and finalize them.
+ *	  Each duplicate packet will be relocated again for the
+ *	  relocations that previously failed and have been adjusted
+ *	  to point at a trampoline.  Once all relocations for a packet
+ *	  have been done, write the packet into target memory.  The
+ *	  duplicate packet and its relocation chain are all freed
+ *	  after use here as they are no longer needed after this.
+ */
+static int priv_dup_pkt_finalize(struct dload_state *dlthis)
+{
+	int ret_val = 1;
+	struct tramp_img_dup_pkt *cur_pkt;
+	struct tramp_img_dup_relo *cur_relo;
+	struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
+	struct doff_scnhdr_t *sect_hdr = NULL;
+	s32 i;
+
+	/* Similar to the trampoline pkt finalize, this function walks each dup
+	 * pkt that was generated and performs all relocations that were
+	 * deferred to a 2nd pass.  This is the equivalent of dload_data() from
+	 * cload.c, but does not need the additional reorder and checksum
+	 * processing as it has already been done.  */
+	cur_pkt = dlthis->tramp.dup_pkts;
+	while ((ret_val != 0) && (cur_pkt != NULL)) {
+		/*  Remove the node from the list, we'll be freeing it
+		 * shortly  */
+		dlthis->tramp.dup_pkts = cur_pkt->next;
+
+		/*  Setup the section and image offset for relocation  */
+		dlthis->image_secn = &dlthis->ldr_sections[cur_pkt->secnn];
+		dlthis->image_offset = cur_pkt->offset;
+
+		/*  In order to get the delta run address, we need to reference
+		 * the original section header.  It's a bit ugly, but needed
+		 * for relo.  */
+		i = (s32)(dlthis->image_secn - dlthis->ldr_sections);
+		sect_hdr = dlthis->sect_hdrs + i;
+		dlthis->delta_runaddr = sect_hdr->ds_paddr;
+
+		/*  Walk all relos in the chain and process each.  */
+		cur_relo = cur_pkt->relo_chain;
+		while (cur_relo != NULL) {
+			/*  Process them a chunk at a time to be efficient  */
+			for (i = 0; (i < MAX_RELOS_PER_PASS)
+				 && (cur_relo != NULL);
+				 i++, cur_relo = cur_relo->next) {
+				relos[i] = &cur_relo->relo;
+				cur_pkt->relo_chain = cur_relo->next;
+			}
+
+			/*  Do the actual relo  */
+			ret_val = priv_pkt_relo(dlthis,
+				cur_pkt->img_pkt.i_bits,
+				relos, i);
+			if (ret_val == 0) {
+				dload_error(dlthis,
+					"Relocation of dup pkt at %x failed",
+					cur_pkt->offset + dlthis->image_secn->
+					run_addr);
+				break;
+			}
+
+			/*  Release all of these relos, we're done with them */
+			while (i > 0) {
+				dlthis->mysym->Deallocate(dlthis->mysym,
+					  GET_CONTAINER(relos[i - 1],
+					struct tramp_img_dup_relo, relo));
+				i--;
+			}
+
+			/*  DO NOT ADVANCE cur_relo, IT IS ALREADY READY TO
+			 * GO!  */
+		}
+
+		/* Done with all relos.  Make sure we didn't have a problem and
+		 * write it out to the target  */
+		if (ret_val != 0) {
+			ret_val = dlthis->myio->writemem(dlthis->myio,
+				   cur_pkt->img_pkt.i_bits,
+				   dlthis->image_secn->load_addr +
+				   cur_pkt->offset, dlthis->image_secn,
+				   BYTE_TO_HOST(cur_pkt->
+				   img_pkt.i_packet_size));
+			if (ret_val == 0) {
+				dload_error(dlthis,
+					"Write to " FMT_UI32 " failed",
+					dlthis->image_secn->load_addr +
+					cur_pkt->offset);
+			}
+
+			dlthis->mysym->Deallocate(dlthis->mysym, cur_pkt);
+
+			/*  Advance to the next packet  */
+			cur_pkt = dlthis->tramp.dup_pkts;
+		}
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	priv_dup_find
+ * Description: Walk the list of existing duplicate packets and find a
+ *	  match based on the section number and image offset.  Return
+ *	  the duplicate packet if found, otherwise NULL.
+ */
+static struct tramp_img_dup_pkt *priv_dup_find(struct dload_state *dlthis,
+					s16 secnn, u32 image_offset)
+{
+	struct tramp_img_dup_pkt *cur_pkt = NULL;
+
+	for (cur_pkt = dlthis->tramp.dup_pkts;
+		 cur_pkt != NULL;
+		 cur_pkt = cur_pkt->next) {
+		if ((cur_pkt->secnn == secnn) &&
+			(cur_pkt->offset == image_offset)) {
+			/*  Found a match, break out  */
+			break;
+		}
+	}
+
+	return cur_pkt;
+}
+
+/*
+ * Function:	priv_img_pkt_dup
+ * Description: Duplicate the original image packet.  If this is the first
+ *	  time this image packet has been seen (based on section number
+ *	  and image offset), create a new duplicate packet and add it
+ *	  to the dup packet list.  If not, just get the existing one and
+ *	  update it with the current packet contents (since relocation
+ *	  on the packet is still ongoing in first pass.)  Create a
+ *	  duplicate of the provided relocation, but update it to point
+ *	  to the new trampoline symbol.  Add the new relocation dup to
+ *	  the dup packet's relo chain for 2nd pass relocation later.
+ */
+static int priv_img_pkt_dup(struct dload_state *dlthis,
+	s16 secnn, u32 image_offset, struct image_packet_t *ipacket,
+	struct reloc_record_t *rp, struct tramp_sym *new_tramp_sym)
+{
+	struct tramp_img_dup_pkt *dup_pkt = NULL;
+	u32 new_dup_size;
+	s32 i;
+	int ret_val = 0;
+	struct tramp_img_dup_relo *dup_relo = NULL;
+
+	/*  Determinne if this image packet is already being tracked in the
+		dup list for other trampolines.  */
+	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
+
+	if (dup_pkt == NULL) {
+		/*  This image packet does not exist in our tracking, so create
+		 * a new one and add it to the head of the list.  */
+		new_dup_size = sizeof(struct tramp_img_dup_pkt) +
+						ipacket->i_packet_size;
+
+		dup_pkt = (struct tramp_img_dup_pkt *)
+			dlthis->mysym->Allocate(dlthis->mysym, new_dup_size);
+		if (dup_pkt != NULL) {
+			/*  Save off the section and offset information  */
+			dup_pkt->secnn = secnn;
+			dup_pkt->offset = image_offset;
+			dup_pkt->relo_chain = NULL;
+
+			/*  Copy the original packet content  */
+			dup_pkt->img_pkt = *ipacket;
+			dup_pkt->img_pkt.i_bits = (u8 *)(dup_pkt + 1);
+			for (i = 0; i < ipacket->i_packet_size; i++)
+				*(dup_pkt->img_pkt.i_bits + i) =
+					*(ipacket->i_bits + i);
+
+			/*  Add the packet to the dup list  */
+			dup_pkt->next = dlthis->tramp.dup_pkts;
+			dlthis->tramp.dup_pkts = dup_pkt;
+		} else
+			dload_error(dlthis, "Failed to create dup packet!");
+	} else {
+		/*  The image packet contents could have changed since
+		 * trampoline detection happens during relocation of the image
+		 * packets.  So, we need to update the image packet contents
+		 * before adding relo information.  */
+		for (i = 0; i < dup_pkt->img_pkt.i_packet_size; i++)
+			*(dup_pkt->img_pkt.i_bits + i) =
+				*(ipacket->i_bits + i);
+	}
+
+	/*  Since the previous code may have allocated a new dup packet for us,
+		double check that we actually have one.  */
+	if (dup_pkt != NULL) {
+		/*  Allocate a new node for the relo chain.  Each image packet
+		 * can potentially have multiple relocations that cause a
+		 * trampoline to be generated.  So, we keep them in a chain,
+		 * order is not important.  */
+		dup_relo = dlthis->mysym->Allocate(dlthis->mysym,
+					   sizeof(struct tramp_img_dup_relo));
+		if (dup_relo != NULL) {
+			/*  Copy the relo contents, adjust for the new
+			 * trampoline and add it to the list.  */
+			dup_relo->relo = *rp;
+			dup_relo->relo.r_symndx = new_tramp_sym->index;
+
+			dup_relo->next = dup_pkt->relo_chain;
+			dup_pkt->relo_chain = dup_relo;
+
+			/*  That's it, we're done.  Make sure we update our
+			 * return value to be success since everything finished
+			 * ok  */
+			ret_val = 1;
+		} else
+			dload_error(dlthis, "Unable to alloc dup relo");
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	dload_tramp_avail
+ * Description: Check to see if the target supports a trampoline for this type
+ *	  of relocation.  Return true if it does, otherwise false.
+ */
+bool dload_tramp_avail(struct dload_state *dlthis, struct reloc_record_t *rp)
+{
+	bool ret_val = false;
+	u16 map_index;
+	u16 gen_index;
+
+	/*  Check type hash vs. target tramp table  */
+	map_index = HASH_FUNC(rp->r_type);
+	gen_index = tramp_map[map_index];
+	if (gen_index != TRAMP_NO_GEN_AVAIL)
+		ret_val = true;
+
+	return ret_val;
+}
+
+/*
+ * Function:	dload_tramp_generate
+ * Description: Create a new trampoline for the provided image packet and
+ *	  relocation causing problems.  This will create the trampoline
+ *	  as well as duplicate/update the image packet and relocation
+ *	  causing the problem, which will be relo'd again during
+ *	  finalization.
+ */
+int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
+	u32 image_offset, struct image_packet_t *ipacket,
+	struct reloc_record_t *rp)
+{
+	u16 map_index;
+	u16 gen_index;
+	int ret_val = 1;
+	char tramp_sym_str[TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN];
+	struct Local_Symbol *ref_sym;
+	struct tramp_sym	*new_tramp_sym;
+	struct tramp_sym	*new_ext_sym;
+	struct tramp_string *new_tramp_str;
+	u32 new_tramp_base;
+	struct Local_Symbol tmp_sym;
+	struct Local_Symbol ext_tmp_sym;
+
+	/*  Hash the relo type to get our generator information  */
+	map_index = HASH_FUNC(rp->r_type);
+	gen_index = tramp_map[map_index];
+	if (gen_index != TRAMP_NO_GEN_AVAIL) {
+		/*  If this is the first trampoline, create the section name in
+		 * our string table for debug help later.  */
+		if (dlthis->tramp.string_head == NULL) {
+			priv_tramp_string_create(dlthis,
+				 strlen(TRAMP_SECT_NAME), TRAMP_SECT_NAME);
+		}
+
+#ifdef ENABLE_TRAMP_DEBUG
+		dload_syms_error(dlthis->mysym,
+			 "Trampoline at img loc %x, references %x",
+			 dlthis->ldr_sections[secnn].run_addr + image_offset +
+			 rp->r_vaddr,
+			 dlthis->local_symtab[rp->r_symndx].value);
+#endif
+
+		/*  Generate the trampoline string, check if already defined.
+		 * If the relo symbol index is -1, it means we need the section
+		 * info for relo later.  To do this we'll dummy up a symbol
+		 * with the section delta and run addresses.  */
+		if (rp->r_symndx == -1) {
+			ext_tmp_sym.value =
+				dlthis->ldr_sections[secnn].run_addr;
+			ext_tmp_sym.delta = dlthis->sect_hdrs[secnn].ds_paddr;
+			ref_sym = &ext_tmp_sym;
+		} else
+			ref_sym = &(dlthis->local_symtab[rp->r_symndx]);
+
+		priv_tramp_sym_gen_name(ref_sym->value, tramp_sym_str);
+		new_tramp_sym = priv_tramp_sym_find(dlthis, tramp_sym_str);
+		if (new_tramp_sym == NULL) {
+			/*  If tramp string not defined, create it and a new
+			 * string, and symbol for it as well as the original
+			 * symbol which caused the trampoline.  */
+			new_tramp_str = priv_tramp_string_create(dlthis,
+				 strlen(tramp_sym_str), tramp_sym_str);
+			if (new_tramp_str == NULL) {
+				dload_error(dlthis, "Failed to create new "
+					"trampoline string\n");
+				ret_val = 0;
+			} else {
+				/*  Allocate tramp section space for the new
+				 * tramp from the target  */
+				new_tramp_base = priv_tramp_sect_alloc(dlthis,
+							   tramp_size_get());
+
+				/*  We have a string, create the new symbol and
+				 * duplicate the external.  */
+				tmp_sym.value = new_tramp_base;
+				tmp_sym.delta = 0;
+				tmp_sym.secnn = -1;
+				tmp_sym.sclass = 0;
+				new_tramp_sym = priv_tramp_sym_create(dlthis,
+					  new_tramp_str->index, &tmp_sym);
+
+				new_ext_sym = priv_tramp_sym_create(dlthis,
+								-1, ref_sym);
+
+				if ((new_tramp_sym != NULL) &&
+					(new_ext_sym != NULL)) {
+					/*  Call the image generator to get the
+					 * new image data and fix up its
+					 * relocations for the external
+					 * symbol.  */
+					ret_val = priv_tgt_img_gen(dlthis,
+					   new_tramp_base, gen_index,
+					   new_ext_sym);
+
+					/*  Add generated image data to tramp
+					 * image list  */
+					if (ret_val != 1) {
+						dload_error(dlthis, "Failed to"
+						   " create image packet for "
+						   "trampoline\n");
+					}
+				} else {
+					dload_error(dlthis, "Failed to create "
+					   "new tramp syms (%8.8X, %8.8X)\n",
+					   new_tramp_sym, new_ext_sym);
+					ret_val = 0;
+				}
+			}
+		}
+
+		/*  Duplicate the image data and relo record that caused the
+		 * tramp, including update the relo data to point to the tramp
+		 * symbol.  */
+		if (ret_val == 1) {
+			ret_val = priv_img_pkt_dup(dlthis, secnn, image_offset,
+				   ipacket, rp, new_tramp_sym);
+			if (ret_val != 1) {
+				dload_error(dlthis, "Failed to create dup of "
+					"original img pkt\n");
+			}
+		}
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	dload_tramp_pkt_update
+ * Description: Update the duplicate copy of this image packet, which the
+ *	  trampoline layer is already tracking.  This is call is critical
+ *	  to make if trampolines were generated anywhere within the
+ *	  packet and first pass relo continued on the remainder.  The
+ *	  trampoline layer needs the updates image data so when 2nd
+ *	  pass relo is done during finalize the image packet can be
+ *	  written to the target since all relo is done.
+ */
+int dload_tramp_pkt_udpate(struct dload_state *dlthis, s16 secnn,
+	   u32 image_offset, struct image_packet_t *ipacket)
+{
+	struct tramp_img_dup_pkt *dup_pkt = NULL;
+	s32 i;
+	int ret_val = 0;
+
+	/*  Find the image packet in question, the caller needs us to update it
+		since a trampoline was previously generated.  */
+	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
+	if (dup_pkt != NULL) {
+		for (i = 0; i < dup_pkt->img_pkt.i_packet_size; i++)
+			*(dup_pkt->img_pkt.i_bits + i) = *(ipacket->i_bits + i);
+
+		ret_val = 1;
+	} else {
+		dload_error(dlthis,
+			"Unable to find existing DUP pkt for %x, offset %x",
+			secnn, image_offset);
+
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	dload_tramp_finalize
+ * Description: If any trampolines were created, finalize everything on the
+ *	  target by allocating the trampoline section on the target,
+ *	  finalizing the trampoline symbols, finalizing the trampoline
+ *	  packets (write the new section to target memory) and finalize
+ *	  the duplicate packets by doing 2nd pass relo over them.
+ */
+int dload_tramp_finalize(struct dload_state *dlthis)
+{
+	int ret_val = 1;
+
+	if (dlthis->tramp.tramp_sect_next_addr != 0) {
+		/*  Finalize strings into a flat table.  This is needed so it
+		 * can be added to the debug string table later.  */
+		ret_val = priv_string_tbl_finalize(dlthis);
+
+		/*  Do target allocation for section BEFORE finalizing
+		 * symbols.  */
+		if (ret_val != 0)
+			ret_val = priv_tramp_sect_tgt_alloc(dlthis);
+
+		/*  Finalize symbols with their correct target information and
+		 * flatten  */
+		if (ret_val != 0)
+			ret_val = priv_tramp_sym_finalize(dlthis);
+
+		/*  Finalize all trampoline packets.  This performs the
+		 * relocation on the packets as well as writing them to target
+		 * memory.  */
+		if (ret_val != 0)
+			ret_val = priv_tramp_pkt_finalize(dlthis);
+
+		/*  Perform a 2nd pass relocation on the dup list.  */
+		if (ret_val != 0)
+			ret_val = priv_dup_pkt_finalize(dlthis);
+	}
+
+	return ret_val;
+}
+
+/*
+ * Function:	dload_tramp_cleanup
+ * Description: Release all temporary resources used in the trampoline layer.
+ *	  Note that the target memory which may have been allocated and
+ *	  written to store the trampolines is NOT RELEASED HERE since it
+ *	  is potentially still in use.  It is automatically released
+ *	  when the module is unloaded.
+ */
+void dload_tramp_cleanup(struct dload_state *dlthis)
+{
+	struct tramp_info *tramp = &dlthis->tramp;
+	struct tramp_sym *cur_sym;
+	struct tramp_string *cur_string;
+	struct tramp_img_pkt *cur_tramp_pkt;
+	struct tramp_img_dup_pkt *cur_dup_pkt;
+	struct tramp_img_dup_relo *cur_dup_relo;
+
+	/*  If there were no tramps generated, just return  */
+	if (tramp->tramp_sect_next_addr == 0)
+		return;
+
+	/*  Destroy all tramp information  */
+	for (cur_sym = tramp->symbol_head;
+		 cur_sym != NULL;
+		 cur_sym = tramp->symbol_head) {
+		tramp->symbol_head = cur_sym->next;
+		if (tramp->symbol_tail == cur_sym)
+			tramp->symbol_tail = NULL;
+
+		dlthis->mysym->Deallocate(dlthis->mysym, cur_sym);
+	}
+
+	if (tramp->final_sym_table != NULL)
+		dlthis->mysym->Deallocate(dlthis->mysym,
+			tramp->final_sym_table);
+
+	for (cur_string = tramp->string_head;
+		 cur_string != NULL;
+		 cur_string = tramp->string_head) {
+		tramp->string_head = cur_string->next;
+		if (tramp->string_tail == cur_string)
+			tramp->string_tail = NULL;
+
+		dlthis->mysym->Deallocate(dlthis->mysym, cur_string);
+	}
+
+	if (tramp->final_string_table != NULL)
+		dlthis->mysym->Deallocate(dlthis->mysym,
+			tramp->final_string_table);
+
+	for (cur_tramp_pkt = tramp->tramp_pkts;
+		 cur_tramp_pkt != NULL;
+		 cur_tramp_pkt = tramp->tramp_pkts) {
+		tramp->tramp_pkts = cur_tramp_pkt->next;
+		dlthis->mysym->Deallocate(dlthis->mysym, cur_tramp_pkt);
+	}
+
+	for (cur_dup_pkt = tramp->dup_pkts;
+		 cur_dup_pkt != NULL;
+		 cur_dup_pkt = tramp->dup_pkts) {
+		tramp->dup_pkts = cur_dup_pkt->next;
+
+		for (cur_dup_relo = cur_dup_pkt->relo_chain;
+			 cur_dup_relo != NULL;
+			 cur_dup_relo = cur_dup_pkt->relo_chain) {
+			cur_dup_pkt->relo_chain = cur_dup_relo->next;
+			dlthis->mysym->Deallocate(dlthis->mysym, cur_dup_relo);
+		}
+
+		dlthis->mysym->Deallocate(dlthis->mysym, cur_dup_pkt);
+	}
+}
diff --git a/drivers/dsp/bridge/dynload/tramp_table_c6000.c b/drivers/dsp/bridge/dynload/tramp_table_c6000.c
new file mode 100644
index 0000000..1a7d974
--- /dev/null
+++ b/drivers/dsp/bridge/dynload/tramp_table_c6000.c
@@ -0,0 +1,164 @@ 
+/*
+ *  Copyright 2009 by Texas Instruments Incorporated.
+ *  All rights reserved. Property of Texas Instruments Incorporated.
+ *  Restricted rights to use, duplicate or disclose this code are
+ *  granted through contract.
+ *
+ *  @(#) DSP/BIOS Bridge
+ */
+#include "dload_internal.h"
+
+/*  These are defined in coff.h, but may not be available on all platforms
+	so we'll go ahead and define them here.  */
+#ifndef R_C60LO16
+#define R_C60LO16	  0x54	   /* C60: MVK Low Half Register	  */
+#define R_C60HI16	  0x55	   /* C60: MVKH/MVKLH High Half Register  */
+#endif
+
+#define C6X_TRAMP_WORD_COUNT			8
+#define C6X_TRAMP_MAX_RELOS			 8
+
+/*  THIS HASH FUNCTION MUST MATCH THE ONE IN reloc_table_c6000.c  */
+#define HASH_FUNC(zz) (((((zz) + 1) * UINT32_C(1845)) >> 11) & 63)
+
+
+/*  THIS MUST MATCH reloc_record_t FOR A SYMBOL BASED RELO  */
+struct c6000_relo_record {
+	s32 r_vaddr;
+	s32 symndx;
+#ifndef _BIG_ENDIAN
+	u16 disp;
+	u16 type;
+#else
+	u16 type;
+	u16 disp;
+#endif
+};
+
+struct c6000_gen_code {
+	struct tramp_gen_code_hdr	hdr;
+	u32 tramp_instrs[C6X_TRAMP_WORD_COUNT];
+	struct c6000_relo_record relos[C6X_TRAMP_MAX_RELOS];
+};
+
+
+/*  Hash mapping for relos that can cause trampolines.  */
+static const u16 tramp_map[] =
+{
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	0,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535,
+	65535
+};
+
+
+static const struct c6000_gen_code   tramp_gen_info[] =
+{
+	/*  Tramp caused by R_C60PCR21  */
+	{
+		/*  Header - 8 instructions, 2 relos  */
+		{
+			sizeof(u32) * C6X_TRAMP_WORD_COUNT,
+			2,
+			FIELD_OFFSET(struct c6000_gen_code, relos)
+		},
+
+		/*  Trampoline instructions  */
+		{
+			0x053C54F7,	/*	 STW.D2T2  B10, *sp--[2]  */
+			0x0500002A,	/*  || MVK.S2	<blank>, B10   */
+			0x0500006A,	/*	 MVKH.S2   <blank>, B10   */
+			0x00280362,	/*	 B.S2	  B10		*/
+			0x053C52E6,	/*	 LDW.D2T2  *++sp[2], B10  */
+			0x00006000,	/*	 NOP	   4		*/
+			0x00000000,	/*	 NOP			*/
+			0x00000000	/*	 NOP			*/
+		},
+
+		/*  Relocations  */
+		{
+			{ 4, 0, 0, R_C60LO16 },
+			{ 8, 0, 0, R_C60HI16 },
+			{ 0, 0, 0, 0x0000 },
+			{ 0, 0, 0, 0x0000 },
+			{ 0, 0, 0, 0x0000 },
+			{ 0, 0, 0, 0x0000 },
+			{ 0, 0, 0, 0x0000 },
+			{ 0, 0, 0, 0x0000 }
+		}
+	}
+};
+
+
+
+/*  TARGET SPECIFIC FUNCTIONS THAT MUST BE DEFINED  */
+static u32 tramp_size_get(void)
+{
+	return sizeof(u32) * C6X_TRAMP_WORD_COUNT;
+}
+
+
+static u32 tramp_img_pkt_size_get(void)
+{
+	return sizeof(struct c6000_gen_code);
+}