All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch] rough Mac OS X loader
@ 2006-01-02  0:38 Hollis Blanchard
  2006-01-02 17:29 ` Marco Gerards
  0 siblings, 1 reply; 6+ messages in thread
From: Hollis Blanchard @ 2006-01-02  0:38 UTC (permalink / raw)
  To: The development of GRUB 2

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

I've been working on a Mac OS X loader for GRUB. During the usual OS X 
boot process, the firmware loads the BootX bootloader (which is a 
hybrid CHRP script and XCOFF binary), which has a Mach-O loader and 
loads the OS X Mach kernel.

Rather than trying to load and run the Mach kernel directly, I chose to 
focus on the BootX bootloader, since it seems to do a fair amount of 
setup work that I would rather not duplicate in GRUB. Also important: 
if OS X is ever updated (for example, the parameter-passing mechanism 
between BootX and the kernel), we would need to track those changes, 
which is a lot more long-term maintenance.

Unfortunately, BootX attempts to claim all memory from 0 to 96MiB, 
which conflicts with GRUB running in this area. To get around that 
problem, I install a trampoline just above 96MiB which releases all of 
GRUB's memory and jumps into BootX. It's a bit of a hack, and for 
example if the code being copied exceeds some fixed size (currently 
0x200 bytes) things will fail mysteriously. I'm open to suggestions on 
that problem.

I'm afraid I don't know if this code works yet. Because the current 
HFS+ driver doesn't support the HFS wrapper found on all Apple 
filesystems, I can't boot from an HFS+ installation. I've copied BootX 
to a plain HFS partition, and that works somewhat (I expect it fails 
when it cannot find /mach_kernel). I'm relatively optimistic, and I'm 
working on the HFS wrapper support now.

There are a few rough edges still, but if there are no comments I will 
be checking this patch in largely unchanged some day.

-Hollis

[-- Attachment #2: macosx.txt --]
[-- Type: text/plain, Size: 19113 bytes --]

Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.52
diff -u -p -r1.52 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk	25 Dec 2005 15:59:50 -0000	1.52
+++ conf/powerpc-ieee1275.rmk	2 Jan 2006 00:34:11 -0000
@@ -9,7 +9,7 @@ COMMON_CFLAGS = -ffreestanding -msoft-fl
 MOSTLYCLEANFILES += grubof_symlist.c kernel_syms.lst
 DEFSYMFILES += kernel_syms.lst
 
-grubof_HEADERS = arg.h boot.h device.h disk.h dl.h elf.h env.h err.h \
+grubof_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h env.h err.h \
 	file.h fs.h kernel.h misc.h mm.h net.h parser.h rescue.h symbol.h \
 	term.h types.h powerpc/libgcc.h loader.h \
 	partition.h pc_partition.h ieee1275/ieee1275.h machine/time.h \
@@ -65,7 +65,7 @@ grubof_SOURCES = kern/powerpc/ieee1275/c
 	kern/powerpc/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/powerpc/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
-	grubof_symlist.c kern/powerpc/cache.S
+	grubof_symlist.c kern/powerpc/cache.S kern/powerpc/misc.S
 grubof_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 grubof_CFLAGS = $(COMMON_CFLAGS)
 grubof_ASFLAGS = $(COMMON_ASFLAGS)
@@ -84,6 +84,8 @@ grub_install_SOURCES = util/powerpc/ieee
 pkgdata_MODULES = halt.mod \
 	_linux.mod \
 	linux.mod \
+	_macosx.mod \
+	macosx.mod \
 	normal.mod \
 	reboot.mod \
 	suspend.mod
@@ -117,4 +119,12 @@ reboot_mod_CFLAGS = $(COMMON_CFLAGS)
 halt_mod_SOURCES = commands/ieee1275/halt.c
 halt_mod_CFLAGS = $(COMMON_CFLAGS)
 
+# For _macosx.mod.
+_macosx_mod_SOURCES = loader/powerpc/ieee1275/macosx.c
+_macosx_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For macosx.mod.
+macosx_mod_SOURCES = loader/powerpc/ieee1275/macosx_normal.c
+macosx_mod_CFLAGS = $(COMMON_CFLAGS)
+
 include $(srcdir)/conf/common.mk
Index: include/grub/xcoff.h
===================================================================
RCS file: include/grub/xcoff.h
diff -N include/grub/xcoff.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/grub/xcoff.h	2 Jan 2006 00:34:11 -0000
@@ -0,0 +1,90 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* See http://www16.boulder.ibm.com/pseries/en_US/files/aixfiles/XCOFF.htm */
+
+#ifndef GRUB_XCOFF_HEADER
+#define GRUB_XCOFF_HEADER	1
+
+#include <grub/types.h>
+
+struct xcoff_func_desc
+{
+  grub_uint32_t address;
+  grub_uint32_t toc;
+};
+
+struct xcoff_filehdr
+{
+  grub_uint16_t f_magic;
+  grub_uint16_t f_nscns;
+  grub_uint32_t f_timdat;
+  grub_uint32_t f_symptr;
+  grub_uint32_t f_nsyms;
+  grub_uint16_t f_opthdr;
+  grub_uint16_t f_flags;
+};
+
+#define XCOFF32_MAGIC 0x01df
+
+struct xcoff_auxhdr
+{
+  grub_uint16_t o_mflag;
+  grub_uint16_t o_vstamp;
+  grub_uint32_t o_tsize;
+  grub_uint32_t o_dsize;
+  grub_uint32_t o_bsize;
+  grub_uint32_t o_entry;
+  grub_uint32_t o_text_start;
+  grub_uint32_t o_data_start;
+  grub_uint32_t o_toc;
+  grub_uint16_t o_snentry;
+  grub_uint16_t o_sntext;
+  grub_uint16_t o_sndata;
+  grub_uint16_t o_sntoc;
+  grub_uint16_t o_snloader;
+  grub_uint16_t o_snbss;
+  grub_uint16_t o_algntext;
+  grub_uint16_t o_algndata;
+  grub_uint16_t o_modtype;
+  grub_uint8_t o_cpuflag;
+  grub_uint8_t o_cputype;
+  grub_uint32_t o_maxstack;
+  grub_uint32_t o_maxdata;
+  grub_uint32_t o_debugger;
+  char o_resv2[8];
+};
+
+#define XCOFF_MFLAGS_PAGEALIGNED 0x010b
+
+struct xcoff_scnhdr
+{
+  char s_name[8];
+  grub_uint32_t s_paddr;
+  grub_uint32_t s_vaddr;
+  grub_uint32_t s_size;
+  grub_uint32_t s_scnptr;
+  grub_uint32_t s_relptr;
+  grub_uint32_t s_lnnoptr;
+  grub_uint16_t s_nreloc;
+  grub_uint16_t s_nlnno;
+  grub_uint16_t s_flags;
+};
+
+#endif
Index: include/grub/powerpc/ieee1275/kernel.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/kernel.h,v
retrieving revision 1.3
diff -u -p -r1.3 kernel.h
--- include/grub/powerpc/ieee1275/kernel.h	3 Aug 2005 22:53:50 -0000	1.3
+++ include/grub/powerpc/ieee1275/kernel.h	2 Jan 2006 00:34:11 -0000
@@ -26,6 +26,9 @@ void EXPORT_FUNC (abort) (void);
 void EXPORT_FUNC (grub_reboot) (void);
 void EXPORT_FUNC (grub_halt) (void);
 
+void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long stack,
+			      unsigned long arg1, unsigned long arg2);
+
 /* Where grub-mkimage places the core modules in memory.  */
 #define GRUB_IEEE1275_MODULE_BASE 0x00300000
 
Index: include/grub/powerpc/ieee1275/loader.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/loader.h,v
retrieving revision 1.4
diff -u -p -r1.4 loader.h
--- include/grub/powerpc/ieee1275/loader.h	31 Jan 2005 21:44:35 -0000	1.4
+++ include/grub/powerpc/ieee1275/loader.h	2 Jan 2006 00:34:11 -0000
@@ -24,6 +24,7 @@
    loader.  */
 void grub_rescue_cmd_linux (int argc, char *argv[]);
 void grub_rescue_cmd_initrd (int argc, char *argv[]);
+void grub_rescue_cmd_macosx (int argc, char *argv[]);
 
 void grub_linux_init (void);
 void grub_linux_fini (void);
Index: kern/powerpc/misc.S
===================================================================
RCS file: kern/powerpc/misc.S
diff -N kern/powerpc/misc.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ kern/powerpc/misc.S	2 Jan 2006 00:34:11 -0000
@@ -0,0 +1,30 @@
+/* misc.S - Miscellaneous assembly routines.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+	.text
+
+	/* Jump to a function and switch to a new stack.  */
+	.globl grub_jump
+grub_jump:
+	mtctr 3
+	mr 1, 4
+	mr 3, 5
+	mr 4, 6
+	bctr
Index: loader/powerpc/ieee1275/macosx.c
===================================================================
RCS file: loader/powerpc/ieee1275/macosx.c
diff -N loader/powerpc/ieee1275/macosx.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ loader/powerpc/ieee1275/macosx.c	2 Jan 2006 00:34:11 -0000
@@ -0,0 +1,324 @@
+/* macosx.c - boot Mac OS X */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* BootX, the Mac OS X bootloader, is an XCOFF executable with a CHRP script
+ * prepended to it.  We skip the script and load the XCOFF file.  */
+
+#include <grub/xcoff.h>
+#include <grub/loader.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/rescue.h>
+#include <grub/misc.h>
+#include <grub/cache.h>
+#include <grub/ieee1275/ieee1275.h>
+
+#define MAX_XCOFF_POS (8<<10) /* Search first 8 KiB.  */
+#define READ_SIZE 512
+#define END_STRING "</CHRP-BOOT>\n\x04"
+
+#define GRUB_MACOSX_CHAIN_AREA    0x06000000
+#define GRUB_MACOSX_RELEASE_AREA  0x06000200
+#define GRUB_MACOSX_STACK_AREA    0x06000400
+
+static grub_dl_t my_mod;
+
+static int loaded;
+static grub_addr_t macosx_entry;
+
+
+static grub_err_t
+grub_macosx_boot (void)
+{
+  grub_dprintf ("loader", "entry point: 0x%x\n", macosx_entry);
+  grub_dprintf ("loader", "jumping to Mac OS X...\n");
+
+  /* Call the trampoline to boot the kernel.  */
+  grub_jump (GRUB_MACOSX_CHAIN_AREA, GRUB_MACOSX_STACK_AREA + 0x200,
+	     macosx_entry, GRUB_MACOSX_RELEASE_AREA);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_macosx_release_mem (void)
+{
+  /* XXX write me */
+#if 0
+  if (macosx_addr && grub_ieee1275_release (macosx_addr, macosx_size))
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory");
+
+  macosx_addr = 0;
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_macosx_unload (void)
+{
+  grub_err_t err;
+
+  err = grub_macosx_release_mem ();
+  grub_dl_unref (my_mod);
+
+  loaded = 0;
+
+  return err;
+}
+
+static grub_err_t
+grub_xcoff_load_section (grub_file_t file, grub_off_t xcoff_pos,
+			 struct xcoff_scnhdr *scnhdr)
+{
+  int rc;
+
+  grub_dprintf ("loader", "section %.8s:\n", scnhdr->s_name);
+  grub_dprintf ("loader", "  paddr 0x%08x\n", scnhdr->s_paddr);
+  grub_dprintf ("loader", "  vaddr 0x%08x\n", scnhdr->s_vaddr);
+  grub_dprintf ("loader", "  size 0x%x\n", scnhdr->s_size);
+  grub_dprintf ("loader", "  scnptr 0x%x\n", scnhdr->s_scnptr);
+  grub_dprintf ("loader", "  flags 0x%x\n", scnhdr->s_flags);
+
+  rc = grub_claimmap (scnhdr->s_paddr, scnhdr->s_size);
+  if (rc == -1)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not claim 0x%x",
+		       scnhdr->s_paddr);
+
+  if (scnhdr->s_scnptr)
+    {
+      grub_file_seek (file, xcoff_pos + scnhdr->s_scnptr);
+
+      if (grub_file_read (file, (void *)scnhdr->s_paddr, scnhdr->s_size)
+	  != (grub_ssize_t)scnhdr->s_size)
+	return grub_error (GRUB_ERR_READ_ERROR,
+			   "could not load section %.8s\n",
+			   scnhdr->s_name);
+      grub_arch_sync_caches ((void *) scnhdr->s_paddr, scnhdr->s_size);
+    }
+  else
+    /* BSS.  */
+    grub_memset ((void *) scnhdr->s_paddr, 0, scnhdr->s_size);
+
+  return 0;
+}
+
+static grub_err_t
+grub_xcoff_load_file (grub_file_t file, grub_off_t xcoff_pos)
+{
+  struct xcoff_filehdr _filehdr;
+  struct xcoff_auxhdr _auxhdr;
+  struct xcoff_filehdr *filehdr = &_filehdr;
+  struct xcoff_auxhdr *auxhdr = &_auxhdr;
+  struct xcoff_scnhdr *scnhdrs;
+  struct xcoff_func_desc *desc;
+  int scnhdr_bytes;
+  int i;
+
+  /* Read the file header.  */
+  if (grub_file_read (file, (void *)filehdr, sizeof (struct xcoff_filehdr))
+      != sizeof (struct xcoff_filehdr))
+    {
+      grub_error (GRUB_ERR_READ_ERROR, "could not read the XCOFF file header");
+      goto out;
+    }
+
+  if (filehdr->f_magic != XCOFF32_MAGIC)
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "bad XCOFF magic: 0x%x",
+		  filehdr->f_magic);
+      goto out;
+    }
+
+  grub_dprintf ("loader", "number of sections: %d\n", filehdr->f_nscns);
+  grub_dprintf ("loader", "flags: 0x%x\n", filehdr->f_flags);
+
+  /* Read the auxiliary header.  */
+  if (filehdr->f_opthdr != sizeof (struct xcoff_auxhdr))
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "missing auxiliary header");
+      goto out;
+    }
+
+  if (grub_file_read (file, (void *)auxhdr, sizeof (struct xcoff_auxhdr))
+      != sizeof (struct xcoff_auxhdr))
+    return grub_error (GRUB_ERR_READ_ERROR,
+		       "could not read the XCOFF auxiliary header");
+
+  if (auxhdr->o_mflag != XCOFF_MFLAGS_PAGEALIGNED)
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+		       "unknown auxiliary header flags: 0x%x\n",
+		       auxhdr->o_mflag);
+
+  /* Load all section headers.  */
+  scnhdr_bytes = filehdr->f_nscns * sizeof (struct xcoff_scnhdr);
+  scnhdrs = grub_malloc (scnhdr_bytes);
+  if (! scnhdrs)
+    return grub_errno;
+
+  if (grub_file_read (file, (void *)scnhdrs, scnhdr_bytes) != scnhdr_bytes)
+    return grub_error (GRUB_ERR_READ_ERROR,
+		       "could not read XCOFF section headers");
+
+  for (i = 0; i < filehdr->f_nscns; i++)
+    {
+      if (grub_xcoff_load_section (file, xcoff_pos, scnhdrs + i))
+	break;
+    }
+
+  /* Find the entry point.  */
+  desc = (struct xcoff_func_desc *)auxhdr->o_entry;
+  macosx_entry = desc->address;
+  grub_dprintf ("loader", "entry point 0x%08x\n", macosx_entry);
+
+ out:
+  return grub_errno;
+}
+
+/* Find NULL-terminated `needle' in non-terminated `haystack'.  */
+static void *
+grub_memstr (void *haystack, int len, char *needle)
+{
+  char *ptr = haystack;
+  int needle_len = grub_strlen (needle);
+  int i;
+
+  for (i = 0; i < len - needle_len; i++)
+    {
+      if (0 == grub_memcmp (ptr + i, needle, needle_len))
+	return ptr + i;
+    }
+
+  return 0;
+}
+
+/* grub_chain_trampoline is copied somewhere other than its link address
+ * and executes after all other code has been blown away. In order to call
+ * other functions from here, they must have been copied into a safe place and
+ * their addresses passed as parameters. */
+typedef void (*kernel_entry_t) (unsigned long, unsigned long, int (void *));
+typedef int (*release_t) (grub_addr_t addr, grub_size_t size);
+static void
+grub_chain_trampoline (kernel_entry_t entry, release_t release)
+{
+  release (0x00003000, 0x06000000 - 0x3000);
+  entry (0, 0, grub_ieee1275_entry_fn);
+}
+
+static int
+grub_macosx_install_trampoline (void)
+{
+  int rc;
+
+  /* XXX don't use magic numbers here */
+  rc = grub_claimmap (GRUB_MACOSX_CHAIN_AREA, 0x200);
+  rc |= grub_claimmap (GRUB_MACOSX_RELEASE_AREA, 0x200);
+  rc |= grub_claimmap (GRUB_MACOSX_STACK_AREA, 0x200);
+  if (rc)
+    return rc;
+
+  grub_memcpy ((void *) GRUB_MACOSX_CHAIN_AREA, grub_chain_trampoline, 0x200);
+  grub_arch_sync_caches ((void *) GRUB_MACOSX_CHAIN_AREA, 0x200);
+  grub_memcpy ((void *) GRUB_MACOSX_RELEASE_AREA, grub_ieee1275_release, 0x200);
+  grub_arch_sync_caches ((void *) GRUB_MACOSX_RELEASE_AREA, 0x200);
+}
+
+void
+grub_rescue_cmd_macosx (int argc, char *argv[])
+{
+  static char _buf[READ_SIZE];
+  char *buf = _buf;
+  grub_file_t file = 0;
+  grub_off_t pos = 0;
+  grub_ssize_t bytes_read;
+
+  grub_dl_ref (my_mod);
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
+      goto out;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (! file)
+    goto out;
+
+  /* Search for the end of the script to find the XCOFF header.  */
+  while (pos < MAX_XCOFF_POS) {
+    char *match;
+
+    bytes_read = grub_file_read (file, buf, READ_SIZE);
+    if (bytes_read < 0)
+      goto out;
+
+    match = grub_memstr (buf, bytes_read, END_STRING);
+    if (match)
+      {
+	pos += (int) (match - buf) + grub_strlen (END_STRING);
+	grub_dprintf ("loader", "XCOFF header at file offset 0x%x\n", pos);
+	grub_file_seek (file, pos);
+	break;
+      }
+
+    pos += READ_SIZE;
+  }
+
+  if (pos < MAX_XCOFF_POS)
+    {
+      /* Install the trampoline we need to jump through.  */
+      if (grub_macosx_install_trampoline ())
+	{
+	  grub_error (GRUB_ERR_OUT_OF_RANGE, "Failed to install trampoline.\n");
+	  goto out;
+	}
+      /* Load the XCOFF.  */
+      grub_xcoff_load_file (file, pos);
+    }
+
+ out:
+
+  if (file)
+    grub_file_close (file);
+
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_macosx_release_mem ();
+      grub_dl_unref (my_mod);
+      loaded = 0;
+      return;
+    }
+
+  grub_loader_set (grub_macosx_boot, grub_macosx_unload);
+  loaded = 1;
+}
+
+\f
+GRUB_MOD_INIT (macosx)
+{
+  grub_rescue_register_command ("macosx", grub_rescue_cmd_macosx,
+				"load BootX, the Mac OS X bootloader");
+  my_mod = mod;
+}
+
+GRUB_MOD_FINI (macosx)
+{
+  grub_rescue_unregister_command ("macosx");
+}
Index: loader/powerpc/ieee1275/macosx_normal.c
===================================================================
RCS file: loader/powerpc/ieee1275/macosx_normal.c
diff -N loader/powerpc/ieee1275/macosx_normal.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ loader/powerpc/ieee1275/macosx_normal.c	2 Jan 2006 00:34:11 -0000
@@ -0,0 +1,49 @@
+/* macosx_normal.c - boot Mac OS X */
+/*
+ *  GRUB  --  Preliminary Universal Programming Architecture for GRUB
+ *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/machine/loader.h>
+
+static const struct grub_arg_option options[] =
+  {
+    {0, 0, 0, 0, 0, 0}
+  };
+
+static grub_err_t
+grub_cmd_macosx (struct grub_arg_list *state  __attribute__ ((unused)),
+		int argc, char **args)
+{
+  grub_rescue_cmd_macosx (argc, args);
+  return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(macosx_normal)
+{
+  (void) mod;
+  grub_register_command ("macosx", grub_cmd_macosx, GRUB_COMMAND_FLAG_BOTH,
+			 "macosx [KERNELARGS...]",
+			 "Loads BootX, the Mac OS X bootloader.", options);
+}
+
+GRUB_MOD_FINI(macosx_normal)
+{
+  grub_unregister_command ("macosx");
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] rough Mac OS X loader
  2006-01-02  0:38 [patch] rough Mac OS X loader Hollis Blanchard
@ 2006-01-02 17:29 ` Marco Gerards
  2006-01-02 17:50   ` Hollis Blanchard
  0 siblings, 1 reply; 6+ messages in thread
From: Marco Gerards @ 2006-01-02 17:29 UTC (permalink / raw)
  To: The development of GRUB 2

Hollis Blanchard <hollis@penguinppc.org> writes:

Hi Hollis,

> I've been working on a Mac OS X loader for GRUB. During the usual OS X
> boot process, the firmware loads the BootX bootloader (which is a
> hybrid CHRP script and XCOFF binary), which has a Mach-O loader and
> loads the OS X Mach kernel.

This is really great news!  Thanks a lot for doing this great job. :-)

> Rather than trying to load and run the Mach kernel directly, I chose
> to focus on the BootX bootloader, since it seems to do a fair amount
> of setup work that I would rather not duplicate in GRUB. Also
> important: if OS X is ever updated (for example, the parameter-passing
> mechanism between BootX and the kernel), we would need to track those
> changes, which is a lot more long-term maintenance.

Agreed.

> Unfortunately, BootX attempts to claim all memory from 0 to 96MiB,
> which conflicts with GRUB running in this area. To get around that
> problem, I install a trampoline just above 96MiB which releases all of
> GRUB's memory and jumps into BootX. It's a bit of a hack, and for
> example if the code being copied exceeds some fixed size (currently
> 0x200 bytes) things will fail mysteriously. I'm open to suggestions on
> that problem.
>
> I'm afraid I don't know if this code works yet. Because the current
> HFS+ driver doesn't support the HFS wrapper found on all Apple
> filesystems, I can't boot from an HFS+ installation. I've copied BootX
> to a plain HFS partition, and that works somewhat (I expect it fails
> when it cannot find /mach_kernel). I'm relatively optimistic, and I'm
> working on the HFS wrapper support now.

Cool.  If you need any help let me know.  I will look into this as
well, I assume we can discuss things in detail on IRC.

> There are a few rough edges still, but if there are no comments I will
> be checking this patch in largely unchanged some day.

Can you provide a changelog entry? :-)

There are some comments below, I hope some of them even make sense. ;)

>  include $(srcdir)/conf/common.mk
> Index: include/grub/xcoff.h
> ===================================================================

Is it possible to use the grub_ namespace in this file?  In elf.h this
is not done because it should be possible to update it from glibc,
AFAIK.

> Index: include/grub/powerpc/ieee1275/kernel.h
> ===================================================================
> RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/kernel.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 kernel.h
> --- include/grub/powerpc/ieee1275/kernel.h	3 Aug 2005 22:53:50 -0000	1.3
> +++ include/grub/powerpc/ieee1275/kernel.h	2 Jan 2006 00:34:11 -0000
> @@ -26,6 +26,9 @@ void EXPORT_FUNC (abort) (void);
>  void EXPORT_FUNC (grub_reboot) (void);
>  void EXPORT_FUNC (grub_halt) (void);
>  
> +void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long stack,
> +			      unsigned long arg1, unsigned long arg2);

Shouldn't a pointer be used here?

> +/* BootX, the Mac OS X bootloader, is an XCOFF executable with a CHRP script
> + * prepended to it.  We skip the script and load the XCOFF file.  */

What is in this script?  Are you completely sure it can be skipped?

Can you please remove the `*' on the second line so the comment
matches the style of the other sourcecode?


> +static grub_err_t
> +grub_macosx_release_mem (void)
> +{
> +  /* XXX write me */

I assume you encountered a bug in the firmware while writing this
function? :-)

> +  /* Load all section headers.  */
> +  scnhdr_bytes = filehdr->f_nscns * sizeof (struct xcoff_scnhdr);
> +  scnhdrs = grub_malloc (scnhdr_bytes);
> +  if (! scnhdrs)
> +    return grub_errno;
> +
> +  if (grub_file_read (file, (void *)scnhdrs, scnhdr_bytes) != scnhdr_bytes)
> +    return grub_error (GRUB_ERR_READ_ERROR,
> +		       "could not read XCOFF section headers");

You don't free scnhdrs here, is that intentional?

> +/* Find NULL-terminated `needle' in non-terminated `haystack'.  */
> +static void *
> +grub_memstr (void *haystack, int len, char *needle)

Perhaps it is better to move this to kern/misc.c?

> +/* grub_chain_trampoline is copied somewhere other than its link address
> + * and executes after all other code has been blown away. In order to call
> + * other functions from here, they must have been copied into a safe place and
> + * their addresses passed as parameters. */

