]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Support v2 xnu boot arguments.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 28 Feb 2012 03:04:19 +0000 (04:04 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 28 Feb 2012 03:04:19 +0000 (04:04 +0100)
* grub-core/loader/i386/xnu.c (grub_cpu_xnu_fill_devicetree):
New argument fsbfreq_out.
(grub_xnu_set_video): Receive an argument grub_xnu_boot_params_common.
(grub_xnu_boot): Support v2 arguments. Disable PIC so that APIC can
be used.
* grub-core/loader/machoXX.c (grub_macho_load): New argument
darwin_version.
* grub-core/loader/xnu.c (grub_xnu_darwin_version): New variable.
* include/grub/i386/xnu.h (grub_xnu_boot_params_common): New struct.
(grub_xnu_boot_params): Rename to ...
(grub_xnu_boot_params_v1): ...this. Use grub_xnu_boot_params_common.
(grub_xnu_boot_params_v2): New struct.

ChangeLog
grub-core/loader/i386/xnu.c
grub-core/loader/machoXX.c
grub-core/loader/xnu.c
include/grub/i386/xnu.h
include/grub/machoload.h
include/grub/xnu.h

index 542a8c6112795285f08b5ef7846844bde5cc48ba..dbdf4a1ffddfec1612e4c94d0b6988ccd2ceece1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2012-02-27  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Support v2 xnu boot arguments.
+
+       * grub-core/loader/i386/xnu.c (grub_cpu_xnu_fill_devicetree):
+       New argument fsbfreq_out.
+       (grub_xnu_set_video): Receive an argument grub_xnu_boot_params_common.
+       (grub_xnu_boot): Support v2 arguments. Disable PIC so that APIC can
+       be used.
+       * grub-core/loader/machoXX.c (grub_macho_load): New argument
+       darwin_version.
+       * grub-core/loader/xnu.c (grub_xnu_darwin_version): New variable.
+       * include/grub/i386/xnu.h (grub_xnu_boot_params_common): New struct.
+       (grub_xnu_boot_params): Rename to ...
+       (grub_xnu_boot_params_v1): ...this. Use grub_xnu_boot_params_common.
+       (grub_xnu_boot_params_v2): New struct.
+
 2012-02-27  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/efiemu/prepare.c (grub_efiemu_crc): Add missing
index a94b6a48e435dd50a002b51ee4190c0f279072d2..6bc090b946abd2a8bd5bfe7ba954f2bb5e333e8c 100644 (file)
@@ -33,6 +33,7 @@
 #include <grub/command.h>
 #include <grub/i18n.h>
 #include <grub/bitmap_scale.h>
+#include <grub/cpu/io.h>
 
 #define min(a,b) (((a) < (b)) ? (a) : (b))
 #define max(a,b) (((a) > (b)) ? (a) : (b))
@@ -623,8 +624,8 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
 
 /* 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)
+static grub_err_t
+grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out)
 {
   struct grub_xnu_devtree_key *efikey;
   struct grub_xnu_devtree_key *cfgtablekey;
@@ -702,13 +703,14 @@ grub_cpu_xnu_fill_devicetree (void)
 
   /* First see if user supplies the value. */
   const char *fsbvar = grub_env_get ("fsb");
-  if (! fsbvar)
-    *((grub_uint64_t *) curval->data) = 0;
-  else
-    *((grub_uint64_t *) curval->data) = readfrequency (fsbvar);
+  grub_uint64_t fsbfreq = 0;
+  if (fsbvar)
+    fsbfreq = readfrequency (fsbvar);
   /* Try autodetect. */
-  if (! *((grub_uint64_t *) curval->data))
-    *((grub_uint64_t *) curval->data) = guessfsb ();
+  if (! fsbfreq)
+    fsbfreq = guessfsb ();
+  *((grub_uint64_t *) curval->data) = fsbfreq;
+  *fsbfreq_out = fsbfreq;
   grub_dprintf ("xnu", "fsb autodetected as %llu\n",
                (unsigned long long) *((grub_uint64_t *) curval->data));
 
@@ -845,7 +847,7 @@ grub_xnu_boot_resume (void)
 
 /* Setup video for xnu. */
 static grub_err_t
-grub_xnu_set_video (struct grub_xnu_boot_params *params)
+grub_xnu_set_video (struct grub_xnu_boot_params_common *params)
 {
   struct grub_video_mode_info mode_info;
   char *tmp;
@@ -950,7 +952,8 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params)
 grub_err_t
 grub_xnu_boot (void)
 {
-  struct grub_xnu_boot_params *bootparams;
+  union grub_xnu_boot_params_any *bootparams;
+  struct grub_xnu_boot_params_common *bootparams_common;
   void *bp_in;
   grub_addr_t bootparams_target;
   grub_err_t err;
@@ -966,6 +969,9 @@ grub_xnu_boot (void)
   grub_size_t devtreelen;
   int i;
   struct grub_relocator32_state state;
+  grub_uint64_t fsbfreq;
+  int v2 = (grub_xnu_darwin_version >= 11);
+  grub_uint32_t efi_system_table = 0;
 
   err = grub_autoefi_prepare ();
   if (err)
@@ -975,7 +981,7 @@ grub_xnu_boot (void)
   if (err)
     return err;
 
-  err = grub_cpu_xnu_fill_devicetree ();
+  err = grub_cpu_xnu_fill_devicetree (&fsbfreq);
   if (err)
     return err;
 
@@ -995,7 +1001,8 @@ grub_xnu_boot (void)
   descriptor_size = 0;
   descriptor_version = 0;
 
-  grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point);
+  grub_dprintf ("xnu", "eip=%x, efi=%x\n", grub_xnu_entry_point,
+               (int) grub_autoefi_system_table);
 
   const char *debug = grub_env_get ("debug");
 
@@ -1012,20 +1019,29 @@ grub_xnu_boot (void)
     return err;
   bootparams = bp_in;
 
+  grub_memset (bootparams, 0, sizeof (*bootparams));
+  if (v2)
+    {
+      bootparams_common = &bootparams->v2.common;
+      bootparams->v2.fsbfreq = fsbfreq;
+    }
+  else
+    bootparams_common = &bootparams->v1.common;
+
   /* Set video. */
-  err = grub_xnu_set_video (bootparams);
+  err = grub_xnu_set_video (bootparams_common);
   if (err != GRUB_ERR_NONE)
     {
       grub_print_error ();
       grub_errno = GRUB_ERR_NONE;
       grub_puts_ (N_("Booting in blind mode"));
 
-      bootparams->lfb_mode = 0;
-      bootparams->lfb_width = 0;
-      bootparams->lfb_height = 0;
-      bootparams->lfb_depth = 0;
-      bootparams->lfb_line_len = 0;
-      bootparams->lfb_base = 0;
+      bootparams_common->lfb_mode = 0;
+      bootparams_common->lfb_width = 0;
+      bootparams_common->lfb_height = 0;
+      bootparams_common->lfb_depth = 0;
+      bootparams_common->lfb_line_len = 0;
+      bootparams_common->lfb_base = 0;
     }
 
   if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
@@ -1045,11 +1061,11 @@ grub_xnu_boot (void)
   if (err)
     return err;
 
-  grub_memcpy (bootparams->cmdline, grub_xnu_cmdline,
-              sizeof (bootparams->cmdline));
+  grub_memcpy (bootparams_common->cmdline, grub_xnu_cmdline,
+              sizeof (bootparams_common->cmdline));
 
-  bootparams->devtree = devtree_target;
-  bootparams->devtreelen = devtreelen;
+  bootparams_common->devtree = devtree_target;
+  bootparams_common->devtreelen = devtreelen;
 
   err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map,
                                           &map_key, &descriptor_size,
@@ -1057,7 +1073,10 @@ grub_xnu_boot (void)
   if (err)
     return err;
 
-  bootparams->efi_system_table = (grub_addr_t) grub_autoefi_system_table;
+  if (v2)
+    bootparams->v2.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
+  else
+    bootparams->v1.efi_system_table = (grub_addr_t) grub_autoefi_system_table;  
 
   firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start
                       + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
@@ -1080,7 +1099,7 @@ grub_xnu_boot (void)
              <= (grub_addr_t) grub_autoefi_system_table
              && curdesc->physical_start + (curdesc->num_pages << 12)
              > (grub_addr_t) grub_autoefi_system_table)
