On Tue, Jun 9, 2009 at 12:01 AM, Pavel Roskin<pro...@gnu.org> wrote: > On Mon, 2009-06-08 at 22:50 +0200, Vladimir 'phcoder' Serbinenko wrote: > >> Here is the improved patch. I deliberately ignored md5 comments >> because this part will be gone anyway whel Michael Gorven signs his >> copyright assignment and we incorporate luks patches > > Please consider if it would be better to supply the filesystem UUID on > the command line rather than the device name. That would make xnu_uuid > leaner and more flexible. I think we need the "uuid" command that would > get the uuid and the "xnu_uuid" command that would convert it. > > It would be great if you run xnu_uuid.c through indent. The coding > style is quite different from that used elsewhere in GRUB. Or at least > please strip trailing spaces. > > "file name required" is a wrong error message. It should be "device > file required". I think it would be better to expand "fs" and "FS" in > error messages as "filesystem". > > If the variable name is not specified, I think xnu_uuid should just > output the UUID without any explanations. Explanations belong to the > help, not to the normal output. GRUB2 becomes increasingly more complex. We try to document it on grub.enbug.org but when user needs the info the most his only system is unbootable. Perhaps we should incorporate a more extensive help into grub2 itself. man format looks rather easy to parse > > "(void)mod;" is not needed. The "buf" variable in grub_cmd_xnu_uuid() > is unused. > > -- > Regards, > Pavel Roskin > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel >
-- Regards Vladimir 'phcoder' Serbinenko
diff --git a/ChangeLog b/ChangeLog index 556b17d..65a859d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2009-06-08 Vladimir Serbinenko <phco...@gmail.com> + xnu_uuid command + + * commands/xnu_uuid.c: new file + * conf/common.rmk (pkglib_MODULES): add xnu_uuid.mod + (xnu_uuid_mod_SOURCES): new variable + (xnu_uuid_mod_CFLAGS): likewise + (xnu_uuid_mod_LDFLAGS): likewise + * conf/i386-coreboot.rmk (grub_emu_SOURCES): add commands/probe.c + * conf/i386-ieee1275.rmk: likewise + * conf/i386-pc.rmk: likewise + * conf/powerpc-ieee1275.rmk: likewise + * conf/sparc64-ieee1275.rmk: likewise + * util/grub.d/30_os-prober.in: use UUID for Mac OS X/Darwin + +2009-06-08 Vladimir Serbinenko <phco...@gmail.com> + probe command * commands/probe.c: new file diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c new file mode 100644 index 0000000..1302881 --- /dev/null +++ b/commands/xnu_uuid.c @@ -0,0 +1,399 @@ +/* xnu_uuid.c - transform 64-bit serial number + to 128-bit uuid suitable for xnu. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1995,1996,1998,1999,2001,2002, + * 2003, 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/types.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/fs.h> +#include <grub/file.h> +#include <grub/misc.h> +#include <grub/env.h> +#include <grub/command.h> + +struct tohash +{ + grub_uint8_t prefix[16]; + grub_uint64_t serial; +} __attribute__ ((packed)); + +/* This prefix is used by xnu and boot-132 to hash + together with volume serial. */ +static grub_uint8_t hash_prefix[16] + = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, + 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; + +#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) + +typedef struct { + grub_uint32_t A,B,C,D; /* chaining variables */ + grub_uint32_t nblocks; + grub_uint8_t buf[64]; + int count; +} MD5_CONTEXT; + +static void +md5_init( void *context ) +{ + MD5_CONTEXT *ctx = context; + + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->nblocks = 0; + ctx->count = 0; +} + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + + +/**************** + * transform n*64 grub_uint8_ts + */ +static void +transform ( MD5_CONTEXT *ctx, const unsigned char *data ) +{ + grub_uint32_t correct_words[16]; + register grub_uint32_t A = ctx->A; + register grub_uint32_t B = ctx->B; + register grub_uint32_t C = ctx->C; + register grub_uint32_t D = ctx->D; + grub_uint32_t *cwp = correct_words; + +#ifdef WORDS_BIGENDIAN + { + int i; + grub_uint8_t *p2, *p1; + for(i=0, p1=data, p2=(grub_uint8_t*)correct_words; i < 16; i++, p2 += 4 ) + { + p2[3] = *p1++; + p2[2] = *p1++; + p2[1] = *p1++; + p2[0] = *p1++; + } + } +#else + memcpy( correct_words, data, 64 ); +#endif + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++) + T; \ + a = rol(a, s); \ + a += b; \ + } \ + while (0) + + /* Before we start, one word about the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + a = rol(a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Put checksum in context given as argument. */ + ctx->A += A; + ctx->B += B; + ctx->C += C; + ctx->D += D; +} + +/* The routine updates the message-digest context to + * account for the presence of each of the characters inBuf[0..inLen-1] + * in the message whose digest is being computed. + */ +static void +md5_write( void *context, const void *inbuf_arg , grub_size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + MD5_CONTEXT *hd = context; + + if( hd->count == 64 ) /* flush the buffer */ + { + transform( hd, hd->buf ); + // _gcry_burn_stack (80+6*sizeof(void*)); + hd->count = 0; + hd->nblocks++; + } + if( !inbuf ) + return; + + if( hd->count ) + { + for( ; inlen && hd->count < 64; inlen-- ) + hd->buf[hd->count++] = *inbuf++; + md5_write( hd, NULL, 0 ); + if( !inlen ) + return; + } + // _gcry_burn_stack (80+6*sizeof(void*)); + + while( inlen >= 64 ) + { + transform( hd, inbuf ); + hd->count = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + for( ; inlen && hd->count < 64; inlen-- ) + hd->buf[hd->count++] = *inbuf++; + +} + + + +/* The routine final terminates the message-digest computation and + * ends with the desired message digest in mdContext->digest[0...15]. + * The handle is prepared for a new MD5 cycle. + * Returns 16 grub_uint8_ts representing the digest. + */ +static void +md5_final( void *context) +{ + MD5_CONTEXT *hd = context; + grub_uint32_t t, msb, lsb; + grub_uint8_t *p; + + md5_write(hd, NULL, 0); /* flush */; + + t = hd->nblocks; + /* multiply by 64 to make a grub_uint8_t count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if( (lsb += hd->count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if( hd->count < 56 ) /* enough room */ + { + hd->buf[hd->count++] = 0x80; /* pad */ + while( hd->count < 56 ) + hd->buf[hd->count++] = 0; /* pad */ + } + else /* need one extra block */ + { + hd->buf[hd->count++] = 0x80; /* pad character */ + while( hd->count < 64 ) + hd->buf[hd->count++] = 0; + md5_write(hd, NULL, 0); /* flush */; + grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + hd->buf[56] = lsb ; + hd->buf[57] = lsb >> 8; + hd->buf[58] = lsb >> 16; + hd->buf[59] = lsb >> 24; + hd->buf[60] = msb ; + hd->buf[61] = msb >> 8; + hd->buf[62] = msb >> 16; + hd->buf[63] = msb >> 24; + transform( hd, hd->buf ); + // _gcry_burn_stack (80+6*sizeof(void*)); + + p = hd->buf; +#ifdef WORDS_BIGENDIAN +#define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ + *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) +#else /* little endian */ +#define X(a) do { *(grub_uint32_t*)p = (*hd).a ; p += 4; } while(0) +#endif + X(A); + X(B); + X(C); + X(D); +#undef X + +} + +/** + * GRUB2 Crypto Interface + * Written by Michael Gorven + */ +static grub_err_t +md5 (const char *in, grub_size_t insize, char *out) +{ + MD5_CONTEXT hd; + + md5_init (&hd); + md5_write (&hd, in, insize); + md5_final (&hd); + grub_memcpy (out, hd.buf, 16); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct tohash hashme; + grub_uint8_t xnu_uuid[16]; + char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; + char *ptr; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); + + hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); + grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); + + md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); + xnu_uuid[6] = (xnu_uuid[6] & 0xf) | 0x30; + xnu_uuid[8] = (xnu_uuid[8] & 0x3f) | 0x80; + grub_sprintf (uuid_string, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], + (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], + (unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5], + (unsigned int) ((xnu_uuid[6] & 0xf) | 0x30), + (unsigned int) xnu_uuid[7], + (unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80), + (unsigned int) xnu_uuid[9], + (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11], + (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13], + (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]); + for (ptr = uuid_string; *ptr; ptr++) + *ptr = grub_toupper (*ptr); + if (argc == 1) + grub_printf ("%s", uuid_string); + if (argc > 1) + grub_env_set (args[1], uuid_string); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; + + +GRUB_MOD_INIT (xnu_uuid) +{ + cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid, + "xnu_uuid GRUBUUID [VARNAME]", + "Transform 64-bit UUID to format " + "suitable for xnu."); +} + +GRUB_MOD_FINI (xnu_uuid) +{ + grub_unregister_command (cmd); +} diff --git a/conf/common.rmk b/conf/common.rmk index b75f50e..584450f 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -591,3 +591,10 @@ bufio_mod_SOURCES = io/bufio.c bufio_mod_CFLAGS = $(COMMON_CFLAGS) bufio_mod_LDFLAGS = $(COMMON_LDFLAGS) +# Misc. +pkglib_MODULES += xnu_uuid.mod + +# For elf.mod. +xnu_uuid_mod_SOURCES = commands/xnu_uuid.c +xnu_uuid_mod_CFLAGS = $(COMMON_CFLAGS) +xnu_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index f2e0dc6..e1fcc46 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -61,7 +61,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/echo.c commands/help.c \ commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ - commands/gptsync.c commands/probe.c \ + commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ lib/hexdump.c commands/i386/cpuid.c \ disk/host.c disk/loopback.c \ \ diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 817a266..7231d28 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -61,7 +61,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/halt.c commands/reboot.c \ - commands/gptsync.c commands/probe.c commands/i386/cpuid.c \ + commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ + commands/i386/cpuid.c \ disk/host.c disk/loopback.c \ \ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index e9496f6..80e8067 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -127,7 +127,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ - commands/gptsync.c commands/probe.c commands/i386/cpuid.c \ + commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ + commands/i386/cpuid.c \ disk/host.c disk/loopback.c disk/scsi.c \ fs/fshelp.c \ \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index b8a0309..4cb8f04 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -45,7 +45,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ commands/search.c commands/handler.c commands/test.c \ commands/ls.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/halt.c commands/reboot.c \ - commands/gptsync.c commands/probe.c \ + commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ disk/loopback.c \ \ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 5700937..82e9b73 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -101,7 +101,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/help.c \ commands/search.c commands/handler.c commands/test.c \ commands/ls.c commands/blocklist.c commands/hexdump.c \ - commands/probe.c \ + commands/probe.c commands/xnu_uuid.c \ lib/hexdump.c commands/halt.c commands/reboot.c \ disk/loopback.c \ \ diff --git a/include/grub/misc.h b/include/grub/misc.h index 23e0ce6..e229062 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -61,6 +61,15 @@ int EXPORT_FUNC(grub_isalpha) (int c); int EXPORT_FUNC(grub_isgraph) (int c); int EXPORT_FUNC(grub_isdigit) (int c); int EXPORT_FUNC(grub_tolower) (int c); +static inline int +grub_toupper (int c) +{ + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + + return c; +} + unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base); unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base); char *EXPORT_FUNC(grub_strdup) (const char *s); diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 7d4d17e..753a367 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -83,12 +83,10 @@ EOF done ;; macosx) - OSXROOT="`grub-probe --target=drive --device ${DEVICE} 2> /dev/null`" - # FIXME: use UUID - OSXDISK=disk"`echo ${OSXROOT} | awk -F , '{ print $1 ; }' | sed 's/(hd//;'`"s"`echo ${OSXROOT} | awk -F , '{ print $2 ; }' | sed 's/)//;'`" + OSXUUID="`grub-probe --target=fs_uuid --device ${DEVICE} 2> /dev/null`" cat << EOF menuentry "${LONGNAME} (on ${DEVICE})" { - set root=${OSXROOT} + search --fs-uuid --set ${OSXUUID} insmod vbe do_resume=0 if [ /var/vm/sleepimage -nt10 / ]; then @@ -97,10 +95,11 @@ menuentry "${LONGNAME} (on ${DEVICE})" { fi fi if [ \$do_resume == 0 ]; then + xnu_uuid ${OSXUUID} uuid if [ -f /Extra/DSDT.aml ]; then acpi -e /Extra/DSDT.aml fi - xnu_kernel /mach_kernel rd=$OSXDISK + xnu_kernel /mach_kernel boot-uuid=\${uuid} rd=*uuid if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then xnu_mkext /System/Library/Extensions.mkext else
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel