diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openhackware/src/libexec/xcoff.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/openhackware/src/libexec/xcoff.c')
-rw-r--r-- | qemu/roms/openhackware/src/libexec/xcoff.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/qemu/roms/openhackware/src/libexec/xcoff.c b/qemu/roms/openhackware/src/libexec/xcoff.c new file mode 100644 index 000000000..a9a6da48b --- /dev/null +++ b/qemu/roms/openhackware/src/libexec/xcoff.c @@ -0,0 +1,216 @@ +/* + * <xcoff.c> + * + * Open Hack'Ware BIOS XCOFF executable file loader + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include <stdlib.h> +#include <stdio.h> +#include "bios.h" +#include "exec.h" + +uint32_t fs_inode_get_size (inode_t *inode); + +/* XCOFF executable loader */ +typedef struct COFF_filehdr_t { + uint16_t f_magic; /* magic number */ + uint16_t f_nscns; /* number of sections */ + uint32_t f_timdat; /* time & date stamp */ + uint32_t f_symptr; /* file pointer to symtab */ + uint32_t f_nsyms; /* number of symtab entries */ + uint16_t f_opthdr; /* sizeof(optional hdr) */ + uint16_t f_flags; /* flags */ +} COFF_filehdr_t; + +/* IBM RS/6000 */ +#define U802WRMAGIC 0730 /* writeable text segments **chh** */ +#define U802ROMAGIC 0735 /* readonly sharable text segments */ +#define U802TOCMAGIC 0737 /* readonly text segments and TOC */ + +/* + * Bits for f_flags: + * + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (i.e. no unresolved external + * references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_MINMAL this is a minimal object file (".m") output of fextract + * F_UPDATE this is a fully bound update file, output of ogen + * F_SWABD this file has had its bytes swabbed (in names) + * F_AR16WR this file has the byte ordering of an AR16WR + * (e.g. 11/70) machine + * F_AR32WR this file has the byte ordering of an AR32WR machine + * (e.g. vax and iNTEL 386) + * F_AR32W this file has the byte ordering of an AR32W machine + * (e.g. 3b,maxi) + * F_PATCH file contains "patch" list in optional header + * F_NODF (minimal file only) no decision functions for + * replaced functions + */ + +#define COFF_F_RELFLG 0000001 +#define COFF_F_EXEC 0000002 +#define COFF_F_LNNO 0000004 +#define COFF_F_LSYMS 0000010 +#define COFF_F_MINMAL 0000020 +#define COFF_F_UPDATE 0000040 +#define COFF_F_SWABD 0000100 +#define COFF_F_AR16WR 0000200 +#define COFF_F_AR32WR 0000400 +#define COFF_F_AR32W 0001000 +#define COFF_F_PATCH 0002000 +#define COFF_F_NODF 0002000 + +typedef struct COFF_aouthdr_t { + uint16_t magic; /* type of file */ + uint16_t vstamp; /* version stamp */ + uint32_t tsize; /* text size in bytes, padded to FW bdry */ + uint32_t dsize; /* initialized data " " */ + uint32_t bsize; /* uninitialized data " " */ + uint32_t entry; /* entry pt. */ + uint32_t text_start; /* base of text used for this file */ + uint32_t data_start; /* base of data used for this file */ + uint32_t o_toc; /* address of TOC */ + uint16_t o_snentry; /* section number of entry point */ + uint16_t o_sntext; /* section number of .text section */ + uint16_t o_sndata; /* section number of .data section */ + uint16_t o_sntoc; /* section number of TOC */ + uint16_t o_snloader; /* section number of .loader section */ + uint16_t o_snbss; /* section number of .bss section */ + uint16_t o_algntext; /* .text alignment */ + uint16_t o_algndata; /* .data alignment */ + uint16_t o_modtype; /* module type (??) */ + uint16_t o_cputype; /* cpu type */ + uint32_t o_maxstack; /* max stack size (??) */ + uint32_t o_maxdata; /* max data size (??) */ + char o_resv2[12]; /* reserved */ +} COFF_aouthdr_t; + +#define AOUT_MAGIC 0x010b + +typedef struct COFF_scnhdr_t { + char s_name[8]; /* section name */ + uint32_t s_paddr; /* physical address, aliased s_nlib */ + uint32_t s_vaddr; /* virtual address */ + uint32_t s_size; /* section size */ + uint32_t s_scnptr; /* file ptr to raw data for section */ + uint32_t s_relptr; /* file ptr to relocation */ + uint32_t s_lnnoptr; /* file ptr to line numbers */ + uint16_t s_nreloc; /* number of relocation entries */ + uint16_t s_nlnno; /* number of line number entries */ + uint32_t s_flags; /* flags */ +} COFF_scnhdr_t; + +int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end, + uint32_t loffset) +{ + COFF_filehdr_t fhdr; + COFF_aouthdr_t ahdr; + COFF_scnhdr_t shdr; + void *first, *last; + uint32_t offset; + int i; + + file_seek(file, loffset); + if (fs_read(file, &fhdr, sizeof(COFF_filehdr_t)) < 0) { + ERROR("Cannot load first bloc of file...\n"); + return -1; + } + if (fhdr.f_magic != U802WRMAGIC && fhdr.f_magic != U802ROMAGIC && + fhdr.f_magic != U802TOCMAGIC && fhdr.f_magic != 0x01DF) { + DPRINTF("Not a XCOFF file %02x %08x\n", fhdr.f_magic, + *(uint32_t *)&fhdr.f_magic); + return -2; + } + if (fhdr.f_magic != 0x01DF && (fhdr.f_flags & COFF_F_EXEC) == 0) { + ERROR("Not an executable XCOFF file %02x\n", fhdr.f_flags); + return -2; + } + if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) { + ERROR("AOUT optional error size missmactch in XCOFF file\n"); + return -2; + } + if (fs_read(file, &ahdr, sizeof(COFF_aouthdr_t)) < 0) { + ERROR("Cannot load XCOFF AOUT header...\n"); + return -1; + } + if (ahdr.magic != AOUT_MAGIC) { + ERROR("Invalid AOUT optional header\n"); + return -2; + } +#if 0 // XXX: buggy: this makes NetBSD fail to boot + if (fhdr.f_magic == 0x01DF) { + /* Load embedded file */ + return _bootfile_load(file, dest, entry, end, loffset + + sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t) + + (fhdr.f_nscns * sizeof(COFF_scnhdr_t)), + -1); + } +#endif + *entry = (void *)ahdr.entry + 0xC; + last = NULL; + first = last - 4; + offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t); + DPRINTF("XCOFF file with %d sections entry:%p\n", fhdr.f_nscns, *entry); + for (i = 0; i < fhdr.f_nscns; i++) { + DPRINTF("Read next header (%0x)\n", offset); + file_seek(file, offset + loffset); + if (fs_read(file, &shdr, sizeof(COFF_scnhdr_t)) < 0) { + ERROR("Cannot load section header %d...\n", i); + return -1; + } + if (strcmp(shdr.s_name, ".text") == 0 || + strcmp(shdr.s_name, ".data") == 0) { + if ((void *)shdr.s_vaddr < first) + first = (void *)shdr.s_vaddr; + if ((void *)shdr.s_vaddr > last) + last = (void *)shdr.s_vaddr; + DPRINTF("Load '%s' section from %0x %0x to %0x (%0x)\n", + shdr.s_name, offset, shdr.s_scnptr, + shdr.s_vaddr, shdr.s_size); +#if 0 + if (shdr.s_scnptr + shdr.s_size > fs_inode_get_size(file)) { + ERROR("Section %d data offset > file size\n", i); + return -1; + } +#endif + file_seek(file, shdr.s_scnptr + loffset); + set_loadinfo((void *)first, last - first); + if (fs_read(file, (void *)shdr.s_vaddr, shdr.s_size) < 0) { + ERROR("Cannot load section %d...\n", i); + return -1; + } + } else if (strcmp(shdr.s_name, ".bss") == 0) { + if ((void *)shdr.s_vaddr < first) + first = (void *)shdr.s_vaddr; + if ((void *)shdr.s_vaddr > last) + last = (void *)shdr.s_vaddr; + DPRINTF("Erase '%s' section at %0x size: %0x\n", + shdr.s_name, shdr.s_vaddr, shdr.s_size); + memset((void *)shdr.s_vaddr, 0, shdr.s_size); + } else { + DPRINTF("Skip '%s' section\n", shdr.s_name); + } + offset += sizeof(COFF_scnhdr_t); + } + *dest = first; + *end = last; + + return 0; +} |