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.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2012-02-29 13:26:13 +01:00
parent ebd17d6f51
commit 99ce1597a4
11 changed files with 339 additions and 80 deletions

View file

@ -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> 2012-02-29 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/disk/pata.c (grub_pata_readwrite): Fix ATAPI protocol error. * grub-core/disk/pata.c (grub_pata_readwrite): Fix ATAPI protocol error.

View file

@ -1378,6 +1378,7 @@ module = {
x86 = loader/macho64.c; x86 = loader/macho64.c;
x86 = loader/macho.c; x86 = loader/macho.c;
x86 = loader/xnu.c; x86 = loader/xnu.c;
x86 = loader/lzss.c;
extra_dist = loader/machoXX.c; extra_dist = loader/machoXX.c;
enable = x86; enable = x86;

56
grub-core/loader/lzss.c Normal file
View file

@ -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;
}

View file

@ -35,8 +35,12 @@ grub_macho_close (grub_macho_t macho)
{ {
grub_file_t file = macho->file; grub_file_t file = macho->file;
grub_free (macho->cmds32); if (!macho->uncompressed32)
grub_free (macho->cmds64); grub_free (macho->cmds32);
grub_free (macho->uncompressed32);
if (!macho->uncompressed64)
grub_free (macho->cmds64);
grub_free (macho->uncompressed64);
grub_free (macho); grub_free (macho);
@ -47,7 +51,7 @@ grub_macho_close (grub_macho_t macho)
} }
grub_macho_t 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; grub_macho_t macho;
union grub_macho_filestart filestart; union grub_macho_filestart filestart;
@ -63,6 +67,10 @@ grub_macho_file (grub_file_t file, const char *filename)
macho->end64 = -1; macho->end64 = -1;
macho->cmds32 = 0; macho->cmds32 = 0;
macho->cmds64 = 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) if (grub_file_seek (macho->file, 0) == (grub_off_t) -1)
goto fail; goto fail;
@ -104,14 +112,14 @@ grub_macho_file (grub_file_t file, const char *filename)
for (i = 0; i < narchs; i++) for (i = 0; i < narchs; i++)
{ {
if (GRUB_MACHO_CPUTYPE_IS_HOST32 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->offset32 = grub_be_to_cpu32 (archs[i].offset);
macho->end32 = grub_be_to_cpu32 (archs[i].offset) macho->end32 = grub_be_to_cpu32 (archs[i].offset)
+ grub_be_to_cpu32 (archs[i].size); + grub_be_to_cpu32 (archs[i].size);
} }
if (GRUB_MACHO_CPUTYPE_IS_HOST64 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->offset64 = grub_be_to_cpu32 (archs[i].offset);
macho->end64 = 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? */ /* 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->offset32 = 0;
macho->end32 = grub_file_size (file); macho->end32 = grub_file_size (file);
} }
/* Is it a thin 64-bit 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->offset64 = 0;
macho->end64 = grub_file_size (file); 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_parse32 (macho, filename);
grub_macho_parse64 (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; return macho;
fail: fail:
macho->file = 0;
grub_macho_close (macho); grub_macho_close (macho);
return 0; return 0;
} }
grub_macho_t grub_macho_t
grub_macho_open (const char *name) grub_macho_open (const char *name, int is_64bit)
{ {
grub_file_t file; grub_file_t file;
grub_macho_t macho; grub_macho_t macho;
@ -155,7 +193,7 @@ grub_macho_open (const char *name)
if (! file) if (! file)
return 0; return 0;
macho = grub_macho_file (file, name); macho = grub_macho_file (file, name, is_64bit);
if (! macho) if (! macho)
grub_file_close (file); grub_file_close (file);

View file

@ -11,6 +11,10 @@ typedef struct grub_macho_thread32 grub_macho_thread_t;
#define cmdsizeXX cmdsize32 #define cmdsizeXX cmdsize32
#define cmdsXX cmds32 #define cmdsXX cmds32
#define endXX end32 #define endXX end32
#define uncompressedXX uncompressed32
#define compressedXX compressed32
#define uncompressed_sizeXX uncompressed_size32
#define compressed_sizeXX compressed_size32
#define XX "32" #define XX "32"
#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC32 #define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC32
#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT32 #define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT32

View file

@ -11,6 +11,10 @@ typedef struct grub_macho_thread64 grub_macho_thread_t;
#define cmdsizeXX cmdsize64 #define cmdsizeXX cmdsize64
#define cmdsXX cmds64 #define cmdsXX cmds64
#define endXX end64 #define endXX end64
#define uncompressedXX uncompressed64
#define compressedXX compressed64
#define uncompressed_sizeXX uncompressed_size64
#define compressed_sizeXX compressed_size64
#define XX "64" #define XX "64"
#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC64 #define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC64
#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT64 #define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT64

View file

@ -6,7 +6,7 @@
#define min(a,b) (((a) < (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b))
int static int
SUFFIX (grub_macho_contains_macho) (grub_macho_t macho) SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
{ {
return macho->offsetXX != -1; return macho->offsetXX != -1;
@ -15,16 +15,19 @@ SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
void void
SUFFIX (grub_macho_parse) (grub_macho_t macho, const char *filename) 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? */ /* Is there any candidate at all? */
if (macho->offsetXX == -1) if (macho->offsetXX == -1)
return; return;
/* Read header and check magic*/ /* Read header and check magic. */
if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1 if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
|| grub_file_read (macho->file, &head, sizeof (head)) || grub_file_read (macho->file, &head, sizeof (head))
!= sizeof(head)) != sizeof (head))
{ {
if (!grub_errno) if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), 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; macho->offsetXX = -1;
return; 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"); grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
macho->offsetXX = -1; macho->offsetXX = -1;
@ -40,12 +61,14 @@ SUFFIX (grub_macho_parse) (grub_macho_t macho, const char *filename)
} }
/* Read commands. */ /* Read commands. */
macho->ncmdsXX = head.ncmds; macho->ncmdsXX = head.macho.ncmds;
macho->cmdsizeXX = head.sizeofcmds; macho->cmdsizeXX = head.macho.sizeofcmds;
macho->cmdsXX = grub_malloc(macho->cmdsizeXX); macho->cmdsXX = grub_malloc (macho->cmdsizeXX);
if (! macho->cmdsXX) if (! macho->cmdsXX)
return; 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_size_t) macho->cmdsizeXX)
!= (grub_ssize_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 static grub_err_t
grub_macho_cmds_iterate (grub_macho_t macho, grub_macho_cmds_iterate (grub_macho_t macho,
grub_macho_iter_hook_t hook, 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; 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) if (! macho->cmdsXX)
return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O"); return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
hdrs = macho->cmdsXX;
for (i = 0; i < macho->ncmdsXX; i++) for (i = 0; i < macho->ncmdsXX; i++)
{ {
struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs; 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. */ /* Calculate the amount of memory spanned by the segments. */
grub_err_t grub_err_t
SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start, 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; 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_start = (grub_macho_addr_t) -1;
*segments_end = 0; *segments_end = 0;
grub_macho_cmds_iterate (macho, calcsize, 0); grub_macho_cmds_iterate (macho, calcsize, 0, filename);
if (nr_phdrs == 0) if (nr_phdrs == 0)
return grub_error (GRUB_ERR_BAD_OS, "no program headers present"); 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) if (! hdr->vmsize)
return 0; return 0;
if (grub_file_seek (_macho->file, hdr->fileoff
+ _macho->offsetXX) == (grub_off_t) -1)
return 1;
if (hdr->filesize) if (hdr->filesize)
{ {
grub_ssize_t read; grub_ssize_t read, toread = min (hdr->filesize, hdr->vmsize);
read = grub_file_read (_macho->file, offset + hdr->vmaddr, if (macho->uncompressedXX)
min (hdr->filesize, hdr->vmsize)); {
if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize)) 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'? */ /* XXX How can we free memory from `load_hook'? */
if (!grub_errno) if (!grub_errno)
@ -229,13 +332,13 @@ SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
if (darwin_version) if (darwin_version)
*darwin_version = 0; *darwin_version = 0;
grub_macho_cmds_iterate (macho, do_load, 0); grub_macho_cmds_iterate (macho, do_load, 0, filename);
return grub_errno; return grub_errno;
} }
grub_macho_addr_t 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; grub_macho_addr_t entry_point = 0;
auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho, 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; entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
return 0; return 0;
} }
grub_macho_cmds_iterate (macho, hook, 0); grub_macho_cmds_iterate (macho, hook, 0, filename);
return entry_point; return entry_point;
} }

