All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hollis Blanchard <hollis@penguinppc.org>
To: grub-devel@gnu.org
Subject: PPC multiboot
Date: Fri, 24 Jun 2005 08:51:25 -0500	[thread overview]
Message-ID: <20050624135125.GA3072@miracle> (raw)

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

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 #2: hello-multiboot.tar.bz2 --]
[-- Type: application/octet-stream, Size: 4994 bytes --]

             reply	other threads:[~2005-06-24 14:01 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-06-24 13:51 Hollis Blanchard [this message]
  -- strict thread matches above, loose matches on Subject: below --
2005-05-25 16:49 grub on ppc -- a CHRP script Maurizio Boriani
2005-05-26  6:47 ` Marco Gerards
2005-05-26  7:26   ` Maurizio Boriani
2005-06-21  2:58     ` PPC multiboot Hollis Blanchard
2005-06-21 11:46       ` Marco Gerards

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20050624135125.GA3072@miracle \
    --to=hollis@penguinppc.org \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

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

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