]> git.saurik.com Git - apple/bootx.git/blobdiff - bootx.tproj/sl.subproj/main.c
BootX-59.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / main.c
index f4b8fae9ae396ce05f45cdce0986c86529ff74e2..e06392c55d1f65c07b4e89c50d98c54a382b4e9c 100644 (file)
@@ -65,9 +65,13 @@ long gBootSourceNumberMax;
 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];
 
@@ -115,6 +119,8 @@ static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
 static void Main(ClientInterfacePtr ciPtr)
 {
   long ret;
+  int  trycache;
+  long flags, cachetime, time;
   
   ret = InitEverything(ciPtr);
   if (ret != 0) Exit();
@@ -126,18 +132,53 @@ static void Main(ClientInterfacePtr ciPtr)
   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);
   
@@ -155,6 +196,8 @@ static long InitEverything(ClientInterfacePtr ciPtr)
   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);
@@ -197,6 +240,11 @@ static long InitEverything(ClientInterfacePtr 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);
@@ -334,11 +382,34 @@ long ThinFatBinary(void **binary, unsigned long *length)
   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);
   
@@ -740,6 +811,7 @@ static long TestForKey(long key)
 static long GetBootPaths(void)
 {
   long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
+  unsigned long adler32;
   char *filePath, *buffer;
   
   if (gBootSourceNumber == -1) {
@@ -870,8 +942,18 @@ static long GetBootPaths(void)
       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;
@@ -880,10 +962,10 @@ static long GetBootPaths(void)
   }
   
   // 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;
@@ -892,12 +974,20 @@ static long GetBootPaths(void)
   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++;