staging: ti dspbridge: add DOFF binaries loader
authorOmar Ramirez Luna <omar.ramirez@ti.com>
Wed, 23 Jun 2010 13:02:02 +0000 (16:02 +0300)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 23 Jun 2010 22:39:08 +0000 (15:39 -0700)
Add TI's DSP Bridge DOFF binaries dynamic loader driver sources

Signed-off-by: Omar Ramirez Luna <omar.ramirez@ti.com>
Signed-off-by: Kanigeri, Hari <h-kanigeri2@ti.com>
Signed-off-by: Ameya Palande <ameya.palande@nokia.com>
Signed-off-by: Guzman Lugo, Fernando <fernando.lugo@ti.com>
Signed-off-by: Hebbar, Shivananda <x0hebbar@ti.com>
Signed-off-by: Ramos Falcon, Ernesto <ernesto@ti.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Anna, Suman <s-anna@ti.com>
Signed-off-by: Gupta, Ramesh <grgupta@ti.com>
Signed-off-by: Gomez Castellanos, Ivan <ivan.gomez@ti.com>
Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Signed-off-by: Armando Uribe De Leon <x0095078@ti.com>
Signed-off-by: Deepak Chitriki <deepak.chitriki@ti.com>
Signed-off-by: Menon, Nishanth <nm@ti.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
12 files changed:
drivers/staging/tidspbridge/dynload/cload.c [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/dload_internal.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/doff.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/getsection.c [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/header.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/module_list.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/params.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/reloc.c [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/reloc_table.h [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/reloc_table_c6000.c [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/tramp.c [new file with mode: 0644]
drivers/staging/tidspbridge/dynload/tramp_table_c6000.c [new file with mode: 0644]

diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c
new file mode 100644 (file)
index 0000000..d4f71b5
--- /dev/null
@@ -0,0 +1,1960 @@
+/*
+ * cload.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "header.h"
+
+#include "module_list.h"
+#define LINKER_MODULES_HEADER ("_" MODULES_HEADER)
+
+/*
+ * we use the fact that DOFF section records are shaped just like
+ * ldr_section_info to reduce our section storage usage.  This macro marks
+ * the places where that assumption is made
+ */
+#define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct ldr_section_info *)(pdoffsec))
+
+/*
+ * forward references
+ */
+static void dload_symbols(struct dload_state *dlthis);
+static void dload_data(struct dload_state *dlthis);
+static void allocate_sections(struct dload_state *dlthis);
+static void string_table_free(struct dload_state *dlthis);
+static void symbol_table_free(struct dload_state *dlthis);
+static void section_table_free(struct dload_state *dlthis);
+static void init_module_handle(struct dload_state *dlthis);
+#if BITS_PER_AU > BITS_PER_BYTE
+static char *unpack_name(struct dload_state *dlthis, u32 soffset);
+#endif
+
+static const char cinitname[] = { ".cinit" };
+static const char loader_dllview_root[] = { "?DLModules?" };
+
+/*
+ * Error strings
+ */
+static const char readstrm[] = { "Error reading %s from input stream" };
+static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
+static const char tgtalloc[] = {
+       "Target memory allocate failed, section %s size " FMT_UI32 };
+static const char initfail[] = { "%s to target address " FMT_UI32 " failed" };
+static const char dlvwrite[] = { "Write to DLLview list failed" };
+static const char iconnect[] = { "Connect call to init interface failed" };
+static const char err_checksum[] = { "Checksum failed on %s" };
+
+/*************************************************************************
+ * Procedure dload_error
+ *
+ * Parameters:
+ *     errtxt  description of the error, printf style
+ *     ...             additional information
+ *
+ * Effect:
+ *     Reports or records the error as appropriate.
+ *********************************************************************** */
+void dload_error(struct dload_state *dlthis, const char *errtxt, ...)
+{
+       va_list args;
+
+       va_start(args, errtxt);
+       dlthis->mysym->error_report(dlthis->mysym, errtxt, args);
+       va_end(args);
+       dlthis->dload_errcount += 1;
+
+}                              /* dload_error */
+
+#define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb)
+
+/*************************************************************************
+ * Procedure dload_syms_error
+ *
+ * Parameters:
+ *     errtxt  description of the error, printf style
+ *     ...             additional information
+ *
+ * Effect:
+ *     Reports or records the error as appropriate.
+ *********************************************************************** */
+void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...)
+{
+       va_list args;
+
+       va_start(args, errtxt);
+       syms->error_report(syms, errtxt, args);
+       va_end(args);
+}
+
+/*************************************************************************
+ * Procedure dynamic_load_module
+ *
+ * Parameters:
+ *     module  The input stream that supplies the module image
+ *     syms    Host-side symbol table and malloc/free functions
+ *     alloc   Target-side memory allocation
+ *     init    Target-side memory initialization
+ *     options Option flags DLOAD_*
+ *     mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ *     The module image is read using *module.  Target storage for the new
+ *     image is
+ * obtained from *alloc.  Symbols defined and referenced by the module are
+ * managed using *syms.  The image is then relocated and references
+ *     resolved as necessary, and the resulting executable bits are placed
+ *     into target memory using *init.
+ *
+ * Returns:
+ *     On a successful load, a module handle is placed in *mhandle,
+ *     and zero is returned.  On error, the number of errors detected is
+ *     returned.  Individual errors are reported during the load process
+ *     using syms->error_report().
+ ********************************************************************** */
+int dynamic_load_module(struct dynamic_loader_stream *module,
+                       struct dynamic_loader_sym *syms,
+                       struct dynamic_loader_allocate *alloc,
+                       struct dynamic_loader_initialize *init,
+                       unsigned options, void **mhandle)
+{
+       register unsigned *dp, sz;
+       struct dload_state dl_state;    /* internal state for this call */
+
+       /* blast our internal state */
+       dp = (unsigned *)&dl_state;
+       for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
+               *dp++ = 0;
+
+       /* Enable _only_ BSS initialization if enabled by user */
+       if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
+               dl_state.myoptions = DLOAD_INITBSS;
+
+       /* Check that mandatory arguments are present */
+       if (!module || !syms) {
+               dload_error(&dl_state, "Required parameter is NULL");
+       } else {
+               dl_state.strm = module;
+               dl_state.mysym = syms;
+               dload_headers(&dl_state);
+               if (!dl_state.dload_errcount)
+                       dload_strings(&dl_state, false);
+               if (!dl_state.dload_errcount)
+                       dload_sections(&dl_state);
+
+               if (init && !dl_state.dload_errcount) {
+                       if (init->connect(init)) {
+                               dl_state.myio = init;
+                               dl_state.myalloc = alloc;
+                               /* do now, before reducing symbols */
+                               allocate_sections(&dl_state);
+                       } else
+                               dload_error(&dl_state, iconnect);
+               }
+
+               if (!dl_state.dload_errcount) {
+                       /* fix up entry point address */
+                       unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
+                       if (sref < dl_state.allocated_secn_count)
+                               dl_state.dfile_hdr.df_entrypt +=
+                                   dl_state.ldr_sections[sref].run_addr;
+
+                       dload_symbols(&dl_state);
+               }
+
+               if (init && !dl_state.dload_errcount)
+                       dload_data(&dl_state);
+
+               init_module_handle(&dl_state);
+
+               /* dl_state.myio is init or 0 at this point. */
+               if (dl_state.myio) {
+                       if ((!dl_state.dload_errcount) &&
+                           (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
+                           (!init->execute(init,
+                                           dl_state.dfile_hdr.df_entrypt)))
+                               dload_error(&dl_state, "Init->Execute Failed");
+                       init->release(init);
+               }
+
+               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,
+                                             init);
+                       dl_state.myhandle = NULL;
+               }
+       }
+
+       if (mhandle)
+               *mhandle = dl_state.myhandle;   /* give back the handle */
+
+       return dl_state.dload_errcount;
+}                              /* DLOAD_File */
+
+/*************************************************************************
+ * Procedure dynamic_open_module
+ *
+ * Parameters:
+ *      module  The input stream that supplies the module image
+ *      syms    Host-side symbol table and malloc/free functions
+ *      alloc   Target-side memory allocation
+ *      init    Target-side memory initialization
+ *      options Option flags DLOAD_*
+ *      mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ *      The module image is read using *module.  Target storage for the new
+ *      image is
+ *     obtained from *alloc.  Symbols defined and referenced by the module are
+ *     managed using *syms.  The image is then relocated and references
+ *      resolved as necessary, and the resulting executable bits are placed
+ *      into target memory using *init.
+ *
+ * Returns:
+ *      On a successful load, a module handle is placed in *mhandle,
+ *      and zero is returned.  On error, the number of errors detected is
+ *      returned.  Individual errors are reported during the load process
+ *      using syms->error_report().
+ ********************************************************************** */
+int
+dynamic_open_module(struct dynamic_loader_stream *module,
+                   struct dynamic_loader_sym *syms,
+                   struct dynamic_loader_allocate *alloc,
+                   struct dynamic_loader_initialize *init,
+                   unsigned options, void **mhandle)
+{
+       register unsigned *dp, sz;
+       struct dload_state dl_state;    /* internal state for this call */
+
+       /* blast our internal state */
+       dp = (unsigned *)&dl_state;
+       for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
+               *dp++ = 0;
+
+       /* Enable _only_ BSS initialization if enabled by user */
+       if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
+               dl_state.myoptions = DLOAD_INITBSS;
+
+       /* Check that mandatory arguments are present */
+       if (!module || !syms) {
+               dload_error(&dl_state, "Required parameter is NULL");
+       } else {
+               dl_state.strm = module;
+               dl_state.mysym = syms;
+               dload_headers(&dl_state);
+               if (!dl_state.dload_errcount)
+                       dload_strings(&dl_state, false);
+               if (!dl_state.dload_errcount)
+                       dload_sections(&dl_state);
+
+               if (init && !dl_state.dload_errcount) {
+                       if (init->connect(init)) {
+                               dl_state.myio = init;
+                               dl_state.myalloc = alloc;
+                               /* do now, before reducing symbols */
+                               allocate_sections(&dl_state);
+                       } else
+                               dload_error(&dl_state, iconnect);
+               }
+
+               if (!dl_state.dload_errcount) {
+                       /* fix up entry point address */
+                       unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
+                       if (sref < dl_state.allocated_secn_count)
+                               dl_state.dfile_hdr.df_entrypt +=
+                                   dl_state.ldr_sections[sref].run_addr;
+
+                       dload_symbols(&dl_state);
+               }
+
+               init_module_handle(&dl_state);
+
+               /* dl_state.myio is either 0 or init at this point. */
+               if (dl_state.myio) {
+                       if ((!dl_state.dload_errcount) &&
+                           (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
+                           (!init->execute(init,
+                                           dl_state.dfile_hdr.df_entrypt)))
+                               dload_error(&dl_state, "Init->Execute Failed");
+                       init->release(init);
+               }
+
+               symbol_table_free(&dl_state);
+               section_table_free(&dl_state);
+               string_table_free(&dl_state);
+
+               if (dl_state.dload_errcount) {
+                       dynamic_unload_module(dl_state.myhandle, syms, alloc,
+                                             init);
+                       dl_state.myhandle = NULL;
+               }
+       }
+
+       if (mhandle)
+               *mhandle = dl_state.myhandle;   /* give back the handle */
+
+       return dl_state.dload_errcount;
+}                              /* DLOAD_File */
+
+/*************************************************************************
+ * Procedure dload_headers
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Loads the DOFF header and verify record.  Deals with any byte-order
+ * issues and checks them for validity.
+ *********************************************************************** */
+#define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \
+                            sizeof(struct doff_verify_rec_t))
+
+void dload_headers(struct dload_state *dlthis)
+{
+       u32 map;
+
+       /* Read the header and the verify record as one.  If we don't get it
+          all, we're done */
+       if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr,
+                                     COMBINED_HEADER_SIZE) !=
+           COMBINED_HEADER_SIZE) {
+               DL_ERROR(readstrm, "File Headers");
+               return;
+       }
+       /*
+        * Verify that we have the byte order of the file correct.
+        * If not, must fix it before we can continue
+        */
+       map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle);
+       if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) {
+               /* input is either byte-shuffled or bad */
+               if ((map & 0xFCFCFCFC) == 0) {  /* no obviously bogus bits */
+                       dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE,
+                                     map);
+               }
+               if (dlthis->dfile_hdr.df_byte_reshuffle !=
+                   BYTE_RESHUFFLE_VALUE) {
+                       /* didn't fix the problem, the byte swap map is bad */
+                       dload_error(dlthis,
+                                   "Bad byte swap map " FMT_UI32 " in header",
+                                   dlthis->dfile_hdr.df_byte_reshuffle);
+                       return;
+               }
+               dlthis->reorder_map = map;      /* keep map for future use */
+       }
+
+       /*
+        * Verify checksum of header and verify record
+        */
+       if (~dload_checksum(&dlthis->dfile_hdr,
+                           sizeof(struct doff_filehdr_t)) ||
+           ~dload_checksum(&dlthis->verify,
+                           sizeof(struct doff_verify_rec_t))) {
+               DL_ERROR(err_checksum, "header or verify record");
+               return;
+       }
+#if HOST_ENDIANNESS
+       dlthis->dfile_hdr.df_byte_reshuffle = map;      /* put back for later */
+#endif
+
+       /* Check for valid target ID */
+       if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) &&
+           -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) {
+               dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x",
+                           dlthis->dfile_hdr.df_target_id, TARGET_ID);
+               return;
+       }
+       /* Check for valid file format */
+       if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) {
+               dload_error(dlthis, "Bad DOFF version 0x%x",
+                           dlthis->dfile_hdr.df_doff_version);
+               return;
+       }
+
+       /*
+        * Apply reasonableness checks to count fields
+        */
+       if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) {
+               dload_error(dlthis, "Excessive string table size " FMT_UI32,
+                           dlthis->dfile_hdr.df_strtab_size);
+               return;
+       }
+       if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) {
+               dload_error(dlthis, "Excessive section count 0x%x",
+                           dlthis->dfile_hdr.df_no_scns);
+               return;
+       }
+#ifndef TARGET_ENDIANNESS
+       /*
+        * Check that endianness does not disagree with explicit specification
+        */
+       if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) &
+           dlthis->myoptions & ENDIANNESS_MASK) {
+               dload_error(dlthis,
+                           "Input endianness disagrees with specified option");
+               return;
+       }
+       dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG;
+#endif
+
+}                              /* dload_headers */
+
+/*     COFF Section Processing
+ *
+ *     COFF sections are read in and retained intact.  Each record is embedded
+ *     in a new structure that records the updated load and
+ *     run addresses of the section */
+
+static const char secn_errid[] = { "section" };
+
+/*************************************************************************
+ * Procedure dload_sections
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Loads the section records into an internal table.
+ *********************************************************************** */
+void dload_sections(struct dload_state *dlthis)
+{
+       s16 siz;
+       struct doff_scnhdr_t *shp;
+       unsigned nsecs = dlthis->dfile_hdr.df_no_scns;
+
+       /* allocate space for the DOFF section records */
+       siz = nsecs * sizeof(struct doff_scnhdr_t);
+       shp =
+           (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym,
+                                                                 siz);
+       if (!shp) {             /* not enough storage */
+               DL_ERROR(err_alloc, siz);
+               return;
+       }
+       dlthis->sect_hdrs = shp;
+
+       /* read in the section records */
+       if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) {
+               DL_ERROR(readstrm, secn_errid);
+               return;
+       }
+
+       /* if we need to fix up byte order, do it now */
+       if (dlthis->reorder_map)
+               dload_reorder(shp, siz, dlthis->reorder_map);
+
+       /* check for validity */
+       if (~dload_checksum(dlthis->sect_hdrs, siz) !=
+           dlthis->verify.dv_scn_rec_checksum) {
+               DL_ERROR(err_checksum, secn_errid);
+               return;
+       }
+
+}                              /* dload_sections */
+
+/*****************************************************************************
+ * Procedure allocate_sections
+ *
+ * Parameters:
+ *     alloc   target memory allocator class
+ *
+ * Effect:
+ *     Assigns new (target) addresses for sections
+ **************************************************************************** */
+static void allocate_sections(struct dload_state *dlthis)
+{
+       u16 curr_sect, nsecs, siz;
+       struct doff_scnhdr_t *shp;
+       struct ldr_section_info *asecs;
+       struct my_handle *hndl;
+       nsecs = dlthis->dfile_hdr.df_no_scns;
+       if (!nsecs)
+               return;
+       if ((dlthis->myalloc == NULL) &&
+           (dlthis->dfile_hdr.df_target_scns > 0)) {
+               DL_ERROR("Arg 3 (alloc) required but NULL", 0);
+               return;
+       }
+       /*
+        * 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->dload_allocate(dlthis->mysym,
+                                                             siz);
+       if (!hndl) {            /* not enough storage */
+               DL_ERROR(err_alloc, siz);
+               return;
+       }
+       /* initialize the handle header */
+       hndl->dm.hnext = hndl->dm.hprev = hndl; /* circular list */
+       hndl->dm.hroot = NULL;
+       hndl->dm.dbthis = 0;
+       dlthis->myhandle = hndl;        /* save away for return */
+       /* pointer to the section list of allocated sections */
+       dlthis->ldr_sections = asecs = hndl->secns;
+       /* * Insert names into all sections, make copies of
+          the sections we allocate */
+       shp = dlthis->sect_hdrs;
+       for (curr_sect = 0; curr_sect < nsecs; curr_sect++) {
+               u32 soffset = shp->ds_offset;
+#if BITS_PER_AU <= BITS_PER_BYTE
+               /* attempt to insert the name of this section */
+               if (soffset < dlthis->dfile_hdr.df_strtab_size)
+                       DOFFSEC_IS_LDRSEC(shp)->name = dlthis->str_head +
+                           soffset;
+               else {
+                       dload_error(dlthis, "Bad name offset in section %d",
+                                   curr_sect);
+                       DOFFSEC_IS_LDRSEC(shp)->name = NULL;
+               }
+#endif
+               /* allocate target storage for sections that require it */
+               if (DS_NEEDS_ALLOCATION(shp)) {
+                       *asecs = *DOFFSEC_IS_LDRSEC(shp);
+                       asecs->context = 0;     /* zero the context field */
+#if BITS_PER_AU > BITS_PER_BYTE
+                       asecs->name = unpack_name(dlthis, soffset);
+                       dlthis->debug_string_size = soffset + dlthis->temp_len;
+#else
+                       dlthis->debug_string_size = soffset;
+#endif
+                       if (dlthis->myalloc != NULL) {
+                               if (!dlthis->myalloc->
+                                   dload_allocate(dlthis->myalloc, asecs,
+                                                  DS_ALIGNMENT(asecs->type))) {
+                                       dload_error(dlthis, tgtalloc,
+                                                   asecs->name, asecs->size);
+                                       return;
+                               }
+                       }
+                       /* keep address deltas in original section table */
+                       shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr;
+                       shp->ds_paddr = asecs->run_addr - shp->ds_paddr;
+                       dlthis->allocated_secn_count += 1;
+               }               /* allocate target storage */
+               shp += 1;
+               asecs += 1;
+       }
+#if BITS_PER_AU <= BITS_PER_BYTE
+       dlthis->debug_string_size +=
+           strlen(dlthis->str_head + dlthis->debug_string_size) + 1;
+#endif
+}                              /* allocate sections */
+
+/*************************************************************************
+ * Procedure section_table_free
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Frees any state used by the symbol table.
+ *
+ * WARNING:
+ *     This routine is not allowed to declare errors!
+ *********************************************************************** */
+static void section_table_free(struct dload_state *dlthis)
+{
+       struct doff_scnhdr_t *shp;
+
+       shp = dlthis->sect_hdrs;
+       if (shp)
+               dlthis->mysym->dload_deallocate(dlthis->mysym, shp);
+
+}                              /* section_table_free */
+
+/*************************************************************************
+ * Procedure dload_strings
+ *
+ * Parameters:
+ *  sec_names_only   If true only read in the "section names"
+ *                  portion of the string table
+ *
+ * Effect:
+ *     Loads the DOFF string table into memory. DOFF keeps all strings in a
+ * big unsorted array.  We just read that array into memory in bulk.
+ *********************************************************************** */
+static const char stringtbl[] = { "string table" };
+
+void dload_strings(struct dload_state *dlthis, bool sec_names_only)
+{
+       u32 ssiz;
+       char *strbuf;
+
+       if (sec_names_only) {
+               ssiz = BYTE_TO_HOST(DOFF_ALIGN
+                                   (dlthis->dfile_hdr.df_scn_name_size));
+       } else {
+               ssiz = BYTE_TO_HOST(DOFF_ALIGN
+                                   (dlthis->dfile_hdr.df_strtab_size));
+       }
+       if (ssiz == 0)
+               return;
+
+       /* get some memory for the string table */
+#if BITS_PER_AU > BITS_PER_BYTE
+       strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz +
+                                                      dlthis->dfile_hdr.
+                                                      df_max_str_len);
+#else
+       strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz);
+#endif
+       if (strbuf == NULL) {
+               DL_ERROR(err_alloc, ssiz);
+               return;
+       }
+       dlthis->str_head = strbuf;
+#if BITS_PER_AU > BITS_PER_BYTE
+       dlthis->str_temp = strbuf + ssiz;
+#endif
+       /* read in the strings and verify them */
+       if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf,
+                                                ssiz)) != ssiz) {
+               DL_ERROR(readstrm, stringtbl);
+       }
+       /* if we need to fix up byte order, do it now */
+#ifndef _BIG_ENDIAN
+       if (dlthis->reorder_map)
+               dload_reorder(strbuf, ssiz, dlthis->reorder_map);
+
+       if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) !=
+                                 dlthis->verify.dv_str_tab_checksum)) {
+               DL_ERROR(err_checksum, stringtbl);
+       }
+#else
+       if (dlthis->dfile_hdr.df_byte_reshuffle !=
+           HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
+               /* put strings in big-endian order, not in PC order */
+               dload_reorder(strbuf, ssiz,
+                             HOST_BYTE_ORDER(dlthis->
+                                             dfile_hdr.df_byte_reshuffle));
+       }
+       if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) !=
+                                 dlthis->verify.dv_str_tab_checksum)) {
+               DL_ERROR(err_checksum, stringtbl);
+       }
+#endif
+}                              /* dload_strings */
+
+/*************************************************************************
+ * Procedure string_table_free
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Frees any state used by the string table.
+ *
+ * WARNING:
+ *     This routine is not allowed to declare errors!
+ ************************************************************************ */
+static void string_table_free(struct dload_state *dlthis)
+{
+       if (dlthis->str_head)
+               dlthis->mysym->dload_deallocate(dlthis->mysym,
+                                               dlthis->str_head);
+
+}                              /* string_table_free */
+
+/*
+ * Symbol Table Maintenance Functions
+ *
+ * COFF symbols are read by dload_symbols(), which is called after
+ * sections have been allocated.  Symbols which might be used in
+ * relocation (ie, not debug info) are retained in an internal temporary
+ * compressed table (type local_symbol). A particular symbol is recovered
+ * by index by calling dload_find_symbol().  dload_find_symbol
+ * reconstructs a more explicit representation (type SLOTVEC) which is
+ * used by reloc.c
+ */
+/* real size of debug header */
+#define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect))
+
+static const char sym_errid[] = { "symbol" };
+
+/**************************************************************************
+ * Procedure dload_symbols
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Reads in symbols and retains ones that might be needed for relocation
+ * purposes.
+ *********************************************************************** */
+/* size of symbol buffer no bigger than target data buffer, to limit stack
+ * usage */
+#define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\
+                       sizeof(struct doff_syment_t))
+
+static void dload_symbols(struct dload_state *dlthis)
+{
+       u32 sym_count, siz, dsiz, symbols_left;
+       u32 checks;
+       struct local_symbol *sp;
+       struct dynload_symbol *symp;
+       struct dynload_symbol *newsym;
+
+       sym_count = dlthis->dfile_hdr.df_no_syms;
+       if (sym_count == 0)
+               return;
+
+       /*
+        * 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.  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 = sym_count * sizeof(struct local_symbol);
+       dsiz = DBG_HDR_SIZE +
+           (sizeof(struct dll_sect) * dlthis->allocated_secn_count) +
+           BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1);
+       if (dsiz > siz)
+               siz = dsiz;     /* larger of symbols and .dllview temp */
+       sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
+                                                                 siz);
+       if (!sp) {
+               DL_ERROR(err_alloc, siz);
+               return;
+       }
+       dlthis->local_symtab = sp;
+       /* Read the symbols in the input, store them in the table, and post any
+        * globals to the global symbol table.  In the process, externals
+        become defined from the global symbol table */
+       checks = dlthis->verify.dv_sym_tab_checksum;
+       symbols_left = sym_count;
+       do {                    /* read all symbols */
+               char *sname;
+               u32 val;
+               s32 delta;
+               struct doff_syment_t *input_sym;
+               unsigned syms_in_buf;
+               struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ];
+               input_sym = my_sym_buf;
+               syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ?
+                   MY_SYM_BUF_SIZ : symbols_left;
+               siz = syms_in_buf * sizeof(struct doff_syment_t);
+               if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) !=
+                   siz) {
+                       DL_ERROR(readstrm, sym_errid);
+                       return;
+               }
+               if (dlthis->reorder_map)
+                       dload_reorder(input_sym, siz, dlthis->reorder_map);
+
+               checks += dload_checksum(input_sym, siz);
+               do {            /* process symbols in buffer */
+                       symbols_left -= 1;
+                       /* attempt to derive the name of this symbol */
+                       sname = NULL;
+                       if (input_sym->dn_offset > 0) {
+#if BITS_PER_AU <= BITS_PER_BYTE
+                               if ((u32) input_sym->dn_offset <
+                                   dlthis->dfile_hdr.df_strtab_size)
+                                       sname = dlthis->str_head +
+                                           BYTE_TO_HOST(input_sym->dn_offset);
+                               else
+                                       dload_error(dlthis,
+                                                   "Bad name offset in symbol "
+                                                   " %d", symbols_left);
+#else
+                               sname = unpack_name(dlthis,
+                                                   input_sym->dn_offset);
+#endif
+                       }
+                       val = input_sym->dn_value;
+                       delta = 0;
+                       sp->sclass = input_sym->dn_sclass;
+                       sp->secnn = input_sym->dn_scnum;
+                       /* if this is an undefined symbol,
+                        * define it (or fail) now */
+                       if (sp->secnn == DN_UNDEF) {
+                               /* pointless for static undefined */
+                               if (input_sym->dn_sclass != DN_EXT)
+                                       goto loop_cont;
+
+                               /* try to define symbol from previously
+                                * loaded images */
+                               symp = dlthis->mysym->find_matching_symbol
+                                   (dlthis->mysym, sname);
+                               if (!symp) {
+                                       DL_ERROR
+                                           ("Undefined external symbol %s",
+                                            sname);
+                                       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 */
+                       if (sp->secnn > 0) {
+                               /* symbol references a section */
+                               if ((unsigned)sp->secnn <=
+                                   dlthis->allocated_secn_count) {
+                                       /* section was allocated */
+                                       struct doff_scnhdr_t *srefp =
+                                           &dlthis->sect_hdrs[sp->secnn - 1];
+
+                                       if (input_sym->dn_sclass ==
+                                           DN_STATLAB ||
+                                           input_sym->dn_sclass == DN_EXTLAB) {
+                                               /* load */
+                                               delta = srefp->ds_vaddr;
+                                       } else {
+                                               /* run */
+                                               delta = srefp->ds_paddr;
+                                       }
+                                       val += delta;
+                               }
+                               goto loop_itr;
+                       }
+                       /* This symbol is an absolute symbol */
+                       if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) ||
+                                                   (sp->sclass ==
+                                                    DN_EXTLAB))) {
+                               symp =
+                                   dlthis->mysym->find_matching_symbol(dlthis->
+                                                                       mysym,
+                                                                       sname);
+                               if (!symp)
+                                       goto loop_itr;
+                               /* This absolute symbol is already defined. */
+                               if (symp->value == input_sym->dn_value) {
+                                       /* If symbol values are equal, continue
+                                        * but don't add to the global symbol
+                                        * table */
+                                       sp->value = val;
+                                       sp->delta = delta;
+                                       sp += 1;
+                                       input_sym += 1;
+                                       continue;
+                               } else {
+                                       /* If symbol values are not equal,
+                                        * return with redefinition error */
+                                       DL_ERROR("Absolute symbol %s is "
+                                                "defined multiple times with "
+                                                "different values", sname);
+                                       return;
+                               }
+                       }
+loop_itr:
+                       /* if this is a global symbol, post it to the
+                        * global table */
+                       if (input_sym->dn_sclass == DN_EXT ||
+                           input_sym->dn_sclass == DN_EXTLAB) {
+                               /* Keep this global symbol for subsequent
+                                * modules. Don't complain on error, to allow
+                                * symbol API to suppress global symbols */
+                               if (!sname)
+                                       goto loop_cont;
+
+                               newsym = dlthis->mysym->add_to_symbol_table
+                                   (dlthis->mysym, sname,
+                                    (unsigned)dlthis->myhandle);
+                               if (newsym)
+                                       newsym->value = val;
+
+                       }       /* global */
+loop_cont:
+                       sp->value = val;
+                       sp->delta = delta;
+                       sp += 1;
+                       input_sym += 1;
+               } while ((syms_in_buf -= 1) > 0);       /* process sym in buf */
+       } while (symbols_left > 0);     /* read all symbols */
+       if (~checks)
+               dload_error(dlthis, "Checksum of symbols failed");
+
+}                              /* dload_symbols */
+
+/*****************************************************************************
+ * Procedure symbol_table_free
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Frees any state used by the symbol table.
+ *
+ * WARNING:
+ *     This routine is not allowed to declare errors!
+ **************************************************************************** */
+static void symbol_table_free(struct dload_state *dlthis)
+{
+       if (dlthis->local_symtab) {
+               if (dlthis->dload_errcount) {   /* blow off our symbols */
+                       dlthis->mysym->purge_symbol_table(dlthis->mysym,
+                                                         (unsigned)
+                                                         dlthis->myhandle);
+               }
+               dlthis->mysym->dload_deallocate(dlthis->mysym,
+                                               dlthis->local_symtab);
+       }
+}                              /* symbol_table_free */
+
+/* .cinit Processing
+ *
+ * The dynamic loader does .cinit interpretation.  cload_cinit()
+ * acts as a special write-to-target function, in that it takes relocated
+ * data from the normal data flow, and interprets it as .cinit actions.
+ * Because the normal data flow does not  necessarily process the whole
+ * .cinit section in one buffer, cload_cinit() must be prepared to
+ * interpret the data piecemeal.  A state machine is used for this
+ * purpose.
+ */
+
+/* The following are only for use by reloc.c and things it calls */
+static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0,
+       (ldr_addr)-1, 0, DLOAD_BSS, 0
+};
+
+/*************************************************************************
+ * Procedure cload_cinit
+ *
+ * Parameters:
+ *     ipacket         Pointer to data packet to be loaded
+ *
+ * Effect:
+ *     Interprets the data in the buffer as .cinit data, and performs the
+ * appropriate initializations.
+ *********************************************************************** */
+static void cload_cinit(struct dload_state *dlthis,
+                       struct image_packet_t *ipacket)
+{
+#if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16
+       s32 init_count, left;
+#else
+       s16 init_count, left;
+#endif
+       unsigned char *pktp = ipacket->img_data;
+       unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size);
+       int temp;
+       ldr_addr atmp;
+       struct ldr_section_info cinit_info;
+
+       /*  PROCESS ALL THE INITIALIZATION RECORDS IN THE BUFFER. */
+       while (true) {
+               left = pktend - pktp;
+               switch (dlthis->cinit_state) {
+               case CI_COUNT:  /* count field */
+                       if (left < TDATA_TO_HOST(CINIT_COUNT))
+                               goto loopexit;
+                       temp = dload_unpack(dlthis, (tgt_au_t *) pktp,
+                                           CINIT_COUNT * TDATA_AU_BITS, 0,
+                                           ROP_SGN);
+                       pktp += TDATA_TO_HOST(CINIT_COUNT);
+                       /* negative signifies BSS table, zero means done */
+                       if (temp <= 0) {
+                               dlthis->cinit_state = CI_DONE;
+                               break;
+                       }
+                       dlthis->cinit_count = temp;
+                       dlthis->cinit_state = CI_ADDRESS;
+                       break;
+#if CINIT_ALIGN < CINIT_ADDRESS
+               case CI_PARTADDRESS:
+                       pktp -= TDATA_TO_HOST(CINIT_ALIGN);
+                       /* back up pointer into space courtesy of caller */
+                       *(uint16_t *) pktp = dlthis->cinit_addr;
+                       /* stuff in saved bits  !! FALL THRU !! */
+#endif
+               case CI_ADDRESS:        /* Address field for a copy packet */
+                       if (left < TDATA_TO_HOST(CINIT_ADDRESS)) {
+#if CINIT_ALIGN < CINIT_ADDRESS
+                               if (left == TDATA_TO_HOST(CINIT_ALIGN)) {
+                                       /* address broken into halves */
+                                       dlthis->cinit_addr = *(uint16_t *) pktp;
+                                       /* remember 1st half */
+                                       dlthis->cinit_state = CI_PARTADDRESS;
+                                       left = 0;
+                               }
+#endif
+                               goto loopexit;
+                       }
+                       atmp = dload_unpack(dlthis, (tgt_au_t *) pktp,
+                                           CINIT_ADDRESS * TDATA_AU_BITS, 0,
+                                           ROP_UNS);
+                       pktp += TDATA_TO_HOST(CINIT_ADDRESS);
+#if CINIT_PAGE_BITS > 0
+                       dlthis->cinit_page = atmp &
+                           ((1 << CINIT_PAGE_BITS) - 1);
+                       atmp >>= CINIT_PAGE_BITS;
+#else
+                       dlthis->cinit_page = CINIT_DEFAULT_PAGE;
+#endif
+                       dlthis->cinit_addr = atmp;
+                       dlthis->cinit_state = CI_COPY;
+                       break;
+               case CI_COPY:   /* copy bits to the target */
+                       init_count = HOST_TO_TDATA(left);
+                       if (init_count > dlthis->cinit_count)
+                               init_count = dlthis->cinit_count;
+                       if (init_count == 0)
+                               goto loopexit;  /* get more bits */
+                       cinit_info = cinit_info_init;
+                       cinit_info.page = dlthis->cinit_page;
+                       if (!dlthis->myio->writemem(dlthis->myio, pktp,
+                                                  TDATA_TO_TADDR
+                                                  (dlthis->cinit_addr),
+                                                  &cinit_info,
+                                                  TDATA_TO_HOST(init_count))) {
+                               dload_error(dlthis, initfail, "write",
+                                           dlthis->cinit_addr);
+                       }
+                       dlthis->cinit_count -= init_count;
+                       if (dlthis->cinit_count <= 0) {
+                               dlthis->cinit_state = CI_COUNT;
+                               init_count = (init_count + CINIT_ALIGN - 1) &
+                                   -CINIT_ALIGN;
+                               /* align to next init */
+                       }
+                       pktp += TDATA_TO_HOST(init_count);
+                       dlthis->cinit_addr += init_count;
+                       break;
+               case CI_DONE:   /* no more .cinit to do */
+                       return;
+               }               /* switch (cinit_state) */
+       }                       /* while */
+
+loopexit:
+       if (left > 0) {
+               dload_error(dlthis, "%d bytes left over in cinit packet", left);
+               dlthis->cinit_state = CI_DONE;  /* left over bytes are bad */
+       }
+}                              /* cload_cinit */
+
+/*     Functions to interface to reloc.c
+ *
+ * reloc.c is the relocation module borrowed from the linker, with
+ * minimal (we hope) changes for our purposes.  cload_sect_data() invokes
+ * this module on a section to relocate and load the image data for that
+ * section.  The actual read and write actions are supplied by the global
+ * routines below.
+ */
+
+/************************************************************************
+ * Procedure relocate_packet
+ *
+ * Parameters:
+ *     ipacket         Pointer to an image packet to relocate
+ *
+ * Effect:
+ *     Performs the required relocations on the packet.  Returns a checksum
+ * of the relocation operations.
+ *********************************************************************** */
+#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, bool *tramps_generated)
+{
+       u32 rnum;
+       *tramps_generated = false;
+
+       rnum = ipacket->num_relocs;
+       do {                    /* all relocs */
+               unsigned rinbuf;
+               int siz;
+               struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ];
+               rp = rrec;
+               rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum;
+               siz = rinbuf * sizeof(struct reloc_record_t);
+               if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) {
+                       DL_ERROR(readstrm, "relocation");
+                       return 0;
+               }
+               /* reorder the bytes if need be */
+               if (dlthis->reorder_map)
+                       dload_reorder(rp, siz, dlthis->reorder_map);
+
+               *checks += dload_checksum(rp, siz);
+               do {
+                       /* perform the relocation operation */
+                       dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data,
+                                      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 */
+
+#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
+
+/* VERY dangerous */
+static const char imagepak[] = { "image packet" };
+
+/*************************************************************************
+ * Procedure dload_data
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Read image data from input file, relocate it, and download it to the
+ *     target.
+ *********************************************************************** */
+static void dload_data(struct dload_state *dlthis)
+{
+       u16 curr_sect;
+       struct doff_scnhdr_t *sptr = dlthis->sect_hdrs;
+       struct ldr_section_info *lptr = dlthis->ldr_sections;
+#ifdef OPT_ZERO_COPY_LOADER
+       bool zero_copy = false;
+#endif
+       u8 *dest;
+
+       struct {
+               struct image_packet_t ipacket;
+               u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)];
+       } ibuf;
+
+       /* Indicates whether CINIT processing has occurred */
+       bool cinit_processed = false;
+
+       /* Loop through the sections and load them one at a time.
+        */
+       for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns;
+            curr_sect += 1) {
+               if (DS_NEEDS_DOWNLOAD(sptr)) {
+                       s32 nip;
+                       ldr_addr image_offset = 0;
+                       /* set relocation info for this section */
+                       if (curr_sect < dlthis->allocated_secn_count)
+                               dlthis->delta_runaddr = sptr->ds_paddr;
+                       else {
+                               lptr = DOFFSEC_IS_LDRSEC(sptr);
+                               dlthis->delta_runaddr = 0;
+                       }
+                       dlthis->image_secn = lptr;
+#if BITS_PER_AU > BITS_PER_BYTE
+                       lptr->name = unpack_name(dlthis, sptr->ds_offset);
+#endif
+                       nip = sptr->ds_nipacks;
+                       while ((nip -= 1) >= 0) {       /* process packets */
+
+                               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) {
+                                       DL_ERROR(readstrm, imagepak);
+                                       return;
+                               }
+                               /* reorder the header if need be */
+                               if (dlthis->reorder_map) {
+                                       dload_reorder(&ibuf.ipacket, IPH_SIZE,
+                                                     dlthis->reorder_map);
+                               }
+                               /* now read the rest of the packet */
+                               ipsize =
+                                   BYTE_TO_HOST(DOFF_ALIGN
+                                                (ibuf.ipacket.packet_size));
+                               if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
+                                       DL_ERROR("Bad image packet size %d",
+                                                ipsize);
+                                       return;
+                               }
+                               dest = ibuf.bufr;
+#ifdef OPT_ZERO_COPY_LOADER
+                               zero_copy = false;
+                               if (DLOAD_SECT_TYPE(sptr) != DLOAD_CINIT) {
+                                       dlthis->myio->writemem(dlthis->myio,
+                                                              &dest,
+                                                              lptr->load_addr +
+                                                              image_offset,
+                                                              lptr, 0);
+                                       zero_copy = (dest != ibuf.bufr);
+                               }
+#endif
+                               /* End of determination */
+
+                               if (dlthis->strm->read_buffer(dlthis->strm,
+                                                             ibuf.bufr,
+                                                             ipsize) !=
+                                   ipsize) {
+                                       DL_ERROR(readstrm, imagepak);
+                                       return;
+                               }
+                               ibuf.ipacket.img_data = dest;
+
+                               /* reorder the bytes if need be */
+#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
+                               if (dlthis->reorder_map) {
+                                       dload_reorder(dest, ipsize,
+                                                     dlthis->reorder_map);
+                               }
+                               checks = dload_checksum(dest, ipsize);
+#else
+                               if (dlthis->dfile_hdr.df_byte_reshuffle !=
+                                   TARGET_ORDER(REORDER_MAP
+                                                (BYTE_RESHUFFLE_VALUE))) {
+                                       /* put image bytes in big-endian order,
+                                        * not PC order */
+                                       dload_reorder(dest, ipsize,
+                                                     TARGET_ORDER
+                                                     (dlthis->dfile_hdr.
+                                                      df_byte_reshuffle));
+                               }
+#if TARGET_AU_BITS > 8
+                               checks = dload_reverse_checksum16(dest, ipsize);
+#else
+                               checks = dload_reverse_checksum(dest, ipsize);
+#endif
+#endif
+
+                               checks += dload_checksum(&ibuf.ipacket,
+                                                        IPH_SIZE);
+                               /* relocate the image bits as needed */
+                               if (ibuf.ipacket.num_relocs) {
+                                       dlthis->image_offset = image_offset;
+                                       if (!relocate_packet(dlthis,
+                                                            &ibuf.ipacket,
+                                                            &checks,
+                                                            &tramp_generated))
+                                               return; /* serious error */
+                               }
+                               if (~checks)
+                                       DL_ERROR(err_checksum, imagepak);
+                               /* 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 (!zero_copy) {
+#endif
+                                                       /* FIXME */
+                                                       if (!dlthis->myio->
+                                                           writemem(dlthis->
+                                                               myio,
+                                                               ibuf.bufr,
+                                                               lptr->
+                                                               load_addr +
+                                                               image_offset,
+                                                               lptr,
+                                                               BYTE_TO_HOST
+                                                               (ibuf.
+                                                               ipacket.
+                                                               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.packet_size);
+                       }       /* process packets */
+                       /* if this is a BSS section, we may want to fill it */
+                       if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS)
+                               goto loop_cont;
+
+                       if (!(dlthis->myoptions & DLOAD_INITBSS))
+                               goto loop_cont;
+
+                       if (cinit_processed) {
+                               /* Don't clear BSS after load-time
+                                * initialization */
+                               DL_ERROR
+                                   ("Zero-initialization at " FMT_UI32
+                                    " after " "load-time initialization!",
+                                    lptr->load_addr);
+                               goto loop_cont;
+                       }
+                       /* fill the .bss area */
+                       dlthis->myio->fillmem(dlthis->myio,
+                                             TADDR_TO_HOST(lptr->load_addr),
+                                             lptr, TADDR_TO_HOST(lptr->size),
+                                             DLOAD_FILL_BSS);
+                       goto loop_cont;
+               }
+               /* if DS_DOWNLOAD_MASK */
+               /* If not loading, but BSS, zero initialize */
+               if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS)
+                       goto loop_cont;
+
+               if (!(dlthis->myoptions & DLOAD_INITBSS))
+                       goto loop_cont;
+
+               if (curr_sect >= dlthis->allocated_secn_count)
+                       lptr = DOFFSEC_IS_LDRSEC(sptr);
+
+               if (cinit_processed) {
+                       /*Don't clear BSS after load-time initialization */
+                       DL_ERROR("Zero-initialization at " FMT_UI32
+                                " attempted after "
+                                "load-time initialization!", lptr->load_addr);
+                       goto loop_cont;
+               }
+               /* fill the .bss area */
+               dlthis->myio->fillmem(dlthis->myio,
+                                     TADDR_TO_HOST(lptr->load_addr), lptr,
+                                     TADDR_TO_HOST(lptr->size),
+                                     DLOAD_FILL_BSS);
+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 */
+
+/*************************************************************************
+ * Procedure dload_reorder
+ *
+ * Parameters:
+ *     data    32-bit aligned pointer to data to be byte-swapped
+ *     dsiz    size of the data to be reordered in sizeof() units.
+ *     map             32-bit map defining how to reorder the data.  Value
+ *                     must be REORDER_MAP() of some permutation
+ *                     of 0x00 01 02 03
+ *
+ * Effect:
+ *     Re-arranges the bytes in each word according to the map specified.
+ *
+ *********************************************************************** */
+/* mask for byte shift count */
+#define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE)
+
+void dload_reorder(void *data, int dsiz, unsigned int map)
+{
+       register u32 tmp, tmap, datv;
+       u32 *dp = (u32 *) data;
+
+       map <<= LOG_BITS_PER_BYTE;      /* align map with SHIFT_COUNT_MASK */
+       do {
+               tmp = 0;
+               datv = *dp;
+               tmap = map;
+               do {
+                       tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK);
+                       tmap >>= BITS_PER_BYTE;
+               } while (datv >>= BITS_PER_BYTE);
+               *dp++ = tmp;
+       } while ((dsiz -= sizeof(u32)) > 0);
+}                              /* dload_reorder */
+
+/*************************************************************************
+ * Procedure dload_checksum
+ *
+ * Parameters:
+ *     data    32-bit aligned pointer to data to be checksummed
+ *     siz             size of the data to be checksummed in sizeof() units.
+ *
+ * Effect:
+ *     Returns a checksum of the specified block
+ *
+ *********************************************************************** */
+u32 dload_checksum(void *data, unsigned siz)
+{
+       u32 sum;
+       u32 *dp;
+       int left;
+
+       sum = 0;
+       dp = (u32 *) data;
+       for (left = siz; left > 0; left -= sizeof(u32))
+               sum += *dp++;
+       return sum;
+}                              /* dload_checksum */
+
+#if HOST_ENDIANNESS
+/*************************************************************************
+ * Procedure dload_reverse_checksum
+ *
+ * Parameters:
+ *     data    32-bit aligned pointer to data to be checksummed
+ *     siz             size of the data to be checksummed in sizeof() units.
+ *
+ * Effect:
+ *     Returns a checksum of the specified block, which is assumed to be bytes
+ * in big-endian order.
+ *
+ * Notes:
+ *     In a big-endian host, things like the string table are stored as bytes
+ * in host order. But dllcreate always checksums in little-endian order.
+ * It is most efficient to just handle the difference a word at a time.
+ *
+ ********************************************************************** */
+u32 dload_reverse_checksum(void *data, unsigned siz)
+{
+       u32 sum, temp;
+       u32 *dp;
+       int left;
+
+       sum = 0;
+       dp = (u32 *) data;
+
+       for (left = siz; left > 0; left -= sizeof(u32)) {
+               temp = *dp++;
+               sum += temp << BITS_PER_BYTE * 3;
+               sum += temp >> BITS_PER_BYTE * 3;
+               sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE);
+               sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE;
+       }
+
+       return sum;
+}                              /* dload_reverse_checksum */
+
+#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
+u32 dload_reverse_checksum16(void *data, unsigned siz)
+{
+       uint_fast32_t sum, temp;
+       u32 *dp;
+       int left;
+
+       sum = 0;
+       dp = (u32 *) data;
+
+       for (left = siz; left > 0; left -= sizeof(u32)) {
+               temp = *dp++;
+               sum += temp << BITS_PER_BYTE * 2;
+               sum += temp >> BITS_PER_BYTE * 2;
+       }
+
+       return sum;
+}                              /* dload_reverse_checksum16 */
+#endif
+#endif
+
+/*************************************************************************
+ * Procedure swap_words
+ *
+ * Parameters:
+ *     data    32-bit aligned pointer to data to be swapped
+ *     siz     size of the data to be swapped.
+ *     bitmap  Bit map of how to swap each 32-bit word; 1 => 2 shorts,
+ *             0 => 1 long
+ *
+ * Effect:
+ *     Swaps the specified data according to the specified map
+ *
+ *********************************************************************** */
+static void swap_words(void *data, unsigned siz, unsigned bitmap)
+{
+       register int i;
+#if TARGET_AU_BITS < 16
+       register u16 *sp;
+#endif
+       register u32 *lp;
+
+       siz /= sizeof(u16);
+
+#if TARGET_AU_BITS < 16
+       /* pass 1: do all the bytes */
+       i = siz;
+       sp = (u16 *) data;
+       do {
+               register u16 tmp;
+               tmp = *sp;
+               *sp++ = SWAP16BY8(tmp);
+       } while ((i -= 1) > 0);
+#endif
+
+#if TARGET_AU_BITS < 32
+       /* pass 2: fixup the 32-bit words */
+       i = siz >> 1;
+       lp = (u32 *) data;
+       do {
+               if ((bitmap & 1) == 0) {
+                       register u32 tmp;
+                       tmp = *lp;
+                       *lp = SWAP32BY16(tmp);
+               }
+               lp += 1;
+               bitmap >>= 1;
+       } while ((i -= 1) > 0);
+#endif
+}                              /* swap_words */
+
+/*************************************************************************
+ * Procedure copy_tgt_strings
+ *
+ * Parameters:
+ *     dstp            Destination address.  Assumed to be 32-bit aligned
+ *     srcp            Source address.  Assumed to be 32-bit aligned
+ *     charcount       Number of characters to copy.
+ *
+ * Effect:
+ *     Copies strings from the source (which is in usual .dof file order on
+ * the loading processor) to the destination buffer (which should be in proper
+ * target addressable unit order).  Makes sure the last string in the
+ * buffer is NULL terminated (for safety).
+ * Returns the first unused destination address.
+ *********************************************************************** */
+static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount)
+{
+       register tgt_au_t *src = (tgt_au_t *) srcp;
+       register tgt_au_t *dst = (tgt_au_t *) dstp;
+       register int cnt = charcount;
+       do {
+#if TARGET_AU_BITS <= BITS_PER_AU
+               /* byte-swapping issues may exist for strings on target */
+               *dst++ = *src++;
+#else
+               *dst++ = *src++;
+#endif
+       } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0);
+       /*apply force to make sure that the string table has null terminator */
+#if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE)
+       dst[-1] = 0;
+#else
+       /* little endian */
+       dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1;
+#endif
+       return (char *)dst;
+}                              /* copy_tgt_strings */
+
+/*************************************************************************
+ * Procedure init_module_handle
+ *
+ * Parameters:
+ *     none
+ *
+ * Effect:
+ *     Initializes the module handle we use to enable unloading, and installs
+ * the debug information required by the target.
+ *
+ * Notes:
+ * The handle returned from dynamic_load_module needs to encapsulate all the
+ * allocations done for the module, and enable them plus the modules symbols to
+ * be deallocated.
+ *
+ *********************************************************************** */
+#ifndef _BIG_ENDIAN
+static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
+       (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0
+};
+#else
+static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
+       (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0
+};
+#endif
+static void init_module_handle(struct dload_state *dlthis)
+{
+       struct my_handle *hndl;
+       u16 curr_sect;
+       struct ldr_section_info *asecs;
+       struct dll_module *dbmod;
+       struct dll_sect *dbsec;
+       struct dbg_mirror_root *mlist;
+       register char *cp;
+       struct modules_header mhdr;
+       struct ldr_section_info dllview_info;
+       struct dynload_symbol *debug_mirror_sym;
+       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)
+               hndl->secn_count += 1;  /* flag for big-endian */
+#endif
+       if (dlthis->dload_errcount)
+               return;         /* abandon if errors detected */
+       /* Locate the symbol that names the header for the CCS debug list
+          of modules. If not found, we just don't generate the debug record.
+          If found, we create our modules list.  We make sure to create the
+          loader_dllview_root even if there is no relocation info to record,
+          just to try to put both symbols in the same symbol table and
+          module. */
+       debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
+                                                       loader_dllview_root);
+       if (!debug_mirror_sym) {
+               struct dynload_symbol *dlmodsym;
+               struct dbg_mirror_root *mlst;
+
+               /* our root symbol is not yet present;
+                  check if we have DLModules defined */
+               dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
+                                                       LINKER_MODULES_HEADER);
+               if (!dlmodsym)
+                       return; /* no DLModules list so no debug info */
+               /* if we have DLModules defined, construct our header */
+               mlst = (struct dbg_mirror_root *)
+                   dlthis->mysym->dload_allocate(dlthis->mysym,
+                                                 sizeof(struct
+                                                        dbg_mirror_root));
+               if (!mlst) {
+                       DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root));
+                       return;
+               }
+               mlst->hnext = NULL;
+               mlst->changes = 0;
+               mlst->refcount = 0;
+               mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value);
+               /* add our root symbol */
+               debug_mirror_sym = dlthis->mysym->add_to_symbol_table
+                   (dlthis->mysym, loader_dllview_root,
+                    (unsigned)dlthis->myhandle);
+               if (!debug_mirror_sym) {
+                       /* failed, recover memory */
+                       dlthis->mysym->dload_deallocate(dlthis->mysym, mlst);
+                       return;
+               }
+               debug_mirror_sym->value = (u32) mlst;
+       }
+       /* First create the DLLview record and stuff it into the buffer.
+          Then write it to the DSP.  Record pertinent locations in our hndl,
+          and add it to the per-processor list of handles with debug info. */
+#ifndef DEBUG_HEADER_IN_LOADER
+       mlist = (struct dbg_mirror_root *)debug_mirror_sym->value;
+       if (!mlist)
+               return;
+#else
+       mlist = (struct dbg_mirror_root *)&debug_list_header;
+#endif
+       hndl->dm.hroot = mlist; /* set pointer to root into our handle */
+       if (!dlthis->allocated_secn_count)
+               return;         /* no load addresses to be recorded */
+       /* reuse temporary symbol storage */
+       dbmod = (struct dll_module *)dlthis->local_symtab;
+       /* Create the DLLview record in the memory we retain for our handle */
+       dbmod->num_sects = dlthis->allocated_secn_count;
+       dbmod->timestamp = dlthis->verify.dv_timdat;
+       dbmod->version = INIT_VERSION;
+       dbmod->verification = VERIFICATION;
+       asecs = dlthis->ldr_sections;
+       dbsec = dbmod->sects;
+       for (curr_sect = dlthis->allocated_secn_count;
+            curr_sect > 0; curr_sect -= 1) {
+               dbsec->sect_load_adr = asecs->load_addr;
+               dbsec->sect_run_adr = asecs->run_addr;
+               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 */
+       dllview_info = dllview_info_init;
+       dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
+       /* Initialize memory context to default heap */
+       dllview_info.context = 0;
+       hndl->dm.context = 0;
+       /* fill in next pointer and size */
+       if (mlist->hnext) {
+               dbmod->next_module = TADDR_TO_TDATA(mlist->hnext->dm.dbthis);
+               dbmod->next_module_size = mlist->hnext->dm.dbsiz;
+       } else {
+               dbmod->next_module_size = 0;
+               dbmod->next_module = 0;
+       }
+       /* allocate memory for on-DSP DLLview debug record */
+       if (!dlthis->myalloc)
+               return;
+       if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info,
+                                            HOST_TO_TADDR(sizeof(u32)))) {
+               return;
+       }
+       /* Store load address of .dllview section */
+       hndl->dm.dbthis = dllview_info.load_addr;
+       /* Store memory context (segid) in which .dllview section
+        * was  allocated */
+       hndl->dm.context = dllview_info.context;
+       mlist->refcount += 1;
+       /* swap bytes in the entire debug record, but not the string table */
+       if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
+               swap_words(dbmod, (char *)dbsec - (char *)dbmod,
+                          DLL_MODULE_BITMAP);
+       }
+       /* Update the DLLview list on the DSP write new record */
+       if (!dlthis->myio->writemem(dlthis->myio, dbmod,
+                                   dllview_info.load_addr, &dllview_info,
+                                   TADDR_TO_HOST(dllview_info.size))) {
+               return;
+       }
+       /* write new header */
+       mhdr.first_module_size = hndl->dm.dbsiz;
+       mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr);
+       /* swap bytes in the module header, if needed */
+       if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
+               swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
+                          MODULES_HEADER_BITMAP);
+       }
+       dllview_info = dllview_info_init;
+       if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis,
+                                   &dllview_info,
+                                   sizeof(struct modules_header) -
+                                   sizeof(u16))) {
+               return;
+       }
+       /* Add the module handle to this processor's list
+          of handles with debug info */
+       hndl->dm.hnext = mlist->hnext;
+       if (hndl->dm.hnext)
+               hndl->dm.hnext->dm.hprev = hndl;
+       hndl->dm.hprev = (struct my_handle *)mlist;
+       mlist->hnext = hndl;    /* insert after root */
+}                              /* init_module_handle */
+
+/*************************************************************************
+ * Procedure dynamic_unload_module
+ *
+ * Parameters:
+ *     mhandle A module handle from dynamic_load_module
+ *     syms    Host-side symbol table and malloc/free functions
+ *     alloc   Target-side memory allocation
+ *
+ * Effect:
+ *     The module specified by mhandle is unloaded.  Unloading causes all
+ * target memory to be deallocated, all symbols defined by the module to
+ * be purged, and any host-side storage used by the dynamic loader for
+ * this module to be released.
+ *
+ * Returns:
+ *     Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report().
+ *********************************************************************** */
+int dynamic_unload_module(void *mhandle,
+                         struct dynamic_loader_sym *syms,
+                         struct dynamic_loader_allocate *alloc,
+                         struct dynamic_loader_initialize *init)
+{
+       s16 curr_sect;
+       struct ldr_section_info *asecs;
+       struct my_handle *hndl;
+       struct dbg_mirror_root *root;
+       unsigned errcount = 0;
+       struct ldr_section_info dllview_info = dllview_info_init;
+       struct modules_header mhdr;
+
+       hndl = (struct my_handle *)mhandle;
+       if (!hndl)
+               return 0;       /* if handle is null, nothing to do */
+       /* Clear out the module symbols
+        * Note that if this is the module that defined MODULES_HEADER
+        (the head of the target debug list)
+        * then this operation will blow away that symbol.
+        It will therefore be impossible for subsequent
+        * operations to add entries to this un-referenceable list. */
+       if (!syms)
+               return 1;
+       syms->purge_symbol_table(syms, (unsigned)hndl);
+       /* 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;
+                    curr_sect -= 1) {
+                       asecs->name = NULL;
+                       alloc->dload_deallocate(alloc, asecs++);
+               }
+       root = hndl->dm.hroot;
+       if (!root) {
+               /* there is a debug list containing this module */
+               goto func_end;
+       }
+       if (!hndl->dm.dbthis) { /* target-side dllview record exists */
+               goto loop_end;
+       }
+       /* Retrieve memory context in which .dllview was allocated */
+       dllview_info.context = hndl->dm.context;
+       if (hndl->dm.hprev == hndl)
+               goto exitunltgt;
+
+       /* target-side dllview record is in list */
+       /* dequeue this record from our GPP-side mirror list */
+       hndl->dm.hprev->dm.hnext = hndl->dm.hnext;
+       if (hndl->dm.hnext)
+               hndl->dm.hnext->dm.hprev = hndl->dm.hprev;
+       /* Update next_module of previous entry in target list
+        * We are using mhdr here as a surrogate for either a
+        struct modules_header or a dll_module */
+       if (hndl->dm.hnext) {
+               mhdr.first_module = TADDR_TO_TDATA(hndl->dm.hnext->dm.dbthis);
+               mhdr.first_module_size = hndl->dm.hnext->dm.dbsiz;
+       } else {
+               mhdr.first_module = 0;
+               mhdr.first_module_size = 0;
+       }
+       if (!init)
+               goto exitunltgt;
+
+       if (!init->connect(init)) {
+               dload_syms_error(syms, iconnect);
+               errcount += 1;
+               goto exitunltgt;
+       }
+       /* swap bytes in the module header, if needed */
+       if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) {
+               swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
+                          MODULES_HEADER_BITMAP);
+       }
+       if (!init->writemem(init, &mhdr, hndl->dm.hprev->dm.dbthis,
+                           &dllview_info, sizeof(struct modules_header) -
+                           sizeof(mhdr.update_flag))) {
+               dload_syms_error(syms, dlvwrite);
+               errcount += 1;
+       }
+       /* update change counter */
+       root->changes += 1;
+       if (!init->writemem(init, &(root->changes),
+                           root->dbthis + HOST_TO_TADDR
+                           (sizeof(mhdr.first_module) +
+                            sizeof(mhdr.first_module_size)),
+                           &dllview_info, sizeof(mhdr.update_flag))) {
+               dload_syms_error(syms, dlvwrite);
+               errcount += 1;
+       }
+       init->release(init);
+exitunltgt:
+       /* release target storage */
+       dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
+       dllview_info.load_addr = hndl->dm.dbthis;
+       if (alloc)
+               alloc->dload_deallocate(alloc, &dllview_info);
+       root->refcount -= 1;
+       /* target-side dllview record exists */
+loop_end:
+#ifndef DEBUG_HEADER_IN_LOADER
+       if (root->refcount <= 0) {
+               /* if all references gone, blow off the header */
+               /* our root symbol may be gone due to the Purge above,
+                  but if not, do not destroy the root */
+               if (syms->find_matching_symbol
+                   (syms, loader_dllview_root) == NULL)
+                       syms->dload_deallocate(syms, root);
+       }
+#endif
+func_end:
+       /* there is a debug list containing this module */
+       syms->dload_deallocate(syms, mhandle);  /* release our storage */
+       return errcount;
+}                              /* dynamic_unload_module */
+
+#if BITS_PER_AU > BITS_PER_BYTE
+/*************************************************************************
+ * Procedure unpack_name
+ *
+ * Parameters:
+ *     soffset Byte offset into the string table
+ *
+ * Effect:
+ *     Returns a pointer to the string specified by the offset supplied, or
+ * NULL for error.
+ *
+ *********************************************************************** */
+static char *unpack_name(struct dload_state *dlthis, u32 soffset)
+{
+       u8 tmp, *src;
+       char *dst;
+
+       if (soffset >= dlthis->dfile_hdr.df_strtab_size) {
+               dload_error(dlthis, "Bad string table offset " FMT_UI32,
+                           soffset);
+               return NULL;
+       }
+       src = (uint_least8_t *) dlthis->str_head +
+           (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
+       dst = dlthis->str_temp;
+       if (soffset & 1)
+               *dst++ = *src++;        /* only 1 character in first word */
+       do {
+               tmp = *src++;
+               *dst = (tmp >> BITS_PER_BYTE);
+               if (!(*dst++))
+                       break;
+       } while ((*dst++ = tmp & BYTE_MASK));
+       dlthis->temp_len = dst - dlthis->str_temp;
+       /* squirrel away length including terminating null */
+       return dlthis->str_temp;
+}                              /* unpack_name */
+#endif
diff --git a/drivers/staging/tidspbridge/dynload/dload_internal.h b/drivers/staging/tidspbridge/dynload/dload_internal.h
new file mode 100644 (file)
index 0000000..8037561
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * dload_internal.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DLOAD_INTERNAL_
+#define _DLOAD_INTERNAL_
+
+#include <linux/types.h>
+
+/*
+ * Internal state definitions for the dynamic loader
+ */
+
+#define TRUE 1
+#define FALSE 0
+
+/* type used for relocation intermediate results */
+typedef s32 rvalue;
+
+/* unsigned version of same; must have at least as many bits */
+typedef u32 urvalue;
+
+/*
+ * Dynamic loader configuration constants
+ */
+/* error issued if input has more sections than this limit */
+#define REASONABLE_SECTION_LIMIT 100
+
+/* (Addressable unit) value used to clear BSS section */
+#define DLOAD_FILL_BSS 0
+
+/*
+ * Reorder maps explained (?)
+ *
+ * The doff file format defines a 32-bit pattern used to determine the
+ * byte order of an image being read.  That value is
+ * BYTE_RESHUFFLE_VALUE == 0x00010203
+ * For purposes of the reorder routine, we would rather have the all-is-OK
+ * for 32-bits pattern be 0x03020100.  This first macro makes the
+ * translation from doff file header value to MAP value: */
+#define REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303)
+/* This translation is made in dload_headers.  Thereafter, the all-is-OK
+ * value for the maps stored in dlthis is REORDER_MAP(BYTE_RESHUFFLE_VALUE).
+ * But sadly, not all bits of the doff file are 32-bit integers.
+ * The notable exceptions are strings and image bits.
+ * Strings obey host byte order: */
+#if defined(_BIG_ENDIAN)
+#define HOST_BYTE_ORDER(cookedmap) ((cookedmap) ^ 0x3030303)
+#else
+#define HOST_BYTE_ORDER(cookedmap) (cookedmap)
+#endif
+/* Target bits consist of target AUs (could be bytes, or 16-bits,
+ * or 32-bits) stored as an array in host order.  A target order
+ * map is defined by: */
+#if !defined(_BIG_ENDIAN) || TARGET_AU_BITS > 16
+#define TARGET_ORDER(cookedmap) (cookedmap)
+#elif TARGET_AU_BITS > 8
+#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x2020202)
+#else
+#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x3030303)
+#endif
+
+/* forward declaration for handle returned by dynamic loader */
+struct my_handle;
+
+/*
+ * a list of module handles, which mirrors the debug list on the target
+ */
+struct dbg_mirror_root {
+       /* must be same as dbg_mirror_list; __DLModules address on target */
+       u32 dbthis;
+       struct my_handle *hnext;        /* must be same as dbg_mirror_list */
+       u16 changes;            /* change counter */
+       u16 refcount;           /* number of modules referencing this root */
+};
+
+struct dbg_mirror_list {
+       u32 dbthis;
+       struct my_handle *hnext, *hprev;
+       struct dbg_mirror_root *hroot;
+       u16 dbsiz;
+       u32 context;    /* Save context for .dllview memory allocation */
+};
+
+#define VARIABLE_SIZE 1
+/*
+ * the structure we actually return as an opaque module handle
+ */
+struct my_handle {
+       struct dbg_mirror_list dm;      /* !!! must be first !!! */
+       /* sections following << 1, LSB is set for big-endian target */
+       u16 secn_count;
+       struct ldr_section_info secns[VARIABLE_SIZE];
+};
+#define MY_HANDLE_SIZE (sizeof(struct my_handle) -\
+                       sizeof(struct ldr_section_info))
+/* real size of my_handle */
+
+/*
+ * reduced symbol structure used for symbols during relocation
+ */
+struct local_symbol {
+       s32 value;              /* Relocated symbol value */
+       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"
+/* MUST MATCH THE LENGTH ABOVE!! */
+#define TRAMP_SYM_PREFIX_LEN            9
+/* Includes NULL termination */
+#define TRAMP_SYM_HEX_ASCII_LEN         9
+
+#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
+ */
+enum cinit_mode {
+       CI_COUNT = 0,           /* expecting a count */
+       CI_ADDRESS,             /* expecting an address */
+#if CINIT_ALIGN < CINIT_ADDRESS        /* handle case of partial address field */
+       CI_PARTADDRESS,         /* have only part of the address */
+#endif
+       CI_COPY,                /* in the middle of copying data */
+       CI_DONE                 /* end of .cinit table */
+};
+
+/*
+ * The internal state of the dynamic loader, which is passed around as
+ * an object
+ */
+struct dload_state {
+       struct dynamic_loader_stream *strm;     /* The module input stream */
+       struct dynamic_loader_sym *mysym;       /* Symbols for this session */
+       /* target memory allocator */
+       struct dynamic_loader_allocate *myalloc;
+       struct dynamic_loader_initialize *myio; /* target memory initializer */
+       unsigned myoptions;     /* Options parameter dynamic_load_module */
+
+       char *str_head;         /* Pointer to string table */
+#if BITS_PER_AU > BITS_PER_BYTE
+       char *str_temp;         /* Pointer to temporary buffer for strings */
+       /* big enough to hold longest string */
+       unsigned temp_len;      /* length of last temporary string */
+       char *xstrings;         /* Pointer to buffer for expanded */
+       /* strings for sec names */
+#endif
+       /* Total size of strings for DLLView section names */
+       unsigned debug_string_size;
+       /* Pointer to parallel section info for allocated sections only */
+       struct doff_scnhdr_t *sect_hdrs;        /* Pointer to section table */
+       struct ldr_section_info *ldr_sections;
+#if TMS32060
+       /* The address of the start of the .bss section */
+       ldr_addr bss_run_base;
+#endif
+       struct local_symbol *local_symtab;      /* Relocation symbol table */
+
+       /* pointer to DL section info for the section being relocated */
+       struct ldr_section_info *image_secn;
+       /* change in run address for current section during relocation */
+       ldr_addr delta_runaddr;
+       ldr_addr image_offset;  /* offset of current packet in section */
+       enum cinit_mode cinit_state;    /* current state of cload_cinit() */
+       int cinit_count;        /* the current count */
+       ldr_addr cinit_addr;    /* the current address */
+       s16 cinit_page;         /* the current page */
+       /* Handle to be returned by dynamic_load_module */
+       struct my_handle *myhandle;
+       unsigned dload_errcount;        /* Total # of errors reported so far */
+       /* Number of target sections that require allocation and relocation */
+       unsigned allocated_secn_count;
+#ifndef TARGET_ENDIANNESS
+       int big_e_target;       /* Target data in big-endian format */
+#endif
+       /* map for reordering bytes, 0 if not needed */
+       u32 reorder_map;
+       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];
+
+};
+
+#ifdef TARGET_ENDIANNESS
+#define TARGET_BIG_ENDIAN TARGET_ENDIANNESS
+#else
+#define TARGET_BIG_ENDIAN (dlthis->big_e_target)
+#endif
+
+/*
+ * Exports from cload.c to rest of the world
+ */
+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, 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);
+
+#if HOST_ENDIANNESS
+extern uint32_t dload_reverse_checksum(void *data, unsigned siz);
+#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
+extern uint32_t dload_reverse_checksum16(void *data, unsigned siz);
+#endif
+#endif
+
+#define IS_DATA_SCN(zzz) (DLOAD_SECTION_TYPE((zzz)->type) != DLOAD_TEXT)
+#define IS_DATA_SCN_NUM(zzz) \
+               (DLOAD_SECT_TYPE(&dlthis->sect_hdrs[(zzz)-1]) != DLOAD_TEXT)
+
+/*
+ * exported by reloc.c
+ */
+extern void dload_relocate(struct dload_state *dlthis, tgt_au_t * data,
+                          struct reloc_record_t *rp, bool * tramps_generated,
+                          bool second_pass);
+
+extern rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data,
+                          int fieldsz, int offset, unsigned sgn);
+
+extern int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_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/staging/tidspbridge/dynload/doff.h b/drivers/staging/tidspbridge/dynload/doff.h
new file mode 100644 (file)
index 0000000..5bf9924
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * doff.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Structures & definitions used for dynamically loaded modules file format.
+ * This format is a reformatted version of COFF. It optimizes the layout for
+ * the dynamic loader.
+ *
+ * .dof files, when viewed as a sequence of 32-bit integers, look the same
+ * on big-endian and little-endian machines.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DOFF_H
+#define _DOFF_H
+
+#ifndef UINT32_C
+#define UINT32_C(zzz) ((u32)zzz)
+#endif
+
+#define BYTE_RESHUFFLE_VALUE UINT32_C(0x00010203)
+
+/* DOFF file header containing fields categorizing the remainder of the file */
+struct doff_filehdr_t {
+
+       /* string table size, including filename, in bytes */
+       u32 df_strtab_size;
+
+       /* entry point if one exists */
+       u32 df_entrypt;
+
+       /* identifies byte ordering of file;
+        * always set to BYTE_RESHUFFLE_VALUE */
+       u32 df_byte_reshuffle;
+
+       /* Size of the string table up to and including the last section name */
+       /* Size includes the name of the COFF file also */
+       u32 df_scn_name_size;
+
+#ifndef _BIG_ENDIAN
+       /* number of symbols */
+       u16 df_no_syms;
+
+       /* length in bytes of the longest string, including terminating NULL */
+       /* excludes the name of the file */
+       u16 df_max_str_len;
+
+       /* total number of sections including no-load ones */
+       u16 df_no_scns;
+
+       /* number of sections containing target code allocated or downloaded */
+       u16 df_target_scns;
+
+       /* unique id for dll file format & version */
+       u16 df_doff_version;
+
+       /* identifies ISA */
+       u16 df_target_id;
+
+       /* useful file flags */
+       u16 df_flags;
+
+       /* section reference for entry point, N_UNDEF for none, */
+       /* N_ABS for absolute address */
+       s16 df_entry_secn;
+#else
+       /* length of the longest string, including terminating NULL */
+       u16 df_max_str_len;
+
+       /* number of symbols */
+       u16 df_no_syms;
+
+       /* number of sections containing target code allocated or downloaded */
+       u16 df_target_scns;
+
+       /* total number of sections including no-load ones */
+       u16 df_no_scns;
+
+       /* identifies ISA */
+       u16 df_target_id;
+
+       /* unique id for dll file format & version */
+       u16 df_doff_version;
+
+       /* section reference for entry point, N_UNDEF for none, */
+       /* N_ABS for absolute address */
+       s16 df_entry_secn;
+
+       /* useful file flags */
+       u16 df_flags;
+#endif
+       /* checksum for file header record */
+       u32 df_checksum;
+
+};
+
+/* flags in the df_flags field */
+#define  DF_LITTLE   0x100
+#define  DF_BIG      0x200
+#define  DF_BYTE_ORDER (DF_LITTLE | DF_BIG)
+
+/* Supported processors */
+#define TMS470_ID   0x97
+#define LEAD_ID     0x98
+#define TMS32060_ID 0x99
+#define LEAD3_ID    0x9c
+
+/* Primary processor for loading */
+#if TMS32060
+#define TARGET_ID   TMS32060_ID
+#endif
+
+/* Verification record containing values used to test integrity of the bits */
+struct doff_verify_rec_t {
+
+       /* time and date stamp */
+       u32 dv_timdat;
+
+       /* checksum for all section records */
+       u32 dv_scn_rec_checksum;
+
+       /* checksum for string table */
+       u32 dv_str_tab_checksum;
+
+       /* checksum for symbol table */
+       u32 dv_sym_tab_checksum;
+
+       /* checksum for verification record */
+       u32 dv_verify_rec_checksum;
+
+};
+
+/* String table is an array of null-terminated strings.  The first entry is
+ * the filename, which is added by DLLcreate.  No new structure definitions
+ * are required.
+ */
+
+/* Section Records including information on the corresponding image packets */
+/*
+ *      !!WARNING!!
+ *
+ * This structure is expected to match in form ldr_section_info in
+ * dynamic_loader.h
+ */
+
+struct doff_scnhdr_t {
+
+       s32 ds_offset;          /* offset into string table of name */
+       s32 ds_paddr;           /* RUN address, in target AU */
+       s32 ds_vaddr;           /* LOAD address, in target AU */
+       s32 ds_size;            /* section size, in target AU */
+#ifndef _BIG_ENDIAN
+       u16 ds_page;            /* memory page id */
+       u16 ds_flags;           /* section flags */
+#else
+       u16 ds_flags;           /* section flags */
+       u16 ds_page;            /* memory page id */
+#endif
+       u32 ds_first_pkt_offset;
+       /* Absolute byte offset into the file */
+       /* where the first image record resides */
+
+       s32 ds_nipacks;         /* number of image packets */
+
+};
+
+/* Symbol table entry */
+struct doff_syment_t {
+
+       s32 dn_offset;          /* offset into string table of name */
+       s32 dn_value;           /* value of symbol */
+#ifndef _BIG_ENDIAN
+       s16 dn_scnum;           /* section number */
+       s16 dn_sclass;          /* storage class */
+#else
+       s16 dn_sclass;          /* storage class */
+       s16 dn_scnum;           /* section number, 1-based */
+#endif
+
+};
+
+/* special values for dn_scnum */
+#define  DN_UNDEF  0           /* undefined symbol */
+#define  DN_ABS    (-1)                /* value of symbol is absolute */
+/* special values for dn_sclass */
+#define DN_EXT     2
+#define DN_STATLAB 20
+#define DN_EXTLAB  21
+
+/* Default value of image bits in packet */
+/* Configurable by user on the command line */
+#define IMAGE_PACKET_SIZE 1024
+
+/* An image packet contains a chunk of data from a section along with */
+/* information necessary for its processing. */
+struct image_packet_t {
+
+       s32 num_relocs;         /* number of relocations for */
+       /* this packet */
+
+       s32 packet_size;        /* number of bytes in array */
+       /* "bits" occupied  by */
+       /* valid data.  Could be */
+       /* < IMAGE_PACKET_SIZE to */
+       /* prevent splitting a */
+       /* relocation across packets. */
+       /* Last packet of a section */
+       /* will most likely contain */
+       /* < IMAGE_PACKET_SIZE bytes */
+       /* of valid data */
+
+       s32 img_chksum;         /* Checksum for image packet */
+       /* and the corresponding */
+       /* relocation records */
+
+       u8 *img_data;           /* Actual data in section */
+
+};
+
+/* The relocation structure definition matches the COFF version.  Offsets */
+/* however are relative to the image packet base not the section base. */
+struct reloc_record_t {
+
+       s32 vaddr;
+
+       /* expressed in target AUs */
+
+       union {
+               struct {
+#ifndef _BIG_ENDIAN
+                       u8 _offset;     /* bit offset of rel fld */
+                       u8 _fieldsz;    /* size of rel fld */
+                       u8 _wordsz;     /* # bytes containing rel fld */
+                       u8 _dum1;
+                       u16 _dum2;
+                       u16 _type;
+#else
+                       unsigned _dum1:8;
+                       unsigned _wordsz:8;     /* # bytes containing rel fld */
+                       unsigned _fieldsz:8;    /* size of rel fld */
+                       unsigned _offset:8;     /* bit offset of rel fld */
+                       u16 _type;
+                       u16 _dum2;
+#endif
+               } _r_field;
+
+               struct {
+                       u32 _spc;       /* image packet relative PC */
+#ifndef _BIG_ENDIAN
+                       u16 _dum;
+                       u16 _type;      /* relocation type */
+#else
+                       u16 _type;      /* relocation type */
+                       u16 _dum;
+#endif
+               } _r_spc;
+
+               struct {
+                       u32 _uval;      /* constant value */
+#ifndef _BIG_ENDIAN
+                       u16 _dum;
+                       u16 _type;      /* relocation type */
+#else
+                       u16 _type;      /* relocation type */
+                       u16 _dum;
+#endif
+               } _r_uval;
+
+               struct {
+                       s32 _symndx;    /* 32-bit sym tbl index */
+#ifndef _BIG_ENDIAN
+                       u16 _disp;      /* extra addr encode data */
+                       u16 _type;      /* relocation type */
+#else
+                       u16 _type;      /* relocation type */
+                       u16 _disp;      /* extra addr encode data */
+#endif
+               } _r_sym;
+       } _u_reloc;
+
+};
+
+/* abbreviations for convenience */
+#ifndef TYPE
+#define TYPE      _u_reloc._r_sym._type
+#define UVAL      _u_reloc._r_uval._uval
+#define SYMNDX    _u_reloc._r_sym._symndx
+#define OFFSET    _u_reloc._r_field._offset
+#define FIELDSZ   _u_reloc._r_field._fieldsz
+#define WORDSZ    _u_reloc._r_field._wordsz
+#define R_DISP      _u_reloc._r_sym._disp
+#endif
+
+/**************************************************************************** */
+/* */
+/* Important DOFF macros used for file processing */
+/* */
+/**************************************************************************** */
+
+/* DOFF Versions */
+#define         DOFF0                       0
+
+/* Return the address/size >= to addr that is at a 32-bit boundary */
+/* This assumes that a byte is 8 bits */
+#define         DOFF_ALIGN(addr)            (((addr) + 3) & ~UINT32_C(3))
+
+/**************************************************************************** */
+/* */
+/* The DOFF section header flags field is laid out as follows: */
+/* */
+/*  Bits 0-3 : Section Type */
+/*  Bit    4 : Set when section requires target memory to be allocated by DL */
+/*  Bit    5 : Set when section requires downloading */
+/*  Bits 8-11: Alignment, same as COFF */
+/* */
+/**************************************************************************** */
+
+/* Enum for DOFF section types (bits 0-3 of flag): See dynamic_loader.h */
+
+/* Macros to help processing of sections */
+#define DLOAD_SECT_TYPE(s_hdr)      ((s_hdr)->ds_flags & 0xF)
+
+/* DS_ALLOCATE indicates whether a section needs space on the target */
+#define DS_ALLOCATE_MASK            0x10
+#define DS_NEEDS_ALLOCATION(s_hdr)  ((s_hdr)->ds_flags & DS_ALLOCATE_MASK)
+
+/* DS_DOWNLOAD indicates that the loader needs to copy bits */
+#define DS_DOWNLOAD_MASK            0x20
+#define DS_NEEDS_DOWNLOAD(s_hdr)    ((s_hdr)->ds_flags & DS_DOWNLOAD_MASK)
+
+/* Section alignment requirement in AUs */
+#define DS_ALIGNMENT(ds_flags) (1 << (((ds_flags) >> 8) & 0xF))
+
+#endif /* _DOFF_H */
diff --git a/drivers/staging/tidspbridge/dynload/getsection.c b/drivers/staging/tidspbridge/dynload/getsection.c
new file mode 100644 (file)
index 0000000..029898f
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * getsection.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <dspbridge/getsection.h>
+#include "header.h"
+
+/*
+ * Error strings
+ */
+static const char readstrm[] = { "Error reading %s from input stream" };
+static const char seek[] = { "Set file position to %d failed" };
+static const char isiz[] = { "Bad image packet size %d" };
+static const char err_checksum[] = { "Checksum failed on %s" };
+
+static const char err_reloc[] = { "dload_get_section unable to read"
+           "sections containing relocation entries"
+};
+
+#if BITS_PER_AU > BITS_PER_BYTE
+static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
+static const char stbl[] = { "Bad string table offset " FMT_UI32 };
+#endif
+
+/*
+ * we use the fact that DOFF section records are shaped just like
+ * ldr_section_info to reduce our section storage usage.  These macros
+ * marks the places where that assumption is made
+ */
+#define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct ldr_section_info *)(pdoffsec))
+#define LDRSEC_IS_DOFFSEC(ldrsec) ((struct doff_scnhdr_t *)(ldrsec))
+
+/************************************************************** */
+/********************* SUPPORT FUNCTIONS ********************** */
+/************************************************************** */
+
+#if BITS_PER_AU > BITS_PER_BYTE
+/**************************************************************************
+ * Procedure unpack_sec_name
+ *
+ * Parameters:
+ *  dlthis             Handle from dload_module_open for this module
+ *     soffset     Byte offset into the string table
+ *  dst         Place to store the expanded string
+ *
+ * Effect:
+ *     Stores a string from the string table into the destination, expanding
+ * it in the process.  Returns a pointer just past the end of the stored
+ * string on success, or NULL on failure.
+ *
+ ************************************************************************ */
+static char *unpack_sec_name(struct dload_state *dlthis, u32 soffset, char *dst)
+{
+       u8 tmp, *src;
+
+       if (soffset >= dlthis->dfile_hdr.df_scn_name_size) {
+               dload_error(dlthis, stbl, soffset);
+               return NULL;
+       }
+       src = (u8 *) dlthis->str_head +
+           (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
+       if (soffset & 1)
+               *dst++ = *src++;        /* only 1 character in first word */
+       do {
+               tmp = *src++;
+               *dst = (tmp >> BITS_PER_BYTE)
+                   if (!(*dst++))
+                       break;
+       } while ((*dst++ = tmp & BYTE_MASK));
+
+       return dst;
+}
+
+/**************************************************************************
+ * Procedure expand_sec_names
+ *
+ * Parameters:
+ *  dlthis             Handle from dload_module_open for this module
+ *
+ * Effect:
+ *    Allocates a buffer, unpacks and copies strings from string table into it.
+ * Stores a pointer to the buffer into a state variable.
+ ************************************************************************* */
+static void expand_sec_names(struct dload_state *dlthis)
+{
+       char *xstrings, *curr, *next;
+       u32 xsize;
+       u16 sec;
+       struct ldr_section_info *shp;
+       /* assume worst-case size requirement */
+       xsize = dlthis->dfile_hdr.df_max_str_len * dlthis->dfile_hdr.df_no_scns;
+       xstrings = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, xsize);
+       if (xstrings == NULL) {
+               dload_error(dlthis, err_alloc, xsize);
+               return;
+       }
+       dlthis->xstrings = xstrings;
+       /* For each sec, copy and expand its name */
+       curr = xstrings;
+       for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+               shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]);
+               next = unpack_sec_name(dlthis, *(u32 *) &shp->name, curr);
+               if (next == NULL)
+                       break;  /* error */
+               shp->name = curr;
+               curr = next;
+       }
+}
+
+#endif
+
+/************************************************************** */
+/********************* EXPORTED FUNCTIONS ********************* */
+/************************************************************** */
+
+/**************************************************************************
+ * Procedure dload_module_open
+ *
+ * Parameters:
+ *     module  The input stream that supplies the module image
+ *     syms    Host-side malloc/free and error reporting functions.
+ *                     Other methods are unused.
+ *
+ * Effect:
+ *     Reads header information from a dynamic loader module using the
+    specified
+ * stream object, and returns a handle for the module information.  This
+ * handle may be used in subsequent query calls to obtain information
+ * contained in the module.
+ *
+ * Returns:
+ *     NULL if an error is encountered, otherwise a module handle for use
+ * in subsequent operations.
+ ************************************************************************* */
+void *dload_module_open(struct dynamic_loader_stream *module,
+                                   struct dynamic_loader_sym *syms)
+{
+       struct dload_state *dlthis;     /* internal state for this call */
+       unsigned *dp, sz;
+       u32 sec_start;
+#if BITS_PER_AU <= BITS_PER_BYTE
+       u16 sec;
+#endif
+
+       /* Check that mandatory arguments are present */
+       if (!module || !syms) {
+               if (syms != NULL)
+                       dload_syms_error(syms, "Required parameter is NULL");
+
+               return NULL;
+       }
+
+       dlthis = (struct dload_state *)
+           syms->dload_allocate(syms, sizeof(struct dload_state));
+       if (!dlthis) {
+               /* not enough storage */
+               dload_syms_error(syms, "Can't allocate module info");
+               return NULL;
+       }
+
+       /* clear our internal state */
+       dp = (unsigned *)dlthis;
+       for (sz = sizeof(struct dload_state) / sizeof(unsigned);
+            sz > 0; sz -= 1)
+               *dp++ = 0;
+
+       dlthis->strm = module;
+       dlthis->mysym = syms;
+
+       /* read in the doff image and store in our state variable */
+       dload_headers(dlthis);
+
+       if (!dlthis->dload_errcount)
+               dload_strings(dlthis, true);
+
+       /* skip ahead past the unread portion of the string table */
+       sec_start = sizeof(struct doff_filehdr_t) +
+           sizeof(struct doff_verify_rec_t) +
+           BYTE_TO_HOST(DOFF_ALIGN(dlthis->dfile_hdr.df_strtab_size));
+
+       if (dlthis->strm->set_file_posn(dlthis->strm, sec_start) != 0) {
+               dload_error(dlthis, seek, sec_start);
+               return NULL;
+       }
+
+       if (!dlthis->dload_errcount)
+               dload_sections(dlthis);
+
+       if (dlthis->dload_errcount) {
+               dload_module_close(dlthis);     /* errors, blow off our state */
+               dlthis = NULL;
+               return NULL;
+       }
+#if BITS_PER_AU > BITS_PER_BYTE
+       /* Expand all section names from the string table into the */
+       /* state variable, and convert section names from a relative */
+       /* string table offset to a pointers to the expanded string. */
+       expand_sec_names(dlthis);
+#else
+       /* Convert section names from a relative string table offset */
+       /* to a pointer into the string table. */
+       for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+               struct ldr_section_info *shp =
+                   DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]);
+               shp->name = dlthis->str_head + *(u32 *) &shp->name;
+       }
+#endif
+
+       return dlthis;
+}
+
+/***************************************************************************
+ * Procedure dload_get_section_info
+ *
+ * Parameters:
+ *  minfo              Handle from dload_module_open for this module
+ *     sectionName     Pointer to the string name of the section desired
+ *     sectionInfo     Address of a section info structure pointer to be
+ *                     initialized
+ *
+ * Effect:
+ *     Finds the specified section in the module information, and initializes
+ * the provided struct ldr_section_info pointer.
+ *
+ * Returns:
+ *     true for success, false for section not found
+ ************************************************************************* */
+int dload_get_section_info(void *minfo, const char *sectionName,
+                          const struct ldr_section_info **const sectionInfo)
+{
+       struct dload_state *dlthis;
+       struct ldr_section_info *shp;
+       u16 sec;
+
+       dlthis = (struct dload_state *)minfo;
+       if (!dlthis)
+               return false;
+
+       for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+               shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]);
+               if (strcmp(sectionName, shp->name) == 0) {
+                       *sectionInfo = shp;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
+#define REVERSE_REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303)
+
+/**************************************************************************
+ * Procedure dload_get_section
+ *
+ * Parameters:
+ *  minfo              Handle from dload_module_open for this module
+ *     sectionInfo     Pointer to a section info structure for the desired
+ *                     section
+ *     sectionData     Buffer to contain the section initialized data
+ *
+ * Effect:
+ *     Copies the initialized data for the specified section into the
+ * supplied buffer.
+ *
+ * Returns:
+ *     true for success, false for section not found
+ ************************************************************************* */
+int dload_get_section(void *minfo,
+                     const struct ldr_section_info *sectionInfo,
+                     void *sectionData)
+{
+       struct dload_state *dlthis;
+       u32 pos;
+       struct doff_scnhdr_t *sptr = NULL;
+       s32 nip;
+       struct image_packet_t ipacket;
+       s32 ipsize;
+       u32 checks;
+       s8 *dest = (s8 *) sectionData;
+
+       dlthis = (struct dload_state *)minfo;
+       if (!dlthis)
+               return false;
+       sptr = LDRSEC_IS_DOFFSEC(sectionInfo);
+       if (sptr == NULL)
+               return false;
+
+       /* skip ahead to the start of the first packet */
+       pos = BYTE_TO_HOST(DOFF_ALIGN((u32) sptr->ds_first_pkt_offset));
+       if (dlthis->strm->set_file_posn(dlthis->strm, pos) != 0) {
+               dload_error(dlthis, seek, pos);
+               return false;
+       }
+
+       nip = sptr->ds_nipacks;
+       while ((nip -= 1) >= 0) {       /* for each packet */
+               /* get the fixed header bits */
+               if (dlthis->strm->read_buffer(dlthis->strm, &ipacket,
+                                             IPH_SIZE) != IPH_SIZE) {
+                       dload_error(dlthis, readstrm, "image packet");
+                       return false;
+               }
+               /* reorder the header if need be */
+               if (dlthis->reorder_map)
+                       dload_reorder(&ipacket, IPH_SIZE, dlthis->reorder_map);
+
+               /* Now read the packet image bits. Note: round the size up to
+                * the next multiple of 4 bytes; this is what checksum
+                * routines want. */
+               ipsize = BYTE_TO_HOST(DOFF_ALIGN(ipacket.packet_size));
+               if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
+                       dload_error(dlthis, isiz, ipsize);
+                       return false;
+               }
+               if (dlthis->strm->read_buffer
+                   (dlthis->strm, dest, ipsize) != ipsize) {
+                       dload_error(dlthis, readstrm, "image packet");
+                       return false;
+               }
+               /* reorder the bytes if need be */
+#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
+               if (dlthis->reorder_map)
+                       dload_reorder(dest, ipsize, dlthis->reorder_map);
+
+               checks = dload_checksum(dest, ipsize);
+#else
+               if (dlthis->dfile_hdr.df_byte_reshuffle !=
+                   TARGET_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
+                       /* put image bytes in big-endian order, not PC order */
+                       dload_reorder(dest, ipsize,
+                                     TARGET_ORDER(dlthis->
+                                               dfile_hdr.df_byte_reshuffle));
+               }
+#if TARGET_AU_BITS > 8
+               checks = dload_reverse_checksum16(dest, ipsize);
+#else
+               checks = dload_reverse_checksum(dest, ipsize);
+#endif
+#endif
+               checks += dload_checksum(&ipacket, IPH_SIZE);
+
+               /* NYI: unable to handle relocation entries here.  Reloc
+                * entries referring to fields that span the packet boundaries
+                * may result in packets of sizes that are not multiple of
+                * 4 bytes. Our checksum implementation works on 32-bit words
+                * only. */
+               if (ipacket.num_relocs != 0) {
+                       dload_error(dlthis, err_reloc, ipsize);
+                       return false;
+               }
+
+               if (~checks) {
+                       dload_error(dlthis, err_checksum, "image packet");
+                       return false;
+               }
+
+               /*Advance destination ptr by the size of the just-read packet */
+               dest += ipsize;
+       }
+
+       return true;
+}
+
+/***************************************************************************
+ * Procedure dload_module_close
+ *
+ * Parameters:
+ *  minfo              Handle from dload_module_open for this module
+ *
+ * Effect:
+ *     Releases any storage associated with the module handle.  On return,
+ * the module handle is invalid.
+ *
+ * Returns:
+ *     Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report(), where syms was
+ * an argument to dload_module_open
+ ************************************************************************* */
+void dload_module_close(void *minfo)
+{
+       struct dload_state *dlthis;
+
+       dlthis = (struct dload_state *)minfo;
+       if (!dlthis)
+               return;
+
+       if (dlthis->str_head)
+               dlthis->mysym->dload_deallocate(dlthis->mysym,
+                                               dlthis->str_head);
+
+       if (dlthis->sect_hdrs)
+               dlthis->mysym->dload_deallocate(dlthis->mysym,
+                                               dlthis->sect_hdrs);
+
+#if BITS_PER_AU > BITS_PER_BYTE
+       if (dlthis->xstrings)
+               dlthis->mysym->dload_deallocate(dlthis->mysym,
+                                               dlthis->xstrings);
+
+#endif
+
+       dlthis->mysym->dload_deallocate(dlthis->mysym, dlthis);
+}
diff --git a/drivers/staging/tidspbridge/dynload/header.h b/drivers/staging/tidspbridge/dynload/header.h
new file mode 100644 (file)
index 0000000..5cef360
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * header.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define TRUE 1
+#define FALSE 0
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include <linux/string.h>
+#define DL_STRCMP  strcmp
+
+/* maximum parenthesis nesting in relocation stack expressions */
+#define STATIC_EXPR_STK_SIZE 10
+
+#include <linux/types.h>
+
+#include "doff.h"
+#include <dspbridge/dynamic_loader.h>
+#include "params.h"
+#include "dload_internal.h"
+#include "reloc_table.h"
+
+/*
+ * Plausibility limits
+ *
+ * These limits are imposed upon the input DOFF file as a check for validity.
+ * They are hard limits, in that the load will fail if they are exceeded.
+ * The numbers selected are arbitrary, in that the loader implementation does
+ * not require these limits.
+ */
+
+/* maximum number of bytes in string table */
+#define MAX_REASONABLE_STRINGTAB (0x100000)
+/* maximum number of code,data,etc. sections */
+#define MAX_REASONABLE_SECTIONS (200)
+/* maximum number of linker symbols */
+#define MAX_REASONABLE_SYMBOLS (100000)
+
+/* shift count to align F_BIG with DLOAD_LITTLE */
+#define ALIGN_COFF_ENDIANNESS 7
+#define ENDIANNESS_MASK (DF_BYTE_ORDER >> ALIGN_COFF_ENDIANNESS)
diff --git a/drivers/staging/tidspbridge/dynload/module_list.h b/drivers/staging/tidspbridge/dynload/module_list.h
new file mode 100644 (file)
index 0000000..a216bb1
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * dspbridge/mpu_driver/src/dynload/module_list.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This C header file gives the layout of the data structure created by the
+ * dynamic loader to describe the set of modules loaded into the DSP.
+ *
+ * Linked List Structure:
+ * ----------------------
+ * The data structure defined here is a singly-linked list.  The list
+ * represents the set of modules which are currently loaded in the DSP memory.
+ * The first entry in the list is a header record which contains a flag
+ * representing the state of the list.  The rest of the entries in the list
+ * are module records.
+ *
+ * Global symbol  _DLModules designates the first record in the list (i.e. the
+ * header record).  This symbol must be defined in any program that wishes to
+ * use DLLview plug-in.
+ *
+ * String Representation:
+ * ----------------------
+ * The string names of the module and its sections are stored in a block of
+ * memory which follows the module record itself.  The strings are ordered:
+ * module name first, followed by section names in order from the first
+ * section to the last.  String names are tightly packed arrays of 8-bit
+ * characters (two characters per 16-bit word on the C55x).  Strings are
+ * zero-byte-terminated.
+ *
+ * Creating and updating the list:
+ * -------------------------------
+ * Upon loading a new module into the DSP memory the dynamic loader inserts a
+ * new module record as the first module record in the list.  The fields of
+ * this module record are initialized to reflect the properties of the module.
+ * The dynamic loader does NOT increment the flag/counter in the list's header
+ * record.
+ *
+ * Upon unloading a module from the DSP memory the dynamic loader removes the
+ * module's record from this list.  The dynamic loader also increments the
+ * flag/counter in the list's header record to indicate that the list has been
+ * changed.
+ */
+
+#ifndef _MODULE_LIST_H_
+#define _MODULE_LIST_H_
+
+#include <linux/types.h>
+
+/* Global pointer to the modules_header structure */
+#define MODULES_HEADER "_DLModules"
+#define MODULES_HEADER_NO_UNDERSCORE "DLModules"
+
+/* Initial version number */
+#define INIT_VERSION 1
+
+/* Verification number -- to be recorded in each module record */
+#define VERIFICATION 0x79
+
+/* forward declarations */
+struct dll_module;
+struct dll_sect;
+
+/* the first entry in the list is the modules_header record;
+ * its address is contained in the global _DLModules pointer */
+struct modules_header {
+
+       /*
+        * Address of the first dll_module record in the list or NULL.
+        * Note: for C55x this is a word address (C55x data is
+        * word-addressable)
+        */
+       u32 first_module;
+
+       /* Combined storage size (in target addressable units) of the
+        * dll_module record which follows this header record, or zero
+        * if the list is empty.  This size includes the module's string table.
+        * Note: for C55x the unit is a 16-bit word */
+       u16 first_module_size;
+
+       /* Counter is incremented whenever a module record is removed from
+        * the list */
+       u16 update_flag;
+
+};
+
+/* for each 32-bits in above structure, a bitmap, LSB first, whose bits are:
+ * 0 => a 32-bit value, 1 => 2 16-bit values */
+/* swapping bitmap for type modules_header */
+#define MODULES_HEADER_BITMAP 0x2
+
+/* information recorded about each section in a module */
+struct dll_sect {
+
+       /* Load-time address of the section.
+        * Note: for C55x this is a byte address for program sections, and
+        * a word address for data sections.  C55x program memory is
+        * byte-addressable, while data memory is word-addressable. */
+       u32 sect_load_adr;
+
+       /* Run-time address of the section.
+        * Note 1: for C55x this is a byte address for program sections, and
+        * a word address for data sections.
+        * Note 2: for C55x two most significant bits of this field indicate
+        * the section type: '00' for a code section, '11' for a data section
+        * (C55 addresses are really only 24-bits wide). */
+       u32 sect_run_adr;
+
+};
+
+/* the rest of the entries in the list are module records */
+struct dll_module {
+
+       /* Address of the next dll_module record in the list, or 0 if this is
+        * the last record in the list.
+        * Note: for C55x this is a word address (C55x data is
+        * word-addressable) */
+       u32 next_module;
+
+       /* Combined storage size (in target addressable units) of the
+        * dll_module record which follows this one, or zero if this is the
+        * last record in the list.  This size includes the module's string
+        * table.
+        * Note: for C55x the unit is a 16-bit word. */
+       u16 next_module_size;
+
+       /* version number of the tooling; set to INIT_VERSION for Phase 1 */
+       u16 version;
+
+       /* the verification word; set to VERIFICATION */
+       u16 verification;
+
+       /* Number of sections in the sects array */
+       u16 num_sects;
+
+       /* Module's "unique" id; copy of the timestamp from the host
+        * COFF file */
+       u32 timestamp;
+
+       /* Array of num_sects elements of the module's section records */
+       struct dll_sect sects[1];
+};
+
+/* for each 32 bits in above structure, a bitmap, LSB first, whose bits are:
+ * 0 => a 32-bit value, 1 => 2 16-bit values */
+#define DLL_MODULE_BITMAP 0x6  /* swapping bitmap for type dll_module */
+
+#endif /* _MODULE_LIST_H_ */
diff --git a/drivers/staging/tidspbridge/dynload/params.h b/drivers/staging/tidspbridge/dynload/params.h
new file mode 100644 (file)
index 0000000..d797fcd
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * params.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file defines host and target properties for all machines
+ * supported by the dynamic loader.  To be tedious...
+ *
+ * host: the machine on which the dynamic loader runs
+ * target: the machine that the dynamic loader is loading
+ *
+ * Host and target may or may not be the same, depending upon the particular
+ * use.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/******************************************************************************
+ *
+ *                                                     Host Properties
+ *
+ **************************************************************************** */
+
+#define BITS_PER_BYTE 8                /* bits in the standard PC/SUN byte */
+#define LOG_BITS_PER_BYTE 3    /* log base 2 of same */
+#define BYTE_MASK ((1U<<BITS_PER_BYTE)-1)
+
+#if defined(__TMS320C55X__) || defined(_TMS320C5XX)
+#define BITS_PER_AU 16
+#define LOG_BITS_PER_AU 4
+ /* use this print string in error messages for uint32_t */
+#define FMT_UI32 "0x%lx"
+#define FMT8_UI32 "%08lx"      /* same but no 0x, fixed width field */
+#else
+/* bits in the smallest addressable data storage unit */
+#define BITS_PER_AU 8
+/* log base 2 of the same; useful for shift counts */
+#define LOG_BITS_PER_AU 3
+#define FMT_UI32 "0x%x"
+#define FMT8_UI32 "%08x"
+#endif
+
+/* generic fastest method for swapping bytes and shorts */
+#define SWAP32BY16(zz) (((zz) << 16) | ((zz) >> 16))
+#define SWAP16BY8(zz) (((zz) << 8) | ((zz) >> 8))
+
+/* !! don't be tempted to insert type definitions here; use <stdint.h> !! */
+
+/******************************************************************************
+ *
+ *                                                     Target Properties
+ *
+ **************************************************************************** */
+
+/*-------------------------------------------------------------------------- */
+/* TMS320C6x Target Specific Parameters (byte-addressable) */
+/*-------------------------------------------------------------------------- */
+#if TMS32060
+#define MEMORG          0x0L   /* Size of configured memory */
+#define MEMSIZE         0x0L   /* (full address space) */
+
+#define CINIT_ALIGN     8      /* alignment of cinit record in TDATA AUs */
+#define CINIT_COUNT    4       /* width of count field in TDATA AUs */
+#define CINIT_ADDRESS  4       /* width of address field in TDATA AUs */
+#define CINIT_PAGE_BITS        0       /* Number of LSBs of address that
+                                * are page number */
+
+#define LENIENT_SIGNED_RELEXPS 0       /* DOES SIGNED ALLOW MAX UNSIGNED */
+
+#undef TARGET_ENDIANNESS       /* may be big or little endian */
+
+/* align a target address to a word boundary */
+#define TARGET_WORD_ALIGN(zz) (((zz) + 0x3) & -0x4)
+#endif
+
+/*--------------------------------------------------------------------------
+ *
+ *                     DEFAULT SETTINGS and DERIVED PROPERTIES
+ *
+ * This section establishes defaults for values not specified above
+ *-------------------------------------------------------------------------- */
+#ifndef TARGET_AU_BITS
+#define TARGET_AU_BITS 8       /* width of the target addressable unit */
+#define LOG_TARGET_AU_BITS 3   /* log2 of same */
+#endif
+
+#ifndef CINIT_DEFAULT_PAGE
+#define CINIT_DEFAULT_PAGE 0   /* default .cinit page number */
+#endif
+
+#ifndef DATA_RUN2LOAD
+#define DATA_RUN2LOAD(zz) (zz) /* translate data run address to load address */
+#endif
+
+#ifndef DBG_LIST_PAGE
+#define DBG_LIST_PAGE 0                /* page number for .dllview section */
+#endif
+
+#ifndef TARGET_WORD_ALIGN
+/* align a target address to a word boundary */
+#define TARGET_WORD_ALIGN(zz) (zz)
+#endif
+
+#ifndef TDATA_TO_TADDR
+#define TDATA_TO_TADDR(zz) (zz)        /* target data address to target AU address */
+#define TADDR_TO_TDATA(zz) (zz)        /* target AU address to target data address */
+#define TDATA_AU_BITS  TARGET_AU_BITS  /* bits per data AU */
+#define LOG_TDATA_AU_BITS      LOG_TARGET_AU_BITS
+#endif
+
+/*
+ *
+ * Useful properties and conversions derived from the above
+ *
+ */
+
+/*
+ * Conversions between host and target addresses
+ */
+#if LOG_BITS_PER_AU == LOG_TARGET_AU_BITS
+/* translate target addressable unit to host address */
+#define TADDR_TO_HOST(x) (x)
+/* translate host address to target addressable unit */
+#define HOST_TO_TADDR(x) (x)
+#elif LOG_BITS_PER_AU > LOG_TARGET_AU_BITS
+#define TADDR_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS))
+#define HOST_TO_TADDR(x) ((x) << (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS))
+#else
+#define TADDR_TO_HOST(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU))
+#endif
+
+#if LOG_BITS_PER_AU == LOG_TDATA_AU_BITS
+/* translate target addressable unit to host address */
+#define TDATA_TO_HOST(x) (x)
+/* translate host address to target addressable unit */
+#define HOST_TO_TDATA(x) (x)
+/* translate host address to target addressable unit, round up */
+#define HOST_TO_TDATA_ROUND(x) (x)
+/* byte offset to host offset, rounded up for TDATA size */
+#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x)
+#elif LOG_BITS_PER_AU > LOG_TDATA_AU_BITS
+#define TDATA_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define HOST_TO_TDATA(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define HOST_TO_TDATA_ROUND(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x)
+#else
+#define TDATA_TO_HOST(x) ((x) << (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TDATA(x) ((x) >> (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TDATA_ROUND(x) (((x) +\
+                               (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))-1) >>\
+                               (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define BYTE_TO_HOST_TDATA_ROUND(x) (BYTE_TO_HOST((x) +\
+       (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_BYTE))-1) &\
+       -(TDATA_AU_BITS/BITS_PER_AU))
+#endif
+
+/*
+ * Input in DOFF format is always expresed in bytes, regardless of loading host
+ * so we wind up converting from bytes to target and host units even when the
+ * host is not a byte machine.
+ */
+#if LOG_BITS_PER_AU == LOG_BITS_PER_BYTE
+#define BYTE_TO_HOST(x) (x)
+#define BYTE_TO_HOST_ROUND(x) (x)
+#define HOST_TO_BYTE(x) (x)
+#elif LOG_BITS_PER_AU >= LOG_BITS_PER_BYTE
+#define BYTE_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#define BYTE_TO_HOST_ROUND(x) ((x + (BITS_PER_AU/BITS_PER_BYTE-1)) >>\
+                             (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#define HOST_TO_BYTE(x) ((x) << (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#else
+/* lets not try to deal with sub-8-bit byte machines */
+#endif
+
+#if LOG_TARGET_AU_BITS == LOG_BITS_PER_BYTE
+/* translate target addressable unit to byte address */
+#define TADDR_TO_BYTE(x) (x)
+/* translate byte address to target addressable unit */
+#define BYTE_TO_TADDR(x) (x)
+#elif LOG_TARGET_AU_BITS > LOG_BITS_PER_BYTE
+#define TADDR_TO_BYTE(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE))
+#define BYTE_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE))
+#else
+/* lets not try to deal with sub-8-bit byte machines */
+#endif
+
+#ifdef _BIG_ENDIAN
+#define HOST_ENDIANNESS 1
+#else
+#define HOST_ENDIANNESS 0
+#endif
+
+#ifdef TARGET_ENDIANNESS
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (HOST_ENDIANNESS^TARGET_ENDIANNESS)
+#elif HOST_ENDIANNESS
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (!(rtend))
+#else
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (rtend)
+#endif
+
+/* the unit in which we process target image data */
+#if TARGET_AU_BITS <= 8
+typedef u8 tgt_au_t;
+#elif TARGET_AU_BITS <= 16
+typedef u16 tgt_au_t;
+#else
+typedef u32 tgt_au_t;
+#endif
+
+/* size of that unit */
+#if TARGET_AU_BITS < BITS_PER_AU
+#define TGTAU_BITS BITS_PER_AU
+#define LOG_TGTAU_BITS LOG_BITS_PER_AU
+#else
+#define TGTAU_BITS TARGET_AU_BITS
+#define LOG_TGTAU_BITS LOG_TARGET_AU_BITS
+#endif
diff --git a/drivers/staging/tidspbridge/dynload/reloc.c b/drivers/staging/tidspbridge/dynload/reloc.c
new file mode 100644 (file)
index 0000000..316a38c
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * reloc.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "header.h"
+
+#if TMS32060
+/* the magic symbol for the start of BSS */
+static const char bsssymbol[] = { ".bss" };
+#endif
+
+#if TMS32060
+#include "reloc_table_c6000.c"
+#endif
+
+#if TMS32060
+/* From coff.h - ignore these relocation operations */
+#define R_C60ALIGN     0x76    /* C60: Alignment info for compressor */
+#define R_C60FPHEAD    0x77    /* C60: Explicit assembly directive */
+#define R_C60NOCMP    0x100    /* C60: Don't compress this code scn */
+#endif
+
+/**************************************************************************
+ * Procedure dload_unpack
+ *
+ * Parameters:
+ *     data    pointer to storage unit containing lowest host address of
+ *             image data
+ *     fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
+ *     offset  Offset from LSB, 0 <= offset < BITS_PER_AU
+ *     sgn     Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
+ *
+ * Effect:
+ *     Extracts the specified field and returns it.
+ ************************************************************************* */
+rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, int fieldsz,
+                   int offset, unsigned sgn)
+{
+       register rvalue objval;
+       register int shift, direction;
+       register tgt_au_t *dp = data;
+
+       fieldsz -= 1;   /* avoid nastiness with 32-bit shift of 32-bit value */
+       /* * collect up enough bits to contain the desired field */
+       if (TARGET_BIG_ENDIAN) {
+               dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
+               direction = -1;
+       } else
+               direction = 1;
+       objval = *dp >> offset;
+       shift = TGTAU_BITS - offset;
+       while (shift <= fieldsz) {
+               dp += direction;
+               objval += (rvalue) *dp << shift;
+               shift += TGTAU_BITS;
+       }
+
+       /* * sign or zero extend the value appropriately */
+       if (sgn == ROP_UNS)
+               objval &= (2 << fieldsz) - 1;
+       else {
+               shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz;
+               objval = (objval << shift) >> shift;
+       }
+
+       return objval;
+
+}                              /* dload_unpack */
+
+/**************************************************************************
+ * Procedure dload_repack
+ *
+ * Parameters:
+ *     val             Value to insert
+ *     data    Pointer to storage unit containing lowest host address of
+ *             image data
+ *     fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
+ *     offset  Offset from LSB, 0 <= offset < BITS_PER_AU
+ *     sgn     Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
+ *
+ * Effect:
+ *     Stuffs the specified value in the specified field.  Returns 0 for
+ *     success
+ * or 1 if the value will not fit in the specified field according to the
+ * specified signedness rule.
+ ************************************************************************* */
+static const unsigned char ovf_limit[] = { 1, 2, 2 };
+
+int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data,
+                int fieldsz, int offset, unsigned sgn)
+{
+       register urvalue objval, mask;
+       register int shift, direction;
+       register tgt_au_t *dp = data;
+
+       fieldsz -= 1;   /* avoid nastiness with 32-bit shift of 32-bit value */
+       /* clip the bits */
+       mask = ((UINT32_C(2) << fieldsz) - 1);
+       objval = (val & mask);
+       /* * store the bits through the specified mask */
+       if (TARGET_BIG_ENDIAN) {
+               dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
+               direction = -1;
+       } else
+               direction = 1;
+
+       /* insert LSBs */
+       *dp = (*dp & ~(mask << offset)) + (objval << offset);
+       shift = TGTAU_BITS - offset;
+       /* align mask and objval with AU boundary */
+       objval >>= shift;
+       mask >>= shift;
+
+       while (mask) {
+               dp += direction;
+               *dp = (*dp & ~mask) + objval;
+               objval >>= TGTAU_BITS;
+               mask >>= TGTAU_BITS;
+       }
+
+       /*
+        * check for overflow
+        */
+       if (sgn) {
+               unsigned tmp = (val >> fieldsz) + (sgn & 0x1);
+               if (tmp > ovf_limit[sgn - 1])
+                       return 1;
+       }
+       return 0;
+
+}                              /* dload_repack */
+
+/* lookup table for the scaling amount in a C6x instruction */
+#if TMS32060
+#define SCALE_BITS 4           /* there are 4 bits in the scale field */
+#define SCALE_MASK 0x7         /* we really only use the bottom 3 bits */
+static const u8 c60_scale[SCALE_MASK + 1] = {
+       1, 0, 0, 0, 1, 1, 2, 2
+};
+#endif
+
+/**************************************************************************
+ * Procedure dload_relocate
+ *
+ * Parameters:
+ *     data    Pointer to base of image data
+ *     rp              Pointer to relocation operation
+ *
+ * Effect:
+ *     Performs the specified relocation operation
+ ************************************************************************* */
+void dload_relocate(struct dload_state *dlthis, tgt_au_t * data,
+                   struct reloc_record_t *rp, bool * tramps_genereted,
+                   bool second_pass)
+{
+       rvalue val, reloc_amt, orig_val = 0;
+       unsigned int fieldsz = 0;
+       unsigned int offset = 0;
+       unsigned int reloc_info = 0;
+       unsigned int reloc_action = 0;
+       register int rx = 0;
+       rvalue *stackp = NULL;
+       int top;
+       struct local_symbol *svp = NULL;
+#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 img_data 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->TYPE);
+       while (rop_map1[rx] != rp->TYPE) {
+               rx = HASH_L(rop_map2[rx]);
+               if (rx < 0) {
+#if TMS32060
+                       switch (rp->TYPE) {
+                       case R_C60ALIGN:
+                       case R_C60NOCMP:
+                       case R_C60FPHEAD:
+                               /* Ignore these reloc types and return */
+                               break;
+                       default:
+                               /* Unknown reloc type, print error and return */
+                               dload_error(dlthis, "Bad coff operator 0x%x",
+                                           rp->TYPE);
+                       }
+#else
+                       dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE);
+#endif
+                       return;
+               }
+       }
+       rx = HASH_I(rop_map2[rx]);
+       if ((rx < (sizeof(rop_action) / sizeof(u16)))
+           && (rx < (sizeof(rop_info) / sizeof(u16))) && (rx > 0)) {
+               reloc_action = rop_action[rx];
+               reloc_info = rop_info[rx];
+       } else {
+               dload_error(dlthis, "Buffer Overflow - Array Index Out "
+                           "of Bounds");
+       }
+
+       /* Compute the relocation amount for the referenced symbol, if any */
+       reloc_amt = rp->UVAL;
+       if (RFV_SYM(reloc_info)) {      /* relocation uses a symbol reference */
+               /* If this is first pass, use the module local symbol table,
+                * else use the trampoline symbol table. */
+               if (second_pass == false) {
+                       if ((u32) rp->SYMNDX < dlthis->dfile_hdr.df_no_syms) {
+                               /* real symbol reference */
+                               svp = &dlthis->local_symtab[rp->SYMNDX];
+                               reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
+                                   svp->delta : svp->value;
+                       }
+                       /* reloc references current section */
+                       else if (rp->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;
+       top = RFV_STK(reloc_info);
+       if (top) {
+               top += dlthis->relstkidx - RSTK_UOP;
+               if (top >= STATIC_EXPR_STK_SIZE) {
+                       dload_error(dlthis,
+                                   "Expression stack overflow in %s at offset "
+                                   FMT_UI32, dlthis->image_secn->name,
+                                   rp->vaddr + dlthis->image_offset);
+                       return;
+               }
+               val = dlthis->relstk[dlthis->relstkidx];
+               dlthis->relstkidx = top;
+               stackp = &dlthis->relstk[top];
+       }
+       /* Derive field position and size, if we need them */
+       if (reloc_info & ROP_RW) {      /* read or write action in our future */
+               fieldsz = RFV_WIDTH(reloc_action);
+               if (fieldsz) {  /* field info from table */
+                       offset = RFV_POSN(reloc_action);
+                       if (TARGET_BIG_ENDIAN)
+                               /* make sure vaddr is the lowest target
+                                * address containing bits */
+                               rp->vaddr += RFV_BIGOFF(reloc_info);
+               } else {        /* field info from relocation op */
+                       fieldsz = rp->FIELDSZ;
+                       offset = rp->OFFSET;
+                       if (TARGET_BIG_ENDIAN)
+                               /* make sure vaddr is the lowest target
+                                  address containing bits */
+                               rp->vaddr += (rp->WORDSZ - offset - fieldsz)
+                                   >> LOG_TARGET_AU_BITS;
+               }
+               data = (tgt_au_t *) ((char *)data + TADDR_TO_HOST(rp->vaddr));
+               /* compute lowest host location of referenced data */
+#if BITS_PER_AU > TARGET_AU_BITS
+               /* conversion from target address to host address may lose
+                  address bits; add loss to offset */
+               if (TARGET_BIG_ENDIAN) {
+                       offset += -((rp->vaddr << LOG_TARGET_AU_BITS) +
+                                   offset + fieldsz) &
+                           (BITS_PER_AU - TARGET_AU_BITS);
+               } else {
+                       offset += (rp->vaddr << LOG_TARGET_AU_BITS) &
+                           (BITS_PER_AU - 1);
+               }
+#endif
+#ifdef RFV_SCALE
+               scale = RFV_SCALE(reloc_info);
+#endif
+       }
+       /* read the object value from the current image, if so ordered */
+       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
+       }
+       /* perform the necessary arithmetic */
+       switch (RFV_ACTION(reloc_action)) {     /* relocation actions */
+       case RACT_VAL:
+               break;
+       case RACT_ASGN:
+               val = reloc_amt;
+               break;
+       case RACT_ADD:
+               val += reloc_amt;
+               break;
+       case RACT_PCR:
+               /*-----------------------------------------------------------
+                * Handle special cases of jumping from absolute sections
+                * (special reloc type) or to absolute destination
+                * (symndx == -1).  In either case, set the appropriate
+                * relocation amount to 0.
+                *----------------------------------------------------------- */
+               if (rp->SYMNDX == -1)
+                       reloc_amt = 0;
+               val += reloc_amt - dlthis->delta_runaddr;
+               break;
+       case RACT_ADDISP:
+               val += rp->R_DISP + reloc_amt;
+               break;
+       case RACT_ASGPC:
+               val = dlthis->image_secn->run_addr + reloc_amt;
+               break;
+       case RACT_PLUS:
+               if (stackp != NULL)
+                       val += *stackp;
+               break;
+       case RACT_SUB:
+               if (stackp != NULL)
+                       val = *stackp - val;
+               break;
+       case RACT_NEG:
+               val = -val;
+               break;
+       case RACT_MPY:
+               if (stackp != NULL)
+                       val *= *stackp;
+               break;
+       case RACT_DIV:
+               if (stackp != NULL)
+                       val = *stackp / val;
+               break;
+       case RACT_MOD:
+               if (stackp != NULL)
+                       val = *stackp % val;
+               break;
+       case RACT_SR:
+               if (val >= sizeof(rvalue) * BITS_PER_AU)
+                       val = 0;
+               else if (stackp != NULL)
+                       val = (urvalue) *stackp >> val;
+               break;
+       case RACT_ASR:
+               if (val >= sizeof(rvalue) * BITS_PER_AU)
+                       val = sizeof(rvalue) * BITS_PER_AU - 1;
+               else if (stackp != NULL)
+                       val = *stackp >> val;
+               break;
+       case RACT_SL:
+               if (val >= sizeof(rvalue) * BITS_PER_AU)
+                       val = 0;
+               else if (stackp != NULL)
+                       val = *stackp << val;
+               break;
+       case RACT_AND:
+               if (stackp != NULL)
+                       val &= *stackp;
+               break;
+       case RACT_OR:
+               if (stackp != NULL)
+                       val |= *stackp;
+               break;
+       case RACT_XOR:
+               if (stackp != NULL)
+                       val ^= *stackp;
+               break;
+       case RACT_NOT:
+               val = ~val;
+               break;
+#if TMS32060
+       case RACT_C6SECT:
+               /* actually needed address of secn containing symbol */
+               if (svp != NULL) {
+                       if (rp->SYMNDX >= 0)
+                               if (svp->secnn > 0)
+                                       reloc_amt = dlthis->ldr_sections
+                                           [svp->secnn - 1].run_addr;
+               }
+               /* !!! FALL THRU !!! */
+       case RACT_C6BASE:
+               if (dlthis->bss_run_base == 0) {
+                       struct dynload_symbol *symp;
+                       symp = dlthis->mysym->find_matching_symbol
+                           (dlthis->mysym, bsssymbol);
+                       /* lookup value of global BSS base */
+                       if (symp)
+                               dlthis->bss_run_base = symp->value;
+                       else
+                               dload_error(dlthis,
+                                           "Global BSS base referenced in %s "
+                                           "offset" FMT_UI32 " but not "
+                                           "defined",
+                                           dlthis->image_secn->name,
+                                           rp->vaddr + dlthis->image_offset);
+               }
+               reloc_amt -= dlthis->bss_run_base;
+               /* !!! FALL THRU !!! */
+       case RACT_C6DSPL:
+               /* scale factor determined by 3 LSBs of field */
+               scale = c60_scale[val & SCALE_MASK];
+               offset += SCALE_BITS;
+               fieldsz -= SCALE_BITS;
+               val >>= SCALE_BITS;     /* ignore the scale field hereafter */
+               val <<= scale;
+               val += reloc_amt;       /* do the usual relocation */
+               if (((1 << scale) - 1) & val)
+                       dload_error(dlthis,
+                                   "Unaligned reference in %s offset "
+                                   FMT_UI32, dlthis->image_secn->name,
+                                   rp->vaddr + dlthis->image_offset);
+               break;
+#endif
+       }                       /* relocation actions */
+       /* * Put back result as required */
+       if (reloc_info & ROP_W) {       /* relocation writes image value */
+#ifdef RFV_SCALE
+               val >>= scale;
+#endif
+               if (dload_repack(dlthis, val, data, fieldsz, offset,
+                                RFV_SIGN(reloc_info))) {
+                       /* 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 val " FMT_UI32
+                                                   " overflows %d bits in %s "
+                                                   "offset " FMT_UI32, val,
+                                                   fieldsz,
+                                                   dlthis->image_secn->name,
+                                                   dlthis->image_offset +
+                                                   rp->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->vaddr);
+                       }
+               }
+       } else if (top)
+               *stackp = val;
+}                              /* reloc_value */
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table.h b/drivers/staging/tidspbridge/dynload/reloc_table.h
new file mode 100644 (file)
index 0000000..6aab03d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * reloc_table.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _RELOC_TABLE_H_
+#define _RELOC_TABLE_H_
+/*
+ * Table of relocation operator properties
+ */
+#include <linux/types.h>
+
+/* How does this relocation operation access the program image? */
+#define ROP_N  0               /* does not access image */
+#define ROP_R  1               /* read from image */
+#define ROP_W  2               /* write to image */
+#define ROP_RW 3               /* read from and write to image */
+
+/* For program image access, what are the overflow rules for the bit field? */
+/* Beware! Procedure repack depends on this encoding */
+#define ROP_ANY        0               /* no overflow ever, just truncate the value */
+#define ROP_SGN        1               /* signed field */
+#define ROP_UNS        2               /* unsigned field */
+#define ROP_MAX 3      /* allow maximum range of either signed or unsigned */
+
+/* How does the relocation operation use the symbol reference */
+#define ROP_IGN        0               /* no symbol is referenced */
+#define ROP_LIT 0              /* use rp->UVAL literal field */
+#define ROP_SYM        1               /* symbol value is used in relocation */
+#define ROP_SYMD 2             /* delta value vs last link is used */
+
+/* How does the reloc op use the stack? */
+#define RSTK_N 0               /* Does not use */
+#define RSTK_POP 1             /* Does a POP */
+#define RSTK_UOP 2             /* Unary op, stack position unaffected */
+#define RSTK_PSH 3             /* Does a push */
+
+/*
+ * Computational actions performed by the dynamic loader
+ */
+enum dload_actions {
+       /* don't alter the current val (from stack or mem fetch) */
+       RACT_VAL,
+       /* set value to reference amount (from symbol reference) */
+       RACT_ASGN,
+       RACT_ADD,               /* add reference to value */
+       RACT_PCR,               /* add reference minus PC delta to value */
+       RACT_ADDISP,            /* add reference plus R_DISP */
+       RACT_ASGPC,             /* set value to section addr plus reference */
+
+       RACT_PLUS,              /* stack + */
+       RACT_SUB,               /* stack - */
+       RACT_NEG,               /* stack unary - */
+
+       RACT_MPY,               /* stack * */
+       RACT_DIV,               /* stack / */
+       RACT_MOD,               /* stack % */
+
+       RACT_SR,                /* stack unsigned >> */
+       RACT_ASR,               /* stack signed >> */
+       RACT_SL,                /* stack << */
+       RACT_AND,               /* stack & */
+       RACT_OR,                /* stack | */
+       RACT_XOR,               /* stack ^ */
+       RACT_NOT,               /* stack ~ */
+       RACT_C6SECT,            /* for C60 R_SECT op */
+       RACT_C6BASE,            /* for C60 R_BASE op */
+       RACT_C6DSPL,            /* for C60 scaled 15-bit displacement */
+       RACT_PCR23T             /* for ARM Thumb long branch */
+};
+
+/*
+ * macros used to extract values
+ */
+#define RFV_POSN(aaa) ((aaa) & 0xF)
+#define RFV_WIDTH(aaa) (((aaa) >> 4) & 0x3F)
+#define RFV_ACTION(aaa) ((aaa) >> 10)
+
+#define RFV_SIGN(iii) (((iii) >> 2) & 0x3)
+#define RFV_SYM(iii) (((iii) >> 4) & 0x3)
+#define RFV_STK(iii) (((iii) >> 6) & 0x3)
+#define RFV_ACCS(iii) ((iii) & 0x3)
+
+#if (TMS32060)
+#define RFV_SCALE(iii) ((iii) >> 11)
+#define RFV_BIGOFF(iii) (((iii) >> 8) & 0x7)
+#else
+#define RFV_BIGOFF(iii) ((iii) >> 8)
+#endif
+
+#endif /* _RELOC_TABLE_H_ */
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c
new file mode 100644 (file)
index 0000000..8ae3b38
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * reloc_table_c6000.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Tables generated for c6000 */
+
+#define HASH_FUNC(zz) (((((zz) + 1) * UINT32_C(1845)) >> 11) & 63)
+#define HASH_L(zz) ((zz) >> 8)
+#define HASH_I(zz) ((zz) & 0xFF)
+
+static const u16 rop_map1[] = {
+       0,
+       1,
+       2,
+       20,
+       4,
+       5,
+       6,
+       15,
+       80,
+       81,
+       82,
+       83,
+       84,
+       85,
+       86,
+       87,
+       17,
+       18,
+       19,
+       21,
+       16,
+       16394,
+       16404,
+       65535,
+       65535,
+       65535,
+       65535,
+       65535,
+       65535,
+       32,
+       65535,
+       65535,
+       65535,
+       65535,
+       65535,
+       65535,
+       40,
+       112,
+       113,
+       65535,
+       16384,
+       16385,
+       16386,
+       16387,
+       16388,
+       16389,
+       16390,
+       16391,
+       16392,
+       16393,
+       16395,
+       16396,
+       16397,
+       16398,
+       16399,
+       16400,
+       16401,
+       16402,
+       16403,
+       16405,
+       16406,
+       65535,
+       65535,
+       65535
+};
+
+static const s16 rop_map2[] = {
+       -256,
+       -255,
+       -254,
+       -245,
+       -253,
+       -252,
+       -251,
+       -250,
+       -241,
+       -240,
+       -239,
+       -238,
+       -237,
+       -236,
+       1813,
+       5142,
+       -248,
+       -247,
+       778,
+       -244,
+       -249,
+       -221,
+       -211,
+       -1,
+       -1,
+       -1,
+       -1,
+       -1,
+       -1,
+       -243,
+       -1,
+       -1,
+       -1,
+       -1,
+       -1,
+       -1,
+       -242,
+       -233,
+       -232,
+       -1,
+       -231,
+       -230,
+       -229,
+       -228,
+       -227,
+       -226,
+       -225,
+       -224,
+       -223,
+       5410,
+       -220,
+       -219,
+       -218,
+       -217,
+       -216,
+       -215,
+       -214,
+       -213,
+       5676,
+       -210,
+       -209,
+       -1,
+       -1,
+       -1
+};
+
+static const u16 rop_action[] = {
+       2560,
+       2304,
+       2304,
+       2432,
+       2432,
+       2560,
+       2176,
+       2304,
+       2560,
+       3200,
+       3328,
+       3584,
+       3456,
+       2304,
+       4208,
+       20788,
+       21812,
+       3415,
+       3245,
+       2311,
+       4359,
+       19764,
+       2311,
+       3191,
+       3280,
+       6656,
+       7680,
+       8704,
+       9728,
+       10752,
+       11776,
+       12800,
+       13824,
+       14848,
+       15872,
+       16896,
+       17920,
+       18944,
+       0,
+       0,
+       0,
+       0,
+       1536,
+       1536,
+       1536,
+       5632,
+       512,
+       0
+};
+
+static const u16 rop_info[] = {
+       0,
+       35,
+       35,
+       35,
+       35,
+       35,
+       35,
+       35,
+       35,
+       39,
+       39,
+       39,
+       39,
+       35,
+       34,
+       283,
+       299,
+       4135,
+       4391,
+       291,
+       33059,
+       283,
+       295,
+       4647,
+       4135,
+       64,
+       64,
+       128,
+       64,
+       64,
+       64,
+       64,
+       64,
+       64,
+       64,
+       64,
+       64,
+       128,
+       201,
+       197,
+       74,
+       70,
+       208,
+       196,
+       200,
+       192,
+       192,
+       66
+};
diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c
new file mode 100644 (file)
index 0000000..7b593fc
--- /dev/null
@@ -0,0 +1,1143 @@
+/*
+ * tramp.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#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->dload_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->dload_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->dload_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->dload_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->dload_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->dload_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->dload_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->dload_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].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, tgt_au_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->
+                                                              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,
+                                               (tgt_au_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->dload_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.img_data,
+                                               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->dload_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.
+                                                        img_data,
+                                                        dlthis->image_secn->
+                                                        load_addr +
+                                                        cur_pkt->offset,
+                                                        dlthis->image_secn,
+                                                        BYTE_TO_HOST
+                                                        (cur_pkt->img_pkt.
+                                                         packet_size));
+                       if (ret_val == 0) {
+                               dload_error(dlthis,
+                                           "Write to " FMT_UI32 " failed",
+                                           dlthis->image_secn->load_addr +
+                                           cur_pkt->offset);
+                       }
+
+                       dlthis->mysym->dload_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->packet_size;
+
+               dup_pkt = (struct tramp_img_dup_pkt *)
+                   dlthis->mysym->dload_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.img_data = (u8 *) (dup_pkt + 1);
+                       for (i = 0; i < ipacket->packet_size; i++)
+                               *(dup_pkt->img_pkt.img_data + i) =
+                                   *(ipacket->img_data + 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.packet_size; i++)
+                       *(dup_pkt->img_pkt.img_data + i) =
+                           *(ipacket->img_data + 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->dload_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.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->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->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->vaddr,
+                                dlthis->local_symtab[rp->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->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->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 img pkt 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.packet_size; i++)
+                       *(dup_pkt->img_pkt.img_data + i) =
+                           *(ipacket->img_data + 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->dload_deallocate(dlthis->mysym, cur_sym);
+       }
+
+       if (tramp->final_sym_table != NULL)
+               dlthis->mysym->dload_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->dload_deallocate(dlthis->mysym, cur_string);
+       }
+
+       if (tramp->final_string_table != NULL)
+               dlthis->mysym->dload_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->dload_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->dload_deallocate(dlthis->mysym,
+                                                       cur_dup_relo);
+               }
+
+               dlthis->mysym->dload_deallocate(dlthis->mysym, cur_dup_pkt);
+       }
+}
diff --git a/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c
new file mode 100644 (file)
index 0000000..e38d631
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * tramp_table_c6000.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#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 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);
+}