Same as above.

> +typedef void (*kernel_entry_t) (unsigned long, unsigned long, int (void *));
> +typedef int (*release_t) (grub_addr_t addr, grub_size_t size);
> +static void
> +grub_chain_trampoline (kernel_entry_t entry, release_t release)
> +{
> +  release (0x00003000, 0x06000000 - 0x3000);
> +  entry (0, 0, grub_ieee1275_entry_fn);
> +}
> +
> +static int
> +grub_macosx_install_trampoline (void)
> +{
> +  int rc;
> +
> +  /* XXX don't use magic numbers here */
> +  rc = grub_claimmap (GRUB_MACOSX_CHAIN_AREA, 0x200);
> +  rc |= grub_claimmap (GRUB_MACOSX_RELEASE_AREA, 0x200);
> +  rc |= grub_claimmap (GRUB_MACOSX_STACK_AREA, 0x200);
> +  if (rc)
> +    return rc;
> +
> +  grub_memcpy ((void *) GRUB_MACOSX_CHAIN_AREA, grub_chain_trampoline, 0x200);
> +  grub_arch_sync_caches ((void *) GRUB_MACOSX_CHAIN_AREA, 0x200);
> +  grub_memcpy ((void *) GRUB_MACOSX_RELEASE_AREA, grub_ieee1275_release, 0x200);
> +  grub_arch_sync_caches ((void *) GRUB_MACOSX_RELEASE_AREA, 0x200);

What is 0x200?  The maximum size of grub_chain_trampoline?  Perhaps
you can do something like: `grub_macosx_release_area -
grub_chain_trampoline', or do you think that is too unpredictable and
too ugly?

Thanks,
Marco




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] rough Mac OS X loader
  2006-01-02 17:29 ` Marco Gerards
@ 2006-01-02 17:50   ` Hollis Blanchard
  2006-01-02 18:02     ` Marco Gerards
  0 siblings, 1 reply; 6+ messages in thread
From: Hollis Blanchard @ 2006-01-02 17:50 UTC (permalink / raw)
  To: The development of GRUB 2

Thanks for your comments.

On Jan 2, 2006, at 11:29 AM, Marco Gerards wrote:
>
>> Index: include/grub/xcoff.h
>> ===================================================================
>
> Is it possible to use the grub_ namespace in this file?  In elf.h this
> is not done because it should be possible to update it from glibc,
> AFAIK.

Ok, that should be fine.

>> Index: include/grub/powerpc/ieee1275/kernel.h
>> ===================================================================
>> RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/kernel.h,v
>> retrieving revision 1.3
>> diff -u -p -r1.3 kernel.h
>> --- include/grub/powerpc/ieee1275/kernel.h	3 Aug 2005 22:53:50 
>> -0000	1.3
>> +++ include/grub/powerpc/ieee1275/kernel.h	2 Jan 2006 00:34:11 -0000
>> @@ -26,6 +26,9 @@ void EXPORT_FUNC (abort) (void);
>>  void EXPORT_FUNC (grub_reboot) (void);
>>  void EXPORT_FUNC (grub_halt) (void);
>>
>> +void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long 
>> stack,
>> +			      unsigned long arg1, unsigned long arg2);
>
> Shouldn't a pointer be used here?

Used where?

>> +/* BootX, the Mac OS X bootloader, is an XCOFF executable with a 
>> CHRP script
>> + * prepended to it.  We skip the script and load the XCOFF file.  */
>
> What is in this script?  Are you completely sure it can be skipped?

It loads the XCOFF into memory. Yes.

> Can you please remove the `*' on the second line so the comment
> matches the style of the other sourcecode?

Yes.

>> +static grub_err_t
>> +grub_macosx_release_mem (void)
>> +{
>> +  /* XXX write me */
>
> I assume you encountered a bug in the firmware while writing this
> function? :-)

No, just haven't written it yet. :) I think the XCOFF sections in BootX 
are contiguous though, so if that's true it should not be difficult.

>> +  /* Load all section headers.  */
>> +  scnhdr_bytes = filehdr->f_nscns * sizeof (struct xcoff_scnhdr);
>> +  scnhdrs = grub_malloc (scnhdr_bytes);
>> +  if (! scnhdrs)
>> +    return grub_errno;
>> +
>> +  if (grub_file_read (file, (void *)scnhdrs, scnhdr_bytes) != 
>> scnhdr_bytes)
>> +    return grub_error (GRUB_ERR_READ_ERROR,
>> +		       "could not read XCOFF section headers");
>
> You don't free scnhdrs here, is that intentional?

Accidental, thanks.

>> +/* Find NULL-terminated `needle' in non-terminated `haystack'.  */
>> +static void *
>> +grub_memstr (void *haystack, int len, char *needle)
>
> Perhaps it is better to move this to kern/misc.c?

