X-Git-Url: https://git.saurik.com/apple/boot.git/blobdiff_plain/75b89a82fae8b6d553467b92cb5431b2b5b4df7e..HEAD:/i386/libsaio/load.c diff --git a/i386/libsaio/load.c b/i386/libsaio/load.c index 77e6ad0..30e549d 100644 --- a/i386/libsaio/load.c +++ b/i386/libsaio/load.c @@ -1,293 +1,218 @@ /* - * 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 +#include +#include -static int devMajor[3] = { 6, 3, 1 }; // sd, hd, fd major dev #'s +#include -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; } +