View file

@ -351,17 +351,12 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
grub_xnu_unload (); grub_xnu_unload ();
macho = grub_macho_open (args[0]); macho = grub_macho_open (args[0], 0);
if (! macho) if (! macho)
return grub_errno; 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) if (err)
{ {
grub_macho_close (macho); grub_macho_close (macho);
@ -396,7 +391,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
return err; 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) if (! grub_xnu_entry_point)
{ {
grub_macho_close (macho); grub_macho_close (macho);
@ -461,17 +456,12 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
grub_xnu_unload (); grub_xnu_unload ();
macho = grub_macho_open (args[0]); macho = grub_macho_open (args[0], 1);
if (! macho) if (! macho)
return grub_errno; 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) if (err)
{ {
grub_macho_close (macho); grub_macho_close (macho);
@ -509,7 +499,8 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
return err; 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) if (! grub_xnu_entry_point)
{ {
grub_macho_close (macho); grub_macho_close (macho);
@ -667,18 +658,16 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
/* Compute the needed space. */ /* Compute the needed space. */
if (binaryfile) if (binaryfile)
{ {
macho = grub_macho_file (binaryfile, filename); macho = grub_macho_file (binaryfile, filename, grub_xnu_is_64bit);
if (! macho || ! grub_macho_contains_macho32 (macho)) if (!macho)
{ grub_file_close (binaryfile);
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 else
machosize = grub_macho_filesize32 (macho); {
if (grub_xnu_is_64bit)
machosize = grub_macho_filesize64 (macho);
else
machosize = grub_macho_filesize32 (macho);
}
neededspace += machosize; neededspace += machosize;
} }
else else

View file

@ -68,14 +68,6 @@ struct grub_macho_header64
grub_uint32_t reserved; grub_uint32_t reserved;
} __attribute__ ((packed)); } __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. */ /* Common header of Mach-O commands. */
struct grub_macho_cmd struct grub_macho_cmd
{ {
@ -121,4 +113,28 @@ struct grub_macho_segment64
#define GRUB_MACHO_CMD_THREAD 5 #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 #endif

View file

@ -33,27 +33,38 @@ struct grub_macho_file
int ncmds32; int ncmds32;
grub_size_t cmdsize32; grub_size_t cmdsize32;
grub_uint8_t *cmds32; 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 offset64;
grub_ssize_t end64; grub_ssize_t end64;
int ncmds64; int ncmds64;
grub_size_t cmdsize64; grub_size_t cmdsize64;
grub_uint8_t *cmds64; 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; typedef struct grub_macho_file *grub_macho_t;
grub_macho_t grub_macho_open (const char *); grub_macho_t grub_macho_open (const char *, int is_64bit);
grub_macho_t grub_macho_file (grub_file_t file, const char *filename); 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); 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_err_t grub_macho_size32 (grub_macho_t macho, grub_uint32_t *segments_start,
grub_uint32_t *segments_end, int flags); grub_uint32_t *segments_end, int flags,
grub_uint32_t grub_macho_get_entry_point32 (grub_macho_t macho); 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_err_t grub_macho_size64 (grub_macho_t macho, grub_uint64_t *segments_start,
grub_uint64_t *segments_end, int flags); grub_uint64_t *segments_end, int flags,
grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho); const char *filename);
grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho,
const char *filename);
/* Ignore BSS segments when loading. */ /* Ignore BSS segments when loading. */
#define GRUB_MACHO_NOBSS 0x1 #define GRUB_MACHO_NOBSS 0x1

View file

@ -66,8 +66,11 @@ EOF
if [ -f /Extra/DSDT.aml ]; then if [ -f /Extra/DSDT.aml ]; then
acpi -e /Extra/DSDT.aml acpi -e /Extra/DSDT.aml
fi fi
$1 /mach_kernel boot-uuid=\${uuid} rd=*uuid if [ /kernelcache -nt /System/Library/Extensions ]; then
if [ /System/Library/Extensions.mkext -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 xnu_mkext /System/Library/Extensions.mkext
else else
xnu_kextdir /System/Library/Extensions xnu_kextdir /System/Library/Extensions