diff options
Diffstat (limited to 'qemu/roms/openhackware/src/libexec/pef.c')
-rw-r--r-- | qemu/roms/openhackware/src/libexec/pef.c | 307 |
1 files changed, 307 insertions, 0 deletions
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, §ion, sizeof(PEF_section_t)) < 0) { + ERROR("Cannot read section %d\n", i); + return -1; + } + pos += sizeof(PEF_section_t); + addr = (void *)get_be32(§ion.address); + sections[i] = addr; + if (addr < first) + first = addr; + size = get_be32(§ion.total_size); + lpos = get_be32(§ion.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(§ion.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; +} |