#include <sl_words.h>
#include <libclite.h>
-void putchar(int ch)
+int putchar(int ch)
{
if ((ch == '\r') || (ch == '\n')) CallMethod(0, 0, SLWordsIH, "slw_cr");
else CallMethod(1, 0, SLWordsIH, "slw_emit", ch);
+
+ return ch;
}
return 1;
}
+//
+// BinaryUnicodeCompare - Compare two Unicode strings; produce a relative ordering
+// Compared using a 16-bit binary comparison (no case folding)
+//
+int32_t BinaryUnicodeCompare (u_int16_t * str1, u_int32_t length1,
+ u_int16_t * str2, u_int32_t length2)
+{
+ register u_int16_t c1, c2;
+ int32_t bestGuess;
+ u_int32_t length;
+
+ bestGuess = 0;
+
+ if (length1 < length2) {
+ length = length1;
+ --bestGuess;
+ } else if (length1 > length2) {
+ length = length2;
+ ++bestGuess;
+ } else {
+ length = length1;
+ }
+
+ while (length--) {
+ c1 = *(str1++);
+ c2 = *(str2++);
+
+ if (c1 > c2)
+ return (1);
+ if (c1 < c2)
+ return (-1);
+ }
+
+ return (bestGuess);
+}
/*
* UTF-8 (UCS Transformation Format)
#define kNumPartInfos (16)
static PartInfo gParts[kNumPartInfos];
+static char gMakeDirSpec[1024];
// Private function prototypes
long LookupPartition(char *devSpec);
{
long ret, index = 0;
char *curName;
+
+ if (!dirSpec) {
+ long idx, len;
+
+ len = strlen(name);
+
+ for (idx = len; idx && (name[idx] != '\\'); idx--) {}
+ idx++;
+ strncpy(gMakeDirSpec, name, idx);
+ name += idx;
+ dirSpec = gMakeDirSpec;
+ }
while (1) {
ret = GetDirEntry(dirSpec, &index, &curName, flags, time);
static CICell gCurrentIH;
static long long gAllocationOffset;
static long gIsHFSPlus;
+static long gCaseSensitive;
static long gBlockSize;
static char gBTreeHeaderBuffer[512];
static BTHeaderRec *gBTHeaders[2];
extern long FastRelString(char *str1, char *str2);
extern long FastUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1,
u_int16_t *uniStr2, u_int32_t len2);
+extern long BinaryUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1,
+ u_int16_t *uniStr2, u_int32_t len2);
extern void utf_encodestr(const u_int16_t *ucsp, int ucslen,
u_int8_t *utf8p, u_int32_t bufsize);
extern void utf_decodestr(const u_int8_t *utf8p, u_int16_t *ucsp,
gAllocationOffset = 0;
gIsHFSPlus = 0;
+ gCaseSensitive = 0;
gBTHeaders[0] = 0;
gBTHeaders[1] = 0;
Read(ih, (long)gHFSPlusHeader, kBlockSize);
// Not a HFS[+] volume.
- if (gHFSPlus->signature != kHFSPlusSigWord) return -1;
+ if ((gHFSPlus->signature != kHFSPlusSigWord) &&
+ (gHFSPlus->signature != kHFSXSigWord)) return -1;
gIsHFSPlus = 1;
gBlockSize = gHFSPlus->blockSize;
gBTreeHeaderBuffer + btree * 256, 0);
gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 +
sizeof(BTNodeDescriptor));
+ if ((gIsHFSPlus && btree == kBTreeCatalog) &&
+ (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) {
+ gCaseSensitive = 1;
+ }
}
curNode = gBTHeaders[btree]->rootNode;
if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))
result = searchKey->nodeName.length - trialKey->nodeName.length;
else
- result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
- searchKey->nodeName.length,
- &trialKey->nodeName.unicode[0],
- trialKey->nodeName.length);
+ if (gCaseSensitive) {
+ result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],
+ searchKey->nodeName.length,
+ &trialKey->nodeName.unicode[0],
+ trialKey->nodeName.length);
+ } else {
+ result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
+ searchKey->nodeName.length,
+ &trialKey->nodeName.unicode[0],
+ trialKey->nodeName.length);
+ }
}
return result;
};
typedef struct boot_args boot_args, *boot_args_ptr;
+struct compressed_kernel_header {
+ u_int32_t signature;
+ u_int32_t compress_type;
+ u_int32_t adler32;
+ u_int32_t uncompressed_size;
+ u_int32_t compressed_size;
+ u_int32_t reserved[11];
+ char platform_name[64];
+ char root_path[256];
+ u_int8_t data[0];
+};
+typedef struct compressed_kernel_header compressed_kernel_header;
+
#endif /* ! _BOOTX_BOOT_ARGS_H_ */
#include <stddef.h>
// ci_io.c
-extern void putchar(int ch);
+extern int putchar(int ch);
// prf.c
extern void prf(const char *fmt, unsigned int *adx, void (*putfn_p)(),
// mem.c
extern void *memcpy(void *dst, const void *src, size_t len);
extern void *memset(void *dst, int ch, size_t len);
-extern void *bcopy(void *src, void *dst, int len);
+extern void bcopy(const void *src, void *dst, size_t len);
extern void bzero(void *dst, int len);
// bsearch.c
extern long gBootMode;
extern long gBootDeviceType;
extern long gBootFileType;
+extern char gHaveKernelCache;
extern char gBootDevice[256];
extern char gBootFile[256];
-extern char gRootDir[256];
extern char gTempStr[4096];
extern long InitConfig(void);
extern long ParseConfigFile(char *addr);
+// Externs for lzss.c
+extern int decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen);
+
#endif /* ! _BOOTX_SL_H_ */
return dst;
}
-void *bcopy(void *src, void *dst, int len)
+void bcopy(const void *src, void *dst, size_t len)
{
- return memcpy(dst, src, len);
+ memcpy(dst, src, len);
}
void bzero(void *dst, int len)
#define SPACE 1
#define ZERO 2
+#define UCASE 16
/*
* Scaled down version of C Library printf.
}
cp = prbuf;
do {
- *cp++ = "0123456789abcdef"[n%b];
+ *cp++ = "0123456789abcdef0123456789ABCDEF"[(flag & UCASE) + n%b];
n /= b;
width++;
} while (n);
minwidth *= 10;
minwidth += c - '0';
goto again;
- case 'x': case 'X':
+ case 'X':
+ flag |= UCASE;
+ /* fall through */
+ case 'x':
b = 16;
goto number;
case 'd':
HFILES = appleboot.h clut.h elf.h failedboot.h netboot.h
-CFILES = main.c macho.c device_tree.c display.c drivers.c elf.c
+CFILES = main.c macho.c device_tree.c display.c drivers.c elf.c lzss.c
OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
netboot.h
);
M_FILES = ();
- OTHER_LINKED = (main.c, macho.c, device_tree.c, display.c, elf.c, drivers.c);
+ OTHER_LINKED = (main.c, macho.c, device_tree.c, display.c, elf.c, drivers.c, lzss.c);
OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble);
SUBPROJECTS = ();
TOOLS = ();
static ModulePtr gModuleHead, gModuleTail;
static TagPtr gPersonalityHead, gPersonalityTail;
-static char gExtensionsSpec[4096];
static char gDriverSpec[4096];
static char gFileSpec[4096];
static char gTempSpec[4096];
if (gBootFileType == kNetworkDeviceType) {
NetLoadDrivers(dirSpec);
} else if (gBootFileType == kBlockDeviceType) {
- strcpy(gExtensionsSpec, dirSpec);
- strcat(gExtensionsSpec, "System\\Library\\");
- FileLoadDrivers(gExtensionsSpec, 0);
+ FileLoadDrivers(dirSpec, 0);
} else {
return 0;
}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * Copyright (c) 1999-2003 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 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.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/**************************************************************
+ LZSS.C -- A Data Compression Program
+***************************************************************
+ 4/6/1989 Haruhiko Okumura
+ Use, distribute, and modify this program freely.
+ Please send me your improved versions.
+ PC-VAN SCIENCE
+ NIFTY-Serve PAF01022
+ CompuServe 74050,1022
+
+**************************************************************/
+/*
+ * lzss.c - Package for decompressing lzss compressed objects
+ *
+ * Copyright (c) 2003 Apple Computer, Inc.
+ *
+ * DRI: Josh de Cesare
+ */
+
+#include <sl.h>
+
+#define N 4096 /* size of ring buffer - must be power of 2 */
+#define F 18 /* upper limit for match_length */
+#define THRESHOLD 2 /* encode string into position and length
+ if match_length is greater than this */
+#define NIL N /* index for root of binary search trees */
+
+int
+decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen)
+{
+ /* ring buffer of size N, with extra F-1 bytes to aid string comparison */
+ u_int8_t text_buf[N + F - 1];
+ u_int8_t *dststart = dst;
+ u_int8_t *srcend = src + srclen;
+ int i, j, k, r, c;
+ unsigned int flags;
+
+ dst = dststart;
+ srcend = src + srclen;
+ for (i = 0; i < N - F; i++)
+ text_buf[i] = ' ';
+ r = N - F;
+ flags = 0;
+ for ( ; ; ) {
+ if (((flags >>= 1) & 0x100) == 0) {
+ if (src < srcend) c = *src++; else break;
+ flags = c | 0xFF00; /* uses higher byte cleverly */
+ } /* to count eight */
+ if (flags & 1) {
+ if (src < srcend) c = *src++; else break;
+ *dst++ = c;
+ text_buf[r++] = c;
+ r &= (N - 1);
+ } else {
+ if (src < srcend) i = *src++; else break;
+ if (src < srcend) j = *src++; else break;
+ i |= ((j & 0xF0) << 4);
+ j = (j & 0x0F) + THRESHOLD;
+ for (k = 0; k <= j; k++) {
+ c = text_buf[(i + k) & (N - 1)];
+ *dst++ = c;
+ text_buf[r++] = c;
+ r &= (N - 1);
+ }
+ }
+ }
+
+ return dst - dststart;
+}
// Add the Segment to the memory-map.
sprintf(rangeName, "Kernel-%s", segCmd->segname);
AllocateMemoryRange(rangeName, (long)vmaddr, vmsize);
+
+ if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0))
+ gHaveKernelCache = 1;
// Handle special segments first.
long gBootMode = kBootModeNormal;
long gBootDeviceType;
long gBootFileType;
+char gHaveKernelCache = 0;
char gBootDevice[256];
char gBootFile[256];
-char gRootDir[256];
+static char gBootKernelCacheFile[512];
+static char gExtensionsSpec[4096];
+static char gCacheNameAdler[64 + sizeof(gBootFile)];
+static char *gPlatformName = gCacheNameAdler;
char gTempStr[4096];
static void Main(ClientInterfacePtr ciPtr)
{
long ret;
+ int trycache;
+ long flags, cachetime, time;
ret = InitEverything(ciPtr);
if (ret != 0) Exit();
DrawSplashScreen(0);
while (ret == 0) {
+ trycache = (0 == (gBootMode & kBootModeSafe))
+ && (gBootKernelCacheFile[0] != 0);
+
+ if (trycache && (gBootFileType == kBlockDeviceType)) do {
+
+ // if we haven't found the kernel yet, don't use the cache
+ ret = GetFileInfo(NULL, gBootFile, &flags, &time);
+ if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
+ trycache = 0;
+ break;
+ }
+ ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
+ if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
+ || (cachetime < time)) {
+ trycache = 0;
+ break;
+ }
+ ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &time);
+ if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
+ && (cachetime < time)) {
+ trycache = 0;
+ break;
+ }
+ } while (0);
+
+ if (trycache) {
+ ret = LoadFile(gBootKernelCacheFile);
+ if (ret != -1) {
+ ret = DecodeKernel();
+ if (ret != -1) break;
+ }
+ }
ret = LoadFile(gBootFile);
+ if (ret != -1)
+ ret = DecodeKernel();
if (ret != -1) break;
ret = GetBootPaths();
if (ret != 0) FailToBoot(2);
}
- ret = DecodeKernel();
if (ret != 0) FailToBoot(3);
- ret = LoadDrivers(gRootDir);
- if (ret != 0) FailToBoot(4);
+ if (!gHaveKernelCache) {
+ ret = LoadDrivers(gExtensionsSpec);
+ if (ret != 0) FailToBoot(4);
+ }
DrawSplashScreen(1);
long ret, mem_base, mem_base2, size;
CICell keyboardPH;
char name[32], securityMode[33];
+ long length;
+ char *compatible;
// Init the OF Client Interface.
ret = InitCI(ciPtr);
return -1;
}
+ // Get first element of root's compatible property.
+ ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length);
+ if (ret != -1)
+ strcpy(gPlatformName, compatible);
+
// Get stdout's IH, so that the boot display can be found.
ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4);
if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH);
return ret;
}
-
static long DecodeKernel(void)
{
void *binary = (void *)kLoadAddr;
long ret;
+ compressed_kernel_header * kernel_header = (compressed_kernel_header *) kLoadAddr;
+ u_int32_t size;
+
+ if (kernel_header->signature == 'comp') {
+ if (kernel_header->compress_type != 'lzss')
+ return -1;
+ if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
+ return -1;
+ if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
+ return -1;
+
+ binary = AllocateBootXMemory(kernel_header->uncompressed_size);
+
+ size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0], kernel_header->compressed_size);
+ if (kernel_header->uncompressed_size != size) {
+ printf("size mismatch from lzss %x\n", size);
+ return -1;
+ }
+ if (kernel_header->adler32 !=
+ Alder32(binary, kernel_header->uncompressed_size)) {
+ printf("adler mismatch\n");
+ return -1;
+ }
+ }
ThinFatBinary(&binary, 0);
static long GetBootPaths(void)
{
long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
+ unsigned long adler32;
char *filePath, *buffer;
if (gBootSourceNumber == -1) {
strncpy(gBootFile, gBootDevice, cnt + 1);
sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel",
partNum, ((gBootSourceNumber & 1) ? "" : "\\"));
+
+ // and the cache file name
+
+ bzero(gCacheNameAdler + 64, sizeof(gBootFile));
+ strcpy(gCacheNameAdler + 64, gBootFile);
+ adler32 = Alder32(gCacheNameAdler, sizeof(gCacheNameAdler));
+
+ strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1);
+ sprintf(gBootKernelCacheFile + cnt + 1,
+ "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32);
break;
-
+
default:
printf("Failed to infer Boot Device Type.\n");
return -1;
}
// Figure out the root dir.
- ret = ConvertFileSpec(gBootFile, gRootDir, &filePath);
+ ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath);
if (ret == -1) return -1;
- strcat(gRootDir, ",");
+ strcat(gExtensionsSpec, ",");
// Add in any extra path to gRootDir.
cnt = 0;
if (cnt != 0) {
for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
if (filePath[cnt2] == '\\') {
- strncat(gRootDir, filePath, cnt2 + 1);
+ strncat(gExtensionsSpec, filePath, cnt2 + 1);
break;
}
}
}
-
+
+ // Figure out the extensions dir.
+ if (gBootFileType == kBlockDeviceType) {
+ cnt = strlen(gExtensionsSpec);
+ if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\'))
+ cnt--;
+ strcpy(gExtensionsSpec + cnt, "System\\Library\\");
+ }
+
SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
gBootSourceNumber++;