grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

PPC multiboot


From: Hollis Blanchard
Subject: PPC multiboot
Date: Fri, 24 Jun 2005 08:51:25 -0500
User-agent: Mutt/1.5.6+20040907i

I did some hacking on a multiboot loader for PPC last night. I wasn't
trying to properly update the multiboot spec for non-x86 architectures,
but rather just use the existing structures and code.

I've also attached a "hello world" PPC multiboot client. I noticed the
top-level "hello" directory is a simple GRUB module, but I'm not sure
how useful that is. It might be more useful to create
hello/powerpc/ieee1275 and hello/i386/pc directories including the
simplest possible multiboot clients. (Right now my hello application is
mysteriously failing on my G3, apparently on the first stack reference,
which may be the result of a firmware "quirk".)

This patch is not meant to be applied, but I'm putting it out here for
the curious.

-Hollis

Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.30
diff -u -p -r1.30 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk   1 May 2005 03:45:35 -0000       1.30
+++ conf/powerpc-ieee1275.rmk   24 Jun 2005 13:41:24 -0000
@@ -72,7 +72,7 @@ pkgdata_MODULES = _linux.mod linux.mod f
        hfs.mod jfs.mod normal.mod hello.mod font.mod ls.mod \
        boot.mod cmp.mod cat.mod terminal.mod fshelp.mod amiga.mod apple.mod \
        pc.mod suspend.mod loopback.mod help.mod reboot.mod halt.mod sun.mod \
-       default.mod timeout.mod configfile.mod
+       default.mod timeout.mod configfile.mod _multiboot.mod multiboot.mod
 
 # For fshelp.mod.
 fshelp_mod_SOURCES = fs/fshelp.c
@@ -114,6 +114,14 @@ _linux_mod_CFLAGS = $(COMMON_CFLAGS)
 linux_mod_SOURCES = loader/powerpc/ieee1275/linux_normal.c
 linux_mod_CFLAGS = $(COMMON_CFLAGS)
 
+# For _multiboot.mod.
+_multiboot_mod_SOURCES = loader/powerpc/ieee1275/multiboot.c
+_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For multiboot.mod.
+multiboot_mod_SOURCES = loader/powerpc/ieee1275/multiboot_normal.c
+multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
+
 # For normal.mod.
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c    \
        normal/context.c normal/main.c normal/menu.c                    \
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      24 Jun 2005 13:41:25 -0000
@@ -25,6 +25,9 @@
 void grub_rescue_cmd_linux (int argc, char *argv[]);
 void grub_rescue_cmd_initrd (int argc, char *argv[]);
 
+void grub_rescue_cmd_multiboot (int argc, char *argv[]);
+void grub_rescue_cmd_module  (int argc, char *argv[]);
+
 void grub_linux_init (void);
 void grub_linux_fini (void);
 void grub_linux_normal_init (void);
