diff options
Diffstat (limited to 'qemu/roms/openhackware/src/libexec/elf.c')
-rw-r--r-- | qemu/roms/openhackware/src/libexec/elf.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/qemu/roms/openhackware/src/libexec/elf.c b/qemu/roms/openhackware/src/libexec/elf.c new file mode 100644 index 000000000..ae9f8e00e --- /dev/null +++ b/qemu/roms/openhackware/src/libexec/elf.c @@ -0,0 +1,239 @@ +/* + * <elf.c> + * + * Open Hack'Ware BIOS ELF 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); + +/* ELF executable loader */ +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Addr; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr_t { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr_t; + +typedef struct elf32_phdr_t { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr_t; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ +#define EM_SH 42 /* SuperH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* HP/Intel IA-64 */ +#define EM_X86_64 62 /* AMD x86-64 */ +#define EM_S390 22 /* IBM S/390 */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_V850 87 /* NEC v850 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 +/* Bogus old v850 magic number, used by old tools. */ +#define EM_CYGNUS_V850 0x9080 +/* + * This is the old interim value for S/390 architecture + */ +#define EM_S390_OLD 0xA390 + +int exec_load_elf (inode_t *file, void **dest, void **entry, void **end, + uint32_t loffset) +{ + Elf32_Ehdr_t ehdr; + Elf32_Phdr_t phdr; + void *address, *first, *last; + uint32_t offset, fsize, msize; + int i; + + file_seek(file, loffset); + if (fs_read(file, &ehdr, sizeof(Elf32_Ehdr_t)) < 0) { + ERROR("Cannot load first bloc of file...\n"); + return -1; + } + DPRINTF("Check ELF file\n"); + /* Check ident */ + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || + ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || + ehdr.e_ident[EI_MAG3] != ELFMAG3) { + DPRINTF("Not an ELF file %0x\n", *(uint32_t *)ehdr.e_ident); + return -2; + } + if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { + ERROR("Not a 32 bits ELF file\n"); + return -2; + } + if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { + ERROR("Not a big-endian ELF file\n"); + return -2; + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT /*|| + ehdr->e_version != EV_CURRENT*/) { + ERROR("Invalid ELF executable version %d %08x\n", + ehdr.e_ident[EI_VERSION], ehdr.e_version); + return -2; + } + if (ehdr.e_type != ET_EXEC) { + ERROR("Not an executable ELF file\n"); + return -2; + } + if (ehdr.e_machine != EM_PPC) { + ERROR("Not a PPC ELF executable\n"); + return -2; + } + /* All right, seems to be a regular ELF program for PPC */ + *entry = (void *)ehdr.e_entry; + DPRINTF("ELF file found entry = %p\n", *entry); + last = NULL; + first = last - 4; + fsize = msize = 0; + offset = ehdr.e_phoff; + for (i = 0; i < ehdr.e_phnum; i++) { +#if 0 + if (offset > fs_inode_get_size(file)) { + ERROR("ELF program header %d offset > file size %d %d\n", i, + offset, fs_inode_get_size(file)); + return -1; + } +#endif + DPRINTF("Load program header %d from %08x\n", i, offset); + file_seek(file, offset + loffset); + if (fs_read(file, &phdr, sizeof(Elf32_Phdr_t)) < 0) { + ERROR("Cannot load ELF program header %d...\n", i); + return -1; + } + DPRINTF("Load program header %d %08x %08x %08x %08x\n", i, + phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz); +#if 0 + if (phdr.p_offset > fs_inode_get_size(file)) { + ERROR("ELF program %d offset > file size %d %d\n", + i, phdr.p_offset, fs_inode_get_size(file)); + return -1; + } +#endif + /* As we won't remap memory, load it at it's virtual address (!) */ + address = (void *)phdr.p_vaddr; + if (address < first) + first = address; + fsize = phdr.p_filesz; + msize = phdr.p_memsz; + if (address + msize > last) + last = address + msize; + file_seek(file, phdr.p_offset + loffset); + set_loadinfo((void *)first, last - first); + if (fs_read(file, address, fsize) < 0) { + ERROR("Cannot load ELF program %d...\n", i); + return -1; + } + if (msize > fsize) { + memset(address + fsize, 0, msize - fsize); + } + offset += ehdr.e_phentsize; + } + *dest = (void *)first; + *end = (void *)last; + DPRINTF("ELF file loaded at %p => %p fsize %08x msize %08x " + "(%08x %08x)\n", *dest, *entry, fsize, msize, + *(uint32_t *)entry, *((uint32_t *)entry + 1)); + + return 0; +} |