From: Omar Ramirez Luna Date: Wed, 23 Jun 2010 13:02:02 +0000 (+0300) Subject: staging: ti dspbridge: add DOFF binaries loader X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=26f8db7d2e20218272cbf889edfdb8328b4cd9c3;p=linux-beck.git staging: ti dspbridge: add DOFF binaries loader Add TI's DSP Bridge DOFF binaries dynamic loader driver sources Signed-off-by: Omar Ramirez Luna Signed-off-by: Kanigeri, Hari Signed-off-by: Ameya Palande Signed-off-by: Guzman Lugo, Fernando Signed-off-by: Hebbar, Shivananda Signed-off-by: Ramos Falcon, Ernesto Signed-off-by: Felipe Contreras Signed-off-by: Anna, Suman Signed-off-by: Gupta, Ramesh Signed-off-by: Gomez Castellanos, Ivan Signed-off-by: Andy Shevchenko Signed-off-by: Armando Uribe De Leon Signed-off-by: Deepak Chitriki Signed-off-by: Menon, Nishanth Signed-off-by: Phil Carmody Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c new file mode 100644 index 000000000000..d4f71b585a53 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -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 index 000000000000..803756198bc5 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/dload_internal.h @@ -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 + +/* + * 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 index 000000000000..5bf99240f9fe --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/doff.h @@ -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 index 000000000000..029898fc091f --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/getsection.c @@ -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 +#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 index 000000000000..5cef3600157e --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/header.h @@ -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 +#define DL_STRCMP strcmp + +/* maximum parenthesis nesting in relocation stack expressions */ +#define STATIC_EXPR_STK_SIZE 10 + +#include + +#include "doff.h" +#include +#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 index 000000000000..a216bb131a40 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/module_list.h @@ -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 + +/* 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 index 000000000000..d797fcd3b662 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/params.h @@ -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<> 16)) +#define SWAP16BY8(zz) (((zz) << 8) | ((zz) >> 8)) + +/* !! don't be tempted to insert type definitions here; use !! */ + +/****************************************************************************** + * + * 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 index 000000000000..316a38c2a1fd --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc.c @@ -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 index 000000000000..6aab03d4668d --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc_table.h @@ -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 + +/* 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 index 000000000000..8ae3b38f3983 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c @@ -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 index 000000000000..7b593fc2b692 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/tramp.c @@ -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 index 000000000000..e38d631b3217 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c @@ -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 , B10 */ + 0x0500006A, /* MVKH.S2 , 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); +}