-           bootparams->efi_system_table
+           efi_system_table
              = (grub_addr_t) grub_autoefi_system_table
              - curdesc->physical_start + curdesc->virtual_start;
          if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
@@ -1090,24 +1109,33 @@ grub_xnu_boot (void)
 
   lastruntimepage = curruntimepage;
 
-  bootparams->efi_mmap = memory_map_target;
-  bootparams->efi_mmap_size = memory_map_size;
-  bootparams->efi_mem_desc_size = descriptor_size;
-  bootparams->efi_mem_desc_version = descriptor_version;
-
-  bootparams->heap_start = grub_xnu_heap_target_start;
-  bootparams->heap_size = grub_xnu_heap_size;
-  bootparams->efi_runtime_first_page = firstruntimepage;
-
-  bootparams->efi_runtime_npages = lastruntimepage - firstruntimepage;
-  bootparams->efi_uintnbits = SIZEOF_OF_UINTN * 8;
+  if (v2)
+    {
+      bootparams->v2.efi_uintnbits = SIZEOF_OF_UINTN * 8;
+      bootparams->v2.verminor = GRUB_XNU_BOOTARGSV2_VERMINOR;
+      bootparams->v2.vermajor = GRUB_XNU_BOOTARGSV2_VERMAJOR;
+      bootparams->v2.efi_system_table = efi_system_table;
+    }
+  else
+    {
+      bootparams->v1.efi_uintnbits = SIZEOF_OF_UINTN * 8;
+      bootparams->v1.verminor = GRUB_XNU_BOOTARGSV1_VERMINOR;
+      bootparams->v1.vermajor = GRUB_XNU_BOOTARGSV1_VERMAJOR;
+      bootparams->v1.efi_system_table = efi_system_table;
+    }
 
