/* * getsection.c * * DSP-BIOS Bridge driver support functions for TI OMAP processors. * * Copyright (C) 2005-2006 Texas Instruments, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include <dspbridge/getsection.h> #include "header.h" /* * Error strings */ static const char readstrm[] = { "Error reading %s from input stream" }; static const char seek[] = { "Set file position to %d failed" }; static const char isiz[] = { "Bad image packet size %d" }; static const char err_checksum[] = { "Checksum failed on %s" }; static const char err_reloc[] = { "dload_get_section unable to read" "sections containing relocation entries" }; #if BITS_PER_AU > BITS_PER_BYTE static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" }; static const char stbl[] = { "Bad string table offset " FMT_UI32 }; #endif /************************************************************** */ /********************* 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 = (struct ldr_section_info *)&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 = (struct ldr_section_info *)&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 * section_name Pointer to the string name of the section desired * section_info 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 *section_name, const struct ldr_section_info **const section_info) { 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 = (struct ldr_section_info *)&dlthis->sect_hdrs[sec]; if (strcmp(section_name, shp->name) == 0) { *section_info = shp; return true; } } return false; } #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) /************************************************************************** * Procedure dload_get_section * * Parameters: * minfo Handle from dload_module_open for this module * section_info Pointer to a section info structure for the desired * section * section_data 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 *section_info, void *section_data) { 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 *) section_data; dlthis = (struct dload_state *)minfo; if (!dlthis) return false; sptr = (struct doff_scnhdr_t *)section_info; 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); }