commit-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[2163] 2009-05-03 Vladimir Serbinenko <address@hidden>


From: Vladimir Serbinenko
Subject: [2163] 2009-05-03 Vladimir Serbinenko <address@hidden>
Date: Sat, 02 May 2009 23:19:21 +0000

Revision: 2163
          http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=2163
Author:   phcoder
Date:     2009-05-02 23:19:20 +0000 (Sat, 02 May 2009)
Log Message:
-----------
2009-05-03  Vladimir Serbinenko  <address@hidden>

        xnu support

        * conf/i386-efi.rmk (kernel_mod_HEADERS): added i386/pit.h
        (pkglib_MODULES): add xnu.mod
        (xnu_mod_SOURCES): new variable
        (xnu_mod_CFLAGS): likewise
        (xnu_mod_LDFLAGS): likewise
        (xnu_mod_ASFLAGS): likewise
        * conf/i386-pc.rmk: likewise
        * conf/x86_64-efi.rmk: likewise
        * include/grub/efi/efi.h (grub_efi_finish_boot_services): 
        new declaration
        * include/grub/i386/macho.h: new file
        * include/grub/i386/xnu.h: likewise
        * include/grub/macho.h: likewise
        * include/grub/machoload.h: likewise
        * include/grub/x86_64/macho.h: likewise
        * include/grub/x86_64/xnu.h: likewise
        * include/grub/xnu.h: likewise
        * kern/efi/efi.c (grub_efi_finish_boot_services): new function
        * kern/efi/mm.c (MAX_HEAP_SIZE): increase
        * loader/i386/efi/xnu.c: new file
        * loader/i386/pc/xnu.c: likewise
        * loader/i386/xnu.c: likewise
        * loader/i386/xnu_helper.S: likewise
        * loader/macho.c: likewise
        * loader/xnu.c: likewise
        * loader/xnu_resume.c: likewise
        * util/grub-dumpdevtree: likewise
        * include/grub/i386/pit.h: include grub/err.h
        (grub_pit_wait): export
        * util/grub.d/30_os-prober.in: support Darwin/Mac OS X
        

Modified Paths:
--------------
    trunk/grub2/ChangeLog
    trunk/grub2/conf/i386-efi.rmk
    trunk/grub2/conf/i386-pc.rmk
    trunk/grub2/conf/x86_64-efi.rmk
    trunk/grub2/include/grub/efi/efi.h
    trunk/grub2/include/grub/i386/pit.h
    trunk/grub2/kern/efi/efi.c
    trunk/grub2/kern/efi/mm.c
    trunk/grub2/util/grub.d/30_os-prober.in

Added Paths:
-----------
    trunk/grub2/include/grub/i386/macho.h
    trunk/grub2/include/grub/i386/xnu.h
    trunk/grub2/include/grub/macho.h
    trunk/grub2/include/grub/machoload.h
    trunk/grub2/include/grub/x86_64/macho.h
    trunk/grub2/include/grub/x86_64/xnu.h
    trunk/grub2/include/grub/xnu.h
    trunk/grub2/loader/i386/efi/xnu.c
    trunk/grub2/loader/i386/pc/xnu.c
    trunk/grub2/loader/i386/xnu.c
    trunk/grub2/loader/i386/xnu_helper.S
    trunk/grub2/loader/macho.c
    trunk/grub2/loader/xnu.c
    trunk/grub2/loader/xnu_resume.c
    trunk/grub2/util/grub-dumpdevtree

Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog       2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/ChangeLog       2009-05-02 23:19:20 UTC (rev 2163)
@@ -1,3 +1,38 @@
+2009-05-03  Vladimir Serbinenko  <address@hidden>
+
+       xnu support
+
+       * conf/i386-efi.rmk (kernel_mod_HEADERS): added i386/pit.h
+       (pkglib_MODULES): add xnu.mod
+       (xnu_mod_SOURCES): new variable
+       (xnu_mod_CFLAGS): likewise
+       (xnu_mod_LDFLAGS): likewise
+       (xnu_mod_ASFLAGS): likewise
+       * conf/i386-pc.rmk: likewise
+       * conf/x86_64-efi.rmk: likewise
+       * include/grub/efi/efi.h (grub_efi_finish_boot_services): 
+       new declaration
+       * include/grub/i386/macho.h: new file
+       * include/grub/i386/xnu.h: likewise
+       * include/grub/macho.h: likewise
+       * include/grub/machoload.h: likewise
+       * include/grub/x86_64/macho.h: likewise
+       * include/grub/x86_64/xnu.h: likewise
+       * include/grub/xnu.h: likewise
+       * kern/efi/efi.c (grub_efi_finish_boot_services): new function
+       * kern/efi/mm.c (MAX_HEAP_SIZE): increase
+       * loader/i386/efi/xnu.c: new file
+       * loader/i386/pc/xnu.c: likewise
+       * loader/i386/xnu.c: likewise
+       * loader/i386/xnu_helper.S: likewise
+       * loader/macho.c: likewise
+       * loader/xnu.c: likewise
+       * loader/xnu_resume.c: likewise
+       * util/grub-dumpdevtree: likewise
+       * include/grub/i386/pit.h: include grub/err.h
+       (grub_pit_wait): export
+       * util/grub.d/30_os-prober.in: support Darwin/Mac OS X
+       
 2009-05-02  Vladimir Serbinenko  <address@hidden>
 
        Efiemu

Modified: trunk/grub2/conf/i386-efi.rmk
===================================================================
--- trunk/grub2/conf/i386-efi.rmk       2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/conf/i386-efi.rmk       2009-05-02 23:19:20 UTC (rev 2163)
@@ -101,7 +101,7 @@
 kernel_mod_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
        env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
        partition.h pc_partition.h reader.h symbol.h term.h time.h types.h \
-       efi/efi.h efi/time.h efi/disk.h list.h handler.h command.h
+       efi/efi.h efi/time.h efi/disk.h i386/pit.h list.h handler.h command.h
 kernel_mod_CFLAGS = $(COMMON_CFLAGS)
 kernel_mod_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -187,5 +187,12 @@
 fixvideo_mod_CFLAGS = $(COMMON_CFLAGS)
 fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += xnu.mod
+xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c\
+        loader/macho.c loader/xnu.c loader/i386/xnu_helper.S
+xnu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+xnu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+xnu_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 include $(srcdir)/conf/i386.mk
 include $(srcdir)/conf/common.mk

Modified: trunk/grub2/conf/i386-pc.rmk
===================================================================
--- trunk/grub2/conf/i386-pc.rmk        2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/conf/i386-pc.rmk        2009-05-02 23:19:20 UTC (rev 2163)
@@ -62,7 +62,7 @@
        partition.h pc_partition.h reader.h symbol.h term.h time.h types.h \
        machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \
        machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \
-       machine/kernel.h machine/pxe.h list.h handler.h command.h
+       machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h
 kernel_img_CFLAGS = $(COMMON_CFLAGS)
 kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) 
-Wl,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS)
@@ -229,6 +229,13 @@
 linux_mod_CFLAGS = $(COMMON_CFLAGS)
 linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += xnu.mod
+xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/pc/xnu.c\
+        loader/macho.c loader/xnu.c loader/i386/xnu_helper.S
+xnu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+xnu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+xnu_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 # For reboot.mod.
 reboot_mod_SOURCES = commands/reboot.c
 reboot_mod_CFLAGS = $(COMMON_CFLAGS)

Modified: trunk/grub2/conf/x86_64-efi.rmk
===================================================================
--- trunk/grub2/conf/x86_64-efi.rmk     2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/conf/x86_64-efi.rmk     2009-05-02 23:19:20 UTC (rev 2163)
@@ -99,8 +99,8 @@
 kernel_mod_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
        env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
        partition.h pc_partition.h reader.h symbol.h term.h time.h types.h \
-       efi/efi.h efi/time.h efi/disk.h machine/loader.h list.h handler.h \
-       command.h
+       efi/efi.h efi/time.h efi/disk.h machine/loader.h i386/pit.h list.h \
+       handler.h command.h
 kernel_mod_CFLAGS = $(COMMON_CFLAGS)
 kernel_mod_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -186,4 +186,11 @@
 fixvideo_mod_CFLAGS = $(COMMON_CFLAGS)
 fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += xnu.mod
+xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c\
+        loader/macho.c loader/xnu.c loader/i386/xnu_helper.S
+xnu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+xnu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+xnu_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 include $(srcdir)/conf/common.mk

Modified: trunk/grub2/include/grub/efi/efi.h
===================================================================
--- trunk/grub2/include/grub/efi/efi.h  2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/include/grub/efi/efi.h  2009-05-02 23:19:20 UTC (rev 2163)
@@ -56,6 +56,7 @@
 int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key);
 void EXPORT_FUNC (grub_reboot) (void);
 void EXPORT_FUNC (grub_halt) (void);
+int EXPORT_FUNC (grub_efi_finish_boot_services) (void);
 
 void grub_efi_mm_init (void);
 void grub_efi_mm_fini (void);

Added: trunk/grub2/include/grub/i386/macho.h
===================================================================
--- trunk/grub2/include/grub/i386/macho.h                               (rev 0)
+++ trunk/grub2/include/grub/i386/macho.h       2009-05-02 23:19:20 UTC (rev 
2163)
@@ -0,0 +1,11 @@
+#define GRUB_MACHO_CPUTYPE_IS_HOST32(x) ((x)==0x00000007)
+#define GRUB_MACHO_CPUTYPE_IS_HOST64(x) ((x)==0x01000007)
+
+struct grub_macho_thread32
+{
+  grub_uint32_t cmd;
+  grub_uint32_t cmdsize;
+  grub_uint8_t unknown1[48];
+  grub_uint32_t entry_point;
+  grub_uint8_t unknown2[20];
+} __attribute__ ((packed));

Modified: trunk/grub2/include/grub/i386/pit.h
===================================================================
--- trunk/grub2/include/grub/i386/pit.h 2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/include/grub/i386/pit.h 2009-05-02 23:19:20 UTC (rev 2163)
@@ -20,7 +20,8 @@
 #define KERNEL_CPU_PIT_HEADER   1
 
 #include <grub/types.h>
+#include <grub/err.h>
 
-extern void grub_pit_wait (grub_uint16_t tics);
+void EXPORT_FUNC(grub_pit_wait) (grub_uint16_t tics);
 
 #endif /* ! KERNEL_CPU_PIT_HEADER */

Added: trunk/grub2/include/grub/i386/xnu.h
===================================================================
--- trunk/grub2/include/grub/i386/xnu.h                         (rev 0)
+++ trunk/grub2/include/grub/i386/xnu.h 2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,60 @@
+#ifndef GRUB_CPU_XNU_H
+#define GRUB_CPU_XNU_H 1
+
+#define GRUB_XNU_PAGESIZE 4096
+typedef grub_uint32_t grub_xnu_ptr_t;
+
+struct grub_xnu_boot_params
+{
+  grub_uint16_t verminor; 
+  grub_uint16_t vermajor; 
+  /* Command line passed to xnu. */
+  grub_uint8_t cmdline[1024]; 
+
+  /* Later are the same as EFI's get_memory_map (). */
+  grub_xnu_ptr_t efi_mmap;               
+  grub_uint32_t efi_mmap_size;          
+  grub_uint32_t efi_mem_desc_size;      
+  grub_uint32_t efi_mem_desc_version;   
+
+  /* Later are video parameters. */
+  grub_xnu_ptr_t lfb_base;
+#define GRUB_XNU_VIDEO_SPLASH 1
+#define GRUB_XNU_VIDEO_TEXT_IN_VIDEO 2
+  grub_uint32_t lfb_mode; 
+  grub_uint32_t lfb_line_len;
+  grub_uint32_t lfb_width;
+  grub_uint32_t lfb_height;
+  grub_uint32_t lfb_depth;
+
+  /* Pointer to device tree and its len. */
+  grub_xnu_ptr_t devtree;
+  grub_uint32_t devtreelen;
+  
+  /* First used address by kernel or boot structures. */
+  grub_xnu_ptr_t heap_start;
+  /* Last used address by kernel or boot structures minus previous value. */  
+  grub_uint32_t heap_size;
+  
+  /* First memory page containing runtime code or data. */
+  grub_uint32_t efi_runtime_first_page;
+  /* First memory page containing runtime code or data minus previous value. */
+  grub_uint32_t efi_runtime_npages;
+  grub_uint32_t efi_system_table;
+  /* Size of grub_efi_uintn_t in bits. */
+  grub_uint8_t efi_uintnbits;
+} __attribute__ ((packed));
+#define GRUB_XNU_BOOTARGS_VERMINOR 4
+#define GRUB_XNU_BOOTARGS_VERMAJOR 1
+
+extern grub_uint32_t grub_xnu_entry_point;
+extern grub_uint32_t grub_xnu_stack;
+extern grub_uint32_t grub_xnu_arg1;
+extern char grub_xnu_cmdline[1024];
+grub_err_t grub_xnu_boot (void);
+grub_err_t grub_cpu_xnu_fill_devicetree (void);
+grub_err_t grub_xnu_set_video (struct grub_xnu_boot_params *bootparams_relloc);
+extern grub_uint32_t grub_xnu_heap_will_be_at;
+extern grub_uint8_t grub_xnu_launcher_start[];
+extern grub_uint8_t grub_xnu_launcher_end[];
+#endif

