dspload.c
来自「Omap5910 上实现双核通信 DSP GateWay」· C语言 代码 · 共 536 行
C
536 行
/* * dspapps/utils/dspload.c * * control utility for DSP Gateway * * Copyright (C) 2002-2005 Nokia Corporation * * Written by Toshihiro Kobayashi <toshihiro.kobayashi@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 * * 2004/12/28: DSP Gateway version 3.3 */#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include <fcntl.h>#include <assert.h>#include <sys/stat.h>#include <sys/mman.h>#include "dspctl.h"#define BAD_ENTRYPTR 0xffffffff#define DARAM_BASE 0x000000#define DARAM_END 0x010000#define SARAM_BASE 0x010000#define SARAM_END 0x028000#define SPACE_DARAM 1#define SPACE_SARAM 2#define SPACE_EXTERN 3#define SPACE_CROSSING -2enum scntyp { SCNTYP_LOAD, SCNTYP_NOLOAD, SCNTYP_NODATA, SCNTYP_ZEROSZ, SCNTYP_CINIT_RAM,};struct coff { unsigned char *src; off_t size; COFF_AOUTHDR *aouthdr; COFF_FILHDR *coffhdr; COFF_SCNHDR *scnhdr; COFF_SYMENT *symtbl; char *strtbl;};static struct coff coff;static int open_coff(char *coffname);static int close_coff(int fd);static int load_scns(void);static char *scnname(COFF_SCNHDR *hdr);static COFF_SCNHDR *find_scn_by_name(char *name);static enum scntyp get_scntyp(COFF_SCNHDR *hdr);static int spaceof(unsigned long addr, size_t size);static int load_to_dspmem(int fd, unsigned long addr, size_t size, unsigned char *data);static void copy_byteswap(void *dst, void *src, size_t size);static int cinit_bss_init(int fd, unsigned char *p, size_t size);/* * load_coff(): * load the DSP binary into the DSP memory. */unsigned long load_coff(char *coffname){ int fd; int ret = BAD_ENTRYPTR; if ((fd = open_coff(coffname)) < 0) return BAD_ENTRYPTR; if (!coff.aouthdr) goto out; if (load_scns() < 0) goto out; ret = COFF_LONG(coff.aouthdr->entry);out: close_coff(fd); return ret;}/* * read_dspgw_version(): * read version info in the DSP binary. */struct COFF_dspgw_version { char major[2]; char minor[2]; char extra1[2]; char extra2[2];};#define COFF_DSPGW_VERSION struct COFF_dspgw_version#define COFF_DSPGW_VERSION_SZ 8int read_dspgw_version(struct dspgw_version *version, char *coffname){ int fd; COFF_SCNHDR *version_hdr; unsigned long ptr; size_t size; COFF_DSPGW_VERSION *data; int ret = -1; if ((fd = open_coff(coffname)) < 0) return -1; if (!coff.aouthdr) goto out; /* read version info */ if ((version_hdr = find_scn_by_name("dspgw_version")) == NULL) goto out; ptr = COFF_LONG(version_hdr->s_scnptr); size = COFF_LONG(version_hdr->s_size); if (!ptr || (size < COFF_DSPGW_VERSION_SZ)) goto out; data = (COFF_DSPGW_VERSION *)&coff.src[ptr]; version->major = COFF_SHORT_H(data->major); version->minor = COFF_SHORT_H(data->minor); version->extra1 = COFF_SHORT_H(data->extra1); version->extra2 = COFF_SHORT_H(data->extra2); ret = 0;out: close_coff(fd); return ret;}static int open_coff(char *coffname){ int fd; struct stat stat; unsigned short opthdrsz; unsigned long nsyms; off_t symptr; fd = open(coffname, O_RDONLY); if (fd < 0) { perror("open"); return -1; } if (fstat(fd, &stat) < 0) { perror("fstat"); return -1; } coff.size = stat.st_size; coff.src = mmap(0, coff.size, PROT_READ, MAP_SHARED, fd, 0); if ((int)coff.src < 0) { perror("mmap"); return -1; } coff.coffhdr = (COFF_FILHDR*)&coff.src[0]; opthdrsz = COFF_SHORT(coff.coffhdr->f_opthdr); nsyms = COFF_LONG(coff.coffhdr->f_nsyms); symptr = COFF_LONG(coff.coffhdr->f_symptr); /* a.out header */ coff.aouthdr = opthdrsz ? (COFF_AOUTHDR*)&coff.src[COFF_FILHSZ] : NULL; /* section header */ coff.scnhdr = (COFF_SCNHDR*)&coff.src[COFF_FILHSZ + opthdrsz]; /* string table */ coff.strtbl = &coff.src[symptr + COFF_SYMESZ * nsyms]; return fd;}static int close_coff(int fd){ munmap(coff.src, coff.size); close(fd); return 0;}static int load_scns(void){ int fd; char *msg; int ret = 0; int i; unsigned short nscns = COFF_SHORT(coff.coffhdr->f_nscns); fd = open(DSPMEMDEVNM, O_RDWR); if (fd < 0) { perror("open dspmem device"); return -1; } for (i = 0; i < nscns; i++) { COFF_SCNHDR *hdr = &coff.scnhdr[i]; unsigned long vaddr, ptr; size_t size; vaddr = COFF_LONG(hdr->s_vaddr); ptr = COFF_LONG(hdr->s_scnptr); size = COFF_LONG(hdr->s_size); switch (get_scntyp(hdr)) { case SCNTYP_CINIT_RAM: /* .cinit will be treated later */ continue; case SCNTYP_NOLOAD: msg = " ... ignored."; break; case SCNTYP_ZEROSZ: case SCNTYP_NODATA: msg = ""; break; case SCNTYP_LOAD: { unsigned char *data; int size_loaded; if (ptr) { data = &coff.src[ptr]; } else { /* .bss */ data = malloc(size); memset(data, 0, size); } size_loaded = load_to_dspmem(fd, vaddr, size, data); if (!ptr) free(data); if (size_loaded == size) { msg = " ... initialized."; } else { msg = " ... initialization failed!!"; ret = -1; } } } printf("%-15s : adr = 0x%06lx, size=%5d %s\n", scnname(hdr), vaddr, size, msg); if (ret < 0) goto finish; } /* RAM Mode .cinit handling */ for (i = 0; i < nscns; i++) { COFF_SCNHDR *hdr = &coff.scnhdr[i]; unsigned long vaddr, ptr; size_t size; if (get_scntyp(hdr) != SCNTYP_CINIT_RAM) continue; vaddr = COFF_LONG(hdr->s_vaddr); ptr = COFF_LONG(hdr->s_scnptr); size = COFF_LONG(hdr->s_size); if (cinit_bss_init(fd, &coff.src[ptr], size) < 0) { msg = " ... .bss variables initialization failed!!"; ret = -1; } else { msg = " ... .bss variables are initialized."; } printf("%-15s : adr = 0x%06lx, size=%5d %s\n", scnname(hdr), vaddr, size, msg); if (ret < 0) goto finish; }finish: close(fd); return ret;}static char *scnname(COFF_SCNHDR *hdr){ static char nm[9]; if (hdr->s_name[0] == 0) { unsigned long idx = COFF_LONG((&hdr->s_name[4])); return &coff.strtbl[idx]; } else { strncpy(nm, hdr->s_name, 8); nm[8] = '\0'; return nm; }}static COFF_SCNHDR *find_scn_by_name(char *name){ int i; unsigned short nscns = COFF_SHORT(coff.coffhdr->f_nscns); for (i = 0; i < nscns; i++) { if (!strcmp(scnname(&coff.scnhdr[i]), name)) return &coff.scnhdr[i]; } return NULL;}static enum scntyp get_scntyp(COFF_SCNHDR *hdr){ unsigned long ptr; unsigned long flags; size_t size; ptr = COFF_LONG(hdr->s_scnptr); size = COFF_LONG(hdr->s_size); flags = COFF_LONG(hdr->s_flags); if (size == 0) return SCNTYP_ZEROSZ; if (ptr == 0) { if (flags & COFF_STYP_BSS) return SCNTYP_LOAD; else return SCNTYP_NODATA; } if (flags & (COFF_STYP_DSECT | COFF_STYP_NOLOAD | COFF_STYP_PAD)) return SCNTYP_NOLOAD; if (flags & COFF_STYP_COPY) { if (!strcmp(scnname(hdr), ".cinit")) return SCNTYP_CINIT_RAM; else return SCNTYP_NOLOAD; } return SCNTYP_LOAD;}static int spaceof(unsigned long addr, size_t size){ if ((addr >= DARAM_BASE) && (addr < DARAM_END)) { if (addr + size > DARAM_END) return SPACE_CROSSING; else return SPACE_DARAM; } else if ((addr >= SARAM_BASE) && (addr < SARAM_END)) { if (addr + size > SARAM_END) return SPACE_CROSSING; else return SPACE_SARAM; } else { return SPACE_EXTERN; }}static int load_to_dspmem(int fd, unsigned long addr, size_t size, unsigned char *data){ /* * 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; unsigned char data_bs[size+8], *dst; size_t writesize; unsigned long writeaddr; unsigned char *writesrc; if (spaceof(addr, size) == SPACE_CROSSING) { fprintf(stderr, "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 printf("\n"); printf("addr = %08lx\n", addr); printf("size = %08lx, %x:%x:%x\n", size, size1, size2, size3);#endif writesize = 0; if (size1) {#ifdef DEBUG printf("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 printf("%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 printf("%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 printf("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 printf("%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 printf("%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 printf("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;}static void copy_byteswap(void *dst, void *src, size_t size){ unsigned long *dst_l = dst; unsigned char *src_c = src; size_t size_l = size/4; int i; assert(((unsigned long)dst & 3) == 0); assert((size & 3) == 0); for (i = 0; i < size_l; i++, src_c+=4, dst_l++) { *dst_l = ((unsigned long)src_c[2] << 24) | ((unsigned long)src_c[3] << 16) | ((unsigned long)src_c[0] << 8) | src_c[1]; }}static int cinit_bss_init(int fd, unsigned char *p, size_t size){ int i = 0; while(i < size) { COFF_CINIT *cinit = (COFF_CINIT *)&p[i]; /* size and addr are written in big-endian format */ unsigned short size = COFF_SHORT_H(cinit->size) * 2; /* size in word */ unsigned long addr = COFF_24BIT_H(cinit->addr) * 2; /* addr in word */ unsigned char flags = *cinit->flags; int cnt;#ifdef DEBUG{ int j; printf("\n i=%d, size=%04x, addr=%06lx, flags=%02x\n", i, size, addr, flags); for (j = 0; j < size; j += 2) { printf("%02x: %02x %02x\n", j, cinit->data[j], cinit->data[j+1]); }}#endif if (size == 0) { i+= 2; if (i != size) { fprintf(stderr, "warning: found zero-sized " "cinit entry at 0x%x\n", i-2); } continue; } if ((flags & 0x01) == COFF_CINIT_FLAG_IO) { fprintf(stderr, "We can't handle cinit data for I/O space!\n"); return -1; } cnt = load_to_dspmem(fd, addr, size, cinit->data); if (cnt < size) return -1; i += COFF_CINITSZ + size; } if (i > size) { fprintf(stderr, "cinit data size is inconsistent.\n"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?