-  bootparams->verminor = GRUB_XNU_BOOTARGS_VERMINOR;
-  bootparams->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR;
+  bootparams_common->efi_runtime_first_page = firstruntimepage;
+  bootparams_common->efi_runtime_npages = lastruntimepage - firstruntimepage;
+  bootparams_common->efi_mem_desc_size = descriptor_size;
+  bootparams_common->efi_mem_desc_version = descriptor_version;
+  bootparams_common->efi_mmap = memory_map_target;
+  bootparams_common->efi_mmap_size = memory_map_size;
+  bootparams_common->heap_start = grub_xnu_heap_target_start;
+  bootparams_common->heap_size = grub_xnu_heap_size;
 
   /* Parameters for asm helper. */
-  grub_xnu_stack = bootparams->heap_start
-    + bootparams->heap_size + GRUB_XNU_PAGESIZE;
+  grub_xnu_stack = bootparams_common->heap_start
+    + bootparams_common->heap_size + GRUB_XNU_PAGESIZE;
   grub_xnu_arg1 = bootparams_target;
 
   grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
@@ -1117,6 +1145,11 @@ grub_xnu_boot (void)
   state.eax = grub_xnu_arg1;
   state.esp = grub_xnu_stack;
   state.ebp = grub_xnu_stack;
+
+  /* XNU uses only APIC. Disable PIC.  */
+  grub_outb (0xff, 0x21);
+  grub_outb (0xff, 0xa1);
+
   return grub_relocator32_boot (grub_xnu_relocator, state);
 }
 
index 58770ddf8fdc15e72f1a506648487a39bcdba902..313c5baa7a2890d934dfa5203a933fe211c3528d 100644 (file)
@@ -164,7 +164,7 @@ SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
 /* Load every loadable segment into memory specified by `_load_hook'.  */
 grub_err_t
 SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
-                         char *offset, int flags)
+                         char *offset, int flags, int *darwin_version)
 {
   auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
                               struct grub_macho_cmd *hdr0,
@@ -201,6 +201,23 @@ SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
 
            return 1;
          }
+       if (darwin_version)
+         {
+           const char *ptr = offset + hdr->vmaddr;
+           const char *end = ptr + min (hdr->filesize, hdr->vmsize)
+             - (sizeof ("Darwin Kernel Version ") - 1);
+           for (; ptr < end; ptr++)
+             if (grub_memcmp (ptr, "Darwin Kernel Version ",
+                              sizeof ("Darwin Kernel Version ") - 1) == 0)
+               {
+                 ptr += sizeof ("Darwin Kernel Version ") - 1;
+                 *darwin_version = 0;
+                 end += (sizeof ("Darwin Kernel Version ") - 1);
+                 while (ptr < end && grub_isdigit (*ptr))
+                   *darwin_version = (*ptr++ - '0') + *darwin_version * 10;
+                 break;
+               }
+         }
       }
 
     if (hdr->filesize < hdr->vmsize)
@@ -209,6 +226,9 @@ SUFFIX (grub_macho_load) (grub_macho_t macho, const char *filename,
     return 0;
   }
 
+  if (darwin_version)
+    *darwin_version = 0;
+
   grub_macho_cmds_iterate (macho, do_load, 0);
 
   return grub_errno;
