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 + +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 +#include +#include +#include +#include +#include +#include +#include + +#define MAX_XCOFF_POS (8<<10) /* Search first 8 KiB. */ +#define READ_SIZE 512 +#define END_STRING "\n" + +#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; +} + + +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 +#include +#include + +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"); +}