/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.1 (the "License"). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 2.0 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
*
- * The Original Code and all software distributed under the License are
+ * This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
- * Copyright 1993 NeXT Computer, Inc.
- * All rights reserved.
+ * load.c - Functions for decoding a Mach-o Kernel.
+ *
+ * Copyright (c) 1998-2003 Apple Computer, Inc.
+ *
*/
-#include "libsaio.h"
-#include "rcz_common.h"
-#include "rcz_decompress_file.h"
#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include <mach/machine/thread_status.h>
-static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s
+#include <sl.h>
-static int xread(int fd, char * addr, int size);
-static int loadmacho(struct mach_header * head, int dev, int io,
- entry_t * rentry, char ** raddr, int * rsize,
- int file_offset);
+static long DecodeSegment(long cmdBase, unsigned int*load_addr, unsigned int *load_size);
+static long DecodeUnixThread(long cmdBase, unsigned int *entry);
-//==========================================================================
-// Open a file for reading. If the file doesn't exist,
-// try opening the compressed version.
-#ifdef RCZ_COMPRESSED_FILE_SUPPORT
-int openfile(const char * filename, int ignored)
-{
- unsigned char *buf;
- int fd, size, ret;
- unsigned char *addr;
-
- if ((fd = open(filename, 0)) < 0) {
- buf = malloc(256);
- sprintf(buf, "%s%s", filename, RCZ_EXTENSION);
- if ((fd = open(buf, 0)) >= 0) {
- size = rcz_file_size(fd);
- addr = (unsigned char *)((KERNEL_ADDR + KERNEL_LEN) - size);
- ret = rcz_decompress_file(fd, addr);
- close(fd);
- if (ret < 0)
- fd = -1;
- else
- fd = openmem(addr, size);
- }
- free(buf);
- }
- return fd;
-}
-#else
-int openfile(char * filename, int ignored)
-{
- return open(filename, 0);
-}
-#endif
+static unsigned long gBinaryAddress;
+BOOL gHaveKernelCache;
-//==========================================================================
-// loadprog
+// Public Functions
-int loadprog( int dev, int fd, struct mach_header * headOut,
- entry_t * entry, /* entry point */
- char ** addr, /* load address */
- int * size ) /* size of loaded program */
+long ThinFatFile(void **binary, unsigned long *length)
{
- struct mach_header head;
- int file_offset = 0;
-
-read_again:
-
- /* get file header */
- read(fd, (char *) &head, sizeof(head));
-
- if ( headOut )
- bcopy((char *) &head, (char *) headOut, sizeof(head));
-
- if ( head.magic == MH_MAGIC )
- {
- return loadmacho(&head, dev, fd, entry, addr, size, file_offset);
+ unsigned long nfat, swapped, size = 0;
+ struct fat_header *fhp = (struct fat_header *)*binary;
+ struct fat_arch *fap =
+ (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header));
+
+ if (fhp->magic == FAT_MAGIC) {
+ nfat = fhp->nfat_arch;
+ swapped = 0;
+ } else if (fhp->magic == FAT_CIGAM) {
+ nfat = OSSwapInt32(fhp->nfat_arch);
+ swapped = 1;
+ } else {
+ return -1;
+ }
+
+ for (; nfat > 0; nfat--, fap++) {
+ if (swapped) {
+ fap->cputype = OSSwapInt32(fap->cputype);
+ fap->offset = OSSwapInt32(fap->offset);
+ fap->size = OSSwapInt32(fap->size);
}
- else if ( file_offset == 0 &&
- ((head.magic == FAT_CIGAM) || (head.magic == FAT_MAGIC)) )
- {
- int swap = (head.magic == FAT_CIGAM) ? 1 : 0;
- struct fat_header * fhp = (struct fat_header *) &head;
- struct fat_arch * fap;
- int i, narch = swap ? NXSwapLong(fhp->nfat_arch) : fhp->nfat_arch;
- int cpu, size;
- char * buf;
-
- size = sizeof(struct fat_arch) * narch;
- buf = malloc(size);
- b_lseek(fd, 0, 0);
- read(fd, buf, size);
- for ( i = 0, fap = (struct fat_arch *)(buf+sizeof(struct fat_header));
- i < narch;
- i++, fap++ )
- {
- cpu = swap ? NXSwapLong(fap->cputype) : fap->cputype;
- if (cpu == CPU_TYPE_I386)
- {
- /* that's specific enough */
- free(buf);
- file_offset = swap ? NXSwapLong(fap->offset) : fap->offset;
- b_lseek(fd, file_offset, 0);
- goto read_again;
- }
- }
- free(buf);
- error("Fat binary file doesn't contain i386 code\n");
- return -1;
+ if (fap->cputype == CPU_TYPE_I386) {
+ *binary = (void *) ((unsigned long)*binary + fap->offset);
+ size = fap->size;
+ break;
}
- error("Unrecognized binary format: %08x\n", head.magic);
- return -1;
+ }
+
+ if (length != 0) *length = size;
+
+ return 0;
}
-//==========================================================================
-// xread
-//
-// Read from file descriptor. addr is a physical address.
-
-static int xread( int fd, char * addr, int size )
+long DecodeMachO(void *binary, entry_t *rentry, char **raddr, int *rsize)
{
- char * orgaddr = addr;
- long offset;
- unsigned count;
- long max;
-#define BUFSIZ 8192
- char * buf;
- int bufsize = BUFSIZ;
-
-#if 0
- printf("xread: addr=%x, size=%x\n", addr, size);
- sleep(1);
-#endif
-
- buf = malloc(BUFSIZ);
-
- // align your read to increase speed
- offset = tell(fd) & 4095;
- if ( offset != 0 )
- max = 4096 - offset;
- else
- max = bufsize;
-
- while ( size > 0 )
- {
- if ( size > max ) count = max;
- else count = size;
-#if 0
- printf("xread: loop size=%x, count=%x\n", size, count);
- sleep(1);
+ struct mach_header *mH;
+ unsigned long ncmds, cmdBase, cmd, cmdsize;
+ // long headerBase, headerAddr, headerSize;
+ unsigned int vmaddr = ~0;
+ unsigned int vmend = 0;
+ unsigned long cnt;
+ long ret = -1;
+ unsigned int entry = 0;
+
+ gBinaryAddress = (unsigned long)binary;
+
+ // headerBase = gBinaryAddress;
+ cmdBase = (unsigned long)gBinaryAddress + sizeof(struct mach_header);
+
+ mH = (struct mach_header *)(gBinaryAddress);
+ if (mH->magic != MH_MAGIC) {
+ error("Mach-O file has bad magic number\n");
+ return -1;
+ }
+
+#if DEBUG
+ printf("magic: %x\n", (unsigned)mH->magic);
+ printf("cputype: %x\n", (unsigned)mH->cputype);
+ printf("cpusubtype: %x\n", (unsigned)mH->cpusubtype);
+ printf("filetype: %x\n", (unsigned)mH->filetype);
+ printf("ncmds: %x\n", (unsigned)mH->ncmds);
+ printf("sizeofcmds: %x\n", (unsigned)mH->sizeofcmds);
+ printf("flags: %x\n", (unsigned)mH->flags);
+ getc();
#endif
-
- if ( read(fd, buf, count) != count) break;
-
- bcopy(buf, ptov(addr), count);
- size -= count;
- addr += count;
-
- max = bufsize;
-
-#if 0
- tick += count;
- if ( tick > (50*1024) )
- {
- putchar('+');
- tick = 0;
- }
+
+ ncmds = mH->ncmds;
+
+ for (cnt = 0; cnt < ncmds; cnt++) {
+ cmd = ((long *)cmdBase)[0];
+ cmdsize = ((long *)cmdBase)[1];
+ unsigned int load_addr;
+ unsigned int load_size;
+
+ switch (cmd) {
+
+ case LC_SEGMENT:
+ ret = DecodeSegment(cmdBase, &load_addr, &load_size);
+ if (ret == 0 && load_size != 0 && load_addr >= KERNEL_ADDR) {
+ vmaddr = min(vmaddr, load_addr);
+ vmend = max(vmend, load_addr + load_size);
+ }
+ break;
+
+ case LC_UNIXTHREAD:
+ ret = DecodeUnixThread(cmdBase, &entry);
+ break;
+
+ default:
+#if NOTDEF
+ printf("Ignoring cmd type %d.\n", (unsigned)cmd);
#endif
+ break;
}
-
- free(buf);
- return addr-orgaddr;
+
+ if (ret != 0) return -1;
+
+ cmdBase += cmdsize;
+ }
+
+ *rentry = (entry_t)( (unsigned long) entry & 0x3fffffff );
+ *rsize = vmend - vmaddr;
+ *raddr = (char *)vmaddr;
+
+ return ret;
}
-//==========================================================================
-// loadmacho
+// Private Functions
-static int loadmacho( struct mach_header * head, int dev, int io,
- entry_t * rentry, char ** raddr, int * rsize,
- int file_offset )
+static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size)
{
- int ncmds;
- void * cmds;
- void * cp;
- unsigned int entry = 0;
- int vmsize = 0;
- unsigned int vmaddr = ~0;
- unsigned int vmend = 0;
-
- struct xxx_thread_command {
- unsigned long cmd;
- unsigned long cmdsize;
- unsigned long flavor;
- unsigned long count;
- i386_thread_state_t state;
- } * th;
-
- // XXX should check cputype
- cmds = malloc(head->sizeofcmds);
- b_lseek(io, sizeof(struct mach_header) + file_offset, 0);
-
- if ( read(io, (char *) cmds, head->sizeofcmds) != head->sizeofcmds )
- {
- error("loadmacho: error reading commands\n");
- goto shread;
- }
-
- for ( ncmds = head->ncmds, cp = cmds; ncmds > 0; ncmds-- )
- {
- unsigned int addr;
-
-#define lcp ((struct load_command *) cp)
-#define scp ((struct segment_command *) cp)
-
- switch ( lcp->cmd )
- {
- case LC_SEGMENT:
- addr = (scp->vmaddr & 0x3fffffff) + (int)*raddr;
- if ( scp->filesize )
- {
- vmsize += scp->vmsize;
- vmaddr = min(vmaddr, addr);
- vmend = max(vmend, addr + scp->vmsize);
-
- // Zero any space at the end of the segment.
-
- bzero((char *)(addr + scp->filesize),
- scp->vmsize - scp->filesize);
-
- // FIXME: check to see if we overflow
- // the available space (should be passed in
- // as the size argument).
+ struct segment_command *segCmd;
+ unsigned long vmaddr, fileaddr;
+ long vmsize, filesize;
+
+ segCmd = (struct segment_command *)cmdBase;
-#if 0
- printf("LC: fileoff %x, filesize %x, off %x, addr %x\n",
- scp->fileoff, scp->filesize, file_offset, addr);
- sleep(1);
+ vmaddr = (segCmd->vmaddr & 0x3fffffff);
+ vmsize = segCmd->vmsize;
+
+ fileaddr = (gBinaryAddress + segCmd->fileoff);
+ filesize = segCmd->filesize;
+
+ if (filesize == 0) {
+ *load_addr = ~0;
+ *load_size = 0;
+ return 0;
+ }
+
+#if DEBUG
+ printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
+ segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
+ (unsigned) segCmd->nsects, (unsigned)segCmd->flags);
+ getc();
#endif
+
+ if (! ((vmaddr >= KERNEL_ADDR &&
+ (vmaddr + vmsize) <= (KERNEL_ADDR + KERNEL_LEN)) ||
+ (vmaddr >= HIB_ADDR &&
+ (vmaddr + vmsize) <= (HIB_ADDR + HIB_LEN)))) {
+ stop("Kernel overflows available space");
+ }
+
+ if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0)) {
+ gHaveKernelCache = 1;
+ }
+
+ // Copy from file load area.
+ bcopy((char *)fileaddr, (char *)vmaddr, filesize);
+
+ // Zero space at the end of the segment.
+ bzero((char *)(vmaddr + filesize), vmsize - filesize);
- b_lseek(io, scp->fileoff + file_offset, 0);
- if ( xread(io, (char *)addr, scp->filesize)
- != scp->filesize)
- {
- error("loadmacho: error loading section\n");
- goto shread;
- }
- }
- break;
-
- case LC_THREAD:
- case LC_UNIXTHREAD:
- th = (struct xxx_thread_command *) cp;
- entry = th->state.eip;
- break;
- }
- cp += lcp->cmdsize;
- }
-
- kernBootStruct->rootdev = (dev & 0xffffff00) | devMajor[B_TYPE(dev)];
-
- free(cmds);
+ *load_addr = vmaddr;
+ *load_size = vmsize;
- *rentry = (entry_t)( (int) entry & 0x3fffffff );
- *rsize = vmend - vmaddr;
- *raddr = (char *)vmaddr;
+ return 0;
+}
- return 0;
-shread:
- free(cmds);
- return -1;
+static long DecodeUnixThread(long cmdBase, unsigned int *entry)
+{
+ i386_thread_state_t *i386ThreadState;
+
+ i386ThreadState = (i386_thread_state_t *)
+ (cmdBase + sizeof(struct thread_command) + 8);
+
+ *entry = i386ThreadState->eip;
+
+ return 0;
}
+