index 80dd1984ed771871df7115cd06fda4f84a3c47ce..88c17a58254d361e7d0910e8e54224f70aab3c87 100644 (file)
@@ -44,6 +44,7 @@ struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
 static int driverspackagenum = 0;
 static int driversnum = 0;
 int grub_xnu_is_64bit = 0;
+int grub_xnu_darwin_version = 0;
 
 grub_addr_t grub_xnu_heap_target_start = 0;
 grub_size_t grub_xnu_heap_size = 0;
@@ -387,7 +388,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
 
   /* Load kernel. */
   err = grub_macho_load32 (macho, args[0], (char *) loadaddr - startcode,
-                          GRUB_MACHO_NOBSS);
+                          GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
   if (err)
     {
       grub_macho_close (macho);
@@ -500,7 +501,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
 
   /* Load kernel. */
   err = grub_macho_load64 (macho, args[0], (char *) loadaddr - startcode,
-                          GRUB_MACHO_NOBSS);
+                          GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
   if (err)
     {
       grub_macho_close (macho);
index 386c8b9e07af33d84f7fe2e0491687e9e967590c..12b1e60bc8735f928c145dd33fd64d88d709e31f 100644 (file)
 #define GRUB_XNU_PAGESIZE 4096
 typedef grub_uint32_t grub_xnu_ptr_t;
 
-struct grub_xnu_boot_params
+struct grub_xnu_boot_params_common
 {
-  grub_uint16_t verminor;
-  grub_uint16_t vermajor;
   /* Command line passed to xnu. */
   grub_uint8_t cmdline[1024];
 
@@ -59,17 +57,50 @@ struct grub_xnu_boot_params
   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;
+} __attribute__ ((packed));
+
+struct grub_xnu_boot_params_v1
+{
+  grub_uint16_t verminor;
+  grub_uint16_t vermajor;
+  struct grub_xnu_boot_params_common common;
+
   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 5
-#define GRUB_XNU_BOOTARGS_VERMAJOR 1
+#define GRUB_XNU_BOOTARGSV1_VERMINOR 5
+#define GRUB_XNU_BOOTARGSV1_VERMAJOR 1
+
+struct grub_xnu_boot_params_v2
+{
+  grub_uint16_t verminor;
+  grub_uint16_t vermajor;
+
+  /* Size of grub_efi_uintn_t in bits. */
+  grub_uint8_t efi_uintnbits;
+  grub_uint8_t unused[3];
+
+  struct grub_xnu_boot_params_common common;
+
+  grub_uint64_t efi_runtime_first_page_virtual;
+  grub_uint32_t efi_system_table;
+  grub_uint32_t unused2[11];
+  grub_uint64_t fsbfreq;
+  grub_uint32_t unused3[734];
+} __attribute__ ((packed));
+#define GRUB_XNU_BOOTARGSV2_VERMINOR 0
+#define GRUB_XNU_BOOTARGSV2_VERMAJOR 2
+
+union grub_xnu_boot_params_any
+{
+  struct grub_xnu_boot_params_v1 v1;
+  struct grub_xnu_boot_params_v2 v2;
+};
 
 struct grub_xnu_devprop_header
 {
@@ -114,5 +145,4 @@ 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);
 #endif
index 9ad509b6e6c540be89d0a85f1308ce8ae459aaa5..bb0374c882c29d9b36fe4365a75893ad94e1f33d 100644 (file)
@@ -58,9 +58,9 @@ grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho);
 /* Ignore BSS segments when loading. */
 #define GRUB_MACHO_NOBSS 0x1
 grub_err_t grub_macho_load32 (grub_macho_t macho, const char *filename,
-                             char *offset, int flags);
+                             char *offset, int flags, int *darwin_version);
 grub_err_t grub_macho_load64 (grub_macho_t macho, const char *filename,
-                             char *offset, int flags);
+                             char *offset, int flags, int *darwin_version);
 
 /* Like filesize and file_read but take only 32-bit part
    for current architecture. */
index 2a096d803b7379676b5d7cdf6ce74f1bbcd44e43..9b17717a9fc9c396683c2023c61e796f3623c679 100644 (file)
@@ -115,4 +115,5 @@ typedef enum {GRUB_XNU_BITMAP_CENTER, GRUB_XNU_BITMAP_STRETCH}
 extern grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
 extern int grub_xnu_is_64bit;
 extern grub_addr_t grub_xnu_heap_target_start;
+extern int grub_xnu_darwin_version;
 #endif