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