--- /dev/null   2004-12-18 12:15:49.000000000 -0600
+++ loader/powerpc/ieee1275/multiboot.c 2005-06-23 23:42:48.000000000 -0500
@@ -0,0 +1,400 @@
+/* multiboot.c - boot a multiboot OS image. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003, 2004, 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/loader.h>
+#include <grub/machine/loader.h>
+#include <grub/machine/multiboot.h>
+#include <grub/machine/ieee1275.h>
+#include <grub/elf.h>
+#include <grub/file.h>
+#include <grub/err.h>
+#include <grub/rescue.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+static grub_dl_t my_mod;
+static struct grub_multiboot_info *mbi;
+static grub_addr_t entry;
+
+typedef void (*kernel_entry_t) (struct grub_multiboot_info *, unsigned long,
+                               void *);
+
+static grub_err_t
+grub_multiboot_boot (void)
+{
+  kernel_entry_t kernel;
+
+  grub_dprintf ("loader", "Jumping to entry point: 0x%x\n", entry);
+
+  kernel = (kernel_entry_t) entry;
+  kernel (mbi, GRUB_MB_MAGIC2, grub_ieee1275_entry_fn);
+
+  /* Not reached.  */
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_multiboot_unload (void)
+{
+  if (mbi)
+    {
+      unsigned int i;
+      for (i = 0; i < mbi->mods_count; i++)
+       {
+         grub_free ((void *)
+                    ((struct grub_mod_list *) mbi->mods_addr)[i].mod_start);
+         grub_free ((void *)
+                    ((struct grub_mod_list *) mbi->mods_addr)[i].cmdline);
+       }
+      grub_free ((void *) mbi->mods_addr);
+      grub_free ((void *) mbi->cmdline);
+      grub_free (mbi);
+    }
+
+
+  mbi = 0;
+  grub_dl_unref (my_mod);
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+grub_ieee1275_mbi_memory (struct grub_multiboot_info *info)
+{
+  grub_ieee1275_phandle_t memory;
+  struct grub_ieee1275_mem_region regions[4]; /* XXX Don't hardcode me.  */
+  int i;
+
+  /* XXX Examine all memory nodes, not just the first.  */
+  if (-1 == grub_ieee1275_finddevice ("/memory", &memory))
+    return;
+
+  if (0 != grub_ieee1275_get_property (memory, "reg", &regions,
+                                 sizeof regions, 0))
+    return;
+
+  info->mem_lower = 0;
+  info->mem_upper = 0;
+
+  for (i = 0; i < 4; i++)
+    info->mem_lower += regions[i].size;
+
+  grub_dprintf ("loader", "multiboot.mem_lower = 0x%x\n", info->mem_lower);
+
+  info->flags |= GRUB_MB_INFO_MEMORY;
+}
+
+static void
+grub_ieee1275_mbi_cmdline (struct grub_multiboot_info *info, int argc,
+                          char *argv[])
+{
+  char *cmdline;
+  char *p;
+  int i;
+  int len;
+
+  for (i = 0, len = 0; i < argc; i++)
+    len += grub_strlen (argv[i]) + 1;
+
+  cmdline = p = grub_malloc (len);
+  if (!cmdline)
+    return;
+
+  for (i = 0; i < argc; i++)
+    {
+      p = grub_stpcpy (p, argv[i]);
+      *(p++) = ' ';
+    }
+
+  /* Remove the space after the last word.  */
+  *(--p) = '\0';
+
+  info->cmdline = (grub_uint32_t) cmdline;
+  grub_dprintf ("loader", "multiboot.cmdline = 0x%x\n", info->cmdline);
+
+  info->flags |= GRUB_MB_INFO_CMDLINE;
+}
+
+void
+grub_rescue_cmd_multiboot (int argc, char *argv[])
+{
+  grub_file_t file = 0;
+  char buffer[GRUB_MB_SEARCH];
+  struct grub_multiboot_header *header;
+  grub_ssize_t len;
+  grub_size_t size;
+  int i;
+  Elf32_Ehdr *ehdr;
+
+  grub_dl_ref (my_mod);
+
+  grub_loader_unset();
+    
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified");
+      goto fail;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
+      goto fail;
+    }
+
+  len = grub_file_read (file, buffer, GRUB_MB_SEARCH);
+  if (len < 32)
+    {
+      grub_error (GRUB_ERR_BAD_OS, "File too small");
+      goto fail;
+    }
+
+  /* Look for the multiboot header in the buffer.  The header should
+     be at least 12 bytes and aligned on a 4-byte boundary.  */
+  for (header = (struct grub_multiboot_header *) buffer; 
+       ((char *) header <= buffer + len - 12) || (header = 0);
+       header = (struct grub_multiboot_header *) ((char *)header + 4))
+    {
+      if (header->magic == GRUB_MB_MAGIC 
+         && !(header->magic + header->flags + header->checksum))
+         break;
+    }
+  
+  if (header == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "No multiboot header found");
+      goto fail;
+    }
+
+  if (header->flags & GRUB_MB_UNSUPPORTED)
+    {
+      grub_error (GRUB_ERR_UNKNOWN_OS, "Unsupported flag: 0x%x", 
header->flags);
+      goto fail;
+    }
+
+  ehdr = (Elf32_Ehdr *) buffer;
+
+  if (grub_dl_check_header (ehdr, sizeof(*ehdr)))
+    {
+      grub_error (GRUB_ERR_UNKNOWN_OS, "No valid ELF header found");
+      goto fail;
+    }
+
+  if (ehdr->e_type != ET_EXEC)
+    {
+      grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
+      goto fail;
+    }
+
+  /* FIXME: Should we support program headers at strange locations?  */
+  if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH)
+    {
+      grub_error (GRUB_ERR_UNKNOWN_OS, "Program header at a too high offset");
+      goto fail;
+    }
+
+  /* Determine the amount of memory that is required.  */
+  /* XXX discontiguous segments */
+  size = 0;
+  for (i = 0; i < ehdr->e_phnum; i++)
+    {
+      Elf32_Phdr *phdr;
+      phdr = (Elf32_Phdr *) (buffer + ehdr->e_phoff + i * ehdr->e_phentsize);
+
+      size += phdr->p_memsz;
+    }
+  if (-1 == grub_claimmap (ehdr->e_entry, size))
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%x bytes at 
0x%x\n",
+                 size, ehdr->e_entry);
+      goto fail;
+    }
+
+  entry = ehdr->e_entry;
+
+  /* Load every loadable segment in memory.  */
+  for (i = 0; i < ehdr->e_phnum; i++)
+    {
+      Elf32_Phdr *phdr;
+      phdr = (Elf32_Phdr *) (buffer + ehdr->e_phoff + i * ehdr->e_phentsize);
+
+      if (phdr->p_type == PT_LOAD)
+       {
+         if (grub_file_seek (file, phdr->p_offset) == -1)
+           {
+             grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header");
+             goto fail;
+           }
+
+         grub_dprintf ("loader", "Loading segment %d at 0x%x, size 0x%x\n", i,
+                       phdr->p_paddr, phdr->p_filesz);
+
+         if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz) 
+             != (grub_ssize_t) phdr->p_filesz)
+           {
+             grub_error (GRUB_ERR_BAD_OS, "Couldn't read segment from file");
+             goto fail;
+           }
+
+         if (phdr->p_filesz < phdr->p_memsz)
+           grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0, 
+                        phdr->p_memsz - phdr->p_filesz);
+       }
+    }
+
+  mbi = grub_malloc (sizeof (struct grub_multiboot_info));
+  if (!mbi)
+    goto fail;
+
+  mbi->flags = 0;
+
+  grub_ieee1275_mbi_memory (mbi);
+  grub_ieee1275_mbi_cmdline (mbi, argc, argv);
+
+  mbi->flags |= GRUB_MB_INFO_BOOT_LOADER_NAME;
+  mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING);
+
+  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload);
+
+ fail:
+  if (file)
+    grub_file_close (file);
+
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_free (mbi);
+      grub_dl_unref (my_mod);
+    }
+}
+
+
+void
+grub_rescue_cmd_module  (int argc, char *argv[])
+{
+  grub_file_t file = 0;
+  grub_ssize_t size, len = 0;
+  char *module = 0, *cmdline = 0, *p;
+  int i;
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
+      goto fail;
+    }
+
+  if (!mbi)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                 "You need to load the multiboot kernel first");
+      goto fail;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    goto fail;
+
+  size = grub_file_size (file);
+  module = grub_memalign (GRUB_MB_MOD_ALIGN, size);
+  if (!module)
+    goto fail;
+
+  grub_dprintf ("loader", "Loading module %s at %p, size 0x%x\n", argv[0],
+               module, size);
+
+  if (grub_file_read (file, module, size) != size)
+    {
+      grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
+      goto fail;
+    }
+  
+  for (i = 0; i < argc; i++)
+    len += grub_strlen (argv[i]) + 1;
+  
+  cmdline = p = grub_malloc (len);
+  if (!cmdline)
+    goto fail;
+  
+  for (i = 0; i < argc; i++)
+    {
+      p = grub_stpcpy (p, argv[i]);
+      *(p++) = ' ';
+    }
+  
+  /* Remove the space after the last word.  */
+  *(--p) = '\0';
+
+  if (mbi->flags & GRUB_MB_INFO_MODS)
+    {
+      struct grub_mod_list *modlist = (struct grub_mod_list *) mbi->mods_addr;
+
+      modlist = grub_realloc (modlist, (mbi->mods_count + 1) 
+                                      * sizeof (struct grub_mod_list));
+      if (!modlist)
+       goto fail;
+      mbi->mods_addr = (grub_uint32_t) modlist;
+      modlist += mbi->mods_count;
+      modlist->mod_start = (grub_uint32_t) module;
+      modlist->mod_end = (grub_uint32_t) module + size;
+      modlist->cmdline = (grub_uint32_t) cmdline;
+      modlist->pad = 0;
+      mbi->mods_count++;
+    }
+  else
+    {
+      struct grub_mod_list *modlist = grub_malloc (sizeof (struct 
grub_mod_list));
+      if (!modlist)
+       goto fail;
+      modlist->mod_start = (grub_uint32_t) module;
+      modlist->mod_end = (grub_uint32_t) module + size;
+      modlist->cmdline = (grub_uint32_t) cmdline;
+      modlist->pad = 0;
+      mbi->mods_count = 1;
+      mbi->mods_addr = (grub_uint32_t) modlist;
+      mbi->flags |= GRUB_MB_INFO_MODS;
+    }
+
+ fail:
+  if (file)
+    grub_file_close (file);
+
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_free (module);
+      grub_free (cmdline);
+    }
+}
+
+
+GRUB_MOD_INIT
+{
+  grub_rescue_register_command ("multiboot", grub_rescue_cmd_multiboot,
+                               "load a multiboot kernel");
+  grub_rescue_register_command ("module", grub_rescue_cmd_module,
+                               "load a multiboot module");
+  my_mod = mod;
+}
+
+GRUB_MOD_FINI
+{
+  grub_rescue_unregister_command ("multiboot");
+  grub_rescue_unregister_command ("module");
+}
--- /dev/null   2004-12-18 12:15:49.000000000 -0600
+++ loader/powerpc/ieee1275/multiboot_normal.c  2005-06-23 21:15:03.000000000 
-0500
@@ -0,0 +1,61 @@
+/* multiboot_normal.c - boot another boot loader */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2004  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/machine/loader.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+
+static grub_err_t
+grub_normal_cmd_multiboot (struct grub_arg_list *state __attribute__ 
((unused)),
+                          int argc, char **args)
+{
+  grub_rescue_cmd_multiboot (argc, args);
+  return grub_errno;
+}
+
+
+static grub_err_t
+grub_normal_cmd_module (struct grub_arg_list *state __attribute__ ((unused)),
+                       int argc, char **args)
+{
+  grub_rescue_cmd_module (argc, args);
+  return grub_errno;
+}
+
+GRUB_MOD_INIT
+{
+  (void) mod; /* To stop warning.  */
+  grub_register_command ("multiboot", grub_normal_cmd_multiboot,
+                        GRUB_COMMAND_FLAG_BOTH | 
GRUB_COMMAND_FLAG_NO_ARG_PARSE,
+                        "multiboot FILE [ARGS...]",
+                        "Load a multiboot kernel", 0);
+  
+  grub_register_command ("module", grub_normal_cmd_module,
+                        GRUB_COMMAND_FLAG_BOTH | 
GRUB_COMMAND_FLAG_NO_ARG_PARSE,
+                        "module FILE [ARGS...]",
+                        "Load a multiboot module", 0);
+}
+
+GRUB_MOD_FINI
+{
+  grub_unregister_command ("multiboot");
+  grub_unregister_command ("module");
+}

Attachment: hello-multiboot.tar.bz2
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]