Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libexec / elf.c
diff --git a/qemu/roms/openhackware/src/libexec/elf.c b/qemu/roms/openhackware/src/libexec/elf.c
new file mode 100644 (file)
index 0000000..ae9f8e0
--- /dev/null
@@ -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;
+}