summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openhackware/src/libexec
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/openhackware/src/libexec
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (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')
-rw-r--r--qemu/roms/openhackware/src/libexec/chrp.c404
-rw-r--r--qemu/roms/openhackware/src/libexec/core.c151
-rw-r--r--qemu/roms/openhackware/src/libexec/elf.c239
-rw-r--r--qemu/roms/openhackware/src/libexec/exec.h40
-rw-r--r--qemu/roms/openhackware/src/libexec/macho.c517
-rw-r--r--qemu/roms/openhackware/src/libexec/pef.c307
-rw-r--r--qemu/roms/openhackware/src/libexec/prep.c45
-rw-r--r--qemu/roms/openhackware/src/libexec/xcoff.c216
8 files changed, 1919 insertions, 0 deletions
diff --git a/qemu/roms/openhackware/src/libexec/chrp.c b/qemu/roms/openhackware/src/libexec/chrp.c
new file mode 100644
index 000000000..9a2be2ea8
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/chrp.c
@@ -0,0 +1,404 @@
+/*
+ * <chrp.c>
+ *
+ * Open Hack'Ware BIOS CHRP boot 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 <ctype.h>
+#include "bios.h"
+#include "exec.h"
+#include "libfs/libfs.h"
+
+/* Simple XML parser */
+typedef struct XML_tag_t XML_tag_t;
+struct XML_tag_t {
+ unsigned char *name;
+ XML_tag_t *up;
+ int dlen;
+ void *data;
+};
+
+enum {
+ CHRP_TAG_UNKNOWN = 0,
+ CHRP_TAG_CHRP_BOOT,
+ CHRP_TAG_COMPATIBLE,
+ CHRP_TAG_DESCRIPTION,
+ CHRP_TAG_BOOT_SCRIPT,
+ CHRP_TAG_OS_BADGE_ICONS,
+ CHRP_TAG_ICON,
+ CHRP_TAG_BITMAP,
+ CHRP_TAG_LICENSE,
+};
+
+enum {
+ CHRP_SCRIPT_IGNORE = 0,
+ CHRP_SCRIPT_LOAD_BOOT,
+ CHRP_SCRIPT_EMBEDDED,
+};
+
+enum {
+ XML_STATE_OUT = 0,
+ XML_STATE_TAG,
+ XML_STATE_DATA,
+};
+
+static int XML_get_type (const unsigned char *name)
+{
+ int ret;
+
+ if (strcmp(name, "CHRP-BOOT") == 0)
+ ret = CHRP_TAG_CHRP_BOOT;
+ else if (strcmp(name, "COMPATIBLE") == 0)
+ ret = CHRP_TAG_COMPATIBLE;
+ else if (strcmp(name, "DESCRIPTION") == 0)
+ ret = CHRP_TAG_DESCRIPTION;
+ else if (strcmp(name, "BOOT-SCRIPT") == 0)
+ ret = CHRP_TAG_BOOT_SCRIPT;
+ else if (strcmp(name, "OS-BADGE-ICONS") == 0)
+ ret = CHRP_TAG_OS_BADGE_ICONS;
+ else if (strcmp(name, "ICON") == 0)
+ ret = CHRP_TAG_ICON;
+ else if (strcmp(name, "BITMAP") == 0)
+ ret = CHRP_TAG_BITMAP;
+ else if (strcmp(name, "LICENSE") == 0)
+ ret = CHRP_TAG_LICENSE;
+ else
+ ret = CHRP_TAG_UNKNOWN;
+
+ return ret;
+}
+
+static unsigned char *strfind (const unsigned char *buf, const unsigned char *str)
+{
+ const unsigned char *pos;
+ int len = strlen(str);
+
+ // DPRINTF("Look for '%s' in \n'%s'\n", str, buf);
+ for (pos = buf; *pos != '\0'; pos++) {
+ if (memcmp(pos, str, len) == 0)
+ return (unsigned char *)pos;
+ }
+
+ return NULL;
+}
+
+int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+#define TMPNAME_LEN 512
+ unsigned char tmpname[TMPNAME_LEN], *tmpp, *buf, *pos, *endc, c;
+ XML_tag_t *tag, *tmp, *first;
+ part_t *part;
+ inode_t *inode;
+ int state;
+ int script_type = CHRP_SCRIPT_IGNORE;
+ uint32_t crc, offset = 0;
+ int ret, rel = 0;
+
+ buf = malloc(16384);
+ /* Check the file head */
+ file_seek(file, loffset);
+ fs_read(file, buf, 11);
+ if (memcmp(buf, "<CHRP-BOOT>", 11) != 0) {
+ ERROR("Not an Apple CHRP boot file !\n");
+ return -2;
+ }
+ /* Re-seek at start of the file and start parsing it */
+ file_seek(file, loffset);
+ pos = buf;
+ tag = NULL;
+ first = NULL;
+ ret = -1;
+ fs_read(file, &c, 1);
+ offset++;
+ for (state = XML_STATE_TAG; state != XML_STATE_OUT;) {
+ /* Get next char */
+ fs_read(file, &c, 1);
+ offset++;
+ if ((state == XML_STATE_TAG && c != '>') ||
+ (state == XML_STATE_DATA && c != '<')) {
+ *pos++ = c;
+ continue;
+ }
+ *pos++ = '\0';
+ switch (state) {
+ case XML_STATE_TAG:
+ if (*buf == '/') {
+ if (tag == NULL || strcmp(buf + 1, tag->name) != 0) {
+ ERROR("XML error: open name: '%s' close name: '%s'\n",
+ buf + 1, tag->name);
+ goto out;
+ }
+ DPRINTF("Close tag: '%s'\n", tag->name);
+ switch (XML_get_type(tag->name)) {
+ case CHRP_TAG_CHRP_BOOT:
+ /* Nothing to do */
+ break;
+ case CHRP_TAG_COMPATIBLE:
+ /* Won't check... */
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("Compatible: '%s'\n", pos);
+ break;
+ case CHRP_TAG_DESCRIPTION:
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("Description: '%s'\n", pos);
+ break;
+ case CHRP_TAG_BOOT_SCRIPT:
+ /* Here is the interresting part... */
+ crc = crc32(0, tag->data, tag->dlen);
+#if 0
+ DPRINTF("Forth script: %08x\n%s\n",
+ crc, (char *)tag->data);
+#endif
+ switch (crc) {
+ case 0x5464F92C:
+ /* Mandrake 9.1 CD1 boot script */
+ case 0x4BC74ECF:
+ /* Mandrake 10.1 & 10.2 CD1 boot script */
+ case 0x5B265246:
+ /* Gentoo 1.2-r1 */
+ /* Gentoo 2004.1 minimal install CD */
+ /* Gentoo 1.4 live CDROM */
+ /* Knopix PPC beta-pre12 */
+ case 0x75420D8A:
+ /* Debian woody */
+ /* Debian 3.0r1 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x633e4c9c:
+ /* Debian Sarge */
+ case 0xbe3abf60:
+ /* Debian Sarge, installed on a hard disk drive */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x07b86bfe:
+ /* Linux Fedora Core 3 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x9ccdf371:
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0xEF423926:
+ /* OpenBSD 3.4 */
+ case 0x68e4f265:
+ /* OpenBSD 3.5 */
+ case 0x3b7ea9e1:
+ /* OpenBSD 3.6 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0xB7981DBC:
+ /* iBook 2 hw test CDROM */
+#if 1
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+#endif
+
+ case 0xEA06C1A7:
+ /* MacOS 9.2 boot script:
+ * the XCOFF loader is embedded in the file...
+ */
+ case 0x53A95958:
+ /* iBook 2 restore CD (MacOS X 10.2) */
+ script_type = CHRP_SCRIPT_EMBEDDED;
+ pos = strfind(tag->data, "elf-offset");
+ if (pos != NULL) {
+ /* Go backward until we get the value */
+ for (--pos; *pos < '0' || *pos > '9'; pos--)
+ continue;
+ for (; *pos >= '0' && *pos <= '9'; pos--)
+ continue;
+ offset = strtol(pos, NULL, 16);
+ goto do_script;
+ }
+ ERROR("Didn't find boot file offset\n");
+ goto out;
+ case 0x8d5acb86:
+ /* Darwin-7.01
+ * The executable file is embedded after the script
+ */
+ script_type = CHRP_SCRIPT_EMBEDDED;
+ DPRINTF("Boot file embedded at the end of boot script\n");
+ break;
+ default:
+ ERROR("XML error: unknown Forth script: %08x\n%s\n",
+ crc, (char *)tag->data);
+ goto out;
+ }
+ break;
+
+ do_script:
+ switch (script_type) {
+ case CHRP_SCRIPT_LOAD_BOOT:
+ pos = strfind(tag->data, "boot");
+ if (pos != NULL) {
+ /* Eat everything until file name */
+ for (pos += 4; *pos != ','; pos++)
+ continue;
+ /* Eat ',' */
+ for (++pos; isspace(*pos) || *pos == '"'; pos++)
+ continue;
+ /* Find file name end */
+ redo:
+ for (endc = pos;
+ *endc != ' ' && *endc != '"' &&
+ *endc != '\n' && *endc != '\r';
+ endc++) {
+ if (*endc == '\\')
+ *endc = '/';
+ }
+ if (memcmp(pos, "ofwboot", 7) == 0) {
+ for (pos = endc + 1; *pos == ' '; pos++)
+ continue;
+ goto redo;
+ }
+ *endc = '\0';
+ }
+ DPRINTF("Real boot file is: '%s'\n", pos);
+ part = fs_inode_get_part(file);
+ /* check if it's a path or just a file */
+ tmpp = pos;
+ if ((pos[0] == '/' && pos[1] == '/') ||
+ pos[0] != '/') {
+ unsigned char *bootdir;
+ bootdir = fs_get_boot_dirname(part_fs(part));
+ if (bootdir == NULL) {
+ ERROR("Cannot get boot directory name\n");
+ bug();
+ }
+ snprintf(tmpname, TMPNAME_LEN,
+ "%s/%s", bootdir, pos);
+ tmpname[TMPNAME_LEN - 1] = '\0';
+ rel++;
+ pos = tmpname;
+ DPRINTF("'%s' => '%s'\n", bootdir, pos);
+ }
+ retry:
+ inode = fs_open(part_fs(part), pos);
+ if (inode == NULL) {
+ ERROR("Real boot inode '%s' not found\n", pos);
+ /* Try in root directory */
+ if (rel == 1) {
+ for (; *tmpp == '/'; tmpp++)
+ continue;
+ snprintf(tmpname, TMPNAME_LEN, "/%s", tmpp);
+ tmpname[TMPNAME_LEN - 1] = '\0';
+ rel++;
+ goto retry;
+ }
+
+ bug();
+ }
+ ret = _bootfile_load(inode, dest, entry, end, 0, -1);
+ fs_close(inode);
+ goto out;
+ case CHRP_SCRIPT_EMBEDDED:
+ DPRINTF("Exec offset: %d %08x\n", offset, offset);
+ ret = 0;
+ goto out;
+ case CHRP_SCRIPT_IGNORE:
+ break;
+ }
+ break;
+ case CHRP_TAG_OS_BADGE_ICONS:
+ case CHRP_TAG_ICON:
+ /* Ignore it */
+ break;
+ case CHRP_TAG_BITMAP:
+ /* Ignore it */
+ break;
+ case CHRP_TAG_LICENSE:
+ /* Ignore it */
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("License: '%s'\n", pos);
+ break;
+ default:
+ ERROR("XML error: unknown tag: '%s'\n", tag->name);
+ goto out;
+ }
+ tmp = tag->up;
+ if (tmp == NULL)
+ state = XML_STATE_OUT;
+ else
+ state = XML_STATE_DATA;
+ free(tag->name);
+ free(tag->data);
+ free(tag);
+ tag = tmp;
+ } else {
+ tmp = malloc(sizeof(XML_tag_t));
+ if (tmp == NULL) {
+ ERROR("Cannot allocate new tag\n");
+ goto out;
+ }
+ tmp->up = tag;
+ /* Ignore tag attributes */
+ pos = strchr(buf, ' ');
+ if (pos != NULL)
+ *pos = '\0';
+ tmp->name = strdup(buf);
+ tag = tmp;
+ if (first == NULL)
+ first = tag;
+ DPRINTF("Open tag '%s'\n", tag->name);
+ state = XML_STATE_DATA;
+ }
+ break;
+ case XML_STATE_DATA:
+ if (tag->data == NULL) {
+ tag->dlen = pos - buf;
+ tag->data = malloc(tag->dlen);
+ memcpy(tag->data, buf, tag->dlen);
+ }
+ state = XML_STATE_TAG;
+ break;
+ }
+ pos = buf;
+ }
+ ret = 0;
+ fs_read(file, &c, 1);
+ fs_read(file, &c, 1);
+ offset += 2;
+ out:
+#if 1
+ for (; tag != NULL; tag = tmp) {
+ tmp = tag->up;
+ free(tag->name);
+ free(tag->data);
+ free(tag);
+ }
+#endif
+ if (ret == 0 && script_type == CHRP_SCRIPT_EMBEDDED) {
+ DPRINTF("Load embedded file from offset %d (%d => %d)\n",
+ offset, loffset, loffset + offset);
+ ret = _bootfile_load(file, dest, entry, end, loffset + offset, -1);
+ }
+ DPRINTF("Done\n");
+
+ return ret;
+}
diff --git a/qemu/roms/openhackware/src/libexec/core.c b/qemu/roms/openhackware/src/libexec/core.c
new file mode 100644
index 000000000..222a29a8c
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/core.c
@@ -0,0 +1,151 @@
+/*
+ * <file.c>
+ *
+ * Open Hack'Ware BIOS 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 file_seek (inode_t *file, uint32_t pos)
+{
+ uint32_t blocsize, bloc, offset;
+
+ if (file == NULL)
+ return -1;
+ blocsize = part_blocsize(fs_inode_get_part(file));
+ bloc = pos / blocsize;
+ offset = pos % blocsize;
+
+ return fs_seek(file, bloc, offset);
+}
+
+/*****************************************************************************/
+/* Executable file loaders */
+
+enum {
+ FILE_TYPE_ELF = 0,
+ FILE_TYPE_XCOFF,
+ FILE_TYPE_MACHO,
+ FILE_TYPE_PEF,
+ FILE_TYPE_CHRP,
+ FILE_TYPE_PREP,
+ FILE_TYPE_FLAT,
+};
+
+uint32_t fs_inode_get_size (inode_t *inode);
+unsigned int part_get_entry (part_t *part);
+/*****************************************************************************/
+/* Generic boot file loader */
+int _bootfile_load (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset, int type)
+{
+ int (*do_load)(inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+ uint32_t size;
+ int ret;
+ int i;
+
+ if (type == -1)
+ i = 0;
+ else
+ i = type;
+ for (;; i++) {
+ switch (i) {
+ case FILE_TYPE_ELF:
+ do_load = &exec_load_elf;
+ break;
+ case FILE_TYPE_XCOFF:
+ do_load = &exec_load_xcoff;
+ break;
+ case FILE_TYPE_MACHO:
+ do_load = &exec_load_macho;
+ break;
+ case FILE_TYPE_PEF:
+ do_load = &exec_load_pef;
+ break;
+ case FILE_TYPE_CHRP:
+ do_load = &exec_load_chrp;
+ break;
+ case FILE_TYPE_PREP:
+ do_load = &exec_load_prep;
+ break;
+ default:
+ if (*dest == NULL)
+ *dest = (void *)DEFAULT_LOAD_DEST;
+ if (*entry == NULL) {
+ if (part_get_entry(fs_inode_get_part(file)) != 0 || 1) {
+ *entry = (char *)*dest +
+ part_get_entry(fs_inode_get_part(file));
+ dprintf("dest %p entry %08x => %p\n",
+ *dest, part_get_entry(fs_inode_get_part(file)),
+ *entry);
+ } else {
+ *entry = *dest + 0xC;
+ }
+ }
+ size = fs_inode_get_size(file);
+ *end = (char *)*dest + size - loffset;
+ printf("Load raw file into memory at %p %d (%08x) %d (%08x)\n",
+ *dest, size, size, loffset, loffset);
+ file_seek(file, loffset);
+ set_loadinfo(*dest, size);
+ if ((uint32_t)fs_read(file, *dest, size) != size) {
+ ERROR("Error loading file...\n");
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+ goto out;
+ }
+ DPRINTF("Check file type %d at offset %d %p\n", i, loffset, do_load);
+ ret = (*do_load)(file, dest, entry, end, loffset);
+ if (ret >= -1 || type == i) {
+ if (type == i)
+ ret = -2;
+ break;
+ }
+ }
+ out:
+
+ return ret;
+}
+
+int bootfile_load (void **dest, void **entry, void **end,
+ part_t *part, int type, const unsigned char *fname,
+ uint32_t loffset)
+{
+ inode_t *file;
+ int ret;
+
+ DPRINTF("Load file '%s' %p %p type: %d offset: %0x => %d %p\n",
+ fname, part, part_fs(part), type, loffset, part_blocsize(part), *dest);
+ if (fname == NULL)
+ file = fs_get_bootfile(part_fs(part));
+ else
+ file = fs_open(part_fs(part), fname);
+ if (file == NULL)
+ return -1;
+ ret = _bootfile_load(file, dest, entry, end, loffset, type);
+ fs_close(file);
+
+ return ret;
+}
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;
+}
diff --git a/qemu/roms/openhackware/src/libexec/exec.h b/qemu/roms/openhackware/src/libexec/exec.h
new file mode 100644
index 000000000..46f138fdf
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/exec.h
@@ -0,0 +1,40 @@
+/*
+ * <exec.h>
+ *
+ * Open Hack'Ware BIOS: executable files loader definitions
+ *
+ * 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
+ */
+
+#if !defined(__OHW_EXEC_H__)
+#define __OHW_EXEC_H__
+
+int _bootfile_load (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset, int type);
+int exec_load_elf (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_pef (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_prep (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+
+#endif /* !defined(__OHW_EXEC_H__) */
diff --git a/qemu/roms/openhackware/src/libexec/macho.c b/qemu/roms/openhackware/src/libexec/macho.c
new file mode 100644
index 000000000..f07c92144
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/macho.c
@@ -0,0 +1,517 @@
+/*
+ * <macho.c>
+ *
+ * Open Hack'Ware BIOS MACH-O 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"
+
+/* MACH-O executable loader */
+/* FAT definitions */
+/* CPU type definitions */
+typedef enum cpu_type_t {
+ CPU_TYPE_ANY = -1,
+ CPU_TYPE_VAX = 1,
+ CPU_TYPE_MC680x0 = 6,
+ CPU_TYPE_I386 = 7,
+ CPU_TYPE_MIPS = 8,
+ CPU_TYPE_MC98000 = 10,
+ CPU_TYPE_HPPA = 11,
+ CPU_TYPE_ARM = 12,
+ CPU_TYPE_MC88000 = 13,
+ CPU_TYPE_SPARC = 14,
+ CPU_TYPE_I860 = 15,
+ CPU_TYPE_ALPHA = 16,
+ CPU_TYPE_POWERPC = 18,
+} cpu_type_t;
+
+/* Any CPU */
+typedef enum cpu_subtype_any_t {
+ CPU_SUBTYPE_MULTIPLE = -1,
+ CPU_SUBTYPE_LITTLE_ENDIAN = 0,
+ CPU_SUBTYPE_BIG_ENDIAN = 1,
+} cpu_subtype_any_t;
+
+/* PowerPC */
+typedef enum cpu_subtype_ppc_t {
+ CPU_SUBTYPE_PPC_ALL = 0,
+ CPU_SUBTYPE_PPC_601 = 1,
+ CPU_SUBTYPE_PPC_602 = 2,
+ CPU_SUBTYPE_PPC_603 = 3,
+ CPU_SUBTYPE_PPC_603e = 4,
+ CPU_SUBTYPE_PPC_603ev = 5,
+ CPU_SUBTYPE_PPC_604 = 6,
+ CPU_SUBTYPE_PPC_604e = 7,
+ CPU_SUBTYPE_PPC_620 = 8,
+ CPU_SUBTYPE_PPC_750 = 9,
+ CPU_SUBTYPE_PPC_7400 = 10,
+ CPU_SUBTYPE_PPC_7450 = 11,
+} cpu_subtype_ppc_t;
+
+/* Fat header definition */
+#define FAT_MAGIC 0xCAFEBABE
+
+typedef struct fat_head_t {
+ uint32_t magic;
+ uint32_t nfat_arch;
+} fat_head_t;
+
+typedef struct fat_arch_t {
+ cpu_type_t cpu_type;
+ cpu_subtype_ppc_t cpu_subtype;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t align;
+} fat_arch_t;
+
+/* Mach-O binary definitions */
+#define MACH_O_MAGIC 0xFEEDFACE
+
+typedef enum filetype_t {
+ MH_OBJECT = 0x1,
+ MH_EXECUTE = 0x2,
+ MH_FVMLIB = 0x3,
+ MH_CORE = 0x4,
+ MH_PRELOAD = 0x5,
+ MH_DYLIB = 0x6,
+ MH_DYLINKER = 0x7,
+ MH_BUNDLE = 0x8,
+} filetype_t;
+
+enum {
+ MH_NOUNDEFS = 0x01,
+ MH_INCRLINK = 0x02,
+ MH_DYLDLINK = 0x04,
+ MH_BINDATLOAD = 0x08,
+ MH_PREBOUND = 0x10,
+};
+
+typedef struct mach_head_t {
+ uint32_t magic;
+ cpu_type_t cpu_type;
+ cpu_subtype_ppc_t subtype;
+ filetype_t file_type;
+ uint32_t nb_cmds;
+ uint32_t cmds_size;
+ uint32_t flags;
+} mach_head_t;
+
+typedef enum load_cmd_t {
+ LC_SEGMENT = 0x01,
+ LC_SYMTAB = 0x02,
+ LC_SYMSEG = 0x03,
+ LC_THREAD = 0x04,
+ LC_UNIXTHREAD = 0x05,
+ LC_LOADFVMLIB = 0x06,
+ LC_IDFVMLIB = 0x07,
+ LC_IDENT = 0x08,
+ LC_FVMFILE = 0x09,
+ LC_PREPAGE = 0x0A,
+ LC_DYSYMTAB = 0x0B,
+ LC_LOAD_DYLIB = 0x0C,
+ LC_ID_DYLIB = 0x0D,
+ LC_LOAD_DYLINKER = 0x0E,
+ LC_ID_DYLINKER = 0x0F,
+ LC_PREBOUND_DYLIB = 0x10,
+ LC_0x17 = 0x17,
+} load_cmd_t;
+
+typedef struct mach_load_cmd_t {
+ load_cmd_t cmd;
+ uint32_t cmd_size;
+} mach_load_cmd_t;
+
+typedef struct mach_string_t {
+ uint32_t offset;
+} mach_string_t;
+
+enum {
+ SG_HIGHVM = 0x1,
+ SG_FVMLIB = 0x2,
+ SG_NORELOC = 0x4,
+};
+
+typedef struct mach_segment_t {
+ unsigned char segname[16];
+ uint32_t vmaddr;
+ uint32_t vmsize;
+ uint32_t file_offset;
+ uint32_t file_size;
+ uint32_t max_prot;
+ uint32_t init_prot;
+ uint32_t nsects;
+ uint32_t flags;
+} mach_segment_t;
+
+enum {
+ SECTION_TYPE = 0xFF,
+ S_REGULAR = 0x0,
+ S_ZEROFILL = 0x1,
+ S_CSTRING_LITERALS = 0x2,
+ S_4BYTE_LITERALS = 0x3,
+ S_8BYTE_LITERALS = 0x4,
+ S_LITERAL_POINTERS = 0x5,
+ S_NON_LAZY_SYMBOL_POINTERS = 0x6,
+ S_LAZY_SYMBOL_POINTERS = 0x7,
+ S_SYMBOL_STUBS = 0x8,
+ S_MOD_INIT_FUNC_POINTERS = 0x9,
+};
+
+enum {
+ S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
+ S_ATTR_SOME_INSTRUCTIONS = 0x00000400,
+ S_ATTR_EXT_RELOC = 0x00000200,
+ S_ATTR_LOC_RELOC = 0x00000100,
+};
+
+typedef struct mach_section_t {
+ unsigned char sectname[16];
+ unsigned char segname[16];
+ uint32_t vmaddr;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t align;
+ uint32_t reloc_offset;
+ uint32_t nreloc;
+ uint32_t flags;
+ uint32_t res1;
+ uint32_t res2;
+} mach_section_t;
+
+typedef struct mach_symtab_t {
+ uint32_t offset;
+ uint32_t nsyms;
+ uint32_t str_offset;
+ uint32_t str_size;
+} mach_symtab_t;
+
+typedef struct mach_symseg_t {
+ uint32_t offset;
+ uint32_t size;
+} mach_symseg_t;
+
+typedef struct mach_unixth_t {
+ uint32_t flavor;
+ uint32_t count;
+ /* This is supposed to be a stack.
+ * Let's assume it's less than 1kB (arbitrary !)
+ */
+ uint32_t data[256];
+} mach_unixth_t;
+
+typedef struct mach_fvmlib_t {
+ uint32_t str_offset;
+ uint32_t minor_version;
+ uint32_t header_addr;
+} mach_fvmlib_t;
+
+typedef struct mach_fvmfile_t {
+ uint32_t str_offset;
+ uint32_t vmaddr;
+} mach_fvmfile_t;
+
+typedef struct mach_dysymtab_t {
+ uint32_t ilocal_syms;
+ uint32_t nlocal_syms;
+ uint32_t iext_syms;
+ uint32_t next_syms;
+ uint32_t iundef_syms;
+ uint32_t nundef_syms;
+ uint32_t toc_offset;
+ uint32_t ntoc;
+ uint32_t modtab_offset;
+ uint32_t nmodtab;
+ uint32_t extsym_offset;
+ uint32_t nextsym;
+ uint32_t indirect_offset;
+ uint32_t nindirect;
+ uint32_t ext_reloc_offset;
+ uint32_t next_reloc;
+ uint32_t local_reloc_offset;
+ uint32_t nlocal_reloc;
+} mach_dysymtab_t;
+
+typedef struct mach_dylib_t {
+ uint32_t str_offset;
+ uint32_t timestamp;
+ uint32_t cur_version;
+ uint32_t compat_version;
+} mach_dylib_t;
+
+typedef struct mach_prebound_t {
+ uint32_t str_offset;
+ uint32_t nb_modules;
+ unsigned char linked_modules[256];
+} mach_prebound_t;
+
+int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ mach_head_t mhdr;
+ mach_load_cmd_t lcmd;
+ fat_head_t fhdr;
+ fat_arch_t fahdr;
+ void *address, *first, *last;
+ uint32_t k, j, best, offset;
+ int entry_set;
+
+ /* Probe FAT */
+ file_seek(file, loffset);
+ if (fs_read(file, &fhdr, sizeof(fat_head_t)) < 0) {
+ ERROR("Cannot load fat header...\n");
+ return -1;
+ }
+ fhdr.magic = get_be32(&fhdr.magic);
+ if (fhdr.magic != FAT_MAGIC)
+ goto macho_probe;
+ fhdr.nfat_arch = get_be32(&fhdr.nfat_arch);
+ DPRINTF("FAT file: %d archs\n", fhdr.nfat_arch);
+ /* Find the best architecture */
+ best = -1;
+ offset = 0;
+ for (k = 0; k < fhdr.nfat_arch; k++) {
+ if (fs_read(file, &fahdr, sizeof(fat_arch_t)) < 0) {
+ ERROR("Cannot load fat arch header\n");
+ return -1;
+ }
+ fahdr.cpu_type = get_be32(&fahdr.cpu_type);
+ if (fahdr.cpu_type != CPU_TYPE_POWERPC)
+ continue;
+ fahdr.cpu_subtype = get_be32(&fahdr.cpu_subtype);
+ fahdr.offset = get_be32(&fahdr.offset);
+ fahdr.size = get_be32(&fahdr.size);
+ fahdr.align = get_be32(&fahdr.align);
+ switch (fahdr.cpu_subtype) {
+ case CPU_SUBTYPE_PPC_750:
+ best = k;
+ offset = fahdr.offset;
+ goto fat_cpu_ok;
+ case CPU_SUBTYPE_PPC_ALL:
+ if (best == (uint32_t)-1) {
+ offset = fahdr.offset;
+ best = k;
+ }
+ break;
+ case CPU_SUBTYPE_PPC_603:
+ case CPU_SUBTYPE_PPC_603e:
+ case CPU_SUBTYPE_PPC_603ev:
+ case CPU_SUBTYPE_PPC_604:
+ case CPU_SUBTYPE_PPC_604e:
+ best = k;
+ offset = fahdr.offset;
+ break;
+ default:
+ break;
+ }
+ }
+ if (best == (uint32_t)-1) {
+ ERROR("No matching PPC FAT arch\n");
+ return -1;
+ }
+ DPRINTF("Use FAT arch %d at %08x %08x\n", best, offset, loffset);
+ fat_cpu_ok:
+ loffset += offset;
+
+ /* Probe macho */
+ macho_probe:
+ file_seek(file, loffset);
+ if (fs_read(file, &mhdr, sizeof(mach_head_t)) < 0) {
+ ERROR("Cannot load MACH-O header...\n");
+ return -1;
+ }
+ mhdr.magic = get_be32(&mhdr.magic);
+ if (mhdr.magic != MACH_O_MAGIC) {
+ ERROR("Not a MACH-O file\n");
+ return -2;
+ }
+ mhdr.cpu_type = get_be32(&mhdr.cpu_type);
+ mhdr.subtype = get_be32(&mhdr.subtype);
+ mhdr.file_type = get_be32(&mhdr.file_type);
+ mhdr.nb_cmds = get_be32(&mhdr.nb_cmds);
+ mhdr.cmds_size = get_be32(&mhdr.cmds_size);
+ mhdr.flags = get_be32(&mhdr.flags);
+ DPRINTF("MACHO-O file cpu %d %d file type %08x %d cmds size %08x flags "
+ "%08x\n", mhdr.cpu_type, mhdr.subtype, mhdr.file_type,
+ mhdr.nb_cmds, mhdr.cmds_size, mhdr.flags);
+ offset = sizeof(mach_head_t);
+ first = (void *)-1;
+ last = NULL;
+ entry_set = 0;
+ for (k = 0; k < mhdr.nb_cmds; k++) {
+ file_seek(file, loffset + offset);
+ if (fs_read(file, &lcmd, sizeof(mach_load_cmd_t)) < 0) {
+ ERROR("Unable to load MACH-O cmd %d\n", k);
+ return -1;
+ }
+ lcmd.cmd = get_be32(&lcmd.cmd);
+ lcmd.cmd_size = get_be32(&lcmd.cmd_size);
+ DPRINTF("Cmd %d : %08x size %08x (%08x %08x)\n", k, lcmd.cmd,
+ lcmd.cmd_size, offset, offset + loffset);
+ switch (lcmd.cmd) {
+ case LC_SEGMENT:
+ /* To be loaded for execution */
+ {
+ mach_segment_t segment;
+ mach_section_t section;
+ uint32_t pos;
+
+ pos = offset + sizeof(mach_load_cmd_t);
+ if (fs_read(file, &segment, sizeof(mach_segment_t)) < 0) {
+ ERROR("Cannot load MACH-O segment\n");
+ return -1;
+ }
+ pos += sizeof(mach_segment_t);
+ segment.vmaddr = get_be32(&segment.vmaddr);
+ segment.vmsize = get_be32(&segment.vmsize);
+ segment.file_offset = get_be32(&segment.file_offset);
+ segment.file_size = get_be32(&segment.file_size);
+ segment.max_prot = get_be32(&segment.max_prot);
+ segment.init_prot = get_be32(&segment.init_prot);
+ segment.nsects = get_be32(&segment.nsects);
+ segment.flags = get_be32(&segment.flags);
+ DPRINTF("MACH-O segment addr %08x size %08x off %08x fsize "
+ "%08x ns %d fl %08x\n", segment.vmaddr, segment.vmsize,
+ segment.file_offset, segment.file_size,
+ segment.nsects, segment.flags);
+ for (j = 0; j < segment.nsects; j++) {
+ file_seek(file, loffset + pos);
+ if (fs_read(file, &section, sizeof(mach_section_t)) < 0) {
+ ERROR("Cannot load MACH-O section\n");
+ return -1;
+ }
+ pos += sizeof(mach_section_t);
+ section.vmaddr = get_be32(&section.vmaddr);
+ section.size = get_be32(&section.size);
+ section.offset = get_be32(&section.offset);
+ section.align = get_be32(&section.align);
+ section.reloc_offset = get_be32(&section.reloc_offset);
+ section.nreloc = get_be32(&section.nreloc);
+ section.flags = get_be32(&section.flags);
+ section.res1 = get_be32(&section.res1);
+ section.res2 = get_be32(&section.res2);
+ DPRINTF("MACH-O section vmaddr %08x size %08x off %08x "
+ "flags %08x\n", section.vmaddr, section.size,
+ section.offset, section.flags);
+ switch (section.flags & SECTION_TYPE) {
+ case S_REGULAR:
+ case S_CSTRING_LITERALS:
+ case S_4BYTE_LITERALS:
+ case S_8BYTE_LITERALS:
+ case S_LITERAL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_SYMBOL_STUBS:
+ case S_MOD_INIT_FUNC_POINTERS:
+ DPRINTF("Load section of type %d from %08x to %08x"
+ " %08x\n", section.flags, section.offset,
+ section.vmaddr, section.size);
+ file_seek(file, section.offset + loffset);
+ address = (void *)section.vmaddr;
+ if (address < first && address != NULL)
+ first = address;
+ if (address + section.size > last)
+ last = address + section.size;
+ if (fs_read(file, address, section.size) < 0) {
+ ERROR("Cannot load MACH-O section %d %d...\n",
+ k, j);
+ return -1;
+ }
+ break;
+ case S_ZEROFILL:
+ DPRINTF("Fill zero section to %08x %08x\n",
+ section.vmaddr, section.size);
+ address = (void *)section.vmaddr;
+ if (address < first && address != NULL)
+ first = address;
+ if (address + section.size > last)
+ last = address + section.size;
+ memset(address, 0, section.size);
+ break;
+ default:
+ ERROR("Unknown MACH-O section type: %d\n",
+ section.flags);
+ return -1;
+ }
+ }
+ }
+ break;
+ case LC_SYMTAB:
+ /* Don't care */
+ break;
+ case LC_SYMSEG:
+ /* Don't care */
+ break;
+ case LC_UNIXTHREAD:
+ /* To be loaded for execution */
+ {
+ mach_unixth_t unixth;
+
+ if (fs_read(file, &unixth, sizeof(mach_unixth_t)) < 0) {
+ ERROR("Cannot load MACH-O UNIX thread\n");
+ return -1;
+ }
+ DPRINTF("Set entry point to %08x\n", unixth.data[0]);
+ *entry = (void *)unixth.data[0];
+ entry_set = 1;
+ }
+ break;
+ case LC_THREAD:
+ break;
+ case LC_LOADFVMLIB:
+ break;
+ case LC_IDFVMLIB:
+ break;
+ case LC_IDENT:
+ break;
+ case LC_FVMFILE:
+ break;
+ case LC_PREPAGE:
+ printf("Prepage command\n");
+ break;
+ case LC_DYSYMTAB:
+ break;
+ case LC_LOAD_DYLIB:
+ break;
+ case LC_ID_DYLIB:
+ break;
+ case LC_LOAD_DYLINKER:
+ /* To be loaded for execution */
+ break;
+ case LC_ID_DYLINKER:
+ break;
+ case LC_PREBOUND_DYLIB:
+ break;
+ case LC_0x17:
+ /* ? */
+ break;
+ default:
+ printf("unknown MACH-O command (%d %d)\n", k, lcmd.cmd);
+ return -1;
+ }
+ offset += lcmd.cmd_size;
+ }
+ *dest = first;
+ *end = last;
+ // if (entry_set == 0)
+ *entry = *dest;
+
+ return 0;
+}
diff --git a/qemu/roms/openhackware/src/libexec/pef.c b/qemu/roms/openhackware/src/libexec/pef.c
new file mode 100644
index 000000000..2c580147e
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/pef.c
@@ -0,0 +1,307 @@
+/*
+ * <pef.c>
+ *
+ * Open Hack'Ware BIOS Classic MacOS 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"
+
+/* PEF (old MacOS executable format) */
+typedef struct PEF_container_t PEF_container_t;
+struct PEF_container_t {
+ uint32_t tag1;
+ uint32_t tag2;
+ uint32_t arch;
+ uint32_t version;
+ uint32_t timestamp;
+ uint32_t oldDefVersion;
+ uint32_t oldImpVersion;
+ uint32_t currentVersion;
+ uint16_t nb_sections;
+ uint16_t nb_inst_sections;
+ uint32_t pad;
+} __attribute__ (( packed ));
+
+typedef struct PEF_section_t PEF_section_t;
+struct PEF_section_t {
+ int32_t name_offset;
+ uint32_t address;
+ uint32_t total_size;
+ uint32_t unpacked_size;
+ uint32_t packed_size;
+ uint32_t container_offset;
+ uint8_t section_kind;
+ uint8_t share_kind;
+ uint8_t align;
+ uint8_t pad;
+} __attribute__ (( packed ));
+
+typedef struct PEF_loader_t PEF_loader_t;
+struct PEF_loader_t {
+ int32_t main_section;
+ uint32_t main_offset;
+ int32_t init_section;
+ uint32_t init_offset;
+ int32_t term_section;
+ uint32_t term_offset;
+ uint32_t nb_import_libs;
+ uint32_t nb_import_symbols;
+ uint32_t nb_reloc_sections;
+ uint32_t reloc_instr_offset;
+ uint32_t loader_strings_offset;
+ uint32_t export_hash_offset;
+ uint32_t export_hashtable_power;
+ uint32_t nb_export_symbols;
+} __attribute__ (( packed ));
+
+enum {
+ PEF_SECTION_CODE = 0,
+ PEF_SECTION_UNPDATA = 1,
+ PEF_SECTION_INIDATA = 2,
+ PEF_SECTION_CONSTANT = 3,
+ PEF_SECTION_LOADER = 4,
+ PEF_SECTION_DEBUG = 5,
+ PEF_SECTION_EXEC = 6,
+ PEF_SECTION_EXCP = 7,
+ PEF_SECTION_TRACE = 8,
+};
+
+enum {
+ PEF_SHARE_PROCESS = 1,
+ PEF_SHARE_GLOBAL = 4,
+ PEF_SHARE_PROTECTED = 5,
+};
+
+int exec_load_pef (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ PEF_container_t container;
+ PEF_section_t section;
+ PEF_loader_t loader;
+ void *first, *last, *addr, **sections;
+ uint32_t pos, padsize, size, lpos, main_offset;
+ uint8_t opcode;
+ int nb_sections, nb_inst_sections, main_section, i, n;
+
+ file_seek(file, loffset);
+ if (fs_read(file, &container, sizeof(PEF_container_t)) < 0) {
+ ERROR("Cannot load container header\n");
+ return -1;
+ }
+ pos = sizeof(PEF_container_t);
+ /* Check tags and architecture */
+ if (memcmp(&container.tag1, "Joy!", 4) != 0) {
+ DPRINTF("No joy, no PEF\n");
+ return -2;
+ }
+ if (memcmp(&container.tag2, "peff", 4) != 0) {
+ DPRINTF("No PEFF file\n");
+ return -2;
+ }
+ if (memcmp(&container.arch, "pwpc", 4) != 0) {
+ DPRINTF("PEFF file not for PPC\n");
+ return -2;
+ }
+ if (get_be32(&container.version) != 1) {
+ DPRINTF("Unknown PEFF container version\n");
+ return -2;
+ }
+ nb_sections = get_be32(&container.nb_sections);
+ sections = malloc(nb_sections * sizeof(void *));
+ if (sections == NULL) {
+ ERROR("Cannot allocate sections\n");
+ return -1;
+ }
+ nb_inst_sections = get_be32(&container.nb_inst_sections);
+ first = (void *)0xFFFFFFFF;
+ last = NULL;
+ main_section = -1;
+ main_offset = 0;
+ for (i = 0, n = 0; i < nb_sections; i++) {
+ file_seek(file, loffset + pos);
+ if (fs_read(file, &section, sizeof(PEF_section_t)) < 0) {
+ ERROR("Cannot read section %d\n", i);
+ return -1;
+ }
+ pos += sizeof(PEF_section_t);
+ addr = (void *)get_be32(&section.address);
+ sections[i] = addr;
+ if (addr < first)
+ first = addr;
+ size = get_be32(&section.total_size);
+ lpos = get_be32(&section.container_offset);
+ file_seek(file, loffset + lpos);
+ switch (section.section_kind) {
+ case PEF_SECTION_CODE:
+ case PEF_SECTION_UNPDATA:
+ /* Load as raw data */
+ padsize = get_be32(&section.unpacked_size) - size;
+ file_seek(file, loffset + lpos);
+ if (fs_read(file, addr, size) < 0) {
+ ERROR("Cannot load section %d\n", i);
+ return -1;
+ }
+ addr = (char *)addr + size;
+ memset(addr, 0, padsize);
+ addr = (char *)addr + padsize;
+ break;
+ case PEF_SECTION_INIDATA:
+ case PEF_SECTION_CONSTANT:
+ case PEF_SECTION_EXEC:
+ /* Load as compressed data */
+ for (;;) {
+ void *ref;
+ uint32_t total;
+ uint8_t bsize, csize, count, j;
+
+ if (fs_read(file, &opcode, 1) < 0) {
+ ERROR("Cannot get opcode\n");
+ return -1;
+ }
+ bsize = opcode & 0x1F;
+ switch (opcode >> 5) {
+ case 0x0:
+ /* Initialize size bytes to zero */
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ total = bsize;
+ break;
+ case 0x1:
+ /* Copy bloc */
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot copy bloc\n");
+ return -1;
+ }
+ addr = (char *)addr + bsize;
+ total = bsize;
+ break;
+ case 0x2:
+ /* Repeat bloc */
+ if (fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read bloc size\n");
+ return -1;
+ }
+ total = 0;
+ if (count == 0) {
+ break;
+ }
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot read repeat bloc\n");
+ return -1;
+ }
+ ref = addr;
+ addr = (char *)addr + bsize;
+ for (j = 1; j < count; j++) {
+ memcpy(addr, ref, bsize);
+ total += bsize;
+ addr = (char *)addr + bsize;
+ }
+ break;
+ case 0x3:
+ /* Interleave repeat bloc with bloc copy */
+ if (fs_read(file, &csize, 1) < 0 ||
+ fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read repeat params\n");
+ return -1;
+ }
+ ref = addr;
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot read common data\n");
+ return -1;
+ }
+ addr = (char *)addr + bsize;
+ total = bsize;
+ for (j = 0; j < count; j++) {
+ if (fs_read(file, addr, csize) < 0) {
+ ERROR("Cannot read custom data\n");
+ return -1;
+ }
+ addr = (char *)addr + csize;
+ memcpy(addr, ref, bsize);
+ addr = (char *)addr + bsize;
+ total += csize + bsize;
+ }
+ break;
+ case 0x4:
+ /* Interleave repeat bloc with zero */
+ if (fs_read(file, &csize, 1) < 0 ||
+ fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read repeat params\n");
+ return -1;
+ }
+ total = 0;
+ for (j = 0; j < count; j++) {
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ if (fs_read(file, addr, csize) < 0) {
+ ERROR("Cannot read repeat data\n");
+ return -1;
+ }
+ addr = (char *)addr + csize;
+ total += csize + bsize;
+ }
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ total += bsize;
+ break;
+ default:
+ ERROR("Unknown opcode\n");
+ return -1;
+ }
+ if (addr > last)
+ last = addr;
+ if (total >= size)
+ break;
+ size -= total;
+ }
+ break;
+ case PEF_SECTION_LOADER:
+ /* find entry point */
+ if (fs_read(file, &loader, sizeof(PEF_loader_t)) < 0) {
+ ERROR("Cannot read loader header\n");
+ return -1;
+ }
+ main_section = get_be32(&loader.main_section);
+ main_offset = get_be32(&loader.main_offset);
+ if (main_section >= nb_sections) {
+ ERROR("Invalid main section\n");
+ return -1;
+ }
+ break;
+ case PEF_SECTION_DEBUG:
+ case PEF_SECTION_EXCP:
+ case PEF_SECTION_TRACE:
+ break;
+ default:
+ return -2;
+ }
+ }
+ *dest = first;
+ *end = last;
+ if (main_section == -1) {
+ *entry = first;
+ } else {
+ *entry = (char *)sections[main_section] + main_offset;
+ }
+ free(sections);
+
+ return 0;
+}
diff --git a/qemu/roms/openhackware/src/libexec/prep.c b/qemu/roms/openhackware/src/libexec/prep.c
new file mode 100644
index 000000000..15b6ea67d
--- /dev/null
+++ b/qemu/roms/openhackware/src/libexec/prep.c
@@ -0,0 +1,45 @@
+/*
+ * <prep.c>
+ *
+ * Open Hack'Ware BIOS PREP 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"
+
+/* PREP boot loader */
+int exec_load_prep (inode_t *file, unused void **dest,
+ unused void **entry, unused void **end,
+ unused uint32_t loffset)
+{
+ unsigned char buffer[512];
+
+ file_seek(file, loffset);
+ if (fs_read(file, buffer, 512) < 0) {
+ ERROR("Cannot load first bloc of file...\n");
+ return -2;
+ }
+ if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
+ DPRINTF("Not a PREP file\n");
+ return -2;
+ }
+
+ return -2;
+}
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;
+}