Added: trunk/grub2/include/grub/macho.h
===================================================================
--- trunk/grub2/include/grub/macho.h                            (rev 0)
+++ trunk/grub2/include/grub/macho.h    2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,107 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+#ifndef GRUB_MACHO_H
+#define GRUB_MACHO_H 1
+#include <grub/types.h>
+
+/* Multi-architecture header. Always in big-endian. */
+struct grub_macho_fat_header
+{
+  grub_uint32_t magic;
+  grub_uint32_t nfat_arch;
+} __attribute__ ((packed));
+#define GRUB_MACHO_FAT_MAGIC 0xcafebabe
+
+typedef grub_uint32_t grub_macho_cpu_type_t;
+typedef grub_uint32_t grub_macho_cpu_subtype_t;
+
+/* Architecture descriptor. Always in big-endian. */
+struct grub_macho_fat_arch
+{
+  grub_macho_cpu_type_t cputype;
+  grub_macho_cpu_subtype_t cpusubtype;
+  grub_uint32_t offset;
+  grub_uint32_t size;
+  grub_uint32_t align;
+} __attribute__ ((packed));;
+
+/* File header for 32-bit. Always in native-endian. */
+struct grub_macho_header32
+{
+#define GRUB_MACHO_MAGIC32 0xfeedface
+  grub_uint32_t magic;
+  grub_macho_cpu_type_t cputype;
+  grub_macho_cpu_subtype_t cpusubtype;
+  grub_uint32_t filetype;
+  grub_uint32_t ncmds;
+  grub_uint32_t sizeofcmds;
+  grub_uint32_t flags;
+} __attribute__ ((packed));
+
+/* File header for 64-bit. Always in native-endian. */
+struct grub_macho_header64
+{
+#define GRUB_MACHO_MAGIC64 0xfeedfacf
+  grub_uint32_t magic;
+  grub_macho_cpu_type_t cputype;
+  grub_macho_cpu_subtype_t cpusubtype;
+  grub_uint32_t filetype;
+  grub_uint32_t ncmds;
+  grub_uint32_t sizeofcmds;
+  grub_uint32_t flags;
+  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
+{
+  grub_uint32_t cmd;
+  grub_uint32_t cmdsize;
+} __attribute__ ((packed));
+
+typedef grub_uint32_t grub_macho_vmprot_t;
+
+/* 32-bit segment command. */
+struct grub_macho_segment32
+{
+#define GRUB_MACHO_CMD_SEGMENT32  1
+  grub_uint32_t cmd;
+  grub_uint32_t cmdsize;
+  grub_uint8_t segname[16];
+  grub_uint32_t vmaddr;
+  grub_uint32_t vmsize;
+  grub_uint32_t fileoff;
+  grub_uint32_t filesize;
+  grub_macho_vmprot_t maxprot;
+  grub_macho_vmprot_t initprot;
+  grub_uint32_t nsects;
+  grub_uint32_t flags;
+} __attribute__ ((packed));
+
+#define GRUB_MACHO_CMD_THREAD     5
+
+#endif

Added: trunk/grub2/include/grub/machoload.h
===================================================================
--- trunk/grub2/include/grub/machoload.h                                (rev 0)
+++ trunk/grub2/include/grub/machoload.h        2009-05-02 23:19:20 UTC (rev 
2163)
@@ -0,0 +1,62 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+#ifndef GRUB_MACHOLOAD_HEADER
+#define GRUB_MACHOLOAD_HEADER  1
+
+#include <grub/err.h>
+#include <grub/elf.h>
+#include <grub/file.h>
+#include <grub/symbol.h>
+#include <grub/types.h>
+
+struct grub_macho_file
+{
+  grub_file_t file;
+  grub_ssize_t offset32;
+  grub_ssize_t end32;
+  int ncmds32;
+  grub_size_t cmdsize32;
+  grub_uint8_t *cmds32;
+  grub_ssize_t offset64;
+  grub_ssize_t end64;
+  int ncmds64;
+  grub_size_t cmdsize64;
+  grub_uint8_t *cmds64;
+};
+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);
+grub_err_t grub_macho_close (grub_macho_t);
+
+int grub_macho_contains_macho32 (grub_macho_t);
+grub_err_t grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start,
+                             grub_addr_t *segments_end, int flags);
+grub_uint32_t grub_macho32_get_entry_point (grub_macho_t macho);
+
+/* Ignore BSS segments when loading. */
+#define GRUB_MACHO_NOBSS 0x1
+grub_err_t grub_macho32_load (grub_macho_t macho, char *offset, int flags);
+
+/* Like filesize and file_read but take only 32-bit part 
+   for current architecture. */
+grub_size_t grub_macho32_filesize (grub_macho_t macho);
+grub_err_t grub_macho32_readfile (grub_macho_t macho, void *dest);
+
+#endif /* ! GRUB_MACHOLOAD_HEADER */

Added: trunk/grub2/include/grub/x86_64/macho.h
===================================================================
--- trunk/grub2/include/grub/x86_64/macho.h                             (rev 0)
+++ trunk/grub2/include/grub/x86_64/macho.h     2009-05-02 23:19:20 UTC (rev 
2163)
@@ -0,0 +1 @@
+#include <grub/i386/macho.h>

Added: trunk/grub2/include/grub/x86_64/xnu.h
===================================================================
--- trunk/grub2/include/grub/x86_64/xnu.h                               (rev 0)
+++ trunk/grub2/include/grub/x86_64/xnu.h       2009-05-02 23:19:20 UTC (rev 
2163)
@@ -0,0 +1 @@
+#include <grub/i386/xnu.h>

Added: trunk/grub2/include/grub/xnu.h
===================================================================
--- trunk/grub2/include/grub/xnu.h                              (rev 0)
+++ trunk/grub2/include/grub/xnu.h      2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,107 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+#ifndef GRUB_XNU_H
+#define GRUB_XNU_H 1
+
+#include <grub/bitmap.h>
+
+/* Header of a hibernation image. */
+struct grub_xnu_hibernate_header
+{
+  /* Size of the image. Notice that file containing image is usually bigger. */
+  grub_uint64_t image_size;
+  grub_uint8_t unknown1[8];
+  /* Where to copy lauchcode?*/
+  grub_uint32_t launchcode_target_page;
+  /* How many pages of launchcode? */
+  grub_uint32_t launchcode_numpages;
+  /* Where to jump? */
+  grub_uint32_t entry_point;
+  /* %esp at start. */
+  grub_uint32_t stack;
+  grub_uint8_t unknown2[44];
+#define GRUB_XNU_HIBERNATE_MAGIC 0x73696d65  
+  grub_uint32_t magic;
+  grub_uint8_t unknown3[28];
+  /* This value is non-zero if page is encrypted. Unsupported. */
+  grub_uint64_t encoffset;
+  grub_uint8_t unknown4[360];
+  /* The size of additional header used to locate image without parsing FS.
+     Used only to skip it.
+   */
+  grub_uint32_t extmapsize;
+} __attribute__ ((packed));
+
+/* In-memory structure for temporary keeping device tree. */
+struct grub_xnu_devtree_key
+{
+  char *name; 
+  int datasize; /* -1 for not leaves. */
+  union
+  {
+    struct grub_xnu_devtree_key *first_child;
+    void *data;
+  };
+  struct grub_xnu_devtree_key *next;
+};
+
+/* A structure used in memory-map values. */
+struct 
+grub_xnu_extdesc
+{
+  grub_uint32_t addr;
+  grub_uint32_t size;
+} __attribute__ ((packed));
+
+/* Header describing extension in the memory. */
+struct grub_xnu_extheader
+{
+  grub_uint32_t infoplistaddr;
+  grub_uint32_t infoplistsize;
+  grub_uint32_t binaryaddr;
+  grub_uint32_t binarysize;
+} __attribute__ ((packed));
+
+struct grub_xnu_devtree_key *grub_xnu_create_key (struct grub_xnu_devtree_key 
**parent,
+                                                 char *name);
+
+extern struct grub_xnu_devtree_key *grub_xnu_devtree_root;
+
+void grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur);
+
+grub_err_t grub_xnu_writetree_toheap (void **start, grub_size_t *size);
+struct grub_xnu_devtree_key *grub_xnu_create_value (struct 
grub_xnu_devtree_key **parent,
+                                                   char *name);
+
+void grub_xnu_lock (void);
+void grub_xnu_unlock (void);
+grub_err_t grub_xnu_resume (char *imagename);
+struct grub_xnu_devtree_key *grub_xnu_find_key (struct grub_xnu_devtree_key 
*parent,
+                                               char *name);
+grub_err_t grub_xnu_align_heap (int align);
+grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, 
+                                       int maxrecursion);
+grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, 
+                                       int maxrecursion);
+void *grub_xnu_heap_malloc (int size);
+extern grub_uint32_t grub_xnu_heap_real_start;
+extern grub_size_t grub_xnu_heap_size;
+extern char *grub_xnu_heap_start;
+extern struct grub_video_bitmap *grub_xnu_bitmap;
+#endif

Modified: trunk/grub2/kern/efi/efi.c
===================================================================
--- trunk/grub2/kern/efi/efi.c  2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/kern/efi/efi.c  2009-05-02 23:19:20 UTC (rev 2163)
@@ -734,3 +734,26 @@
       dp = (grub_efi_device_path_t *) ((char *) dp + len);
     }
 }
+
+int
+grub_efi_finish_boot_services (void)
+{
+  grub_efi_uintn_t mmap_size = 0;
+  grub_efi_uintn_t map_key;
+  grub_efi_uintn_t desc_size;
+  grub_efi_uint32_t desc_version;
+  void *mmap_buf = 0;
+
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+                              &desc_size, &desc_version) < 0)
+    return 0;
+
+  mmap_buf = grub_malloc (mmap_size);
+  
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+                              &desc_size, &desc_version) <= 0)
+    return 0;
+
+  return grub_efi_exit_boot_services (map_key);
+}
+

Modified: trunk/grub2/kern/efi/mm.c
===================================================================
--- trunk/grub2/kern/efi/mm.c   2009-05-02 22:40:21 UTC (rev 2162)
+++ trunk/grub2/kern/efi/mm.c   2009-05-02 23:19:20 UTC (rev 2163)
@@ -47,7 +47,7 @@
 
 /* The minimum and maximum heap size for GRUB itself.  */
 #define MIN_HEAP_SIZE  0x100000
-#define MAX_HEAP_SIZE  (16 * 0x100000)
+#define MAX_HEAP_SIZE  (1600 * 0x100000)
 
 
 /* Allocate pages. Return the pointer to the first of allocated pages.  */

Added: trunk/grub2/loader/i386/efi/xnu.c
===================================================================
--- trunk/grub2/loader/i386/efi/xnu.c                           (rev 0)
+++ trunk/grub2/loader/i386/efi/xnu.c   2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,177 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/env.h>
+#include <grub/xnu.h>
+#include <grub/cpu/xnu.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/uga_draw.h>
+#include <grub/pci.h>
+#include <grub/misc.h>
+
+/* Setup video for xnu. Big parts are copied from linux.c. */
+
+static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
+
+#define RGB_MASK       0xffffff
+#define RGB_MAGIC      0x121314
+#define LINE_MIN       800
+#define LINE_MAX       4096
+#define FBTEST_STEP    (0x10000 >> 2)
+#define FBTEST_COUNT   8
+
+static int
+find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
+{
+  grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
+  int i;
+
+  for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
+    {
+      if ((*base & RGB_MASK) == RGB_MAGIC)
+       {
+         int j;
+
+         for (j = LINE_MIN; j <= LINE_MAX; j++)
+           {
+             if ((base[j] & RGB_MASK) == RGB_MAGIC)
+               {
+                 *fb_base = (grub_uint32_t) (grub_target_addr_t) base;
+                 *line_len = j << 2;
+
+                 return 1;
+               }
+           }
+
+         break;
+       }
+    }
+
+  return 0;
+}
+
+static int
+find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
+{
+  int found = 0;
+
+  auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                      grub_pci_id_t pciid);
+
+  int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
+                                 grub_pci_id_t pciid)
+    {
+      grub_pci_address_t addr;
+
+      addr = grub_pci_make_address (bus, dev, func, 2);
+      if (grub_pci_read (addr) >> 24 == 0x3)
+       {
+         int i;
+
+         grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
+                      bus, dev, func, pciid);
+         addr += 8;
+         for (i = 0; i < 6; i++, addr += 4)
+           {
+             grub_uint32_t old_bar1, old_bar2, type;
+             grub_uint64_t base64;
+
+             old_bar1 = grub_pci_read (addr);
+             if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
+               continue;
+
+             type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
+             if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+               {
+                 if (i == 5)
+                   break;
+
+                 old_bar2 = grub_pci_read (addr + 4);
+               }
+             else
+               old_bar2 = 0;
+
+             base64 = old_bar2;
+             base64 <<= 32;
+             base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
+
+             grub_printf ("%s(%d): 0x%llx\n",
+                          ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
+                           "VMEM" : "MMIO"), i,
+                          (unsigned long long) base64);
+
+             if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
+               {
+                 *fb_base = base64;
+                 if (find_line_len (fb_base, line_len))
+                   found++;
+               }
+
+             if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+               {
+                 i++;
+                 addr += 4;
+               }
+           }
+       }
+
+      return found;
+    }
+
+  grub_pci_iterate (find_card);
+  return found;
+}
+
+grub_err_t
+grub_xnu_set_video (struct grub_xnu_boot_params *params)
+{
+  grub_efi_uga_draw_protocol_t *c;
+  grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
+  int ret;
+
+  c = grub_efi_locate_protocol (&uga_draw_guid, 0);
+  if (! c)
+    return grub_error (GRUB_ERR_IO, "Couldn't find UGADraw");
+
+  if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
+    return grub_error (GRUB_ERR_IO, "Couldn't retrieve video mode");
+
+  grub_printf ("Video mode: address@hidden", width, height, depth, rate);
+
+  grub_efi_set_text_mode (0);
+  pixel = RGB_MAGIC;
+  efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
+              GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
+  ret = find_framebuf (&fb_base, &line_len);
+  grub_efi_set_text_mode (1);
+
+  if (! ret)
+    return grub_error (GRUB_ERR_IO, "Can\'t find frame buffer address\n");
+
+  grub_printf ("Frame buffer base: 0x%x\n", fb_base);
+  grub_printf ("Video line length: %d\n", line_len);
+
+  params->lfb_width = width;
+  params->lfb_height = height;
+  params->lfb_depth = depth;
+  params->lfb_line_len = line_len;
+  params->lfb_mode = GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
+  params->lfb_base = fb_base;
+  return GRUB_ERR_NONE;
+}

Added: trunk/grub2/loader/i386/pc/xnu.c
===================================================================
--- trunk/grub2/loader/i386/pc/xnu.c                            (rev 0)
+++ trunk/grub2/loader/i386/pc/xnu.c    2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,80 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/env.h>
+#include <grub/misc.h>
+#include <grub/xnu.h>
+#include <grub/cpu/xnu.h>
+#include <grub/machine/vbe.h>
+#include <grub/machine/vga.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Setup video for xnu. */
+grub_err_t
+grub_xnu_set_video (struct grub_xnu_boot_params *params)
+{
+  struct grub_video_mode_info mode_info;
+  struct grub_video_render_target *render_target;
+  int ret;
+  int x,y;
+  grub_err_t err;
+
+  ret = grub_video_get_info (&mode_info);
+  if (ret)
+    return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
+
+  ret = grub_video_get_active_render_target (&render_target);
+  if (ret)
+    return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
+
+  err = GRUB_ERR_NONE;
+  x = mode_info.width - grub_xnu_bitmap->mode_info.width;
+  x /= 2;
+  y = mode_info.height - grub_xnu_bitmap->mode_info.height;
+  y /= 2;
+  err = grub_video_blit_bitmap (grub_xnu_bitmap,
+                               GRUB_VIDEO_BLIT_REPLACE,
+                               x > 0 ? x : 0,
+                               y > 0 ? y : 0,
+                               x < 0 ? -x : 0,
+                               y < 0 ? -y : 0,
+                               min (grub_xnu_bitmap->mode_info.width, 
+                                    mode_info.width), 
+                               min (grub_xnu_bitmap->mode_info.height, 
+                                    mode_info.height));
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+      grub_xnu_bitmap = 0;
+    }
+
+  params->lfb_width = mode_info.width;
+  params->lfb_height = mode_info.height;
+  params->lfb_depth = mode_info.bpp;
+  params->lfb_line_len = mode_info.pitch;
+
+  params->lfb_base = PTR_TO_UINT32 (render_target->data);
+  params->lfb_mode = grub_xnu_bitmap 
+    ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; 
+
+  return GRUB_ERR_NONE;
+}
+

Added: trunk/grub2/loader/i386/xnu.c
===================================================================
--- trunk/grub2/loader/i386/xnu.c                               (rev 0)
+++ trunk/grub2/loader/i386/xnu.c       2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,539 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/env.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/xnu.h>
+#include <grub/cpu/xnu.h>
+#include <grub/mm.h>
+#include <grub/loader.h>
+#include <grub/autoefi.h>
+#include <grub/i386/tsc.h>
+#include <grub/i386/pit.h>
+#include <grub/misc.h>
+#include <grub/term.h>
+
+char grub_xnu_cmdline[1024];
+
+/* Aliases set for some tables. */
+struct tbl_alias
+{
+  grub_efi_guid_t guid;
+  char *name;
+};
+
+struct tbl_alias table_aliases[] =
+  {
+    {GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI_20"},
+    {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"},
+  };
+
+/* The following function is used to be able to debug xnu loader 
+   with grub-emu. */
+#ifdef GRUB_UTIL
+static grub_err_t 
+grub_xnu_launch (void)
+{
+  grub_printf ("Fake launch %x:%p:%p", grub_xnu_entry_point, grub_xnu_arg1,
+              grub_xnu_stack);
+  grub_getkey ();
+  return 0;
+}
+#else
+static void (*grub_xnu_launch) (void) = 0;
+#endif
+
+static int
+utf16_strlen (grub_uint16_t *in)
+{
+  int i;
+  for (i = 0; in[i]; i++);
+  return i;
+}
+
+/* Read frequency from a string in MHz and return it in Hz. */
+static grub_uint64_t
+readfrequency (const char *str)
+{
+  grub_uint64_t num = 0;
+  int mul = 1000000;
+  int found = 0;
+
+  while (*str)
+    {
+      unsigned long digit;
+      
+      digit = grub_tolower (*str) - '0';
+      if (digit > 9)
+       break;
+
+      found = 1;
+
+      num = num * 10 + digit;
+      str++;
+    }
+  num *= 1000000;
+  if (*str == '.')
+    {
+      str++;
+      while (*str)
+       {
+         unsigned long digit;
+         
+         digit = grub_tolower (*str) - '0';
+         if (digit > 9)
+           break;
+
+         found = 1;
+
+         mul /= 10;
+         num = num + mul * digit;
+         str++;
+       }
+    }
+  if (! found)
+    return 0;
+
+  return num;
+}
+
+/* Thanks to Kabyl for precious information about Intel architecture. */
+static grub_uint64_t
+guessfsb (void)
+{
+  const grub_uint64_t sane_value = 100000000;
+  grub_uint32_t manufacturer[3], max_cpuid, capabilities, msrlow;
+  grub_uint64_t start_tsc;
+  grub_uint64_t end_tsc;
+  grub_uint64_t tsc_ticks_per_ms;
+
+  if (! grub_cpu_is_cpuid_supported ())
+    return sane_value;
+  asm volatile ("movl $0, %%eax\n"
+               "cpuid"
+               : "=a" (max_cpuid), "=b" (manufacturer[0]), 
+                 "=d" (manufacturer[1]), "=c" (manufacturer[2]));
+
+  /* Only Intel for now is done. */
+  if (grub_memcmp (manufacturer, "GenuineIntel", 12) != 0)
+    return sane_value;
+
+  /* Check Speedstep. */
+  if (max_cpuid < 1)
+    return sane_value;
+
+  asm volatile ("movl $1, %%eax\n"
+               "cpuid"
+               : "=c" (capabilities):
+               : "%eax", "%ebx", "%edx");
+
+  if (! (capabilities & (1 << 7)))
+    return sane_value;
+
+  /* Calibrate the TSC rate. */
+
+  start_tsc = grub_get_tsc ();
+  grub_pit_wait (0xffff);
+  end_tsc = grub_get_tsc ();
+
+  tsc_ticks_per_ms = grub_divmod64 (end_tsc - start_tsc, 55, 0);
+
+  /* Read the multiplier. */
+  asm volatile ("movl $0x198, %%ecx\n"
+               "rdmsr"
+               : "=d" (msrlow)
+               :
+               : "%ecx", "%eax");
+
+  return grub_divmod64 (2000 * tsc_ticks_per_ms, 
+                       ((msrlow >> 7) & 0x3e) + ((msrlow >> 14) & 1), 0);
+}
+
+/* Fill device tree. */
+/* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
+grub_err_t
+grub_cpu_xnu_fill_devicetree (void)
+{
+  struct grub_xnu_devtree_key *efikey;
+  struct grub_xnu_devtree_key *cfgtablekey;
+  struct grub_xnu_devtree_key *curval;
+  struct grub_xnu_devtree_key *runtimesrvkey;
+  struct grub_xnu_devtree_key *platformkey;
+  unsigned i, j;
+  grub_err_t err;
+
+  err = grub_autoefi_prepare ();
+  if (err)
+    return err;
+
+  /* The value "model". */
+  /* FIXME: may this value be sometimes different? */
+  curval = grub_xnu_create_value (&grub_xnu_devtree_root, "model");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = sizeof ("ACPI");
+  curval->data = grub_strdup ("ACPI");
+  curval = grub_xnu_create_value (&grub_xnu_devtree_root, "compatible");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = sizeof ("ACPI");
+  curval->data = grub_strdup ("ACPI");
+
+  /* The key "efi". */
+  efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
+  if (! efikey)
+    return grub_errno;
+
+  /* Information about firmware. */
+  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-revision");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = (SYSTEM_TABLE_SIZEOF (firmware_revision));
+  curval->data = grub_malloc (curval->datasize);
+  if (! curval->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't create device tree");
+  grub_memcpy (curval->data, (SYSTEM_TABLE_VAR(firmware_revision)),
+              curval->datasize);
+
+  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-vendor");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = 
+    2 * (utf16_strlen (SYSTEM_TABLE_PTR (firmware_vendor)) + 1);
+  curval->data = grub_malloc (curval->datasize);
+  if (! curval->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't create device tree");
+  grub_memcpy (curval->data, SYSTEM_TABLE_PTR (firmware_vendor),
+              curval->datasize);
+
+  curval = grub_xnu_create_value (&(efikey->first_child), "firmware-abi");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = sizeof ("EFI32");
+  curval->data = grub_malloc (curval->datasize);
+  if (! curval->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't create device tree");
+  if (SIZEOF_OF_UINTN == 4)
+    grub_memcpy (curval->data, "EFI32", curval->datasize);
+  else
+    grub_memcpy (curval->data, "EFI64", curval->datasize);
+
+  /* The key "platform". */
+  platformkey = grub_xnu_create_key (&(efikey->first_child), 
+                                    "platform");
+  if (! platformkey)
+    return grub_errno;
+
+  /* Pass FSB frequency to the kernel. */
+  curval = grub_xnu_create_value (&(platformkey->first_child), "FSBFrequency");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = sizeof (grub_uint64_t);
+  curval->data = grub_malloc (curval->datasize);
+  if (!curval->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't create device tree");
+
+  /* First see if user supplies the value. */
+  char *fsbvar = grub_env_get ("fsb");
+  if (! fsbvar)
+    *((grub_uint64_t *) curval->data) = 0; 
+  else
+    *((grub_uint64_t *) curval->data) = readfrequency (fsbvar);
+  /* Try autodetect. */
+  if (! *((grub_uint64_t *) curval->data))
+    *((grub_uint64_t *) curval->data) = guessfsb (); 
+  grub_dprintf ("xnu", "fsb autodetected as %llu\n", 
+               (unsigned long long) *((grub_uint64_t *) curval->data));
+
+  cfgtablekey = grub_xnu_create_key (&(efikey->first_child), 
+                                    "configuration-table");
+  if (!cfgtablekey)
+    return grub_errno;
+
+  /* Fill "configuration-table" key. */
+  for (i = 0; i < SYSTEM_TABLE (num_table_entries); i++)
+    {
+      void *ptr;
+      struct grub_xnu_devtree_key *curkey;
+      grub_efi_guid_t guid;
+      char guidbuf[64];
+
+      /* Retrieve current key. */
+#ifdef GRUB_MACHINE_EFI
+      {
+       ptr = (void *) 
+         grub_efi_system_table->configuration_table[i].vendor_table;
+       guid = grub_efi_system_table->configuration_table[i].vendor_guid;
+      }
+#else 
+      if (SIZEOF_OF_UINTN == 4)
+       {
+         ptr = UINT_TO_PTR (((grub_efiemu_configuration_table32_t *)
+                             SYSTEM_TABLE_PTR (configuration_table))[i]
+                            .vendor_table);
+         guid =
+           ((grub_efiemu_configuration_table32_t *)
+            SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
+       }
+      else
+       {
+         ptr = UINT_TO_PTR (((grub_efiemu_configuration_table64_t *)
+                             SYSTEM_TABLE_PTR (configuration_table))[i]
+                            .vendor_table);
+         guid = 
+           ((grub_efiemu_configuration_table64_t *)
+            SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
+       }
+#endif
+
+      /* The name of key for new table. */
+      grub_sprintf (guidbuf, "%08x-%04x-%04x-%02x%02x-",
+                   guid.data1, guid.data2, guid.data3, guid.data4[0],
+                   guid.data4[1]);
+      for (j = 2; j < 8; j++)
+       grub_sprintf (guidbuf + grub_strlen (guidbuf), "%02x", guid.data4[j]);
+      /* For some reason GUID has to be in uppercase. */
+      for (j = 0; guidbuf[j] ; j++)
+       if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f')
+         guidbuf[j] += 'A' - 'a';
+      curkey = grub_xnu_create_key (&(cfgtablekey->first_child), guidbuf);
+      if (! curkey)
+       return grub_errno;
+
+      curval = grub_xnu_create_value (&(curkey->first_child), "guid");
+      if (! curval)
+       return grub_errno;
+      curval->datasize = sizeof (guid);
+      curval->data = grub_malloc (curval->datasize);
+      if (! curval->data)
+       return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                          "couldn't create device tree");
+      grub_memcpy (curval->data, &guid, curval->datasize);
+
+      /* The value "table". */
+      curval = grub_xnu_create_value (&(curkey->first_child), "table");
+      if (! curval)
+       return grub_errno;
+      curval->datasize = SIZEOF_OF_UINTN;
+      curval->data = grub_malloc (curval->datasize);
+      if (! curval->data)
+       return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                          "couldn't create device tree");
+      if (SIZEOF_OF_UINTN == 4)
+       *((grub_uint32_t *)curval->data) = PTR_TO_UINT32 (ptr);
+      else
+       *((grub_uint64_t *)curval->data) = PTR_TO_UINT64 (ptr);
+
+      /* Create alias. */
+      for (j = 0; j < sizeof (table_aliases) / sizeof (table_aliases[0]); j++)
+       if (grub_memcmp (&table_aliases[j].guid, &guid, sizeof (guid)) == 0)
+         break;
+      if (j != sizeof (table_aliases) / sizeof (table_aliases[0]))
+       {
+         curval = grub_xnu_create_value (&(curkey->first_child), "alias");
+         if (!curval)
+           return grub_errno;
+         curval->datasize = grub_strlen (table_aliases[j].name) + 1;
+         curval->data = grub_malloc (curval->datasize);
+         if (!curval->data)
+           return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                              "couldn't create device tree");
+         grub_memcpy (curval->data, table_aliases[j].name, curval->datasize);
+       }
+    }
+  
+  /* Create and fill "runtime-services" key. */
+  runtimesrvkey = grub_xnu_create_key (&(efikey->first_child), 
+                                      "runtime-services");
+  if (! runtimesrvkey)
+    return grub_errno;
+  curval = grub_xnu_create_value (&(runtimesrvkey->first_child), "table");
+  if (! curval)
+    return grub_errno;
+  curval->datasize = SIZEOF_OF_UINTN;
+  curval->data = grub_malloc (curval->datasize);
+  if (! curval->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                      "couldn't create device tree");
+  if (SIZEOF_OF_UINTN == 4)
+    *((grub_uint32_t *) curval->data) 
+      = PTR_TO_UINT32 (SYSTEM_TABLE_PTR (runtime_services));
+  else
+    *((grub_uint64_t *) curval->data) 
+      = PTR_TO_UINT64 (SYSTEM_TABLE_PTR (runtime_services));
+  
+  return GRUB_ERR_NONE;
+}
+
+/* Boot xnu. */
+grub_err_t 
+grub_xnu_boot (void)
+{
+  struct grub_xnu_boot_params *bootparams_relloc;
+  grub_off_t bootparams_relloc_off;
+  grub_off_t mmap_relloc_off;
+  grub_err_t err;
+  grub_efi_uintn_t memory_map_size = 0;
+  grub_efi_memory_descriptor_t *memory_map;
+  grub_efi_uintn_t map_key = 0;
+  grub_efi_uintn_t descriptor_size = 0;
+  grub_efi_uint32_t descriptor_version = 0;
+  grub_uint64_t firstruntimeaddr, lastruntimeaddr;
+  void *devtree;
+  grub_size_t devtreelen;
+  int i;
+
+  /* Page-align to avoid following parts to be inadvertently freed. */
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    return err;
+
+  /* Pass memory map to kernel. */
+  memory_map_size = 0;
+  memory_map = 0;
+  map_key = 0;
+  descriptor_size = 0;
+  descriptor_version = 0;
+
+  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
+                                  &map_key, &descriptor_size,
+                                  &descriptor_version) < 0)
+    return grub_errno;
+
+  memory_map = grub_xnu_heap_malloc (memory_map_size);
+  if (! memory_map)
+    return grub_errno;
+
+  if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
+                                  &map_key, &descriptor_size,
+                                  &descriptor_version) <= 0)
+    return grub_errno;
+  mmap_relloc_off = (grub_uint8_t *) memory_map 
+    - (grub_uint8_t *) grub_xnu_heap_start;
+
+  firstruntimeaddr = (grub_uint64_t) (-1); 
+  lastruntimeaddr = 0;
+  for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
+    {
+      grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *) 
+       ((char *) memory_map + descriptor_size * i);
+
+      /* Some EFI implementations set physical_start to 0 which 
+        causes XNU crash. */
+      curdesc->virtual_start = curdesc->physical_start;
+
+      if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
+         || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
+       {
+         if (firstruntimeaddr > curdesc->physical_start)
+           firstruntimeaddr = curdesc->physical_start;
+         if (lastruntimeaddr < curdesc->physical_start
+             + curdesc->num_pages * 4096)
+           lastruntimeaddr = curdesc->physical_start
+             + curdesc->num_pages * 4096;
+       }
+    }
+
+  /* Relocate the boot parameters to heap. */
+  bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc));
+  if (! bootparams_relloc)
+    return grub_errno;
+  bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc 
+    - (grub_uint8_t *) grub_xnu_heap_start;
+  err = grub_xnu_writetree_toheap (&devtree, &devtreelen);
+  if (err)
+    return err;
+  bootparams_relloc = (struct grub_xnu_boot_params *)
+    (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start);
+
+  grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline, 
+              sizeof (bootparams_relloc->cmdline));
+
+  bootparams_relloc->devtree = ((char *) devtree - grub_xnu_heap_start) 
+    + grub_xnu_heap_will_be_at;
+  bootparams_relloc->devtreelen = devtreelen;
+
+  bootparams_relloc->heap_start = grub_xnu_heap_will_be_at;
+  bootparams_relloc->heap_size = grub_xnu_heap_size;
+
+  bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off;
+  bootparams_relloc->efi_mmap_size = memory_map_size;          
+  bootparams_relloc->efi_mem_desc_size = descriptor_size;      
+  bootparams_relloc->efi_mem_desc_version = descriptor_version;   
+
+  bootparams_relloc->efi_runtime_first_page = firstruntimeaddr 
+    / GRUB_XNU_PAGESIZE;
+  bootparams_relloc->efi_runtime_npages 
+    = ((lastruntimeaddr + GRUB_XNU_PAGESIZE - 1) / GRUB_XNU_PAGESIZE) 
+    - (firstruntimeaddr / GRUB_XNU_PAGESIZE);
+  bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8;
+  bootparams_relloc->efi_system_table 
+    = PTR_TO_UINT32 (grub_autoefi_system_table);
+
+  bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR;  
+  bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR;
+
+  /* Parameters for asm helper. */
+  grub_xnu_stack = bootparams_relloc->heap_start 
+    + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE;
+  grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at;
+#ifndef GRUB_UTIL
+  grub_xnu_launch = (void (*) (void)) 
+    (grub_xnu_heap_start + grub_xnu_heap_size);
+#endif
+  grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
+  grub_dprintf ("xnu", "launch=%p\n", grub_xnu_launch);
+
+  const char *debug = grub_env_get ("debug");
+    
+  if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
+    {
+      grub_printf ("Press any key to launch xnu\n");
+      grub_getkey ();
+    }
+  
+  /* Set video. */
+  err = grub_xnu_set_video (bootparams_relloc);
+  if (err != GRUB_ERR_NONE)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+      grub_printf ("Booting in blind mode\n");
+
+      bootparams_relloc->lfb_mode = 0;
+      bootparams_relloc->lfb_width = 0;
+      bootparams_relloc->lfb_height = 0;
+      bootparams_relloc->lfb_depth = 0;
+      bootparams_relloc->lfb_line_len = 0;
+      bootparams_relloc->lfb_base = 0;
+    }
+
+  grub_memcpy (grub_xnu_heap_start + grub_xnu_heap_size, 
+              grub_xnu_launcher_start, 
+              grub_xnu_launcher_end - grub_xnu_launcher_start);
+
+
+  if (! grub_autoefi_finish_boot_services ())
+    return grub_error (GRUB_ERR_IO, "can't exit boot services");
+
+  grub_xnu_launch ();
+
+  /* Never reaches here. */
+  return 0;
+}

Added: trunk/grub2/loader/i386/xnu_helper.S
===================================================================
--- trunk/grub2/loader/i386/xnu_helper.S                                (rev 0)
+++ trunk/grub2/loader/i386/xnu_helper.S        2009-05-02 23:19:20 UTC (rev 
2163)
@@ -0,0 +1,192 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/symbol.h>
+       
+
+       .p2align        4       /* force 16-byte alignment */
+
+VARIABLE(grub_xnu_launcher_start)
+base:  
+       cli
+       
+#ifndef __x86_64__
+       /* mov imm32, %eax */
+       .byte   0xb8
+VARIABLE(grub_xnu_heap_will_be_at)
+       .long 0
+       mov %eax, %edi
+       
+       /* mov imm32, %eax */
+       .byte   0xb8
+VARIABLE(grub_xnu_heap_start)
+       .long 0
+       mov %eax, %esi
+       
+       /* mov imm32, %ecx */
+       .byte   0xb9
+VARIABLE(grub_xnu_heap_size)
+       .long 0
+       mov %edi, %eax
+       add %ecx, %eax
+       /* %rax now contains our starting position after relocation. */
+       /* One more page to copy: ourselves. */
+       add $0x403, %ecx
+       shr $2, %ecx
+
+       /* Forward copy.  */
+       cld
+       rep
+       movsl
+
+       mov %eax, %esi
+       add $(cont0-base), %eax
+       jmp *%eax
+cont0: 
+#else
+       xorq %rax, %rax
+       
+       /* mov imm32, %eax */
+       .byte   0xb8
+VARIABLE(grub_xnu_heap_will_be_at)
+       .long 0
+       mov %rax, %rdi
+       
+       /* mov imm32, %rax */
+       .byte   0x48
+       .byte   0xb8
+VARIABLE(grub_xnu_heap_start)
+       .long 0
+       .long 0
+       mov %rax, %rsi
+       
+       /* mov imm32, %rcx */
+       .byte   0x48
+       .byte   0xb9
+VARIABLE(grub_xnu_heap_size)
+       .long 0
+       .long 0
+       mov %rdi, %rax
+       add %rcx, %rax
+       /* %rax now contains our starting position after relocation. */
+       /* One more page to copy: ourselves. */
+       add $0x403, %rcx
+       shr $2, %rcx
+
+       /* Forward copy.  */
+       cld
+       rep
+       movsl
+
+       mov %rax, %rsi
+       add $(cont0-base), %rax
+       jmp *%rax
+
+cont0: 
+
+       lea (cont1-base)(%rsi, 1), %rax
+       mov %eax, (jump_vector-base)(%rsi,1)
+
+       lea (gdt-base)(%rsi, 1), %rax
+       mov %rax, (gdt_addr-base)(%rsi,1)
+       
+       /* Switch to compatibility mode. */
+
+       lgdt (gdtdesc-base)(%rsi,1)
+       
+       /* Update %cs. Thanks to David Miller for pointing this mistake out. */
+       ljmp *(jump_vector-base)(%rsi,1)
+cont1:
+       .code32
+
+       /* Update other registers. */
+       mov $0x18, %eax
+       mov %eax, %ds 
+       mov %eax, %es
+       mov %eax, %fs
+       mov %eax, %gs
+       mov %eax, %ss
+
+       /* Disable paging. */
+       mov %cr0, %eax
+       and $0x7fffffff, %eax
+       mov %eax, %cr0
+
+       /* Disable amd64. */
+       mov $0xc0000080, %ecx
+       rdmsr
+       and $0xfffffeff, %eax
+       wrmsr
+
+       /* Turn off PAE. */
+       movl %cr4, %eax
+       and $0xffffffcf, %eax
+       mov %eax, %cr4
+
+       jmp cont2
+cont2: 
+#endif
+       .code32
+       
+       /* Registers on XNU boot: eip, esp and eax. */
+       /* mov imm32, %ecx */
+       .byte   0xb9
+VARIABLE (grub_xnu_entry_point)
+       .long 0
+       /* mov imm32, %eax */
+       .byte   0xb8
+VARIABLE (grub_xnu_arg1)
+       .long 0
+       /* mov imm32, %ebx */
+       .byte   0xbb
+VARIABLE (grub_xnu_stack)
+       .long 0
+
+       movl %ebx, %esp
+
+       jmp *%ecx
+
+#ifdef __x86_64__
+       /* GDT. Copied from loader/i386/linux.c. */
+       .p2align 4
+gdt:   
+       /* NULL.  */
+       .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       
+       /* Reserved.  */
+       .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       
+       /* Code segment.  */
+       .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
+       
+       /* Data segment.  */
+       .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
+
+gdtdesc:       
+       .word 31
+gdt_addr:      
+       /* Filled by the code. */
+       .quad 0
+       
+       .p2align 4
+jump_vector:
+       /* Jump location. Is filled by the code */
+       .long 0
+       .long 0x10      
+#endif
+VARIABLE(grub_xnu_launcher_end)

Added: trunk/grub2/loader/macho.c
===================================================================
--- trunk/grub2/loader/macho.c                          (rev 0)
+++ trunk/grub2/loader/macho.c  2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,395 @@
+/* macho.c - load Mach-O files. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+/* This Mach-O loader is incomplete and can load only non-relocatable segments.
+   This is however enough to boot xnu (otool -l and Mach-O specs for more 
info).
+*/
+
+#include <grub/err.h>
+#include <grub/macho.h>
+#include <grub/cpu/macho.h>
+#include <grub/machoload.h>
+#include <grub/file.h>
+#include <grub/gzio.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+/* 32-bit. */
+
+int
+grub_macho_contains_macho32 (grub_macho_t macho)
+{
+  return macho->offset32 != -1;
+}
+
+static void
+grub_macho_parse32 (grub_macho_t macho)
+{
+  struct grub_macho_header32 head;
+
+  /* Is there any candidate at all? */
+  if (macho->offset32 == -1)
+    return;
+
+  /* Read header and check magic*/
+  if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1
+      || grub_file_read (macho->file, (char *) &head, sizeof (head)) 
+      != sizeof(head))
+    {
+      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");  
+      macho->offset32 = -1;
+      return;
+    }
+  if (head.magic != GRUB_MACHO_MAGIC32)
+    {
+      grub_error (GRUB_ERR_BAD_OS, "Invalid Mach-O 32-bit header.");  
+      macho->offset32 = -1;
+      return;
+    }
+
+  /* Read commands. */
+  macho->ncmds32 = head.ncmds;
+  macho->cmdsize32 = head.sizeofcmds;
+  macho->cmds32 = grub_malloc(macho->cmdsize32);
+  if (! macho->cmds32)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read 
commands");
+      return;
+    }
+  if (grub_file_read (macho->file, (char *) macho->cmds32, 
+                     (grub_size_t) macho->cmdsize32) 
+      != (grub_ssize_t) macho->cmdsize32)
+    {
+      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");  
+      macho->offset32 = -1;
+    }
+}
+
+typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
+(grub_macho_t , struct grub_macho_cmd *, 
+              void *);
+
+static grub_err_t
+grub_macho32_cmds_iterate (grub_macho_t macho,
+                          grub_macho_iter_hook_t hook,
+                          void *hook_arg)
+{
+  grub_uint8_t *hdrs = macho->cmds32;
+  int i;
+  if (! macho->cmds32)
+    return grub_error (GRUB_ERR_BAD_OS, "Couldn't find 32-bit Mach-O");
+  for (i = 0; i < macho->ncmds32; i++)
+    {
+      struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
+      if (hook (macho, hdr, hook_arg))
+       break;
+      hdrs += hdr->cmdsize;
+    }
+
+  return grub_errno;
+}
+
+grub_size_t
+grub_macho32_filesize (grub_macho_t macho)
+{
+  if (grub_macho_contains_macho32 (macho))
+    return macho->end32 - macho->offset32;
+  return 0;
+}
+
+grub_err_t
+grub_macho32_readfile (grub_macho_t macho, void *dest)
+{
+  grub_ssize_t read;
+  if (! grub_macho_contains_macho32 (macho))
+    return grub_error (GRUB_ERR_BAD_OS, 
+                      "Couldn't read arcitecture-specific part");
+
+  if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1)
+    {
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS,
+                        "Invalid offset in program header.");
+    }
+
+  read = grub_file_read (macho->file, dest, 
+                        macho->end32 - macho->offset32);
+  if (read != (grub_ssize_t) (macho->end32 - macho->offset32))
+    {
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS, 
+                        "Couldn't read arcitecture-specific part");
+    }
+  return GRUB_ERR_NONE;
+}
+
+/* Calculate the amount of memory spanned by the segments. */
+grub_err_t
+grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start,
+                  grub_addr_t *segments_end, int flags)
+{
+  int nr_phdrs = 0;
+
+  /* Run through the program headers to calculate the total memory size we
+     should claim.  */
+  auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho, 
+                                     struct grub_macho_cmd *phdr, void *_arg);
+  int NESTED_FUNC_ATTR calcsize (grub_macho_t UNUSED _macho, 
+                                struct grub_macho_cmd *hdr0, void UNUSED *_arg)
+    {
+      struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
+      if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
+       return 0;
+      if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
+       return 0;
+
+      nr_phdrs++;
+      if (hdr->vmaddr < *segments_start)
+       *segments_start = hdr->vmaddr;
+      if (hdr->vmaddr + hdr->vmsize > *segments_end)
+       *segments_end = hdr->vmaddr + hdr->vmsize;
+      return 0;
+    }
+
+  *segments_start = (grub_uint32_t) -1;
+  *segments_end = 0;
+
+  grub_macho32_cmds_iterate (macho, calcsize, 0);
+
+  if (nr_phdrs == 0)
+    return grub_error (GRUB_ERR_BAD_OS, "No program headers present");
+
+  if (*segments_end < *segments_start)
+    /* Very bad addresses.  */
+    return grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses");
+
+  return GRUB_ERR_NONE;
+}
+
+/* Load every loadable segment into memory specified by `_load_hook'.  */
+grub_err_t
+grub_macho32_load (grub_macho_t macho, char *offset, int flags)
+{
+  grub_err_t err = 0;
+  auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, 
+                              struct grub_macho_cmd *hdr0, 
+                              void UNUSED *_arg);
+  int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, 
+                              struct grub_macho_cmd *hdr0, 
+                              void UNUSED *_arg)
+  {
+    struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
+
+    if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
+      return 0;
+    
+    if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
+      return 0;
+    if (! hdr->vmsize)
+      return 0;
+    
+    if (grub_file_seek (_macho->file, hdr->fileoff 
+                       + _macho->offset32) == (grub_off_t) -1)
+      {
+       grub_error_push ();
+       grub_error (GRUB_ERR_BAD_OS,
+                   "Invalid offset in program header.");
+       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))
+         {
+           /* XXX How can we free memory from `load_hook'? */
+           grub_error_push ();
+           err=grub_error (GRUB_ERR_BAD_OS,
+                           "Couldn't read segment from file: "
+                           "wanted 0x%lx bytes; read 0x%lx bytes.",
+                           hdr->filesize, read);
+           return 1;
+         }
+      }
+    
+    if (hdr->filesize < hdr->vmsize)
+      grub_memset (offset + hdr->vmaddr + hdr->filesize,
+                  0, hdr->vmsize - hdr->filesize);
+    return 0;
+  }
+
+  grub_macho32_cmds_iterate (macho, do_load, 0);
+
+  return err;
+}
+
+grub_uint32_t
+grub_macho32_get_entry_point (grub_macho_t macho)
+{
+  grub_uint32_t entry_point = 0;
+  auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho, 
+                              struct grub_macho_cmd *hdr, 
+                              void UNUSED *_arg);
+  int NESTED_FUNC_ATTR hook(grub_macho_t UNUSED _macho, 
+                              struct grub_macho_cmd *hdr, 
+                              void UNUSED *_arg)
+  {
+    if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
+      entry_point = ((struct grub_macho_thread32 *) hdr)->entry_point;
+    return 0;
+  }
+  grub_macho32_cmds_iterate (macho, hook, 0);
+  return entry_point;
+}
+
+
+grub_err_t
+grub_macho_close (grub_macho_t macho)
+{
+  grub_file_t file = macho->file;
+
+  grub_free (macho->cmds32);
+  grub_free (macho->cmds64);
+
+  grub_free (macho);
+
+  if (file)
+    grub_file_close (file);
+
+  return grub_errno;
+}
+
+grub_macho_t
+grub_macho_file (grub_file_t file)
+{
+  grub_macho_t macho;
+  union grub_macho_filestart filestart;
+
+  macho = grub_malloc (sizeof (*macho));
+  if (! macho)
+    return 0;
+
+  macho->file = file;
+  macho->offset32 = -1;
+  macho->offset64 = -1;
+  macho->end32 = -1;
+  macho->end64 = -1;
+  macho->cmds32 = 0;
+  macho->cmds64 = 0;
+
+  if (grub_file_seek (macho->file, 0) == (grub_off_t) -1)
+    goto fail;
+
+  if (grub_file_read (macho->file, (char *) &filestart, sizeof (filestart))
+      != sizeof (filestart))
+    {
+      grub_error_push ();
+      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
+      goto fail;
+    }
+
+  /* Is it a fat file? */
+  if (filestart.fat.magic == grub_be_to_cpu32 (GRUB_MACHO_FAT_MAGIC))
+    {
+      struct grub_macho_fat_arch *archs;
+      int i, narchs;
+
+      /* Load architecture description. */
+      narchs = grub_be_to_cpu32 (filestart.fat.nfat_arch);
+      if (grub_file_seek (macho->file, sizeof (struct grub_macho_fat_header)) 
+         == (grub_off_t) -1)
+       goto fail;
+      archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
+      if (!archs)
+       goto fail;
+      if (grub_file_read (macho->file, (char *) archs, 
+                         sizeof (struct grub_macho_fat_arch) * narchs)
+         != (grub_ssize_t)sizeof(struct grub_macho_fat_arch) * narchs)
+       {
+         grub_free (archs);
+         grub_error_push ();
+         grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
+         goto fail;
+       }
+
+      for (i = 0; i < narchs; i++)
+       {
+         if (GRUB_MACHO_CPUTYPE_IS_HOST32 
+             (grub_be_to_cpu32 (archs[i].cputype)))
+           {
+             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)))
+           {
+             macho->offset64 = grub_be_to_cpu32 (archs[i].offset);
+             macho->end64 = grub_be_to_cpu32 (archs[i].offset) 
+               + grub_be_to_cpu32 (archs[i].size);
+           }
+       }
+      grub_free (archs);
+    }
+
+  /* Is it a thin 32-bit file? */
+  if (filestart.thin32.magic == GRUB_MACHO_MAGIC32)
+    {
+      macho->offset32 = 0;
+      macho->end32 = grub_file_size (file);
+    }
+
+  /* Is it a thin 64-bit file? */
+  if (filestart.thin64.magic == GRUB_MACHO_MAGIC64)
+    {
+      macho->offset64 = 0;
+      macho->end64 = grub_file_size (file);
+    }
+
+  grub_macho_parse32 (macho);
+  /* FIXME: implement 64-bit.*/
+  /*  grub_macho_parse64 (macho); */
+  
+  return macho;
+
+fail:
+  grub_macho_close (macho);
+  return 0;
+}
+
+grub_macho_t
+grub_macho_open (const char *name)
+{
+  grub_file_t file;
+  grub_macho_t macho;
+
+  file = grub_gzfile_open (name, 1);
+  if (! file)
+    return 0;
+
+  macho = grub_macho_file (file);
+  if (! macho)
+    grub_file_close (file);
+
+  return macho;
+}

Added: trunk/grub2/loader/xnu.c
===================================================================
--- trunk/grub2/loader/xnu.c                            (rev 0)
+++ trunk/grub2/loader/xnu.c    2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,1368 @@
+/* xnu.c - load xnu kernel. Thanks to Florian Idelberger for all the 
+   time he spent testing this
+ */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/file.h>
+#include <grub/xnu.h>
+#include <grub/cpu/xnu.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/loader.h>
+#include <grub/machoload.h>
+#include <grub/macho.h>
+#include <grub/cpu/macho.h>
+#include <grub/gzio.h>
+#include <grub/command.h>
+#include <grub/misc.h>
+
+struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
+static int driverspackagenum = 0;
+static int driversnum = 0;
+
+/* Allocate heap by 32MB-blocks. */
+#define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000
+
+static grub_err_t
+grub_xnu_register_memory (char *prefix, int *suffix, 
+                         void *addr, grub_size_t size);
+void *
+grub_xnu_heap_malloc (int size)
+{
+  void *val;
+
+#if 0
+  /* This way booting is faster but less reliable. 
+     Once we have advanced mm second way will be as fast as this one. */
+  val = grub_xnu_heap_start = (char *) 0x100000;
+#else
+  int oldblknum, newblknum;
+
+  /* The page after the heap is used for stack. Ensure it's usable. */
+  if (grub_xnu_heap_size)
+    oldblknum = (grub_xnu_heap_size + GRUB_XNU_PAGESIZE 
+                + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK;
+  else
+    oldblknum = 0;
+  newblknum = (grub_xnu_heap_size + size + GRUB_XNU_PAGESIZE 
+              + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK;
+  if (oldblknum != newblknum)
+    /* FIXME: instruct realloc to allocate at 1MB if possible once 
+       advanced mm is ready. */
+    val = grub_realloc (grub_xnu_heap_start, 
+                       newblknum * GRUB_XNU_HEAP_ALLOC_BLOCK);
+  else
+    val = grub_xnu_heap_start;
+  if (! val)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                 "not enough space on xnu memory heap");
+      return 0;
+    }
+  grub_xnu_heap_start = val;
+#endif
+
+  val = (char *) grub_xnu_heap_start + grub_xnu_heap_size;
+  grub_xnu_heap_size += size;
+  grub_dprintf ("xnu", "val=%p\n", val);
+  return (char *) val;
+}
+
+/* Make sure next block of the heap will be aligned. 
+   Please notice: aligned are pointers AFTER relocation 
+   and not the current ones. */
+grub_err_t
+grub_xnu_align_heap (int align)
+{
+  int align_overhead = align - grub_xnu_heap_size % align;
+  if (align_overhead == align)
+    return GRUB_ERR_NONE;
+  if (! grub_xnu_heap_malloc (align_overhead))
+    return grub_errno;
+  return GRUB_ERR_NONE;
+}
+
+/* Free subtree pointed by CUR. */
+void
+grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
+{
+  struct grub_xnu_devtree_key *d;
+  while (cur)
+    {
+      grub_free (cur->name);
+      if (cur->datasize == -1)
+       grub_xnu_free_devtree (cur->first_child);
+      else if (cur->data)
+       grub_free (cur->data);
+      d = cur->next;
+      grub_free (cur);      
+      cur = d;
+    }  
+}
+
+/* Compute the size of device tree in xnu format. */
+static grub_size_t
+grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, char *name)
+{
+  grub_size_t ret;
+  struct grub_xnu_devtree_key *cur;
+  
+  /* Key header. */
+  ret = 2 * sizeof (grub_uint32_t);
+
+  /* "name" value. */
+  ret += 32 + sizeof (grub_uint32_t)
+    + grub_strlen (name) + 4 
+    - (grub_strlen (name) % 4);
+
+  for (cur = start; cur; cur = cur->next)
+    if (cur->datasize != -1)
+      {
+       int align_overhead;
+       
+       align_overhead = 4 - (cur->datasize % 4);
+       if (align_overhead == 4)
+         align_overhead = 0;
+       ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
+      }
+    else
+      ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
+  return ret;
+}
+
+/* Write devtree in XNU format at curptr assuming the head is named NAME.*/
+static void *
+grub_xnu_writetree_toheap_real (void *curptr, 
+                               struct grub_xnu_devtree_key *start, char *name)
+{
+  struct grub_xnu_devtree_key *cur;
+  int nkeys = 0, nvals = 0;
+  for (cur = start; cur; cur = cur->next)
+    {
+      if (cur->datasize == -1)
+       nkeys++;
+      else
+       nvals++;
+    }
+  /* For the name. */
+  nvals++; 
+  
+  *((grub_uint32_t *) curptr) = nvals;
+  curptr = ((grub_uint32_t *) curptr) + 1;
+  *((grub_uint32_t *) curptr) = nkeys;
+  curptr = ((grub_uint32_t *) curptr) + 1;
+
+  /* First comes "name" value. */
+  grub_memset (curptr, 0, 32);
+  grub_memcpy (curptr, "name", 4);
+  curptr = ((grub_uint8_t *) curptr) + 32;
+  *((grub_uint32_t *)curptr) = grub_strlen (name) + 1;
+  curptr = ((grub_uint32_t *) curptr) + 1;
+  grub_memcpy (curptr, name, grub_strlen (name));
+  curptr = ((grub_uint8_t *) curptr) + grub_strlen (name);
+  grub_memset (curptr, 0, 4 - (grub_strlen (name) % 4));
+  curptr = ((grub_uint8_t *) curptr) + (4 - (grub_strlen (name) % 4));
+
+  /* Then the other values. */
+  for (cur = start; cur; cur = cur->next)
+    if (cur->datasize != -1)
+      {
+       int align_overhead;
+       
+       align_overhead = 4 - (cur->datasize % 4);
+       if (align_overhead == 4)
+         align_overhead = 0;
+       grub_memset (curptr, 0, 32);
+       grub_strncpy (curptr, cur->name, 31);
+       curptr = ((grub_uint8_t *) curptr) + 32;
+       *((grub_uint32_t *) curptr) = cur->datasize;
+       curptr = ((grub_uint32_t *) curptr) + 1;
+       grub_memcpy (curptr, cur->data, cur->datasize);
+       curptr = ((grub_uint8_t *) curptr) + cur->datasize;
+       grub_memset (curptr, 0, align_overhead);
+       curptr = ((grub_uint8_t *) curptr) + align_overhead;
+      }
+  
+  /* And then the keys. Recursively use this function. */
+  for (cur = start; cur; cur = cur->next)
+    if (cur->datasize == -1)
+      if (!(curptr = grub_xnu_writetree_toheap_real (curptr,
+                                                    cur->first_child, 
+                                                    cur->name)))
+       return 0;
+  return curptr;
+}
+
+grub_err_t
+grub_xnu_writetree_toheap (void **start, grub_size_t *size)
+{
+  struct grub_xnu_devtree_key *chosen;
+  struct grub_xnu_devtree_key *memorymap;
+  struct grub_xnu_devtree_key *driverkey;
+  struct grub_xnu_extdesc *extdesc;
+  grub_err_t err;
+  
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    return err;
+  
+  /* Device tree itself is in the memory map of device tree. */
+  /* Create a dummy value in memory-map. */
+  chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
+  if (! chosen)
+    return grub_errno;
+  memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
+  if (! memorymap)
+    return grub_errno;
+
+  driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof 
(*driverkey));
+  if (! driverkey)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
+  driverkey->name = grub_strdup ("DeviceTree");
+  if (! driverkey->name)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
+  driverkey->datasize = sizeof (*extdesc);
+  driverkey->next = memorymap->first_child;
+  memorymap->first_child = driverkey;
+  driverkey->data = extdesc 
+    = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
+  if (! driverkey->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
+
+  /* Allocate the space based on the size with dummy value. */
+  *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/");
+  *start = grub_xnu_heap_malloc (*size + GRUB_XNU_PAGESIZE 
+                                - *size % GRUB_XNU_PAGESIZE);
+
+  /* Put real data in the dummy. */
+  extdesc->addr = (char *) *start - grub_xnu_heap_start 
+    + grub_xnu_heap_will_be_at;
+  extdesc->size = (grub_uint32_t) *size;
+
+  /* Write the tree to heap. */
+  grub_xnu_writetree_toheap_real (*start, grub_xnu_devtree_root, "/");
+  return GRUB_ERR_NONE;
+}
+
+/* Find a key or value in parent key. */
+struct grub_xnu_devtree_key *
+grub_xnu_find_key (struct grub_xnu_devtree_key *parent, char *name)
+{
+  struct grub_xnu_devtree_key *cur;
+  for (cur = parent; cur; cur = cur->next)
+    if (grub_strcmp (cur->name, name) == 0)
+      return cur;
+  return 0;
+}
+
+struct grub_xnu_devtree_key *
+grub_xnu_create_key (struct grub_xnu_devtree_key **parent, char *name)
+{
+  struct grub_xnu_devtree_key *ret;
+  ret = grub_xnu_find_key (*parent, name);
+  if (ret)
+    return ret;
+  ret = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*ret));
+  if (! ret)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
+      return 0;
+    }
+  ret->name = grub_strdup (name);
+  if (! ret->name)
+    {
+      grub_free (ret);
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
+      return 0;
+    }
+  ret->datasize = -1;
+  ret->first_child = 0;
+  ret->next = *parent;
+  *parent = ret;
+  return ret;
+}
+
+struct grub_xnu_devtree_key *
+grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name)
+{
+  struct grub_xnu_devtree_key *ret;
+  ret = grub_xnu_find_key (*parent, name);
+  if (ret)
+    {
+      if (ret->datasize == -1)
+       grub_xnu_free_devtree (ret->first_child);
+      else if (ret->datasize)
+       grub_free (ret->data);
+      ret->datasize = 0;
+      ret->data = 0;
+      return ret;
+    }
+  ret = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*ret));
+  if (! ret)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
+      return 0;
+    }
+  ret->name = grub_strdup (name);
+  if (! ret->name)
+    {
+      grub_free (ret);
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
+      return 0;
+    }
+  ret->datasize = 0;
+  ret->data = 0;
+  ret->next = *parent;
+  *parent = ret;
+  return ret;
+}
+
+static grub_err_t
+grub_xnu_unload (void)
+{
+  grub_xnu_free_devtree (grub_xnu_devtree_root);
+  grub_xnu_devtree_root = 0;
+
+  /* Free loaded image. */
+  driversnum = 0;
+  driverspackagenum = 0;
+  grub_free (grub_xnu_heap_start);
+  grub_xnu_heap_start = 0;
+  grub_xnu_heap_size = 0;
+  grub_xnu_unlock ();
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
+                    int argc, char *args[])
+{
+  grub_err_t err;
+  grub_macho_t macho;
+  grub_addr_t startcode, endcode;
+  int i;
+  char *ptr, *loadaddr;
+
+  if (argc < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+
+  grub_xnu_unload ();
+
+  macho = grub_macho_open (args[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 architecture");
+    }
+
+  err = grub_macho32_size (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
+  if (err)
+    {
+      grub_macho_close (macho);
+      grub_xnu_unload ();
+      return err;
+    }
+
+  grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", 
+               (unsigned long) endcode, (unsigned long) startcode);
+
+  loadaddr = grub_xnu_heap_malloc (endcode - startcode);
+  grub_xnu_heap_will_be_at = startcode;
+
+  if (! loadaddr)
+    {
+      grub_macho_close (macho);
+      grub_xnu_unload ();
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                        "not enough memory to load kernel");
+    }
+
+  /* Load kernel. */
+  err = grub_macho32_load (macho, loadaddr - startcode, GRUB_MACHO_NOBSS);
+  if (err)
+    {
+      grub_macho_close (macho);
+      grub_xnu_unload ();
+      return err;
+    }
+
+  grub_xnu_entry_point = grub_macho32_get_entry_point (macho);
+  if (! grub_xnu_entry_point)
+    {
+      grub_macho_close (macho);
+      grub_xnu_unload ();
+      return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
+    }
+
+  grub_macho_close (macho);
+
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    {
+      grub_xnu_unload ();
+      return err;
+    }
+
+  /* Copy parameters to kernel command line. */
+  ptr = grub_xnu_cmdline;
+  for (i = 1; i < argc; i++)
+    {
+      if (ptr + grub_strlen (args[i]) + 1 
+         >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
+       break;
+      grub_memcpy (ptr, args[i], grub_strlen (args[i]));
+      ptr += grub_strlen (args[i]);
+      *ptr = ' ';
+      ptr++;
+    }
+
+  /* Replace last space by '\0'. */
+  if (ptr != grub_xnu_cmdline)
+    *(ptr - 1) = 0;  
+
+  err = grub_cpu_xnu_fill_devicetree ();
+  if (err)
+    return err;
+
+  grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);    
+
+  grub_xnu_lock ();
+  return 0;
+}
+
+/* Register a memory in a memory map under name PREFIXSUFFIX 
+   and increment SUFFIX. */
+static grub_err_t
+grub_xnu_register_memory (char *prefix, int *suffix, 
+                         void *addr, grub_size_t size)
+{
+  struct grub_xnu_devtree_key *chosen;
+  struct grub_xnu_devtree_key *memorymap;
+  struct grub_xnu_devtree_key *driverkey;
+  struct grub_xnu_extdesc *extdesc;
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+
+  chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
+  if (! chosen)
+    return grub_errno;
+  memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
+  if (! memorymap)
+    return grub_errno;
+
+  driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof 
(*driverkey));
+  if (! driverkey)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory");
+  if (suffix)
+    {
+      driverkey->name = grub_malloc (grub_strlen (prefix) + 10);
+      if (!driverkey->name)
+       return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory");
+      grub_sprintf (driverkey->name, "%s%d", prefix, (*suffix)++);
+    }
+  else
+    driverkey->name = grub_strdup (prefix);
+  if (! driverkey->name)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension");
+  driverkey->datasize = sizeof (*extdesc);
+  driverkey->next = memorymap->first_child;
+  memorymap->first_child = driverkey;
+  driverkey->data = extdesc 
+    = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
+  if (! driverkey->data)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension");
+  extdesc->addr = grub_xnu_heap_will_be_at + 
+    ((grub_uint8_t *) addr - (grub_uint8_t *) grub_xnu_heap_start);
+  extdesc->size = (grub_uint32_t) size;
+  return GRUB_ERR_NONE;
+}
+
+/* Load .kext. */
+static grub_err_t
+grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile)
+{
+  grub_macho_t macho;
+  grub_err_t err;
+  grub_file_t infoplist;
+  struct grub_xnu_extheader *exthead;
+  int neededspace = sizeof (*exthead);
+  char *buf;
+  grub_size_t infoplistsize = 0, machosize = 0;
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+  
+  /* Compute the needed space. */
+  if (binaryfile)
+    {
+      macho = grub_macho_file (binaryfile);
+      if (! macho || ! grub_macho_contains_macho32 (macho))
+       {
+         if (macho)
+           grub_macho_close (macho);
+         return grub_error (GRUB_ERR_BAD_OS, 
+                            "Extension doesn't contain suitable architecture");
+       }
+      machosize = grub_macho32_filesize (macho);
+      neededspace += machosize;
+    }
+  else
+    macho = 0;
+
+  if (infoplistname)
+    infoplist = grub_gzfile_open (infoplistname, 1);
+  else
+    infoplist = 0;
+  grub_errno = GRUB_ERR_NONE;
+  if (infoplist)
+    {
+      infoplistsize = grub_file_size (infoplist);
+      neededspace += infoplistsize + 1;
+    }
+  else
+    infoplistsize = 0;
+
+  /* Allocate the space. */
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    return err;
+  buf = grub_xnu_heap_malloc (neededspace);
+
+  exthead = (struct grub_xnu_extheader *) buf;
+  grub_memset (exthead, 0, sizeof (*exthead));
+  buf += sizeof (*exthead);
+
+  /* Load the binary. */
+  if (macho)
+    {
+      exthead->binaryaddr = (buf - grub_xnu_heap_start)
+       + grub_xnu_heap_will_be_at;
+      exthead->binarysize = machosize;
+      if ((err = grub_macho32_readfile (macho, buf)))
+       {
+         grub_macho_close (macho);
+         return err;
+       }
+      grub_macho_close (macho);
+      buf += machosize;
+    }
+  grub_errno = GRUB_ERR_NONE;
+
+  /* Load the plist. */
+  if (infoplist)
+    {
+      exthead->infoplistaddr = (buf - grub_xnu_heap_start) 
+       + grub_xnu_heap_will_be_at;
+      exthead->infoplistsize = infoplistsize + 1;
+      if (grub_file_read (infoplist, buf, infoplistsize)
+         != (grub_ssize_t) (infoplistsize))
+       {
+         grub_file_close (infoplist);
+         grub_error_push ();
+         return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s: ",
+                            infoplistname);
+       }
+      grub_file_close (infoplist);
+      buf[infoplistsize] = 0;
+    }
+  grub_errno = GRUB_ERR_NONE;
+
+  /* Announce to kernel */
+  return grub_xnu_register_memory ("Driver-", &driversnum, exthead,
+                                  neededspace);  
+}
+
+/* Load mkext. */
+static grub_err_t
+grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
+                   int argc, char *args[])
+{
+  grub_file_t file;
+  void *loadto;
+  grub_err_t err;
+  grub_off_t readoff = 0;
+  grub_ssize_t readlen = -1;
+  struct grub_macho_fat_header head;
+  struct grub_macho_fat_arch *archs;
+  int narchs, i;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+
+  file = grub_gzfile_open (args[0], 1);
+  if (! file)
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, 
+                      "Couldn't load driver package");
+
+  /* Sometimes caches are fat binary. Errgh. */
+  if (grub_file_read (file, (char *) &head, sizeof (head))
+      != (grub_ssize_t) (sizeof (head)))
+    {
+      /* I don't know the internal structure of package but 
+        can hardly imagine a valid package shorter than 20 bytes. */
+      grub_file_close (file);
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]);
+    }
+
+  /* Find the corresponding architecture. */
+  if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
+    {
+      narchs = grub_be_to_cpu32 (head.nfat_arch);
+      archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
+      if (! archs)
+       {
+         grub_file_close (file);
+         grub_error_push ();
+         return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                            "Couldn't read file %s", args[0]);
+      
+       }
+      if (grub_file_read (file, (char *) archs, 
+                         sizeof (struct grub_macho_fat_arch) * narchs)
+         != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs)
+       {
+         grub_free (archs);
+         grub_error_push ();
+         return grub_error (GRUB_ERR_READ_ERROR, "Cannot read fat header.");
+       }
+      for (i = 0; i < narchs; i++)
+       {
+         if (GRUB_MACHO_CPUTYPE_IS_HOST32 
+             (grub_be_to_cpu32 (archs[i].cputype)))
+           {
+             readoff = grub_be_to_cpu32 (archs[i].offset);
+             readlen = grub_be_to_cpu32 (archs[i].size);
+           }
+       }
+      grub_free (archs);
+    }
+  else
+    {
+      /* It's a flat file. Some sane people still exist. */
+      readoff = 0;
+      readlen = grub_file_size (file);
+    }
+
+  if (readlen == -1)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
+    }
+
+  /* Allocate space. */
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    {
+      grub_file_close (file);
+      return err;
+    }
+
+  loadto = grub_xnu_heap_malloc (readlen);
+  if (! loadto)
+    {
+      grub_file_close (file);
+      return grub_errno;
+    }
+
+  /* Read the file. */
+  grub_file_seek (file, readoff);
+  if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
+    {
+      grub_file_close (file);
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]);
+    }
+  grub_file_close (file);
+
+  /* Pass it to kernel. */
+  return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
+                                  loadto, readlen);  
+}
+
+static grub_err_t
+grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
+                     int argc, char *args[])
+{
+  grub_file_t file;
+  void *loadto;
+  grub_err_t err;
+  grub_size_t size;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+
+  file = grub_gzfile_open (args[0], 1);
+  if (! file)
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, 
+                      "Couldn't load ramdisk");
+
+  err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
+  if (err)
+    return err;
+
+  size = grub_file_size (file);
+  
+  loadto = grub_xnu_heap_malloc (size);
+  if (! loadto)
+    return grub_errno;
+  if (grub_file_read (file, loadto, size)
+      != (grub_ssize_t) (size))
+    {
+      grub_file_close (file);
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]);
+    }
+  return grub_xnu_register_memory ("RAMDisk", 0, loadto, size);  
+}
+
+/* Parse a devtree file. It uses the following format: 
+   valuename:valuedata;
+   keyname{
+     contents
+   }
+   keyname, valuename and valuedata are in hex.
+ */
+static char *
+grub_xnu_parse_devtree (struct grub_xnu_devtree_key **parent,
+                       char *start, char *end)
+{
+  char *ptr, *ptr2;
+  char *name, *data;
+  int namelen, datalen, i;
+  for (ptr = start; ptr && ptr < end; )
+    {
+      if (grub_isspace (*ptr))
+       {
+         ptr++;
+         continue;
+       }
+      if (*ptr == '}')
+       return ptr + 1;
+      namelen = 0;
+      
+      /* Parse the name. */
+      for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2) 
+                                     || (*ptr2 >= '0' && *ptr2 <= '9')
+                                     || (*ptr2 >= 'a' && *ptr2 <= 'f')
+                                     || (*ptr2 >= 'A' && *ptr2 <= 'F')); 
+          ptr2++)
+       if (! grub_isspace (*ptr2))
+         namelen++;
+      if (ptr2 == end)
+       return 0;
+      namelen /= 2;
+      name = grub_malloc (namelen + 1);
+      if (!name)
+       return 0;
+      for (i = 0; i < 2 * namelen; i++)
+       {
+         int hex = 0;
+         while (grub_isspace (*ptr))
+           ptr++;
+         if (*ptr >= '0' && *ptr <= '9')
+           hex = *ptr - '0';
+         if (*ptr >= 'a' && *ptr <= 'f')
+           hex = *ptr - 'a' + 10;
+         if (*ptr >= 'A' && *ptr <= 'F')
+           hex = *ptr - 'A' + 10;
+         
+         if (i % 2 == 0)
+           name[i / 2] = hex << 4;
+         else
+           name[i / 2] |= hex;
+         ptr++;
+       }
+      name [namelen] = 0;
+      while (grub_isspace (*ptr))
+       ptr++;
+
+      /* If it describes a key recursively invoke the function. */
+      if (*ptr == '{')
+       {
+         struct grub_xnu_devtree_key *newkey 
+           = grub_xnu_create_key (parent, name);
+         grub_free (name);
+         if (! newkey)
+           return 0;
+         ptr = grub_xnu_parse_devtree (&(newkey->first_child), ptr + 1, end);
+         continue;
+       }
+
+      /* Parse the data. */
+      if (*ptr != ':')
+       return 0;
+      ptr++;
+      datalen = 0;
+      for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2) 
+                                     || (*ptr2 >= '0' && *ptr2 <= '9')
+                                     || (*ptr2 >= 'a' && *ptr2 <= 'f')
+                                     || (*ptr2 >= 'A' && *ptr2 <= 'F')); 
+          ptr2++)
+       if (! grub_isspace (*ptr2))
+         datalen++;
+      if (ptr2 == end)
+       return 0;
+      datalen /= 2;
+      data = grub_malloc (datalen);
+      if (! data)
+       return 0;
+      for (i = 0; i < 2 * datalen; i++)
+       {
+         int hex = 0;
+         while (grub_isspace (*ptr))
+           ptr++;
+         if (*ptr >= '0' && *ptr <= '9')
+           hex = *ptr - '0';
+         if (*ptr >= 'a' && *ptr <= 'f')
+           hex = *ptr - 'a' + 10;
+         if (*ptr >= 'A' && *ptr <= 'F')
+           hex = *ptr - 'A' + 10;
+         
+         if (i % 2 == 0)
+           data[i / 2] = hex << 4;
+         else
+           data[i / 2] |= hex;
+         ptr++;
+       }
+      while (ptr < end && grub_isspace (*ptr))
+       ptr++;
+      {
+       struct grub_xnu_devtree_key *newkey 
+         = grub_xnu_create_value (parent, name);
+       grub_free (name);
+       if (! newkey)
+         return 0;
+       newkey->datasize = datalen;
+       newkey->data = data;
+      }
+      if (*ptr != ';')
+       return 0;
+      ptr++;
+    }
+  if (ptr >= end && *parent != grub_xnu_devtree_root)
+    return 0;
+  return ptr;
+}
+
+/* Returns true if the kext should be loaded according to plist 
+   and osbundlereq. Also fill BINNAME. */
+static int
+grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq,
+                                  char **binname)
+{
+  grub_file_t file;
+  char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
+  char *stringptr = 0, *ptr2 = 0;
+  grub_size_t size;
+  int depth = 0;
+  int ret;
+  int osbundlekeyfound = 0, binnamekeyfound = 0;
+  if (binname)
+    *binname = 0;
+
+  file = grub_gzfile_open (plistname, 1);
+  if (! file)
+    {
+      grub_file_close (file); 
+      grub_error_push ();
+      grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", plistname);
+      return 0;
+    }
+
+  size = grub_file_size (file);
+  buf = grub_malloc (size);
+  if (! buf)
+    {
+      grub_file_close (file); 
+      grub_error_push ();
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't read file %s", plistname);
+      return 0;
+    }
+  if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
+    {
+      grub_file_close (file); 
+      grub_error_push ();
+      grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", plistname);
+      return 0;
+    }
+  grub_file_close (file); 
+
+  /* Set the return value for the case when no OSBundleRequired tag is found. 
*/
+  if (osbundlereq)
+    ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
+  else
+    ret = 1;
+  
+  /* Parse plist. It's quite dirty and inextensible but does its job. */
+  for (ptr1 = buf; ptr1 < buf + size; ptr1++)
+    switch (*ptr1)
+      {
+      case '<':
+       tagstart = ptr1;
+       *ptr1 = 0;
+       if (keyptr && depth == 4 
+           && grub_strcmp (keyptr, "OSBundleRequired") == 0)
+         osbundlekeyfound = 1;
+       if (keyptr && depth == 4 && 
+           grub_strcmp (keyptr, "CFBundleExecutable") == 0)
+         binnamekeyfound = 1;
+       if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
+         {
+           for (ptr2 = stringptr; *ptr2; ptr2++)
+             *ptr2 = grub_tolower (*ptr2);
+           ret = grub_strword (osbundlereq, stringptr) 
+             || grub_strword (osbundlereq, "all");
+         }
+       if (stringptr && binnamekeyfound && binname && depth == 4)
+         {
+           if (*binname)
+             grub_free (*binname);
+           *binname = grub_strdup (stringptr);
+         }
+
+       *ptr1 = '<';
+       keyptr = 0;
+       stringptr = 0;
+       break;
+      case '>':
+       if (! tagstart)
+         {
+           grub_free (buf);
+           grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
+           return 0;
+         }
+       *ptr1 = 0;
+       if (tagstart[1] == '?' || ptr1[-1] == '/')
+         {
+           osbundlekeyfound = 0;
+           *ptr1 = '>';
+           break;
+         }
+       if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
+         keyptr = ptr1 + 1;
+       if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
+         stringptr = ptr1 + 1; 
+       else if (grub_strcmp (tagstart + 1, "/key") != 0)
+         {
+           osbundlekeyfound = 0;
+           binnamekeyfound = 0;
+         }
+       *ptr1 = '>';
+       
+       if (tagstart[1] == '/')
+         depth--;
+       else
+         depth++;
+       break;
+      }
+  grub_free (buf);
+
+  return ret; 
+}
+
+/* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED 
*/
+grub_err_t
+grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, 
+                            int maxrecursion)
+{
+  grub_device_t dev;
+  char *device_name;
+  grub_fs_t fs;
+  const char *path;
+
+  auto int load_hook (const char *filename, 
+                     const struct grub_dirhook_info *info);
+  int load_hook (const char *filename, const struct grub_dirhook_info *info)
+  {
+    char *newdirname;
+    if (! info->dir)
+      return 0;
+    if (filename[0] == '.')
+      return 0;
+
+    if (grub_strlen (filename) < 5 ||
+       grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
+      return 0;
+
+    newdirname 
+      = grub_malloc (grub_strlen (dirname) + grub_strlen (filename) + 2);
+
+    /* It's a .kext. Try to load it. */
+    if (newdirname)
+      {
+       grub_strcpy (newdirname, dirname);
+       newdirname[grub_strlen (newdirname) + 1] = 0;
+       newdirname[grub_strlen (newdirname)] = '/';
+       grub_strcpy (newdirname + grub_strlen (newdirname), filename);
+       grub_xnu_load_kext_from_dir (newdirname, osbundlerequired, 
+                                    maxrecursion);
+       if (grub_errno == GRUB_ERR_BAD_OS)
+         grub_errno = GRUB_ERR_NONE;
+       grub_free (newdirname);
+      }
+    return 0;
+  }
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+
+  device_name = grub_file_get_device_name (dirname);
+  dev = grub_device_open (device_name);
+  if (dev)
+    {
+      fs = grub_fs_probe (dev);
+      path = grub_strchr (dirname, ')');
+      if (! path)
+       path = dirname;
+      else
+       path++;
+
+      if (fs)
+       (fs->dir) (dev, path, load_hook);
+      grub_device_close (dev);
+    }
+  grub_free (device_name);
+
+  return GRUB_ERR_NONE;
+}
+
+/* Load extension DIRNAME. (extensions are directoris in xnu) */
+grub_err_t
+grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, 
+                            int maxrecursion)
+{
+  grub_device_t dev;
+  char *plistname = 0;
+  char *newdirname;
+  char *newpath;
+  char *device_name;
+  grub_fs_t fs;
+  const char *path;
+  char *binsuffix;
+  int usemacos = 0;
+  grub_file_t binfile;
+
+  auto int load_hook (const char *filename, 
+                     const struct grub_dirhook_info *info);
+
+  int load_hook (const char *filename, const struct grub_dirhook_info *info)
+  {
+    if (grub_strlen (filename) > 15)
+      return 0;
+    grub_strcpy (newdirname + grub_strlen (dirname) + 1, filename); 
+
+    /* If the kext contains directory "Contents" all real stuff is in 
+       this directory. */
+    if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
+      grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
+                                  maxrecursion - 1);
+
+    /* Directory "Plugins" contains nested kexts. */
+    if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
+      grub_xnu_scan_dir_for_kexts (newdirname, osbundlerequired, 
+                                  maxrecursion - 1);
+
+    /* Directory "MacOS" contains executable, otherwise executable is 
+       on the top. */
+    if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
+      usemacos = 1;
+    
+    /* Info.plist is the file which governs our future actions. */
+    if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0 
+       && ! plistname)
+      plistname = grub_strdup (newdirname);
+    return 0;
+  }
+
+  newdirname = grub_malloc (grub_strlen (dirname) + 20);
+  if (! newdirname)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate buffer");
+  grub_strcpy (newdirname, dirname);
+  newdirname[grub_strlen (dirname)] = '/';
+  newdirname[grub_strlen (dirname) + 1] = 0;  
+  device_name = grub_file_get_device_name (dirname);
+  dev = grub_device_open (device_name);
+  if (dev)
+    {
+      fs = grub_fs_probe (dev);
+      path = grub_strchr (dirname, ')');
+      if (! path)
+       path = dirname;
+      else
+       path++;
+
+      newpath = grub_strchr (newdirname, ')');
+      if (! newpath)
+       newpath = newdirname;
+      else
+       newpath++;
+      
+      /* Look at the directory. */
+      if (fs)
+       (fs->dir) (dev, path, load_hook);
+
+      if (plistname && grub_xnu_check_os_bundle_required 
+         (plistname, osbundlerequired, &binsuffix))
+       {
+         if (binsuffix)
+           {
+             /* Open the binary. */
+             char *binname = grub_malloc (grub_strlen (dirname) 
+                                          + grub_strlen (binsuffix) 
+                                          + sizeof ("/MacOS/"));
+             grub_strcpy (binname, dirname);
+             if (usemacos)
+               grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
+             else
+               grub_strcpy (binname + grub_strlen (binname), "/");
+             grub_strcpy (binname + grub_strlen (binname), binsuffix);
+             grub_dprintf ("xnu", "%s:%s\n", plistname, binname);
+             binfile = grub_gzfile_open (binname, 1);
+             if (! binfile) 
+               grub_errno = GRUB_ERR_NONE;
+
+             /* Load the extension. */       
+             grub_xnu_load_driver (plistname, binfile);
+             grub_free (binname);
+             grub_free (binsuffix);
+           }
+         else
+           {
+             grub_dprintf ("xnu", "%s:0\n", plistname);
+             grub_xnu_load_driver (plistname, 0);
+           }
+       }
+      grub_free (plistname);
+      grub_device_close (dev);
+    }
+  grub_free (device_name);
+
+  return GRUB_ERR_NONE;
+}
+
+/* Load devtree file. */
+static grub_err_t
+grub_cmd_xnu_devtree (grub_command_t cmd __attribute__ ((unused)),
+                     int argc, char *args[])
+{
+  grub_file_t file;
+  char *data, *endret;
+  grub_size_t datalen;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "Filename required");
+
+  if (! grub_xnu_heap_size)
+    return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
+
+  /* Load the file. */
+  file = grub_gzfile_open (args[0], 1);
+  if (! file)
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load device tree");
+  datalen = grub_file_size (file);
+  data = grub_malloc (datalen + 1);
+  if (! data)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                        "Could load device tree into memory");
+    }
+  if (grub_file_read (file, data, datalen) != (grub_ssize_t) datalen)
+    {
+      grub_file_close (file); 
+      grub_free (data);
+      grub_error_push ();
+      return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]);
+    }
+  grub_file_close (file);
+  data[datalen] = 0;
+
+  /* Parse the file. */
+  endret = grub_xnu_parse_devtree (&grub_xnu_devtree_root,
+                                  data, data + datalen);
+  grub_free (data);
+
+  if (! endret)
+    return grub_error (GRUB_ERR_BAD_OS, "Couldn't parse devtree");
+
+  return GRUB_ERR_NONE;
+}
+
+static int locked=0;
+static grub_dl_t my_mod;
+
+/* Load the kext. */
+static grub_err_t
+grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
+                  int argc, char *args[])
+{
+  grub_file_t binfile = 0;
+  if (argc == 2)
+    {
+      /* User explicitely specified plist and binary. */
+      if (grub_strcmp (args[1], "-") != 0)
+       {
+         binfile = grub_gzfile_open (args[1], 1);
+         if (! binfile)
+           {
+             grub_error (GRUB_ERR_BAD_OS, "can't open file");
+             return GRUB_ERR_NONE;
+           }
+       }
+      return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
+                                  binfile);    
+    }
+
+  /* load kext normally. */
+  if (argc == 1)
+    return grub_xnu_load_kext_from_dir (args[0], 0, 10);
+
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+}
+
+/* Load a directory containing kexts. */
+static grub_err_t
+grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
+                     int argc, char *args[])
+{
+  if (argc != 1 && argc != 2)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
+
+  if (argc == 1)
+    return grub_xnu_scan_dir_for_kexts (args[0], 
+                                       "console,root,local-root,network-root",
+                                       10);
+  else
+    {
+      char *osbundlerequired = grub_strdup (args[1]), *ptr;
+      grub_err_t err;
+      if (! osbundlerequired)
+       return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                          "couldn't allocate string temporary space");
+      for (ptr = osbundlerequired; *ptr; ptr++)
+       *ptr = grub_tolower (*ptr);
+      err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10);
+      grub_free (osbundlerequired);
+      return err;
+    }
+}
+
+struct grub_video_bitmap *grub_xnu_bitmap = 0;
+
+static grub_err_t
+grub_cmd_xnu_splash (grub_command_t cmd __attribute__ ((unused)),
+                    int argc, char *args[])
+{
+  grub_err_t err;
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");  
+  
+  err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
+  if (err)
+    grub_xnu_bitmap = 0;
+  return err;
+}
+
+
+#ifndef GRUB_UTIL
+static grub_err_t
+grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
+                    int argc, char *args[])
+{
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+  
+  return grub_xnu_resume (args[0]);
+}
+#endif
+
+void
+grub_xnu_lock ()
+{
+#ifndef GRUB_UTIL
+  if (!locked)
+    grub_dl_ref (my_mod);
+#endif
+  locked = 1;
+}
+
+void
+grub_xnu_unlock ()
+{
+#ifndef GRUB_UTIL
+  if (locked)
+    grub_dl_unref (my_mod);
+#endif
+  locked = 0;
+}
+
+static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, cmd_kextdir, 
+  cmd_ramdisk, cmd_devtree, cmd_resume, cmd_splash;
+
+GRUB_MOD_INIT(xnu)
+{
+  (void) mod;                  /* To stop warning. */
+  cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
+                                     "load a xnu kernel");
+  cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0,
+                                    "Load XNU extension package.");
+  cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0,
+                                   "Load XNU extension.");
+  cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir, 
+                                      "xnu_kextdir DIRECTORY 
[OSBundleRequired]",
+                                      "Load XNU extension directory");
+  cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
+                                      "Load XNU ramdisk. "
+                                      "It will be seen as md0");
+  cmd_devtree = grub_register_command ("xnu_devtree", grub_cmd_xnu_devtree, 0,
+                                      "Load XNU devtree");
+  cmd_splash = grub_register_command ("xnu_splash", grub_cmd_xnu_splash, 0,
+                                     "Load a splash image for XNU");
+
+#ifndef GRUB_UTIL
+  cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume, 
+                                     0, "Load XNU hibernate image.");
+#endif
+  my_mod=mod;
+}
+
+GRUB_MOD_FINI(xnu)
+{
+#ifndef GRUB_UTIL
+  grub_unregister_command (cmd_resume);
+#endif
+  grub_unregister_command (cmd_mkext);
+  grub_unregister_command (cmd_kext);
+  grub_unregister_command (cmd_kextdir);
+  grub_unregister_command (cmd_devtree);
+  grub_unregister_command (cmd_ramdisk);
+  grub_unregister_command (cmd_kernel);
+  grub_unregister_command (cmd_splash);
+}

Added: trunk/grub2/loader/xnu_resume.c
===================================================================
--- trunk/grub2/loader/xnu_resume.c                             (rev 0)
+++ trunk/grub2/loader/xnu_resume.c     2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,136 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/normal.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/xnu.h>
+#include <grub/cpu/xnu.h>
+#include <grub/mm.h>
+#include <grub/loader.h>
+
+static void *grub_xnu_hibernate_image;
+
+static grub_err_t
+grub_xnu_resume_unload (void)
+{
+  /* Free loaded image */
+  if (grub_xnu_hibernate_image)
+    grub_free (grub_xnu_hibernate_image);
+  grub_xnu_hibernate_image = 0;
+  grub_xnu_unlock ();
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_xnu_resume (char *imagename)
+{
+  grub_file_t file;
+  grub_size_t total_header_size;
+  struct grub_xnu_hibernate_header hibhead;
+  char *buf, *codetmp;
+
+  grub_uint32_t codedest;
+  grub_uint32_t codesize;
+
+  file = grub_file_open (imagename);
+  if (! file)
+    return 0;
+  
+  /* Read the header. */
+  if (grub_file_read (file, (char *) &hibhead, sizeof (hibhead))
+      !=sizeof (hibhead))
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_READ_ERROR, 
+                        "cannot read the hibernate header");
+    }
+
+  /* Check the header. */
+  if (hibhead.magic != GRUB_XNU_HIBERNATE_MAGIC)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_BAD_OS, 
+                        "hibernate header has incorrect magic number");
+    }
+  if (hibhead.encoffset)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_BAD_OS, 
+                        "encrypted images aren't supported yet");
+    }
+
+  codedest = hibhead.launchcode_target_page;
+  codedest *= GRUB_XNU_PAGESIZE;
+  codesize = hibhead.launchcode_numpages;
+  codesize *= GRUB_XNU_PAGESIZE;
+
+  /* FIXME: check that codedest..codedest+codesize is available. */
+
+  /* Calculate total size before pages to copy. */
+  total_header_size = hibhead.extmapsize + sizeof (hibhead);
+
+  /* Unload image if any. */
+  if (grub_xnu_hibernate_image)
+    grub_free (grub_xnu_hibernate_image);
+
+  /* Try to allocate necessary space. 
+     FIXME: mm isn't good enough yet to handle huge allocations.
+   */
+  grub_xnu_hibernate_image = buf = grub_malloc (hibhead.image_size);
+  if (! buf)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                        "not enough memory to load image");
+    }
+
+  /* Read image. */
+  if (grub_file_seek (file, 0) == (grub_off_t)-1 
+      || grub_file_read (file, buf, hibhead.image_size)
+      != (grub_ssize_t) hibhead.image_size)
+    {
+      grub_file_close (file);
+      return grub_error (GRUB_ERR_READ_ERROR, "Cannot read resume image.");
+    }
+  grub_file_close (file);
+
+  codetmp = grub_memalign (GRUB_XNU_PAGESIZE, codesize + GRUB_XNU_PAGESIZE);
+  /* Setup variables needed by asm helper. */
+  grub_xnu_heap_will_be_at = codedest;
+  grub_xnu_heap_start = codetmp;
+  grub_xnu_heap_size = codesize;
+  grub_xnu_stack = (codedest + hibhead.stack);
+  grub_xnu_entry_point = (codedest + hibhead.entry_point);
+  grub_xnu_arg1 = (long) buf;
+
+  /* Prepare asm helper. */
+  grub_memcpy (codetmp, ((grub_uint8_t *) buf) + total_header_size, codesize);
+  grub_memcpy (codetmp + codesize, grub_xnu_launcher_start, 
+              grub_xnu_launcher_end - grub_xnu_launcher_start);  
+
+  /* We're ready now. */
+  grub_loader_set ((grub_err_t (*) (void)) (codetmp + codesize), 
+                  grub_xnu_resume_unload, 0);
+
+  /* Prevent module from unloading. */
+  grub_xnu_lock ();
+  return GRUB_ERR_NONE;
+}

Added: trunk/grub2/util/grub-dumpdevtree
===================================================================
--- trunk/grub2/util/grub-dumpdevtree                           (rev 0)
+++ trunk/grub2/util/grub-dumpdevtree   2009-05-02 23:19:20 UTC (rev 2163)
@@ -0,0 +1,3 @@
+echo "656669{  6465766963652d70726f70657274696573:"
+ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 
's/.*<//;s/>.*//;'
+echo ";}"

Modified: trunk/grub2/util/grub.d/30_os-prober.in
===================================================================
--- trunk/grub2/util/grub.d/30_os-prober.in     2009-05-02 22:40:21 UTC (rev 
2162)
+++ trunk/grub2/util/grub.d/30_os-prober.in     2009-05-02 23:19:20 UTC (rev 
2163)
@@ -82,6 +82,58 @@
 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/)//;'`"
+        cat << EOF
+menuentry "${LONGNAME} (on ${DEVICE})" {
+       set root=${OSXROOT}
+        insmod vbe
+        insmod gfxterm
+        gfxmode="1024x768x32;800x600x32"
+        terminal_output gfxterm
+        do_resume=0
+        if [ /var/vm/sleepimage -nt10 / ]; then
+           if xnu_resume /var/vm/sleepimage; then
+             do_resume=1
+           fi
+        fi
+        if [ \$do_resume == 0 ]; then
+           if [ -f /Extra/DSDT.aml ]; then
+              acpi -e /Extra/DSDT.aml
+           fi
+           xnu_kernel /mach_kernel rd=$OSXDISK
+           if [ /System/Library/Extensions.mkext -nt 
/System/Library/Extensions ]; then
+              xnu_mkext /System/Library/Extensions.mkext
+           else
+              xnu_kextdir /System/Library/Extensions
+           fi
+           if [ -f /Extra/Extensions.mkext ]; then
+              xnu_mkext /Extra/Extensions.mkext
+           fi
+           if [ -d /Extra/Extensions ]; then
+              xnu_kextdir /Extra/Extensions
+           fi
+           if [ -f /Extra/devtree.txt ]; then
+              xnu_devtree /Extra/devtree.txt
+           fi
+           if [ -f /Extra/splash.jpg ]; then
+              insmod jpeg
+              xnu_splash /Extra/splash.jpg
+           fi
+           if [ -f /Extra/splash.png ]; then
+              insmod png
+              xnu_splash /Extra/splash.png
+           fi
+           if [ -f /Extra/splash.tga ]; then
+              insmod tga
+              xnu_splash /Extra/splash.tga
+           fi
+        fi
+}
+EOF
+    ;;
     hurd|*)
       echo "  ${LONGNAME} is not yet supported by grub-mkconfig." >&2
     ;;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]