[Top][All Lists]
[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", ®ions,
+ 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");
+}
hello-multiboot.tar.bz2
Description: Binary data