Index: conf/i386.rmk =================================================================== --- conf/i386.rmk (revision 1962) +++ conf/i386.rmk (working copy) @@ -14,3 +14,8 @@ vga_text_mod_SOURCES = term/i386/pc/vga_text.c term/i386/vga_common.c vga_text_mod_CFLAGS = $(COMMON_CFLAGS) vga_text_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += xnu.mod +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c +xnu_mod_CFLAGS = $(COMMON_CFLAGS) +xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) Index: include/grub/i386/xnu.h =================================================================== --- include/grub/i386/xnu.h (revision 0) +++ include/grub/i386/xnu.h (revision 0) @@ -0,0 +1,9 @@ +#define XNU_MEMORY_START 0x100000 +#define XNU_MEMORY_END 0x4000000 +#define XNU_PAGESIZE 4096 + +grub_err_t grub_xnu_boot (void); +extern void *grub_xnu_entry_point; +extern void *grub_xnu_stack; +extern void *grub_xnu_arg1; + Index: include/grub/xnu.h =================================================================== --- include/grub/xnu.h (revision 0) +++ include/grub/xnu.h (revision 0) @@ -0,0 +1,18 @@ +#define XNU_HIBERNATE_MAGIC 0x73696d65 +struct xnu_hibernate_header +{ + grub_uint64_t image_size; + grub_uint8_t unknown1[8]; + grub_uint32_t restorepage; + grub_uint32_t numofpages; + grub_uint32_t entry_point; + grub_uint32_t stack; + grub_uint8_t unknown2[20]; + grub_uint32_t restored_checksum; + grub_uint8_t unknown3[20]; + grub_uint32_t magic; + grub_uint8_t unknown4[28]; + grub_uint64_t encoffset; + grub_uint8_t unknown5[360]; + grub_uint32_t extmapsize; +} __attribute__ ((packed)); Index: loader/i386/xnu.c =================================================================== --- loader/i386/xnu.c (revision 0) +++ loader/i386/xnu.c (revision 0) @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers on XNU boot: eip,esp and eax*/ +void *grub_xnu_entry_point=0; +void *grub_xnu_stack=0; +void *grub_xnu_arg1=0; + +grub_err_t +grub_xnu_boot (void) +{ + /*Setup regs and launch xnu*/ + asm volatile ("movl %0, %%eax" : : "m" (grub_xnu_arg1)); + asm volatile ("movl %0, %%ebx" : : "m" (grub_xnu_stack)); + asm volatile ("movl %0, %%ecx" : : "m" (grub_xnu_entry_point)); + asm volatile ("movl %%ebx, %%esp" : : ); + asm volatile ("jmp *%%ecx" : : ); +} Index: loader/xnu_resume.c =================================================================== --- loader/xnu_resume.c (revision 0) +++ loader/xnu_resume.c (revision 0) @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; +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; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_xnu_resume (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) + +{ + grub_file_t file; + grub_size_t total_header_size; + struct xnu_hibernate_header hibhead; + void *buf; + grub_uint32_t csum1, csum2; + grub_uint8_t *ptr; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + file = grub_file_open (args[0]); + 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 != XNU_HIBERNATE_MAGIC) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_OS, + "hibernate header has incorrect magick number"); + } + if (hibhead.encoffset) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_OS, + "encrypted images aren't supported yet"); + } + if (hibhead.restorepage*XNU_PAGESIZEXNU_MEMORY_END) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_OS, + "loading address isn't within allowable space"); + } + + /*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*/ + 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*/ + grub_file_seek (file, 0); + grub_file_read (file, buf, hibhead.image_size); + grub_file_close (file); + + /* Checksum the pages to copy */ + csum1=1; + csum2=0; + for (ptr=(grub_uint8_t*)buf+total_header_size; + ptr<(grub_uint8_t*)buf+total_header_size + +hibhead.numofpages*XNU_PAGESIZE; + ptr++) + { + csum1 += *ptr; + csum2 += csum1; + } + ((struct xnu_hibernate_header *)buf)->restored_checksum=(csum2<<16)|csum1; + + /* Move starting pages to appropriate locations */ + memcpy ((void *)(hibhead.restorepage*XNU_PAGESIZE), + (grub_uint8_t*)buf+total_header_size, + hibhead.restorepage*XNU_PAGESIZE); + + /* Setup variables needed by booter*/ + grub_xnu_stack=(void*)(hibhead.restorepage*XNU_PAGESIZE+hibhead.stack); + grub_xnu_entry_point + = (void*)(hibhead.restorepage*XNU_PAGESIZE+hibhead.entry_point); + grub_xnu_arg1 = buf; + + /* We're ready now */ + grub_loader_set (grub_xnu_boot, + grub_xnu_resume_unload, 1); + grub_dl_ref (my_mod); + + return GRUB_ERR_NONE; +} + + + +GRUB_MOD_INIT(xnu) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("xnu_resume", grub_cmd_xnu_resume, + GRUB_COMMAND_FLAG_BOTH, + "xnu_resume FILE", "Load XNU hibernate image.", 0); + my_mod=mod; +} + +GRUB_MOD_FINI(xnu) +{ + grub_unregister_command ("xnu_resume"); +}