⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dld_section.c

📁 Omap5910 上实现双核通信 DSP GateWay
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * dsp_dld/arm/dld_section.c * * DSP Dynamic Loader Daemon: dld_section.c * * Copyright (C) 2003-2005 Nokia Corporation * * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com> * Written by Kiyotaka Takahashi <kiyotaka.takahashi@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * 2005/07/11:  DSP Gateway version 3.3 */#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include <fcntl.h>#include "list.h"#include "coff-c55x.h"#include "dsp_dld.h"#include "dld_daemon.h"#include "dld_malloc.h"#include "dld_coff.h"#include "dld_memmgr.h"#define RELOC_SYMBOL_FIELD_TYPE_INVALID	0#define RELOC_SYMBOL_FIELD_TYPE_SYMBOL	1#define RELOC_SYMBOL_FIELD_TYPE_VALUE	2#define LDTYP_LOAD	1#define LDTYP_NOLOAD	2#define LDTYP_NODATA	3#define LDTYP_ZEROSZ	4#define LDTYP_CINIT_RAM	5#ifdef STICKY_LISTstatic LIST_HEAD(g_scnlist);#endifstatic u8 dummy_section_data[1];static int load_to_dspmem(int fd, struct taskent *te, u32 addr,			  u32 size, u8 *data);#ifndef DSP_EMULATIONstatic void copy_byteswap(u8 *dst, u8 *src, size_t size);#endifstatic int cinit_bss_init(int fd, struct taskent *te, struct section *scn);static int extra_relocate(struct section *scn, int i);inline int rel_sym_field_type(u16 type);static char *reloc_name(u16 type);#ifdef DEBUG_RELOCATE#define rel_sym_delta(scn,rel,org,new)	__rel_sym_val(scn,rel,org,new,1)#define rel_sym_val(scn,rel)	__rel_sym_val(scn,rel,NULL,NULL,0)static u32 __rel_sym_val(struct section *scn, struct reloc *rel,			 u32 *org, u32 *new, int delta);#else#define rel_sym_delta(scn,rel)	__rel_sym_val(scn,rel,1)#define rel_sym_val(scn,rel)	__rel_sym_val(scn,rel,0)static u32 __rel_sym_val(struct section *scn, struct reloc *rel, int delta);#endifstatic int section_loadtype(struct section *scn);static struct section *section_find_by_addr(struct list_head *list, u32 addr);/* * dummy symbols */static struct symbol symbol_internalreloc = {	.list_head  = { NULL, NULL },	.name       = "Internal Relocation",	.value_orig = 0,	.value      = 0,	.scn        = NULL,	.type       = COFF_T_NULL,	.sclass     = COFF_C_NULL};/* * create and fill functions should be separated since * section and symbol refere each otehr with their index number. * It means fill_scnlist() needs symbol instances as well as * fill_symlist() needs section instances. */void section_createlist(struct list_head *list, u16 n){	int i;	for (i = 0; i < n; i++) {		struct section *scn = dld_malloc(sizeof(struct section), "section");		list_add_tail(&scn->list_head, list);		scn->name = NULL;		scn->size = 0;		scn->data = NULL;		scn->nreloc = 0;		scn->reloc = NULL;	}}void section_freelist(struct list_head *list){	struct section *scn, *tmp;#ifdef STICKY_LIST	if (list == NULL)		list = &g_scnlist;#endif	section_for_each_safe(scn, tmp, list) {		list_del(&scn->list_head);		if (scn->name)			dld_free(scn->name, "section->name");		/* data might be pointing dummy data */		if ((scn->data) && (scn->data != dummy_section_data))			dld_free(scn->data, "section->data");		if (scn->reloc)			dld_free(scn->reloc, "section->reloc");		dld_free(scn, "section");	}}#define reloc_fieldtype_sym(rel) \	(rel_sym_field_type(rel->type) == RELOC_SYMBOL_FIELD_TYPE_SYMBOL)#define reloc_fieldtype_val(rel) \	(rel_sym_field_type(rel->type) == RELOC_SYMBOL_FIELD_TYPE_VALUE)void section_filllist(struct coff *coff, u8 *src,		      struct coffobj *cobj, u16 n, int type){	struct list_head *ptr = &cobj->scnlist;	int i, j;	for (i = 0; i < n; i++) {#if 0		/* arm-gcc doesn't like non-dword-sized structure array */		COFF_SCNHDR *scnsrc = &coff->scnhdr[i];#else		COFF_SCNHDR *scnsrc = (void *)coff->scnhdr + (COFF_SCNHSZ * i);#endif		struct section *scn;		u32 scnptr;		u32 relptr;		ptr = ptr->next;		scn = (struct section *)ptr;		scn->name = dld_strdup(scnname(coff, scnsrc->s_name), "section->name");		scn->vaddr = COFF_LONG(scnsrc->s_vaddr);		scn->vaddr_orig = scn->vaddr;		scn->size = COFF_LONG(scnsrc->s_size);		scn->nreloc = COFF_LONG(scnsrc->s_nreloc);		scn->flags = COFF_LONG(scnsrc->s_flags);		scn->cobj = (type == COFFTYP_KERNEL) ? NULL : cobj;		scnptr = COFF_LONG(scnsrc->s_scnptr);		relptr = COFF_LONG(scnsrc->s_relptr);		if (scnptr) {			scn->data = dld_malloc(scn->size, "section->data");			memcpy(scn->data, &src[scnptr], scn->size);		} else			scn->data = NULL;		if (relptr) {			COFF_RELOC *srel = (COFF_RELOC *)&src[relptr];			scn->reloc = dld_malloc(sizeof(struct reloc) * scn->nreloc, "section->reloc");			for (j = 0; j < scn->nreloc; j++) {				COFF_RELOC *relsrc = &srel[j];				struct reloc *rel = &scn->reloc[j];				u32 symndx;				rel->vaddr = COFF_LONG(relsrc->r_vaddr);				rel->exa   = COFF_SHORT(relsrc->r_exa);				rel->type  = COFF_SHORT(relsrc->r_type);				symndx     = COFF_LONG(relsrc->r_symndx);				if (reloc_fieldtype_sym(rel)) {					rel->sym.sym = (symndx == 0xffffffff) ?						&symbol_internalreloc:						list_entry(list_find_by_idx(&cobj->symlist, symndx), struct symbol, list_head);				} else if (reloc_fieldtype_val(rel)) {					rel->sym.val = symndx;				}			}		} else			scn->reloc = NULL;	}}#ifdef STICKY_LISTvoid section_register_global(struct list_head *list){	struct section *scn;	/*	 * We don't need section contents anymore.	 *	 * We need section header (in fact, only flags) for relocation	 * to detect the relocation address points text or data.	 *	 * And we also need to know whether the section used to have	 * data, so we release the actual data here but	 * make 'scn->data' point to dummy data.	 */	section_for_each(scn, list) {		if (scn->data) {			dld_free(scn->data, "section->data");			scn->data = dummy_section_data;		}		if (scn->reloc)	{ /* should not have... */			dld_free(scn->reloc, "section->reloc");			scn->reloc = NULL;		}	}	/*	 * All sections are moved to g_scnlist	 */	list_splice(list, &g_scnlist);	INIT_LIST_HEAD(list);}#endif /* STICKY_LIST */int section_load(struct list_head *list, struct taskent *te){	int fd;	struct section *scn;	char *msg;	int ret = 0;#ifndef DSP_EMULATION	fd = open(DEVNAME_DSPMEM, O_RDWR);	if (fd < 0) {		prmsg("Can't open %s\n", DEVNAME_DSPMEM);		return -1;	}#endif#if defined(DEBUG_SECTION) || defined(DEBUG_LOAD)	prmsg("section loading ...\n");#endif	section_for_each(scn, list) {		switch (section_loadtype(scn)) {			case LDTYP_CINIT_RAM:				/* .cinit will be treated later */				continue;			case LDTYP_NOLOAD:				msg = " ignored.";				break;			case LDTYP_ZEROSZ:			case LDTYP_NODATA:				msg = "";				break;			case LDTYP_LOAD:			{				unsigned char *data;				int cnt;				if ((data = scn->data) == NULL) {					data = dld_malloc(scn->size, "section->data");					memset(data, 0, scn->size);				}				cnt = load_to_dspmem(fd, te, scn->vaddr,						     scn->size, data);				if (scn->data == NULL)					dld_free(data, "sectionsection->data");				if (cnt == scn->size) {					msg = " initialized.";				} else {					msg = " initialization failed!!";					ret = -1;				}			}		}#if defined(DEBUG_SECTION) || defined(DEBUG_LOAD)		prmsg("%-20s : adr=0x%06lx, size=%06lx, flags=0x%08lx %s\n",		      scn->name, scn->vaddr, scn->size, scn->flags, msg);#endif		if (ret < 0) {			prmsg("error in loading %s!!\n", scn->name);			goto finish;		}	}	/* RAM mode .cinit handling */	section_for_each(scn, list) {		if (section_loadtype(scn) != LDTYP_CINIT_RAM)			continue;		if (cinit_bss_init(fd, te, scn) < 0) {			msg = " .bss variables initialization failed!!";			ret = -1;		} else {			msg = " .bss variables are initialized.";		}#if defined(DEBUG_SECTION) || defined(DEBUG_LOAD)		prmsg("%-20s : adr=0x%06lx, size=%06lx, flags=0x%08lx %s\n",		      scn->name, scn->vaddr, scn->size, scn->flags, msg);#endif		if (ret < 0) {			prmsg("error in loading %s!!\n", scn->name);			goto finish;		}	}finish:#ifndef DSP_EMULATION	close(fd);#endif	return ret;}static int load_to_dspmem(int fd, struct taskent *te, u32 addr,			  u32 size, u8 *data){#ifdef DSP_EMULATION	struct list_head *memlist;	struct memmgr *mem;	u32 offset;	memlist = (te && te->lkcmd) ? &te->lkcmd->memlist : NULL;	mem = memmgr_find_by_addr(memlist, addr, size);	if (mem == NULL)		return 0;	offset = addr - mem->base;	memcpy(mem->img + offset, data, size);	return size;#else /* DSP_EMULATION */	/*	 * We assume MPUI byteswap off for DARAM/SARAM.	 * You should be careful that the copy_from_user routine	 * for 1,2 and 3-bytes is tricky through MPUI.	 */	size_t size1, size2, size3;	u8 data_bs[size+8], *dst;	size_t writesize;	u32 writeaddr;	u8 *writesrc;	if (space_find_by_addr(addr, size) == SPACE_CROSSING) {		prmsg("section crossing memory boundary!\n");		return -1;	}	size1 = (addr & 0x3) ? 4 - (addr & 0x3) : 0;	/* top odd bytes */	size3 = (addr + size) & 0x3;			/* bottom odd bytes */	size2 = size - size1 - size3;			/* multiple of 4 */#ifdef DEBUG_LOAD	prmsg("\n");	prmsg("addr = %08lx\n", addr);	prmsg("size = %08lx, %x:%x:%x\n", size, size1, size2, size3);#endif	writesize = 0;	if (size1) {#ifdef DEBUG_LOAD		prmsg("top: seek to %08lx\n", addr & ~0x3);#endif		lseek(fd, addr & ~0x3, SEEK_SET);		dst = data_bs;		if (read(fd, dst, 4) < 4)			return -1;#ifdef DEBUG_LOAD		prmsg("%02x %02x %02x %02x -> ",		      dst[0], dst[1], dst[2], dst[3]);#endif		if (size1 >= 3)			dst[0] = *(data++);		if (size1 >= 2)			dst[3] = *(data++);		/* if(size1 >= 1) */			dst[2] = *(data++);#ifdef DEBUG_LOAD		prmsg("%02x %02x %02x %02x\n", dst[0], dst[1], dst[2], dst[3]);#endif	}	dst = data_bs + 4;	copy_byteswap(dst, data, size2);	data += size2;	dst  += size2;	if (size3) {#ifdef DEBUG_LOAD		prmsg("bottom: seek to %08lx\n", addr + size1 + size2);#endif		lseek(fd, addr + size1 + size2, SEEK_SET);		if (read(fd, dst, 4) < 4)			return -1;#ifdef DEBUG_LOAD		prmsg("%02x %02x %02x %02x ->", dst[0], dst[1], dst[2], dst[3]);#endif		/* if (size3 >= 1) */			dst[1] = *(data++);		if (size3 >= 2)			dst[0] = *(data++);		if (size3 >= 3)			dst[3] = *(data++);#ifdef DEBUG_LOAD		prmsg("%02x %02x %02x %02x\n", dst[0], dst[1], dst[2], dst[3]);#endif	}	writeaddr = size1 ? addr & ~0x3 : addr;	writesize = (size1 ? 4 : 0) + size2 + (size3 ? 4 : 0);	writesrc  = size1 ? data_bs : data_bs+4;#ifdef DEBUG_LOAD	prmsg("writeaddr = %08lx, writesize = %08lx, src offset = %d\n",	      writeaddr, writesize, writesrc - data_bs);#endif	lseek(fd, writeaddr, SEEK_SET);	if (write(fd, writesrc, writesize) < writesize)		return -1;	return size;#endif /* DSP_EMULATION */}#ifndef DSP_EMULATIONstatic void copy_byteswap(u8 *dst, u8 *src, size_t size){	for (; size >= 2; size -= 2, src += 2, dst += 2) {		dst[1] = src[0];		dst[0] = src[1];	}}#endif /* DSP_EMULATION */static int cinit_bss_init(int fd, struct taskent *te, struct section *scn){	int i = 0;	while (i < scn->size) {		COFF_CINIT *cinit = (COFF_CINIT *)&scn->data[i];		/* size and addr are written in big-endian format */		u16 size  = COFF_SHORT_H(cinit->size) * 2;	/* size in word */		u32 addr  = COFF_24BIT_H(cinit->addr) * 2;	/* addr in word */		u8 flags = *cinit->flags;		int cnt;#ifdef DEBUG_CINIT{		/*		 * at this moment for kernel, g_scnlist is vacant...		 * therefore, section_find_by_addr can not be used. ;-(		 */		int j;		prmsg("\n  i=%d, size=%04x, addr=%06lx, flags=%02x\n",		      i, size, addr, flags);		if (size) {			for (j = 0; j < size; j += 2) {				prmsg("%02x: %02x %02x\n",				      j, (u8)cinit->data[j], (u8)cinit->data[j+1]);			}		}}#endif		/*		 * last entry may be 0-size		 */		if (size == 0) {			i += 2;			if (i != scn->size) {				prmsg("warning: found zero-sized "				      "cinit entry at 0x%x\n", i-2);			}			continue;		}		if (te &&		    (section_find_by_addr(&te->cobj->scnlist, addr) == NULL)) {			prmsg("Warning: cinit target address %06lx "			      "is not in this task. ignoring it.\n", addr);			i += COFF_CINITSZ + size;			continue;		}		if ((flags & 0x01) == COFF_CINIT_FLAG_IO) {			prmsg("We can't handle cinit data for I/O space!\n");			return -1;		}		cnt = load_to_dspmem(fd, te, addr, size, cinit->data);		if (cnt < size)			return -1;		i += COFF_CINITSZ + size;	}	if (i > scn->size) {		prmsg("cinit data size is inconsistent.\n");		return -1;	}	return 0;}/* * Address relocator * * @list: Section list * * Calculate address according to relocation info for sections * */int section_relocate(struct list_head *list){	int i;	struct section *scn;	struct reloc *rel;	u32 vaddr_relative;	u32 delta, val;#ifdef DEBUG_RELOCATE	u32 sym_org, sym_new;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -