[Top][All Lists]
[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
;;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [2163] 2009-05-03 Vladimir Serbinenko <address@hidden>,
Vladimir Serbinenko <=