I had that thought, but "memstr" is not a standard POSIX function so I 
wasn't sure.

>> +/* grub_chain_trampoline is copied somewhere other than its link 
>> address
>> + * and executes after all other code has been blown away. In order 
>> to call
>> + * other functions from here, they must have been copied into a safe 
>> place and
>> + * their addresses passed as parameters. */
>
> Same as above.
>
>> +typedef void (*kernel_entry_t) (unsigned long, unsigned long, int 
>> (void *));
>> +typedef int (*release_t) (grub_addr_t addr, grub_size_t size);
>> +static void
>> +grub_chain_trampoline (kernel_entry_t entry, release_t release)
>> +{
>> +  release (0x00003000, 0x06000000 - 0x3000);
>> +  entry (0, 0, grub_ieee1275_entry_fn);
>> +}
>> +
>> +static int
>> +grub_macosx_install_trampoline (void)
>> +{
>> +  int rc;
>> +
>> +  /* XXX don't use magic numbers here */
>> +  rc = grub_claimmap (GRUB_MACOSX_CHAIN_AREA, 0x200);
>> +  rc |= grub_claimmap (GRUB_MACOSX_RELEASE_AREA, 0x200);
>> +  rc |= grub_claimmap (GRUB_MACOSX_STACK_AREA, 0x200);
>> +  if (rc)
>> +    return rc;
>> +
>> +  grub_memcpy ((void *) GRUB_MACOSX_CHAIN_AREA, 
>> grub_chain_trampoline, 0x200);
>> +  grub_arch_sync_caches ((void *) GRUB_MACOSX_CHAIN_AREA, 0x200);
>> +  grub_memcpy ((void *) GRUB_MACOSX_RELEASE_AREA, 
>> grub_ieee1275_release, 0x200);
>> +  grub_arch_sync_caches ((void *) GRUB_MACOSX_RELEASE_AREA, 0x200);
>
> What is 0x200?  The maximum size of grub_chain_trampoline?  Perhaps
> you can do something like: `grub_macosx_release_area -
> grub_chain_trampoline', or do you think that is too unpredictable and
> too ugly?

We're copying several functions elsewhere. The problem is this: how big 
is that function? In other words, how many bytes do we need to copy? I 
don't have an answer.

-Hollis




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] rough Mac OS X loader
  2006-01-02 17:50   ` Hollis Blanchard
@ 2006-01-02 18:02     ` Marco Gerards
  2006-01-03  0:39       ` Hollis Blanchard
  0 siblings, 1 reply; 6+ messages in thread
From: Marco Gerards @ 2006-01-02 18:02 UTC (permalink / raw)
  To: The development of GRUB 2

Hollis Blanchard <hollis@penguinppc.org> writes:

>>> +void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long
>>> stack,
>>> +			      unsigned long arg1, unsigned long arg2);
>>
>> Shouldn't a pointer be used here?
>
> Used where?

For grub_jump's arguments.  It jumps to some address, right?

>>> +/* BootX, the Mac OS X bootloader, is an XCOFF executable with a
>>> CHRP script
>>> + * prepended to it.  We skip the script and load the XCOFF file.  */
>>
>> What is in this script?  Are you completely sure it can be skipped?
>
> It loads the XCOFF into memory. Yes.

Ah! :)

>>> +static grub_err_t
>>> +grub_macosx_release_mem (void)
>>> +{
>>> +  /* XXX write me */
>>
>> I assume you encountered a bug in the firmware while writing this
>> function? :-)
>
> No, just haven't written it yet. :) I think the XCOFF sections in
> BootX are contiguous though, so if that's true it should not be
> difficult.

Oh, ok.  In that case please add it to the to do list after this patch
is committed.

>>> +/* Find NULL-terminated `needle' in non-terminated `haystack'.  */
>>> +static void *
>>> +grub_memstr (void *haystack, int len, char *needle)
>>
>> Perhaps it is better to move this to kern/misc.c?
>
> I had that thought, but "memstr" is not a standard POSIX function so I
> wasn't sure.

It's looks like a useful function to me.  We can always move it back
if it turns out no one uses it...

