Kernel  |  3.4

下载     查看原文件
C++程序  |  408行  |  12.07 KB
/*
 * 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);
}