]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add LZSS Mach-O support (needed for new xnu kernelcache).
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 29 Feb 2012 12:26:13 +0000 (13:26 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 29 Feb 2012 12:26:13 +0000 (13:26 +0100)
* grub-core/Makefile.core.def (xnu): Add file lzss.c
* grub-core/loader/lzss.c: New file.
* grub-core/loader/xnu.c (grub_xnu_load_driver): Close binaryfile
on Mach-O open failure.
* grub-core/loader/macho.c (grub_macho_close): Free uncompressedXX.
Don't free cmdsXX in uncompressedXX is set.
(grub_macho_file): Init new fields.
New argument is_64bit. All users updated.
Handle compressed. Error out if no suitable architecture is found.
Don't close file.
(grub_macho_open): New argument is_64bit. All users updated.
* grub-core/loader/macho32.c: Add defines for new fields.
* grub-core/loader/macho64.c: Likewise.
* grub-core/loader/machoXX.c (grub_macho_contains_macho): Make static.
(grub_macho_parse): Handle compressed.
Defer actual processing if compressed.
(grub_macho_cmds_iterate): Decompress if compressed. New argument
"filename". All users updated.
(grub_macho_size): New argument "filename". All users updated.
(grub_macho_get_entry_point): Likewise.
(grub_macho_load): Handle compressed.
* include/grub/macho.h (grub_macho_lzss_header): New struct.
(GRUB_MACHO_LZSS_OFFSET): New define.
(grub_decompress_lzss): New proto.
* include/grub/machoload.h (grub_macho_file): New fields to handle
compressed.
(grub_macho_contains_macho64): Remove proto.
(grub_macho_contains_macho32): Likewise.
* util/grub.d/30_os-prober.in: Use kernel cache if available.

ChangeLog
grub-core/Makefile.core.def
grub-core/loader/lzss.c [new file with mode: 0644]
grub-core/loader/macho.c
grub-core/loader/macho32.c
grub-core/loader/macho64.c
grub-core/loader/machoXX.c
grub-core/loader/xnu.c
include/grub/macho.h
include/grub/machoload.h
util/grub.d/30_os-prober.in

index c4b1ae4c843fb43987289897bdcae9185fef784c..51ea4d5dd0eba5f4dd5d32282db774c18e4b1d5f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2012-02-29  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Add LZSS Mach-O support (needed for new xnu kernelcache).
+
+       * grub-core/Makefile.core.def (xnu): Add file lzss.c
+       * grub-core/loader/lzss.c: New file.
+       * grub-core/loader/xnu.c (grub_xnu_load_driver): Close binaryfile
+       on Mach-O open failure.
+       * grub-core/loader/macho.c (grub_macho_close): Free uncompressedXX.
+       Don't free cmdsXX in uncompressedXX is set.
+       (grub_macho_file): Init new fields.
+       New argument is_64bit. All users updated.
+       Handle compressed. Error out if no suitable architecture is found.
+       Don't close file.
+       (grub_macho_open): New argument is_64bit. All users updated.
+       * grub-core/loader/macho32.c: Add defines for new fields.
+       * grub-core/loader/macho64.c: Likewise.
+       * grub-core/loader/machoXX.c (grub_macho_contains_macho): Make static.
+       (grub_macho_parse): Handle compressed.
+       Defer actual processing if compressed.
+       (grub_macho_cmds_iterate): Decompress if compressed. New argument
+       "filename". All users updated.
+       (grub_macho_size): New argument "filename". All users updated.
+       (grub_macho_get_entry_point): Likewise.
+       (grub_macho_load): Handle compressed.
+       * include/grub/macho.h (grub_macho_lzss_header): New struct.
+       (GRUB_MACHO_LZSS_OFFSET): New define.
+       (grub_decompress_lzss): New proto.
+       * include/grub/machoload.h (grub_macho_file): New fields to handle
+       compressed.
+       (grub_macho_contains_macho64): Remove proto.
+       (grub_macho_contains_macho32): Likewise.
+       * util/grub.d/30_os-prober.in: Use kernel cache if available.
+
 2012-02-29  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/disk/pata.c (grub_pata_readwrite): Fix ATAPI protocol error.
index 947a43ab3e61c7e8205157a43aa31adf2f4c7460..4139dd0342f808e93050f4bc98dd81854505c50f 100644 (file)
@@ -1378,6 +1378,7 @@ module = {
   x86 = loader/macho64.c;
   x86 = loader/macho.c;
   x86 = loader/xnu.c;
+  x86 = loader/lzss.c;
 
   extra_dist = loader/machoXX.c;
   enable = x86;
diff --git a/grub-core/loader/lzss.c b/grub-core/loader/lzss.c
new file mode 100644 (file)
index 0000000..532d8e4
--- /dev/null
@@ -0,0 +1,56 @@
+/**************************************************************
+       LZSS.C -- A Data Compression Program
+       (tab = 4 spaces)
+***************************************************************
+       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
+**************************************************************/
+
+#include <grub/types.h>
+#include <grub/macho.h>
+
+#define N               4096   /* size of ring buffer */
+#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 */
+
+#define EOF -1
+#define getc(file) ((src < srcend) ? *src++ : EOF)
+#define putc(c, file) (dst < dstend) ? (*dst++ = (c)) : 0;
+
+grub_size_t
+grub_decompress_lzss (grub_uint8_t *dst, grub_uint8_t *dstend,
+                     grub_uint8_t *src, grub_uint8_t *srcend)
+{
+       int  i, j, k, r, c;
+       unsigned int  flags;
+       static unsigned char text_buf[N + F - 1];
+       grub_uint8_t *dst0 = dst;
+       
+       for (i = 0; i < N - F; i++) text_buf[i] = ' ';
+       r = N - F;  flags = 0;
+       for ( ; ; ) {
+               if (((flags >>= 1) & 256) == 0) {
+                       if ((c = getc(infile)) == EOF) break;
+                       flags = c | 0xff00;             /* uses higher byte cleverly */
+               }                                                       /* to count eight */
+               if (flags & 1) {
+                       if ((c = getc(infile)) == EOF) break;
+                       putc(c, outfile);  text_buf[r++] = c;  r &= (N - 1);
+               } else {
+                       if ((i = getc(infile)) == EOF) break;
+                       if ((j = getc(infile)) == EOF) break;
+                       i |= ((j & 0xf0) << 4);  j = (j & 0x0f) + THRESHOLD;
+                       for (k = 0; k <= j; k++) {
+                               c = text_buf[(i + k) & (N - 1)];
+                               putc(c, outfile);  text_buf[r++] = c;  r &= (N - 1);
+                       }
+               }
+       }
+    return dst - dst0;
+}
index 0a1717fbb2055a0d938e092bd6dfad48712e4e25..bf0bf74f78f2cea634e387b18f8744c93b57f33a 100644 (file)
@@ -35,8 +35,12 @@ grub_macho_close (grub_macho_t macho)
 {
   grub_file_t file = macho->file;
 
-  grub_free (macho->cmds32);
-  grub_free (macho->cmds64);
+  if (!macho->uncompressed32)
+    grub_free (macho->cmds32);
+  grub_free (macho->uncompressed32);
+  if (!macho->uncompressed64)
+    grub_free (macho->cmds64);
+  grub_free (macho->uncompressed64);
 
   grub_free (macho);
 
@@ -47,7 +51,7 @@ grub_macho_close (grub_macho_t macho)
 }
 
 grub_macho_t
-grub_macho_file (grub_file_t file, const char *filename)
+grub_macho_file (grub_file_t file, const char *filename, int is_64bit)
 {
   grub_macho_t macho;
   union grub_macho_filestart filestart;
@@ -63,6 +67,10 @@ grub_macho_file (grub_file_t file, const char *filename)
   macho->end64 = -1;
   macho->cmds32 = 0;
   macho->cmds64 = 0;
+  macho->uncompressed32 = 0;
+  macho->uncompressed64 = 0;
+  macho->compressed32 = 0;
+  macho->compressed64 = 0;
 
   if (grub_file_seek (macho->file, 0) == (grub_off_t) -1)
     goto fail;
@@ -104,14 +112,14 @@ grub_macho_file (grub_file_t file, const char *filename)
       for (i = 0; i < narchs; i++)
        {
          if (GRUB_MACHO_CPUTYPE_IS_HOST32
-             (grub_be_to_cpu32 (archs[i].cputype)))
+             (grub_be_to_cpu32 (archs[i].cputype)) && !is_64bit)
            {
              macho->offset32 = grub_be_to_cpu32 (archs[i].offset);
              macho->end32 = grub_be_to_cpu32 (archs[i].offset)
                + grub_be_to_cpu32 (archs[i].size);
            }
          if (GRUB_MACHO_CPUTYPE_IS_HOST64
-             (grub_be_to_cpu32 (archs[i].cputype)))
+             (grub_be_to_cpu32 (archs[i].cputype)) && is_64bit)
            {
              macho->offset64 = grub_be_to_cpu32 (archs[i].offset);
              macho->end64 = grub_be_to_cpu32 (archs[i].offset)
@@ -122,14 +130,29 @@ grub_macho_file (grub_file_t file, const char *filename)
     }
 
   /* Is it a thin 32-bit file? */
-  if (filestart.thin32.magic == GRUB_MACHO_MAGIC32)
+  if (filestart.thin32.magic == GRUB_MACHO_MAGIC32 && !is_64bit)
     {
       macho->offset32 = 0;
       macho->end32 = grub_file_size (file);
     }
 
   /* Is it a thin 64-bit file? */
-  if (filestart.thin64.magic == GRUB_MACHO_MAGIC64)
+  if (filestart.thin64.magic == GRUB_MACHO_MAGIC64 && is_64bit)
+    {
+      macho->offset64 = 0;
+      macho->end64 = grub_file_size (file);
+    }
+
+  if (grub_memcmp (filestart.lzss.magic, GRUB_MACHO_LZSS_MAGIC,
+                  sizeof (filestart.lzss.magic)) == 0 && !is_64bit)
+    {
+      macho->offset32 = 0;
+      macho->end32 = grub_file_size (file);
+    }
+
+  /* Is it a thin 64-bit file? */
+  if (grub_memcmp (filestart.lzss.magic, GRUB_MACHO_LZSS_MAGIC,
+                  sizeof (filestart.lzss.magic)) == 0 && is_64bit)
     {
       macho->offset64 = 0;
       macho->end64 = grub_file_size (file);
@@ -138,15 +161,30 @@ grub_macho_file (grub_file_t file, const char *filename)
   grub_macho_parse32 (macho, filename);
   grub_macho_parse64 (macho, filename);
 
+  if (macho->offset32 == -1 && !is_64bit)
+    {
+      grub_error (GRUB_ERR_BAD_OS,
+                 "Mach-O doesn't contain suitable 32-bit architecture");
+      goto fail;
+    }
+
+  if (macho->offset64 == -1 && is_64bit)
+    {
+      grub_error (GRUB_ERR_BAD_OS,
+                 "Mach-O doesn't contain suitable 64-bit architecture");
+      goto fail;
+    }
+
   return macho;
 
 fail:
+  macho->file = 0;
   grub_macho_close (macho);
   return 0;
 }
 
 grub_macho_t
-grub_macho_open (const char *name)
+grub_macho_open (const char *name, int is_64bit)
 {
   grub_file_t file;
   grub_macho_t macho;
@@ -155,7 +193,7 @@ grub_macho_open (const char *name)
   if (! file)
     return 0;
 
-  macho = grub_macho_file (file, name);
+  macho = grub_macho_file (file, name, is_64bit);
   if (! macho)
     grub_file_close (file);
 
index 0d740eda7c38bf4f1c53439917393bedd7ca2dcd..eda8d9ed7d67d8738b1efdc671fe3362d7cb6c0f 100644 (file)
@@ -11,6 +11,10 @@ typedef struct grub_macho_thread32 grub_macho_thread_t;
 #define cmdsizeXX cmdsize32
 #define cmdsXX cmds32
 #define endXX end32
+#define uncompressedXX uncompressed32
+#define compressedXX compressed32
+#define uncompressed_sizeXX uncompressed_size32
+#define compressed_sizeXX compressed_size32
 #define XX "32"
 #define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC32
 #define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT32
index 17a8021e0560797d43f5cdeebd08890a5812aed1..417a4a83d5c3c4733cb4fba680f1cd47362aa448 100644 (file)
@@ -11,6 +11,10 @@ typedef struct grub_macho_thread64 grub_macho_thread_t;
 #define cmdsizeXX cmdsize64
 #define cmdsXX cmds64
 #define endXX end64
+#define uncompressedXX uncompressed64
+#define compressedXX compressed64
+#define uncompressed_sizeXX uncompressed_size64
+#define compressed_sizeXX compressed_size64
 #define XX "64"
 #define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC64
 #define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT64
index 313c5baa7a2890d934dfa5203a933fe211c3528d..0778831abab200bc96feef742b475c402f3ea11b 100644 (file)
@@ -6,7 +6,7 @@
 
 #define min(a,b) (((a) < (b)) ? (a) : (b))
 
-int
+static int
 SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
 {
   return macho->offsetXX != -1;
@@ -15,16 +15,19 @@ SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
 void
 SUFFIX (grub_macho_parse) (grub_macho_t macho, const char *filename)
 {
-  grub_macho_header_t head;
+  union {
+    struct grub_macho_lzss_header lzss;
+    grub_macho_header_t macho;
+  } head;
 
   /* Is there any candidate at all? */
   if (macho->offsetXX == -1)
     return;
 
-  /* Read header and check magic*/
+  /* Read header and check magic.  */
   if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
       || grub_file_read (macho->file, &head, sizeof (head))
-      != sizeof(head))
+      != sizeof (head))
     {
       if (!grub_errno)
        grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
@@ -32,7 +35,25 @@ SUFFIX (grub_macho_parse) (grub_macho_t macho, const char *filename)
       macho->offsetXX = -1;
       return;
     }
-  if (head.magic != GRUB_MACHO_MAGIC)
+  if (grub_memcmp (head.lzss.magic, GRUB_MACHO_LZSS_MAGIC,
+                  sizeof (head.lzss.magic)) == 0)
+    {
+      macho->compressed_sizeXX = grub_be_to_cpu32 (head.lzss.compressed_size);
+      macho->uncompressed_sizeXX
+       = grub_be_to_cpu32 (head.lzss.uncompressed_size);
+      if (macho->uncompressed_sizeXX < sizeof (head.macho))
+       {
+         grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+                     filename);
+         macho->offsetXX = -1;
+         return;
+       }
+      /* Skip header check.  */
+      macho->compressedXX = 1;
+      return;
+    }
+
+  if (head.macho.magic != GRUB_MACHO_MAGIC)
     {
       grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
       macho->offsetXX = -1;
@@ -40,12 +61,14 @@ SUFFIX (grub_macho_parse) (grub_macho_t macho, const char *filename)
     }
 
   /* Read commands. */
-  macho->ncmdsXX = head.ncmds;
-  macho->cmdsizeXX = head.sizeofcmds;
-  macho->cmdsXX = grub_malloc(macho->cmdsizeXX);
+  macho->ncmdsXX = head.macho.ncmds;
+  macho->cmdsizeXX = head.macho.sizeofcmds;
+  macho->cmdsXX = grub_malloc (macho->cmdsizeXX);
   if (! macho->cmdsXX)
     return;
-  if (grub_file_read (macho->file, macho->cmdsXX,
+  if (grub_file_seek (macho->file, macho->offsetXX
+                     + sizeof (grub_macho_header_t)) == (grub_off_t) -1
+      || grub_file_read (macho->file, macho->cmdsXX,
                      (grub_size_t) macho->cmdsizeXX)
       != (grub_ssize_t) macho->cmdsizeXX)
     {
@@ -63,12 +86,76 @@ typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
 static grub_err_t
 grub_macho_cmds_iterate (grub_macho_t macho,
                         grub_macho_iter_hook_t hook,
-                        void *hook_arg)
+                        void *hook_arg,
+                        const char *filename)
 {
-  grub_uint8_t *hdrs = macho->cmdsXX;
+  grub_uint8_t *hdrs;
   int i;
+
+  if (macho->compressedXX && !macho->uncompressedXX)
+    {
+      grub_uint8_t *tmp;
+      grub_macho_header_t *head;
+      macho->uncompressedXX = grub_malloc (macho->uncompressed_sizeXX);
+      if (!macho->uncompressedXX)
+       return grub_errno;
+      tmp = grub_malloc (macho->compressed_sizeXX);
+      if (!tmp)
+       {
+         grub_free (macho->uncompressedXX);
+         macho->uncompressedXX = 0;
+         return grub_errno;
+       }
+      if (grub_file_seek (macho->file, macho->offsetXX
+                         + GRUB_MACHO_LZSS_OFFSET) == (grub_off_t) -1
+         || grub_file_read (macho->file, tmp,
+                            (grub_size_t) macho->compressed_sizeXX)
+         != (grub_ssize_t) macho->compressed_sizeXX)
+       {
+         if (!grub_errno)
+           grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+                       filename);
+         grub_free (tmp);
+         grub_free (macho->uncompressedXX);
+         macho->uncompressedXX = 0;
+         macho->offsetXX = -1;
+         return grub_errno;
+       }
+      if (grub_decompress_lzss (macho->uncompressedXX,
+                               macho->uncompressedXX
+                               + macho->uncompressed_sizeXX,
+                               tmp, tmp + macho->compressed_sizeXX)
+         != macho->uncompressed_sizeXX)
+       {
+         if (!grub_errno)
+           grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+                       filename);
+         grub_free (tmp);
+         grub_free (macho->uncompressedXX);
+         macho->uncompressedXX = 0;
+         macho->offsetXX = -1;
+         return grub_errno;
+       }
+      grub_free (tmp);
+      head = (grub_macho_header_t *) macho->uncompressedXX;
+      macho->ncmdsXX = head->ncmds;
+      macho->cmdsizeXX = head->sizeofcmds;
+      macho->cmdsXX = macho->uncompressedXX + sizeof (grub_macho_header_t);
+      if (sizeof (grub_macho_header_t) + macho->cmdsizeXX
+         >= macho->uncompressed_sizeXX)
+       {
+         grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+                     filename);
+         grub_free (macho->uncompressedXX);
+         macho->uncompressedXX = 0;
+         macho->offsetXX = -1;
+         return grub_errno;
+       }
+    }
+
   if (! macho->cmdsXX)
     return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
+  hdrs = macho->cmdsXX;
   for (i = 0; i < macho->ncmdsXX; i++)
     {
       struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
@@ -116,7 +203,8 @@ SUFFIX (grub_macho_readfile) (grub_macho_t macho,
 /* Calculate the amount of memory spanned by the segments. */
 grub_err_t
 SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
-                         grub_macho_addr_t *segments_end, int flags)
+                         grub_macho_addr_t *segments_end, int flags,
+                         const char *filename)
 {
   int nr_phdrs = 0;
 
@@ -149,7 +237,7 @@ SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
   *segments_start = (grub_macho_addr_t) -1;
   *segments_end = 0;
 
-  grub_macho_cmds_iterate (macho, calcsize, 0);
+  grub_macho_cmds_iterate (macho, calcsize, 0, filename);
 
   if (nr_phdrs == 0)
     return grub_error (GRUB_ERR_BAD_OS, "no program headers present");
@@ -183,16 +271,31 @@ SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
     if (! hdr->vmsize)
       return 0;
 
-    if (grub_file_seek (_macho->file, hdr->fileoff
-                       + _macho->offsetXX) == (grub_off_t) -1)
-      return 1;
-
     if (hdr->filesize)
       {
-       grub_ssize_t read;
-       read = grub_file_read (_macho->file, offset + hdr->vmaddr,
-                                  min (hdr->filesize, hdr->vmsize));
-       if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
+       grub_ssize_t read, toread = min (hdr->filesize, hdr->vmsize);
+       if (macho->uncompressedXX)
+         {
+           if (hdr->fileoff + toread
+               > _macho->uncompressed_sizeXX)
+             read = -1;
+           else
+             {
+               read = toread;
+               grub_memcpy (offset + hdr->vmaddr,
+                            _macho->uncompressedXX + hdr->fileoff, read);
+             }
+         }
+       else
+         {
+           if (grub_file_seek (_macho->file, hdr->fileoff
+                               + _macho->offsetXX) == (grub_off_t) -1)
+             return 1;
+           read = grub_file_read (_macho->file, offset + hdr->vmaddr,
+                                  toread);
+         }
+
+       if (read != toread)
          {
            /* XXX How can we free memory from `load_hook'? */
            if (!grub_errno)
@@ -229,13 +332,13 @@ SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
   if (darwin_version)
     *darwin_version = 0;
 
-  grub_macho_cmds_iterate (macho, do_load, 0);
+  grub_macho_cmds_iterate (macho, do_load, 0, filename);
 
   return grub_errno;
 }
 
 grub_macho_addr_t
-SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
+SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho, const char *filename)
 {
   grub_macho_addr_t entry_point = 0;
   auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
@@ -249,6 +352,6 @@ SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
       entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
     return 0;
   }
-  grub_macho_cmds_iterate (macho, hook, 0);
+  grub_macho_cmds_iterate (macho, hook, 0, filename);
   return entry_point;
 }
index 88c17a58254d361e7d0910e8e54224f70aab3c87..ed3fc72a739bec6f4ea6ee7314572c08a2607673 100644 (file)
@@ -351,17 +351,12 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
 
   grub_xnu_unload ();
 
-  macho = grub_macho_open (args[0]);
+  macho = grub_macho_open (args[0], 0);
   if (! macho)
     return grub_errno;
-  if (! grub_macho_contains_macho32 (macho))
-    {
-      grub_macho_close (macho);
-      return grub_error (GRUB_ERR_BAD_OS,
-                        "kernel doesn't contain suitable 32-bit architecture");
-    }
 
-  err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
+  err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
+                          args[0]);
   if (err)
     {
       grub_macho_close (macho);
@@ -396,7 +391,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
       return err;
     }
 
-  grub_xnu_entry_point = grub_macho_get_entry_point32 (macho);
+  grub_xnu_entry_point = grub_macho_get_entry_point32 (macho, args[0]);
   if (! grub_xnu_entry_point)
     {
       grub_macho_close (macho);
@@ -461,17 +456,12 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
 
   grub_xnu_unload ();
 
-  macho = grub_macho_open (args[0]);
+  macho = grub_macho_open (args[0], 1);
   if (! macho)
     return grub_errno;
-  if (! grub_macho_contains_macho64 (macho))
-    {
-      grub_macho_close (macho);
-      return grub_error (GRUB_ERR_BAD_OS,
-                        "kernel doesn't contain suitable 64-bit architecture");
-    }
 
-  err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
+  err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
+                          args[0]);
   if (err)
     {
       grub_macho_close (macho);
@@ -509,7 +499,8 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
       return err;
     }
 
-  grub_xnu_entry_point = grub_macho_get_entry_point64 (macho) & 0x0fffffff;
+  grub_xnu_entry_point = grub_macho_get_entry_point64 (macho, args[0])
+    & 0x0fffffff;
   if (! grub_xnu_entry_point)
     {
       grub_macho_close (macho);
@@ -667,18 +658,16 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
   /* Compute the needed space. */
   if (binaryfile)
     {
-      macho = grub_macho_file (binaryfile, filename);
-      if (! macho || ! grub_macho_contains_macho32 (macho))
+      macho = grub_macho_file (binaryfile, filename, grub_xnu_is_64bit);
+      if (!macho)
+       grub_file_close (binaryfile);
+      else
        {
-         if (macho)
-           grub_macho_close (macho);
-         return grub_error (GRUB_ERR_BAD_OS,
-                            "extension doesn't contain suitable architecture");
+         if (grub_xnu_is_64bit)
+           machosize = grub_macho_filesize64 (macho);
+         else
+           machosize = grub_macho_filesize32 (macho);
        }
-      if (grub_xnu_is_64bit)
-       machosize = grub_macho_filesize64 (macho);
-      else
-       machosize = grub_macho_filesize32 (macho);
       neededspace += machosize;
     }
   else
index 82145835f0d3361f084d3aeb3b2993cf7e05a168..6a98b6e127b7bd5ad0b5085a1a394195ae68b893 100644 (file)
@@ -68,14 +68,6 @@ struct grub_macho_header64
   grub_uint32_t reserved;
 } __attribute__ ((packed));
 
-/* Convenience union. What do we need to load to identify the file type. */
-union grub_macho_filestart
-{
-  struct grub_macho_fat_header fat;
-  struct grub_macho_header32 thin32;
-  struct grub_macho_header64 thin64;
-} __attribute__ ((packed));
-
 /* Common header of Mach-O commands. */
 struct grub_macho_cmd
 {
@@ -121,4 +113,28 @@ struct grub_macho_segment64
 
 #define GRUB_MACHO_CMD_THREAD     5
 
+struct grub_macho_lzss_header
+{
+  char magic[8];
+#define GRUB_MACHO_LZSS_MAGIC "complzss"
+  grub_uint32_t unused;
+  grub_uint32_t uncompressed_size;
+  grub_uint32_t compressed_size;
+};
+
+/* Convenience union. What do we need to load to identify the file type. */
+union grub_macho_filestart
+{
+  struct grub_macho_fat_header fat;
+  struct grub_macho_header32 thin32;
+  struct grub_macho_header64 thin64;
+  struct grub_macho_lzss_header lzss;
+} __attribute__ ((packed));
+
+#define GRUB_MACHO_LZSS_OFFSET 0x180
+
+grub_size_t
+grub_decompress_lzss (grub_uint8_t *dst, grub_uint8_t *dstend,
+                     grub_uint8_t *src, grub_uint8_t *srcend);
+
 #endif
index bb0374c882c29d9b36fe4365a75893ad94e1f33d..1eec118f15f7651f764a54ca5d1db05ea811bd41 100644 (file)
@@ -33,27 +33,38 @@ struct grub_macho_file
   int ncmds32;
   grub_size_t cmdsize32;
   grub_uint8_t *cmds32;
+  grub_uint8_t *uncompressed32;
+  int compressed32;
+  grub_size_t compressed_size32;
+  grub_size_t uncompressed_size32;
   grub_ssize_t offset64;
   grub_ssize_t end64;
   int ncmds64;
   grub_size_t cmdsize64;
   grub_uint8_t *cmds64;
+  grub_uint8_t *uncompressed64;
+  int compressed64;
+  grub_size_t compressed_size64;
+  grub_size_t uncompressed_size64;
 };
 typedef struct grub_macho_file *grub_macho_t;
 
-grub_macho_t grub_macho_open (const char *);
-grub_macho_t grub_macho_file (grub_file_t file, const char *filename);
+grub_macho_t grub_macho_open (const char *, int is_64bit);
+grub_macho_t grub_macho_file (grub_file_t file, const char *filename,
+                             int is_64bit);
 grub_err_t grub_macho_close (grub_macho_t);
 
-int grub_macho_contains_macho32 (grub_macho_t);
 grub_err_t grub_macho_size32 (grub_macho_t macho, grub_uint32_t *segments_start,
-                             grub_uint32_t *segments_end, int flags);
-grub_uint32_t grub_macho_get_entry_point32 (grub_macho_t macho);
+                             grub_uint32_t *segments_end, int flags,
+                             const char *filename);
+grub_uint32_t grub_macho_get_entry_point32 (grub_macho_t macho,
+                                           const char *filename);
 
-int grub_macho_contains_macho64 (grub_macho_t);
 grub_err_t grub_macho_size64 (grub_macho_t macho, grub_uint64_t *segments_start,
-                             grub_uint64_t *segments_end, int flags);
-grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho);
+                             grub_uint64_t *segments_end, int flags,
+                             const char *filename);
+grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho,
+                                           const char *filename);
 
 /* Ignore BSS segments when loading. */
 #define GRUB_MACHO_NOBSS 0x1
index 63800c10b7ef9a56c76cb9de250442aa554d4835..3ba2458b662959a77e99062554d588a50f08ff2e 100644 (file)
@@ -66,8 +66,11 @@ EOF
            if [ -f /Extra/DSDT.aml ]; then
               acpi -e /Extra/DSDT.aml
            fi
-           $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid
-           if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then
+           if [ /kernelcache -nt /System/Library/Extensions ]; then
+              $1 /kernelcache boot-uuid=\${uuid} rd=*uuid
+           else
+              $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid
+           elif [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then
               xnu_mkext /System/Library/Extensions.mkext
            else
               xnu_kextdir /System/Library/Extensions