Thanks,
Marco




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] rough Mac OS X loader
  2006-01-02 18:02     ` Marco Gerards
@ 2006-01-03  0:39       ` Hollis Blanchard
  2006-01-03 18:02         ` Marco Gerards
  0 siblings, 1 reply; 6+ messages in thread
From: Hollis Blanchard @ 2006-01-03  0:39 UTC (permalink / raw)
  To: The development of GRUB 2

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

On Jan 2, 2006, at 12:02 PM, Marco Gerards wrote:

> Hollis Blanchard <hollis@penguinppc.org> writes:
>
>>>> +void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long
>>>> stack,
>>>> +			      unsigned long arg1, unsigned long arg2);
>>>
>>> Shouldn't a pointer be used here?
>>
>> Used where?
>
> For grub_jump's arguments.  It jumps to some address, right?

Yes, but I don't believe using pointers would be appropriate here. The 
addresses passed in are addresses, so would need to be cast into 
pointers.

Here is the updated patch. I believe I've resolved all your other 
comments.

-Hollis

[-- Attachment #2: macosx.txt --]
[-- Type: text/plain, Size: 24046 bytes --]

Index: ChangeLog
===================================================================
RCS file: /cvsroot/grub/grub2/ChangeLog,v
retrieving revision 1.217
diff -u -p -r1.217 ChangeLog
--- ChangeLog	25 Dec 2005 19:40:31 -0000	1.217
+++ ChangeLog	3 Jan 2006 00:35:01 -0000
@@ -1,3 +1,22 @@
+2006-01-02  Hollis Blanchard  <hollis@penguinppc.org>
+
+	* conf/powerpc-ieee1275.rmk (grubof_HEADERS): Add cache.h.
+	(grubof_SOURCES): Add kern/powerpc/misc.S.
+	(pkgdata_MODULES): Add _macosx.mod and macosx.mod.
+	(_macosx_mod_SOURCES): New variable.
+	(_macosx_mod_CFLAGS): Likewise.
+	(macosx_mod_SOURCES): Likewise.
+	(macosx_mod_CFLAGS): Likewise.
+	* include/grub/misc.h (grub_memstr): New prototype.
+	* include/grub/powerpc/ieee1275/kernel.h (grub_jump): Likewise.
+	* include/grub/powerpc/ieee1275/loader.h (grub_rescue_cmd_macosx):
+	Likewise.
+	* kern/misc.c (grub_memstr): New function.
+	* include/grub/xcoff.h: New file.
+	* kern/powerpc/misc.S: Likewise.
+	* loader/powerpc/ieee1275/macosx.c: Likewise.
+	* loader/powerpc/ieee1275/macosx_normal.c: Likewise.
+
 2005-12-25  Yoshinori K. Okuji  <okuji@enbug.org>
 
 	* include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_DRP_ADDR):
Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.52
diff -u -p -r1.52 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk	25 Dec 2005 15:59:50 -0000	1.52
+++ conf/powerpc-ieee1275.rmk	3 Jan 2006 00:35:02 -0000
@@ -9,7 +9,7 @@ COMMON_CFLAGS = -ffreestanding -msoft-fl
 MOSTLYCLEANFILES += grubof_symlist.c kernel_syms.lst
 DEFSYMFILES += kernel_syms.lst
 
-grubof_HEADERS = arg.h boot.h device.h disk.h dl.h elf.h env.h err.h \
+grubof_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h env.h err.h \
 	file.h fs.h kernel.h misc.h mm.h net.h parser.h rescue.h symbol.h \
 	term.h types.h powerpc/libgcc.h loader.h \
 	partition.h pc_partition.h ieee1275/ieee1275.h machine/time.h \
@@ -65,7 +65,7 @@ grubof_SOURCES = kern/powerpc/ieee1275/c
 	kern/powerpc/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/powerpc/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
-	grubof_symlist.c kern/powerpc/cache.S
+	grubof_symlist.c kern/powerpc/cache.S kern/powerpc/misc.S
 grubof_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 grubof_CFLAGS = $(COMMON_CFLAGS)
 grubof_ASFLAGS = $(COMMON_ASFLAGS)
@@ -84,6 +84,8 @@ grub_install_SOURCES = util/powerpc/ieee
 pkgdata_MODULES = halt.mod \
 	_linux.mod \
 	linux.mod \
+	_macosx.mod \
+	macosx.mod \
 	normal.mod \
 	reboot.mod \
 	suspend.mod
@@ -117,4 +119,12 @@ reboot_mod_CFLAGS = $(COMMON_CFLAGS)
 halt_mod_SOURCES = commands/ieee1275/halt.c
 halt_mod_CFLAGS = $(COMMON_CFLAGS)
 
+# For _macosx.mod.
+_macosx_mod_SOURCES = loader/powerpc/ieee1275/macosx.c
+_macosx_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For macosx.mod.
+macosx_mod_SOURCES = loader/powerpc/ieee1275/macosx_normal.c
+macosx_mod_CFLAGS = $(COMMON_CFLAGS)
+
 include $(srcdir)/conf/common.mk
Index: include/grub/misc.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/misc.h,v
retrieving revision 1.17
diff -u -p -r1.17 misc.h
--- include/grub/misc.h	24 Oct 2005 10:23:46 -0000	1.17
+++ include/grub/misc.h	3 Jan 2006 00:35:02 -0000
@@ -1,7 +1,7 @@
 /* misc.h - prototypes for misc functions */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2005  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2005,2006  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
@@ -75,5 +75,6 @@ grub_uint8_t *EXPORT_FUNC(grub_utf16_to_
 grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest,
 					     const grub_uint8_t *src,
 					     grub_size_t size);
+void *EXPORT_FUNC(grub_memstr) (void *haystack, int len, char *needle);
 
 #endif /* ! GRUB_MISC_HEADER */
Index: include/grub/xcoff.h
===================================================================
RCS file: include/grub/xcoff.h
diff -N include/grub/xcoff.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/grub/xcoff.h	3 Jan 2006 00:35:02 -0000
@@ -0,0 +1,90 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* See http://www16.boulder.ibm.com/pseries/en_US/files/aixfiles/XCOFF.htm */
+
+#ifndef GRUB_XCOFF_HEADER
+#define GRUB_XCOFF_HEADER	1
+
+#include <grub/types.h>
+
+struct grub_xcoff_func_desc
+{
+  grub_uint32_t address;
+  grub_uint32_t toc;
+};
+
+struct grub_xcoff_filehdr
+{
+  grub_uint16_t f_magic;
+  grub_uint16_t f_nscns;
+  grub_uint32_t f_timdat;
+  grub_uint32_t f_symptr;
+  grub_uint32_t f_nsyms;
+  grub_uint16_t f_opthdr;
+  grub_uint16_t f_flags;
+};
+
+#define GRUB_XCOFF32_MAGIC 0x01df
+
+struct grub_xcoff_auxhdr
+{
+  grub_uint16_t o_mflag;
+  grub_uint16_t o_vstamp;
+  grub_uint32_t o_tsize;
+  grub_uint32_t o_dsize;
+  grub_uint32_t o_bsize;
+  grub_uint32_t o_entry;
+  grub_uint32_t o_text_start;
+  grub_uint32_t o_data_start;
+  grub_uint32_t o_toc;
+  grub_uint16_t o_snentry;
+  grub_uint16_t o_sntext;
+  grub_uint16_t o_sndata;
+  grub_uint16_t o_sntoc;
+  grub_uint16_t o_snloader;
+  grub_uint16_t o_snbss;
+  grub_uint16_t o_algntext;
+  grub_uint16_t o_algndata;
+  grub_uint16_t o_modtype;
+  grub_uint8_t o_cpuflag;
+  grub_uint8_t o_cputype;
+  grub_uint32_t o_maxstack;
+  grub_uint32_t o_maxdata;
+  grub_uint32_t o_debugger;
+  char o_resv2[8];
+};
+
+#define GRUB_XCOFF_MFLAGS_PAGEALIGNED 0x010b
+
+struct grub_xcoff_scnhdr
+{
+  char s_name[8];
+  grub_uint32_t s_paddr;
+  grub_uint32_t s_vaddr;
+  grub_uint32_t s_size;
+  grub_uint32_t s_scnptr;
+  grub_uint32_t s_relptr;
+  grub_uint32_t s_lnnoptr;
+  grub_uint16_t s_nreloc;
+  grub_uint16_t s_nlnno;
+  grub_uint16_t s_flags;
+};
+
+#endif
Index: include/grub/powerpc/ieee1275/kernel.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/kernel.h,v
retrieving revision 1.3
diff -u -p -r1.3 kernel.h
--- include/grub/powerpc/ieee1275/kernel.h	3 Aug 2005 22:53:50 -0000	1.3
+++ include/grub/powerpc/ieee1275/kernel.h	3 Jan 2006 00:35:02 -0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *  Copyright (C) 2005,2006  Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -26,6 +26,9 @@ void EXPORT_FUNC (abort) (void);
 void EXPORT_FUNC (grub_reboot) (void);
 void EXPORT_FUNC (grub_halt) (void);
 
+void EXPORT_FUNC (grub_jump) (unsigned long text, unsigned long stack,
+			      unsigned long arg1, unsigned long arg2);
+
 /* Where grub-mkimage places the core modules in memory.  */
 #define GRUB_IEEE1275_MODULE_BASE 0x00300000
 
Index: include/grub/powerpc/ieee1275/loader.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/powerpc/ieee1275/loader.h,v
retrieving revision 1.4
diff -u -p -r1.4 loader.h
--- include/grub/powerpc/ieee1275/loader.h	31 Jan 2005 21:44:35 -0000	1.4
+++ include/grub/powerpc/ieee1275/loader.h	3 Jan 2006 00:35:02 -0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2004  Free Software Foundation, Inc.
+ *  Copyright (C) 2004,2005,2006  Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
    loader.  */
 void grub_rescue_cmd_linux (int argc, char *argv[]);
 void grub_rescue_cmd_initrd (int argc, char *argv[]);
+void grub_rescue_cmd_macosx (int argc, char *argv[]);
 
 void grub_linux_init (void);
 void grub_linux_fini (void);
Index: kern/misc.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/misc.c,v
retrieving revision 1.25
diff -u -p -r1.25 misc.c
--- kern/misc.c	28 Oct 2005 03:14:33 -0000	1.25
+++ kern/misc.c	3 Jan 2006 00:35:02 -0000
@@ -1,7 +1,7 @@
 /* misc.c - definitions of misc functions */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005  Free Software Foundation, Inc.
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006  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
@@ -875,3 +875,20 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, 
 
   return p - dest;
 }
+
+/* Find NULL-terminated `needle' in non-terminated `haystack'.  */
+void *
+grub_memstr (void *haystack, int len, char *needle)
+{
+  char *ptr = haystack;
+  int needle_len = grub_strlen (needle);
+  int i;
+
+  for (i = 0; i < len - needle_len; i++)
+    {
+      if (0 == grub_memcmp (ptr + i, needle, needle_len))
+	return ptr + i;
+    }
+
+  return 0;
+}
Index: kern/powerpc/misc.S
===================================================================
RCS file: kern/powerpc/misc.S
diff -N kern/powerpc/misc.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ kern/powerpc/misc.S	3 Jan 2006 00:35:02 -0000
@@ -0,0 +1,30 @@
+/* misc.S - Miscellaneous assembly routines.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+	.text
+
+	/* Jump to a function and switch to a new stack.  */
+	.globl grub_jump
+grub_jump:
+	mtctr 3
+	mr 1, 4
+	mr 3, 5
+	mr 4, 6
+	bctr
Index: loader/powerpc/ieee1275/macosx.c
===================================================================
RCS file: loader/powerpc/ieee1275/macosx.c
diff -N loader/powerpc/ieee1275/macosx.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ loader/powerpc/ieee1275/macosx.c	3 Jan 2006 00:35:02 -0000
@@ -0,0 +1,329 @@
+/* macosx.c - boot Mac OS X */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* BootX, the Mac OS X bootloader, is an XCOFF executable with a CHRP script
+   prepended to it.  We skip the script and load the XCOFF file.  */
+
+#include <grub/xcoff.h>
+#include <grub/loader.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/rescue.h>
+#include <grub/misc.h>
+#include <grub/cache.h>
+#include <grub/machine/kernel.h>
+#include <grub/machine/loader.h>
+#include <grub/ieee1275/ieee1275.h>
+
+#define MAX_XCOFF_POS (8<<10) /* Search first 8 KiB.  */
+#define READ_SIZE 512
+#define END_STRING "</CHRP-BOOT>\n\x04"
+
+/* This must be larger than the functions copied into high memory.  */
+#define TRAMPOLINE_SIZE 0x200
+
+#define GRUB_MACOSX_CHAIN_AREA    0x06000000
+#define GRUB_MACOSX_RELEASE_AREA  (GRUB_MACOSX_CHAIN_AREA + TRAMPOLINE_SIZE)
+#define GRUB_MACOSX_STACK_AREA    (GRUB_MACOSX_RELEASE_AREA + TRAMPOLINE_SIZE)
+
+/* BootX will fail poorly if it is unable to claim this region.  */
+#define GRUB_BOOTX_CLAIM_BASE     0x00003000
+#define GRUB_BOOTX_CLAIM_SIZE     (0x06000000 - GRUB_BOOTX_CLAIM_BASE)
+
+static grub_dl_t my_mod;
+
+static grub_addr_t macosx_entry;
+static grub_size_t macosx_size;
+
+
+static grub_err_t
+grub_macosx_boot (void)
+{
+  grub_dprintf ("loader", "BootX entry point: 0x%x\n", macosx_entry);
+  grub_dprintf ("loader", "trampoline entry point: 0x%x\n",
+		GRUB_MACOSX_CHAIN_AREA);
+  grub_dprintf ("loader", "trampoline stack pointer: 0x%x\n",
+		GRUB_MACOSX_STACK_AREA + TRAMPOLINE_SIZE);
+  grub_dprintf ("loader", "jumping to trampoline...\n");
+
+  /* Call the trampoline to boot the kernel.  */
+  grub_jump (GRUB_MACOSX_CHAIN_AREA, GRUB_MACOSX_STACK_AREA + TRAMPOLINE_SIZE,
+	     macosx_entry, GRUB_MACOSX_RELEASE_AREA);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_macosx_release_mem (void)
+{
+  if (macosx_entry && grub_ieee1275_release (macosx_entry, macosx_size))
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory");
+
+  macosx_entry = 0;
+  macosx_size = 0;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_macosx_unload (void)
+{
+  grub_err_t err;
+
+  err = grub_macosx_release_mem ();
+  grub_dl_unref (my_mod);
+
+  return err;
+}
+
+static grub_err_t
+grub_xcoff_load_section (grub_file_t file, grub_off_t xcoff_pos,
+			 struct grub_xcoff_scnhdr *scnhdr)
+{
+  int rc;
+
+  grub_dprintf ("loader", "section %.8s:\n", scnhdr->s_name);
+  grub_dprintf ("loader", "  paddr 0x%08x\n", scnhdr->s_paddr);
+  grub_dprintf ("loader", "  vaddr 0x%08x\n", scnhdr->s_vaddr);
+  grub_dprintf ("loader", "  size 0x%x\n", scnhdr->s_size);
+  grub_dprintf ("loader", "  scnptr 0x%x\n", scnhdr->s_scnptr);
+  grub_dprintf ("loader", "  flags 0x%x\n", scnhdr->s_flags);
+
+  rc = grub_claimmap (scnhdr->s_paddr, scnhdr->s_size);
+  if (rc == -1)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not claim 0x%x",
+		       scnhdr->s_paddr);
+
+  if (scnhdr->s_scnptr)
+    {
+      grub_file_seek (file, xcoff_pos + scnhdr->s_scnptr);
+
+      if (grub_file_read (file, (void *)scnhdr->s_paddr, scnhdr->s_size)
+	  != (grub_ssize_t)scnhdr->s_size)
+	return grub_error (GRUB_ERR_READ_ERROR,
+			   "could not load section %.8s\n",
+			   scnhdr->s_name);
+      grub_arch_sync_caches ((void *) scnhdr->s_paddr, scnhdr->s_size);
+    }
+  else
+    /* BSS.  */
+    grub_memset ((void *) scnhdr->s_paddr, 0, scnhdr->s_size);
+
+  /* Assume sections are contiguous.  */
+  macosx_size += scnhdr->s_size;
+
+  return 0;
+}
+
+static grub_err_t
+grub_xcoff_load_file (grub_file_t file, grub_off_t xcoff_pos)
+{
+  struct grub_xcoff_filehdr _filehdr;
+  struct grub_xcoff_auxhdr _auxhdr;
+  struct grub_xcoff_filehdr *filehdr = &_filehdr;
+  struct grub_xcoff_auxhdr *auxhdr = &_auxhdr;
+  struct grub_xcoff_scnhdr *scnhdrs;
+  struct grub_xcoff_func_desc *desc;
+  int scnhdr_bytes;
+  int i;
+
+  /* Read the file header.  */
+  if (grub_file_read (file, (void *)filehdr, sizeof (struct grub_xcoff_filehdr))
+      != sizeof (struct grub_xcoff_filehdr))
+    {
+      grub_error (GRUB_ERR_READ_ERROR, "could not read the XCOFF file header");
+      goto out;
+    }
+
+  if (filehdr->f_magic != GRUB_XCOFF32_MAGIC)
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "bad XCOFF magic: 0x%x",
+		  filehdr->f_magic);
+      goto out;
+    }
+
+  grub_dprintf ("loader", "number of sections: %d\n", filehdr->f_nscns);
+  grub_dprintf ("loader", "flags: 0x%x\n", filehdr->f_flags);
+
+  /* Read the auxiliary header.  */
+  if (filehdr->f_opthdr != sizeof (struct grub_xcoff_auxhdr))
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "missing auxiliary header");
+      goto out;
+    }
+
+  if (grub_file_read (file, (void *)auxhdr, sizeof (struct grub_xcoff_auxhdr))
+      != sizeof (struct grub_xcoff_auxhdr))
+    return grub_error (GRUB_ERR_READ_ERROR,
+		       "could not read the XCOFF auxiliary header");
+
+  if (auxhdr->o_mflag != GRUB_XCOFF_MFLAGS_PAGEALIGNED)
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+		       "unknown auxiliary header flags: 0x%x\n",
+		       auxhdr->o_mflag);
+
+  /* Load all section headers.  */
+  scnhdr_bytes = filehdr->f_nscns * sizeof (struct grub_xcoff_scnhdr);
+  scnhdrs = grub_malloc (scnhdr_bytes);
+  if (! scnhdrs)
+    return grub_errno;
+
+  if (grub_file_read (file, (void *) scnhdrs, scnhdr_bytes) != scnhdr_bytes)
+    {
+      grub_free (scnhdrs);
+      return grub_error (GRUB_ERR_READ_ERROR,
+			 "could not read XCOFF section headers");
+    }
+
+  for (i = 0; i < filehdr->f_nscns; i++)
+    {
+      if (grub_xcoff_load_section (file, xcoff_pos, scnhdrs + i))
+	break;
+    }
+
+  /* Find the entry point.  */
+  desc = (struct grub_xcoff_func_desc *) auxhdr->o_entry;
+  macosx_entry = desc->address;
+  grub_dprintf ("loader", "entry point 0x%08x\n", macosx_entry);
+
+ out:
+  return grub_errno;
+}
+
+/* grub_chain_trampoline is copied somewhere other than its link address
+   and executes after all other code has been blown away. In order to call
+   other functions from here, they must have been copied into a safe place and
+   their addresses passed as parameters. */
+typedef void (*kernel_entry_t) (unsigned long, unsigned long, int (void *));
+typedef int (*release_t) (grub_addr_t addr, grub_size_t size);
+static void
+grub_chain_trampoline (kernel_entry_t entry, release_t release)
+{
+  /* Release all memory BootX will claim.  */
+  release (GRUB_BOOTX_CLAIM_BASE, GRUB_BOOTX_CLAIM_SIZE);
+  entry (0, 0, grub_ieee1275_entry_fn);
+}
+
+static int
+grub_macosx_install_trampoline (void)
+{
+  int rc;
+
+  /* We want to copy grub_chain_trampoline and grub_ieee1275_release into high
+     memory for use after we release all other code. Unfortunately, we don't
+     know exactly how big those functions are, so we just hope that
+     TRAMPOLINE_SIZE is big enough.  */
+
+  rc = grub_claimmap (GRUB_MACOSX_CHAIN_AREA, TRAMPOLINE_SIZE);
+  rc |= grub_claimmap (GRUB_MACOSX_RELEASE_AREA, TRAMPOLINE_SIZE);
+  rc |= grub_claimmap (GRUB_MACOSX_STACK_AREA, TRAMPOLINE_SIZE);
+  if (rc)
+    return rc;
+
+  grub_memcpy ((void *) GRUB_MACOSX_CHAIN_AREA, grub_chain_trampoline,
+	       TRAMPOLINE_SIZE);
+  grub_arch_sync_caches ((void *) GRUB_MACOSX_CHAIN_AREA, TRAMPOLINE_SIZE);
+  grub_memcpy ((void *) GRUB_MACOSX_RELEASE_AREA, grub_ieee1275_release,
+	       TRAMPOLINE_SIZE);
+  grub_arch_sync_caches ((void *) GRUB_MACOSX_RELEASE_AREA, TRAMPOLINE_SIZE);
+
+  return 0;
+}
+
+void
+grub_rescue_cmd_macosx (int argc, char *argv[])
+{
+  static char _buf[READ_SIZE];
+  char *buf = _buf;
+  grub_file_t file = 0;
+  grub_off_t pos = 0;
+  grub_ssize_t bytes_read;
+
+  grub_dl_ref (my_mod);
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
+      goto out;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (! file)
+    goto out;
+
+  /* Search for the end of the script to find the XCOFF header.  */
+  while (pos < MAX_XCOFF_POS) {
+    char *match;
+
+    bytes_read = grub_file_read (file, buf, READ_SIZE);
+    if (bytes_read < 0)
+      goto out;
+
+    match = grub_memstr (buf, bytes_read, END_STRING);
+    if (match)
+      {
+	pos += (int) (match - buf) + grub_strlen (END_STRING);
+	grub_dprintf ("loader", "XCOFF header at file offset 0x%x\n", pos);
+	grub_file_seek (file, pos);
+	break;
+      }
+
+    pos += READ_SIZE;
+  }
+
+  if (pos < MAX_XCOFF_POS)
+    {
+      /* Install the trampoline we need to jump through.  */
+      if (grub_macosx_install_trampoline ())
+	{
+	  grub_error (GRUB_ERR_OUT_OF_RANGE, "Failed to install trampoline.\n");
+	  goto out;
+	}
+      /* Load the XCOFF.  */
+      grub_xcoff_load_file (file, pos);
+    }
+
+ out:
+
+  if (file)
+    grub_file_close (file);
+
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_macosx_release_mem ();
+      grub_dl_unref (my_mod);
+      return;
+    }
+
+  grub_loader_set (grub_macosx_boot, grub_macosx_unload);
+}
+
+\f
+GRUB_MOD_INIT (macosx)
+{
+  grub_rescue_register_command ("macosx", grub_rescue_cmd_macosx,
+				"load BootX, the Mac OS X bootloader");
+  my_mod = mod;
+}
+
+GRUB_MOD_FINI (macosx)
+{
+  grub_rescue_unregister_command ("macosx");
+}
Index: loader/powerpc/ieee1275/macosx_normal.c
===================================================================
RCS file: loader/powerpc/ieee1275/macosx_normal.c
diff -N loader/powerpc/ieee1275/macosx_normal.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ loader/powerpc/ieee1275/macosx_normal.c	3 Jan 2006 00:35:02 -0000
@@ -0,0 +1,49 @@
+/* macosx_normal.c - boot Mac OS X */
+/*
+ *  GRUB  --  Preliminary Universal Programming Architecture for GRUB
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/machine/loader.h>
+
+static const struct grub_arg_option options[] =
+  {
+    {0, 0, 0, 0, 0, 0}
+  };
+
+static grub_err_t
+grub_cmd_macosx (struct grub_arg_list *state  __attribute__ ((unused)),
+		int argc, char **args)
+{
+  grub_rescue_cmd_macosx (argc, args);
+  return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(macosx_normal)
+{
+  (void) mod;
+  grub_register_command ("macosx", grub_cmd_macosx, GRUB_COMMAND_FLAG_BOTH,
+			 "macosx [KERNELARGS...]",
+			 "Loads BootX, the Mac OS X bootloader.", options);
+}
+
+GRUB_MOD_FINI(macosx_normal)
+{
+  grub_unregister_command ("macosx");
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] rough Mac OS X loader
  2006-01-03  0:39       ` Hollis Blanchard
@ 2006-01-03 18:02         ` Marco Gerards
  0 siblings, 0 replies; 6+ messages in thread
From: Marco Gerards @ 2006-01-03 18:02 UTC (permalink / raw)
  To: The development of GRUB 2

Hollis Blanchard <hollis@penguinppc.org> writes:

> Here is the updated patch. I believe I've resolved all your other
> comments.

Great!  Feel free to commit it, although it would be nice if you could
test it first (I am really curious if it all works now). ;-)

Thanks,
Marco




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-01-03 18:04 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-02  0:38 [patch] rough Mac OS X loader Hollis Blanchard
2006-01-02 17:29 ` Marco Gerards
2006-01-02 17:50   ` Hollis Blanchard
2006-01-02 18:02     ` Marco Gerards
2006-01-03  0:39       ` Hollis Blanchard
2006-01-03 18:02         ` Marco Gerards

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.