📄 dld_section.c
字号:
/* * 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 + -