All of lore.kernel.org
 help / color / mirror / Atom feed
From: phcoder <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: xnu support
Date: Wed, 28 Jan 2009 06:53:02 +0100	[thread overview]
Message-ID: <497FF2BE.8050101@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 2225 bytes --]

Hello, I'm working on xnu (darwin kernel, under OSI approved APSL) 
support and would like to discuss some interfaces about it.
Issue 1) First in xnu world booter hands the loading of compressed 
hibernation image. Resuming doesn't need to load the kernel conventional 
way. And trying to resume from hibernate should be done before trying to 
load kernel. So I propose the following configuration entries:
menuentry "my XNU"
{
    if ! xnu_resume <hibernate image>; then
	xnu_kernel <kernel> <options>
	xnu_extensions --cache=<cache file> --dir=<cache directory>
	xnu_loadenv <environment description file>
    fi
}

Issue 2) Also normally when hibernation succeeds kernel should 
invalidate the image. Unfortunately in some scenarios it doesn't. A 
reliable way to check the image is to compare modification timestamp of 
FS and image.
I know where to find them on FS but unfortunately now grub has no way of 
interfacing this with FS code. I propose to modify
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
                      int (*hook) (const char *filename, int dir));
to
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
                      int (*hook) (const char *filename, int dir, 
grub_time_t modtime));
Or add
grub_err_t (*file_modtime) (const char *name, grub_time_t *modtime);
and add a function for retrieving FS modification type
grub_err_t (*fs_modtime) (grub_device_t device, grub_time_t *modtime);
to grub_fs_t
This has an additional benefit of invalidating image if FS was modified 
by external tool. This may be overriden by --force option to override it.
File modification timestamp are also needed to check if the extension 
cache is up to date.
Issue 3) Kernel may theoretically request loading parts to any address. 
In practice it does it only in 1Mb-64Mb range. Is it possible to somehow 
secure this range from grub_malloc after xnu_kernel command? (I would 
like to avoid "just before boot" relocations if possible)

I send an implementation of xnu_resume. Not for inclusion of course but 
for illustration
Thanks
Any opinion is appreciated
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: xnu1.patch --]
[-- Type: text/x-diff, Size: 6478 bytes --]

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 <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.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>
+#include <grub/cpu/loader.h>
+
+/* 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 <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.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>
+#include <grub/cpu/loader.h>
+
+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_PAGESIZE<XNU_MEMORY_START 
+      || (hibhead.restorepage+hibhead.numofpages)*XNU_PAGESIZE>XNU_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");
+}

                 reply	other threads:[~2009-01-28  5:53 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=497FF2BE.8050101@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.