* [PATCH] generic ELF loading
@ 2006-10-13 22:37 Hollis Blanchard
2006-10-13 22:40 ` [PATCH] ppc64 Linux ELF loader Hollis Blanchard
2006-10-14 15:33 ` [PATCH] generic ELF loading Yoshinori K. Okuji
0 siblings, 2 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-13 22:37 UTC (permalink / raw)
To: grub-devel
This patch adds generic ELF loading infrastructure for both 32-bit and
64-bit ELF. It provides an "iterate" function for program headers, and a
"load" function for convenience.
I have converted the PowerPC Linux loader to use this infrastructure
(see next mail), and possibly the i386 multiboot loader as well (though
I will need others to test it). The module loader looks a little more
annoying because it actually loads *sections*, not segments.
I will be away next week but intend to commit this soon after, so please
review.
This code is literally duplicated, once for 32-bit and once for 64-bit.
I'm trying to come up with a better way of doing that, and I'm
considering something like this:
elf32.c:
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#include "elfclass.c"
elf64.c:
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#include "elfclass.c"
If you strongly object to #including C files, or have a better way of
doing this, please speak up.
-Hollis
diff -r b53dfa2812ad include/grub/elfload.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/grub/elfload.h Fri Oct 13 16:23:22 2006 -0500
@@ -0,0 +1,57 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003, 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
+ * 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.
+ */
+
+#ifndef GRUB_ELFLOAD_HEADER
+#define GRUB_ELFLOAD_HEADER 1
+
+#include <grub/err.h>
+#include <grub/elf.h>
+#include <grub/file.h>
+#include <grub/symbol.h>
+#include <grub/types.h>
+
+struct grub_elf_file
+{
+ grub_file_t file;
+ union {
+ Elf64_Ehdr ehdr64;
+ Elf32_Ehdr ehdr32;
+ } ehdr;
+ void *phdrs;
+};
+typedef struct grub_elf_file *grub_elf_t;
+
+grub_elf_t EXPORT_FUNC(grub_elf_open) (const char *name);
+grub_err_t EXPORT_FUNC(grub_elf_close) (grub_elf_t elf);
+
+int EXPORT_FUNC(grub_elf_is_elf32) (grub_elf_t elf);
+grub_err_t EXPORT_FUNC(grub_elf32_phdr_iterate) (grub_elf_t elf,
+ int (*hook) (grub_elf_t, Elf32_Phdr *, void *),
+ void *hook_arg);
+grub_err_t EXPORT_FUNC(grub_elf32_load) (grub_elf_t elf,
+ int (*) (Elf32_Phdr *));
+
+int EXPORT_FUNC(grub_elf_is_elf64) (grub_elf_t elf);
+grub_err_t EXPORT_FUNC(grub_elf64_phdr_iterate) (grub_elf_t elf,
+ int (*hook) (grub_elf_t, Elf64_Phdr *, void *),
+ void *hook_arg);
+grub_err_t EXPORT_FUNC(grub_elf64_load) (grub_elf_t elf,
+ int (*) (Elf64_Phdr *));
+
+#endif /* ! GRUB_ELFLOAD_HEADER */
diff -r b53dfa2812ad kern/elf.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kern/elf.c Fri Oct 13 16:23:22 2006 -0500
@@ -0,0 +1,280 @@
+/* elf.c - load ELF files */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003, 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
+ * 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/err.h>
+#include <grub/elf.h>
+#include <grub/elfload.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+/* Check if EHDR is a valid ELF header. */
+static grub_err_t
+grub_elf_check_header (grub_elf_t elf)
+{
+ Elf32_Ehdr *e = &elf->ehdr.ehdr32;
+
+ if (e->e_ident[EI_MAG0] != ELFMAG0
+ || e->e_ident[EI_MAG1] != ELFMAG1
+ || e->e_ident[EI_MAG2] != ELFMAG2
+ || e->e_ident[EI_MAG3] != ELFMAG3
+ || e->e_ident[EI_VERSION] != EV_CURRENT
+ || e->e_version != EV_CURRENT)
+ return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_elf_close (grub_elf_t elf)
+{
+ grub_file_t file = elf->file;
+
+ grub_free (elf->phdrs);
+ grub_free (elf);
+
+ if (file)
+ grub_file_close (file);
+
+ return grub_errno;
+}
+
+grub_elf_t
+grub_elf_open (const char *name)
+{
+ grub_elf_t elf;
+
+ elf = grub_malloc (sizeof (*elf));
+ if (! elf)
+ return 0;
+
+ elf->file = 0;
+ elf->phdrs = 0;
+
+ elf->file = grub_file_open (name);
+ if (! elf->file)
+ goto fail;
+
+ if (grub_file_read (elf->file, (char *) &elf->ehdr, sizeof (elf->ehdr))
+ != sizeof (elf->ehdr))
+ {
+ grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header.");
+ goto fail;
+ }
+
+ if (grub_elf_check_header (elf))
+ goto fail;
+
+ return elf;
+
+fail:
+ grub_elf_close (elf);
+ return 0;
+}
+
+\f
+/* 32-bit */
+
+int
+grub_elf_is_elf32 (grub_elf_t elf)
+{
+ return elf->ehdr.ehdr32.e_ident[EI_CLASS] == ELFCLASS32;
+}
+
+typedef int (*grub_elf32_load_hook_t) (Elf32_Phdr *phdr);
+
+static int
+grub_elf32_load_segment (grub_elf_t elf, Elf32_Phdr *phdr,
+ void *hook)
+{
+ grub_elf32_load_hook_t load_hook = (grub_elf32_load_hook_t) hook;
+
+ if (phdr->p_type != PT_LOAD)
+ return 0;
+
+ if (load_hook && load_hook (phdr))
+ return 1;
+
+ grub_dprintf ("loader", "Loading segment at %llx, size 0x%llx\n",
+ (unsigned long long) phdr->p_paddr,
+ (unsigned long long) phdr->p_filesz);
+
+ if (grub_file_seek (elf->file, phdr->p_offset) == (grub_off_t) -1)
+ {
+ return grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header");
+ }
+
+ if (grub_file_read (elf->file, (void *) (long) phdr->p_paddr, phdr->p_filesz)
+ != (grub_ssize_t) phdr->p_filesz)
+ {
+ return grub_error (GRUB_ERR_BAD_OS, "Couldn't load segment");
+ }
+
+ if (phdr->p_filesz < phdr->p_memsz)
+ grub_memset ((void *) (unsigned long) (phdr->p_paddr + phdr->p_filesz),
+ 0, phdr->p_memsz - phdr->p_filesz);
+
+ return 0;
+}
+
+static grub_err_t
+grub_elf32_load_phdrs (grub_elf_t elf)
+{
+ grub_ssize_t phdrs_size;
+
+ phdrs_size = elf->ehdr.ehdr32.e_phnum * elf->ehdr.ehdr32.e_phentsize;
+
+ grub_dprintf ("elf", "loading program headers: offset 0x%llx, size 0x%x\n",
+ (unsigned long long) elf->ehdr.ehdr32.e_phoff,
+ phdrs_size);
+
+ elf->phdrs = grub_malloc (phdrs_size);
+ if (! elf->phdrs)
+ return grub_errno;
+
+ if ((grub_file_seek (elf->file, elf->ehdr.ehdr32.e_phoff) == (grub_off_t) -1)
+ || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
+ return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_elf32_phdr_iterate (grub_elf_t elf,
+ int (*hook) (grub_elf_t, Elf32_Phdr *, void *),
+ void *hook_arg)
+{
+ Elf32_Phdr *phdrs;
+ unsigned int i;
+
+ if (! elf->phdrs)
+ if (grub_elf32_load_phdrs (elf))
+ return grub_errno;
+
+ phdrs = (Elf32_Phdr *) elf->phdrs;
+ for (i = 0; i < elf->ehdr.ehdr32.e_phnum; i++)
+ if (hook (elf, phdrs + i, hook_arg))
+ break;
+
+ return grub_errno;
+}
+
+/* Load every loadable segment into memory. */
+grub_err_t
+grub_elf32_load (grub_elf_t elf, int (*phdr_hook) (Elf32_Phdr *))
+{
+ return grub_elf32_phdr_iterate (elf, grub_elf32_load_segment,
+ phdr_hook);
+}
+
+\f
+/* 64-bit */
+
+int
+grub_elf_is_elf64 (grub_elf_t elf)
+{
+ return elf->ehdr.ehdr64.e_ident[EI_CLASS] == ELFCLASS64;
+}
+
+typedef int (*grub_elf64_load_hook_t) (Elf64_Phdr *phdr);
+
+static int
+grub_elf64_load_segment (grub_elf_t elf, Elf64_Phdr *phdr,
+ void *hook)
+{
+ grub_elf64_load_hook_t load_hook = (grub_elf64_load_hook_t) hook;
+
+ if (phdr->p_type != PT_LOAD)
+ return 0;
+
+ if (load_hook && load_hook (phdr))
+ return 1;
+
+ grub_dprintf ("loader", "Loading segment at %llx, size 0x%llx\n",
+ (unsigned long long) phdr->p_paddr,
+ (unsigned long long) phdr->p_filesz);
+
+ if (grub_file_seek (elf->file, phdr->p_offset) == (grub_off_t) -1)
+ {
+ return grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header");
+ }
+
+ if (grub_file_read (elf->file, (void *) (long) phdr->p_paddr, phdr->p_filesz)
+ != (grub_ssize_t) phdr->p_filesz)
+ {
+ return grub_error (GRUB_ERR_BAD_OS, "Couldn't load segment");
+ }
+
+ if (phdr->p_filesz < phdr->p_memsz)
+ grub_memset ((void *) (unsigned long) (phdr->p_paddr + phdr->p_filesz),
+ 0, phdr->p_memsz - phdr->p_filesz);
+
+ return 0;
+}
+
+static grub_err_t
+grub_elf64_load_phdrs (grub_elf_t elf)
+{
+ grub_ssize_t phdrs_size;
+
+ phdrs_size = elf->ehdr.ehdr64.e_phnum * elf->ehdr.ehdr64.e_phentsize;
+
+ grub_dprintf ("elf", "loading program headers: offset 0x%llx, size 0x%x\n",
+ (unsigned long long) elf->ehdr.ehdr64.e_phoff,
+ phdrs_size);
+
+ elf->phdrs = grub_malloc (phdrs_size);
+ if (! elf->phdrs)
+ return grub_errno;
+
+ if ((grub_file_seek (elf->file, elf->ehdr.ehdr64.e_phoff) == (grub_off_t) -1)
+ || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
+ return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_elf64_phdr_iterate (grub_elf_t elf,
+ int (*hook) (grub_elf_t, Elf64_Phdr *, void *),
+ void *hook_arg)
+{
+ Elf64_Phdr *phdrs;
+ unsigned int i;
+
+ if (! elf->phdrs)
+ if (grub_elf64_load_phdrs (elf))
+ return grub_errno;
+
+ phdrs = (Elf64_Phdr *) elf->phdrs;
+ for (i = 0; i < elf->ehdr.ehdr64.e_phnum; i++)
+ if (hook (elf, phdrs + i, hook_arg))
+ break;
+
+ return grub_errno;
+}
+
+/* Load every loadable segment into memory. */
+grub_err_t
+grub_elf64_load (grub_elf_t elf, int (*phdr_hook) (Elf64_Phdr *))
+{
+ return grub_elf64_phdr_iterate (elf, grub_elf64_load_segment,
+ phdr_hook);
+}
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH] ppc64 Linux ELF loader
2006-10-13 22:37 [PATCH] generic ELF loading Hollis Blanchard
@ 2006-10-13 22:40 ` Hollis Blanchard
2006-10-14 15:33 ` [PATCH] generic ELF loading Yoshinori K. Okuji
1 sibling, 0 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-13 22:40 UTC (permalink / raw)
To: grub-devel
This patch converts the PowerPC Linux loader to use the ELF
infrastructure in the last patch, which gives us 64-bit ELF support. You
can see examples of how I'm using the ELF "iterate" and "load"
functions.
-Hollis
diff -r b7b3f308a91d include/grub/types.h
--- a/include/grub/types.h Fri Oct 13 13:50:22 2006 -0500
+++ b/include/grub/types.h Fri Oct 13 13:50:22 2006 -0500
@@ -22,6 +22,8 @@
#include <config.h>
#include <grub/cpu/types.h>
+
+#define __unused __attribute__ ((unused))
#ifdef GRUB_UTIL
# define GRUB_CPU_SIZEOF_VOID_P SIZEOF_VOID_P
diff -r b7b3f308a91d loader/powerpc/ieee1275/linux.c
--- a/loader/powerpc/ieee1275/linux.c Fri Oct 13 13:50:22 2006 -0500
+++ b/loader/powerpc/ieee1275/linux.c Fri Oct 13 16:17:32 2006 -0500
@@ -19,6 +19,7 @@
*/
#include <grub/elf.h>
+#include <grub/elfload.h>
#include <grub/loader.h>
#include <grub/dl.h>
#include <grub/mm.h>
@@ -27,6 +28,9 @@
#include <grub/ieee1275/ieee1275.h>
#include <grub/machine/loader.h>
+#define ELF32_LOADMASK (0xc0000000UL)
+#define ELF64_LOADMASK (0xc000000000000000ULL)
+
static grub_dl_t my_mod;
static int loaded;
@@ -97,53 +101,17 @@ grub_linux_unload (void)
return err;
}
-void
-grub_rescue_cmd_linux (int argc, char *argv[])
-{
- grub_file_t file = 0;
- Elf32_Ehdr ehdr;
- Elf32_Phdr *phdrs = 0;
- int i;
- int offset = 0;
- grub_addr_t entry;
+static grub_err_t
+grub_linux_load32 (grub_elf_t elf)
+{
+ Elf32_Addr entry;
+ Elf32_Addr segments_start = (Elf32_Addr) -1;
+ Elf32_Addr segments_end = 0;
int found_addr = 0;
- int size;
- char *dest;
-
- grub_dl_ref (my_mod);
-
- if (argc == 0)
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
- goto fail;
- }
-
- file = grub_file_open (argv[0]);
- if (! file)
- goto fail;
-
- if (grub_file_read (file, (char *) &ehdr, sizeof (ehdr)) != sizeof (ehdr))
- {
- grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux elf header");
- goto fail;
- }
-
- 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,
- "This ELF file is not of the right type\n");
- goto fail;
- }
-
- /* Read the sections. */
- entry = ehdr.e_entry;
- if (entry == 0xc0000000)
+
+ /* Linux's entry point incorrectly contains a virtual address. */
+ entry = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK;
+ if (entry == 0)
{
entry = 0x01400000;
vmlinux = 1;
@@ -151,26 +119,23 @@ grub_rescue_cmd_linux (int argc, char *a
else
vmlinux = 0;
- phdrs = (Elf32_Phdr *) grub_malloc (ehdr.e_phnum * ehdr.e_phentsize);
- grub_file_read (file, (void *) phdrs, ehdr.e_phnum * ehdr.e_phentsize);
-
- /* Release the previously used memory. */
- grub_loader_unset ();
-
- /* Determine the amount of memory that is required. */
- linux_size = 0;
- for (i = 0; i < ehdr.e_phnum; i++)
- {
- Elf32_Phdr *phdr = phdrs + i;
- /* XXX: Is this calculation correct? */
- linux_size += phdr->p_memsz + phdr->p_filesz;
- }
-
- /* Reserve memory for the kernel. */
- linux_size += 0x100000;
-
- /* For some vmlinux kernels the address set above won't work. Just
- try some other addresses just like yaboot does. */
+ /* Run through the program headers to calculate the total memory size we
+ * should claim. */
+ auto int calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg);
+ int calcsize (grub_elf_t __unused _elf, Elf32_Phdr *phdr, void __unused *_arg)
+ {
+ if (phdr->p_paddr < segments_start)
+ segments_start = phdr->p_paddr;
+ if (phdr->p_paddr + phdr->p_memsz > segments_end)
+ segments_end = phdr->p_paddr + phdr->p_memsz;
+ return 1;
+ }
+ grub_elf32_phdr_iterate (elf, calcsize, 0);
+ linux_size = segments_end - segments_start + 0x100000;
+
+ /* On some systems, firmware occupies the memory we're trying to use.
+ * Happily, Linux can be loaded anywhere (it relocates itself). Iterate
+ * until we find an open area. */
for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000)
{
grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
@@ -179,42 +144,120 @@ grub_rescue_cmd_linux (int argc, char *a
if (found_addr != -1)
break;
}
-
if (found_addr == -1)
- {
- grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not claim memory");
- goto fail;
- }
- entry = linux_addr;
-
- /* Load every loadable segment in memory. */
- for (i = 0; i < ehdr.e_phnum; i++)
- {
- Elf32_Phdr *phdr = phdrs + i;
-
- if (phdr->p_type == PT_LOAD)
- {
- void *segment_addr = ((char *) entry) + offset;
-
- if (grub_file_seek (file, phdr->p_offset) == (grub_off_t) -1)
- {
- grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header");
- goto fail;
- }
-
- grub_dprintf ("loader", "Loading segment %d at %p, size 0x%x\n", i,
- segment_addr, phdr->p_filesz);
-
- if (grub_file_read (file, segment_addr, phdr->p_filesz)
- != (grub_ssize_t) phdr->p_filesz)
- goto fail;
-
- if (phdr->p_filesz < phdr->p_memsz)
- grub_memset ((char *) (((char *) entry) + offset) + phdr->p_filesz, 0,
- phdr->p_memsz - phdr->p_filesz);
-
- offset += phdr->p_filesz;
- }
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory.");
+
+ /* Now load the segments into the area we claimed. */
+ auto int offset_phdr (Elf32_Phdr *phdr);
+ int offset_phdr (Elf32_Phdr *phdr)
+ {
+ /* Linux's program headers incorrectly contain virtual addresses. */
+ phdr->p_paddr = phdr->p_paddr & ~ELF32_LOADMASK;
+ /* Offset to the area we claimed. */
+ phdr->p_paddr += linux_addr;
+ return 0;
+ }
+ return grub_elf32_load (elf, offset_phdr);
+}
+
+static grub_err_t
+grub_linux_load64 (grub_elf_t elf)
+{
+ Elf64_Addr entry;
+ Elf64_Addr segments_start = (Elf64_Addr) -1;
+ Elf64_Addr segments_end = 0;
+ int found_addr = 0;
+
+ /* Linux's entry point incorrectly contains a virtual address. */
+ entry = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK;
+ if (entry == 0)
+ {
+ entry = 0x01400000;
+ vmlinux = 1;
+ }
+ else
+ vmlinux = 0;
+
+ /* Run through the program headers to calculate the total memory size we
+ * should claim. */
+ auto int calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
+ int calcsize (grub_elf_t __unused _elf, Elf64_Phdr *phdr, void __unused *_arg)
+ {
+ if (phdr->p_paddr < segments_start)
+ segments_start = phdr->p_paddr;
+ if (phdr->p_paddr + phdr->p_memsz > segments_end)
+ segments_end = phdr->p_paddr + phdr->p_memsz;
+ return 1;
+ }
+ grub_elf64_phdr_iterate (elf, calcsize, 0);
+ linux_size = segments_end - segments_start + 0x100000;
+
+ /* On some systems, firmware occupies the memory we're trying to use.
+ * Happily, Linux can be loaded anywhere (it relocates itself). Iterate
+ * until we find an open area. */
+ for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000)
+ {
+ grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
+ linux_addr, linux_size);
+ found_addr = grub_claimmap (linux_addr, linux_size);
+ if (found_addr != -1)
+ break;
+ }
+ if (found_addr == -1)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory.");
+
+ /* Now load the segments into the area we claimed. */
+ auto int offset_phdr (Elf64_Phdr *phdr);
+ int offset_phdr (Elf64_Phdr *phdr)
+ {
+ /* Linux's program headers incorrectly contain virtual addresses. */
+ phdr->p_paddr = phdr->p_paddr & ~ELF64_LOADMASK;
+ /* Offset to the area we claimed. */
+ phdr->p_paddr += linux_addr;
+ return 0;
+ }
+ return grub_elf64_load (elf, offset_phdr);
+}
+
+void
+grub_rescue_cmd_linux (int argc, char *argv[])
+{
+ grub_elf_t elf = 0;
+ int i;
+ int size;
+ char *dest;
+
+ grub_dl_ref (my_mod);
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
+ goto out;
+ }
+
+ elf = grub_elf_open (argv[0]);
+ if (! elf)
+ goto out;
+
+ if (elf->ehdr.ehdr32.e_type != ET_EXEC)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_OS,
+ "This ELF file is not of the right type\n");
+ goto out;
+ }
+
+ /* Release the previously used memory. */
+ grub_loader_unset ();
+
+ if (grub_elf_is_elf32 (elf))
+ grub_linux_load32 (elf);
+ else
+ if (grub_elf_is_elf64 (elf))
+ grub_linux_load64 (elf);
+ else
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unknown ELF class");
+ goto out;
}
size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]);
@@ -223,7 +266,7 @@ grub_rescue_cmd_linux (int argc, char *a
linux_args = grub_malloc (size);
if (! linux_args)
- goto fail;
+ goto out;
/* Specify the boot file. */
dest = grub_stpcpy (linux_args, "BOOT_IMAGE=");
@@ -235,12 +278,10 @@ grub_rescue_cmd_linux (int argc, char *a
dest = grub_stpcpy (dest, argv[i]);
}
- fail:
-
- if (file)
- grub_file_close (file);
-
- grub_free (phdrs);
+out:
+
+ if (elf)
+ grub_elf_close (elf);
if (grub_errno != GRUB_ERR_NONE)
{
@@ -254,8 +295,6 @@ grub_rescue_cmd_linux (int argc, char *a
initrd_addr = 0;
loaded = 1;
}
-
- return;
}
void
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH] generic ELF loading
2006-10-13 22:37 [PATCH] generic ELF loading Hollis Blanchard
2006-10-13 22:40 ` [PATCH] ppc64 Linux ELF loader Hollis Blanchard
@ 2006-10-14 15:33 ` Yoshinori K. Okuji
2006-10-14 17:23 ` Tristan Gingold
2006-10-24 20:03 ` Hollis Blanchard
1 sibling, 2 replies; 11+ messages in thread
From: Yoshinori K. Okuji @ 2006-10-14 15:33 UTC (permalink / raw)
To: The development of GRUB 2
On Saturday 14 October 2006 00:37, Hollis Blanchard wrote:
> This patch adds generic ELF loading infrastructure for both 32-bit and
> 64-bit ELF. It provides an "iterate" function for program headers, and a
> "load" function for convenience.
The idea is very good. But I don't like that loaded areas are always allocated
from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
to load an image directly instead of consuming the heap.
Thanks,
Okuji
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] generic ELF loading
2006-10-14 15:33 ` [PATCH] generic ELF loading Yoshinori K. Okuji
@ 2006-10-14 17:23 ` Tristan Gingold
2006-10-24 20:41 ` Hollis Blanchard
2006-10-24 20:03 ` Hollis Blanchard
1 sibling, 1 reply; 11+ messages in thread
From: Tristan Gingold @ 2006-10-14 17:23 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Oct 14, 2006 at 05:33:44PM +0200, Yoshinori K. Okuji wrote:
> On Saturday 14 October 2006 00:37, Hollis Blanchard wrote:
> > This patch adds generic ELF loading infrastructure for both 32-bit and
> > 64-bit ELF. It provides an "iterate" function for program headers, and a
> > "load" function for convenience.
>
> The idea is very good. But I don't like that loaded areas are always allocated
> from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
> to load an image directly instead of consuming the heap.
Two points for ia64:
* the area must be allocated from EFI.
* we need to support relocation: loading the ELF file with an offset
(this feature can be on/off/forced).
Tristan.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] generic ELF loading
2006-10-14 17:23 ` Tristan Gingold
@ 2006-10-24 20:41 ` Hollis Blanchard
0 siblings, 0 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-24 20:41 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, 2006-10-14 at 19:23 +0200, Tristan Gingold wrote:
> On Sat, Oct 14, 2006 at 05:33:44PM +0200, Yoshinori K. Okuji wrote:
> > On Saturday 14 October 2006 00:37, Hollis Blanchard wrote:
> > > This patch adds generic ELF loading infrastructure for both 32-bit and
> > > 64-bit ELF. It provides an "iterate" function for program headers, and a
> > > "load" function for convenience.
> >
> > The idea is very good. But I don't like that loaded areas are always allocated
> > from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
> > to load an image directly instead of consuming the heap.
> Two points for ia64:
> * the area must be allocated from EFI.
What does this mean? Open Firmware has a "claim" call, which reserves
memory and makes it available to the application. I assume EFI must have
something similar. This can be called via a hook.
For error handling, you'd probably need to iterate once to claim the
memory, iterate once to copy the ELF file there, and in case of error
iterate again to free the claimed memory.
> * we need to support relocation: loading the ELF file with an offset
> (this feature can be on/off/forced).
This is provided via `load_hook' in grub_elf32_load(). In fact, PowerPC
already does this. Please see offset_phdr() in my second mail (Subject:
Re: [PATCH] ppc64 Linux ELF loader).
-Hollis
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] generic ELF loading
2006-10-14 15:33 ` [PATCH] generic ELF loading Yoshinori K. Okuji
2006-10-14 17:23 ` Tristan Gingold
@ 2006-10-24 20:03 ` Hollis Blanchard
2006-10-24 20:48 ` Johan Rydberg
2006-10-25 5:53 ` Yoshinori K. Okuji
1 sibling, 2 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-24 20:03 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, 2006-10-14 at 17:33 +0200, Yoshinori K. Okuji wrote:
> On Saturday 14 October 2006 00:37, Hollis Blanchard wrote:
> > This patch adds generic ELF loading infrastructure for both 32-bit and
> > 64-bit ELF. It provides an "iterate" function for program headers, and a
> > "load" function for convenience.
>
> The idea is very good. But I don't like that loaded areas are always allocated
> from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
> to load an image directly instead of consuming the heap.
Actually I'm not using the heap, I'm just directly copying wherever
phdr->p_paddr says to. That's not a good thing actually; in the future
we should add some error checking to make sure we don't clobber GRUB
itself.
Also, I made sure that the load hook could veto loading each segment. So
the x86 loader would do something like this:
int x86_load_hook (Elf32_Phdr *phdr)
{
if (phdr->p_paddr not in x86 OS load area)
return 1;
return 0;
}
grub_elf32_load (elf, x86_load_hook);
-Hollis
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH] generic ELF loading
2006-10-24 20:03 ` Hollis Blanchard
@ 2006-10-24 20:48 ` Johan Rydberg
2006-10-24 20:45 ` Hollis Blanchard
2006-10-25 5:53 ` Yoshinori K. Okuji
1 sibling, 1 reply; 11+ messages in thread
From: Johan Rydberg @ 2006-10-24 20:48 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 1171 bytes --]
Hollis Blanchard <hollis@penguinppc.org> writes:
>> The idea is very good. But I don't like that loaded areas are always allocated
>> from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
>> to load an image directly instead of consuming the heap.
>
> Actually I'm not using the heap, I'm just directly copying wherever
> phdr->p_paddr says to. That's not a good thing actually; in the future
> we should add some error checking to make sure we don't clobber GRUB
> itself.
Have you looked at how EFI solves this?
They keep track of all memory regions, and with each region is a
"memory type" associated. Whenever you allocate memory you change the
type of the region (from "free") to some that makes sense (could be
"loader data", "disk cache", ...). You can only allocate memory that
is marked "conventional", meaning it is considered free. The memory
region database is later feed to the operating system. We could do
the same.
Is this case we could allocate the regions specified by the ELF image.
If any of the allocations fail we know there is something already
loaded there, or the image is faulty.
~j
[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] generic ELF loading
2006-10-24 20:48 ` Johan Rydberg
@ 2006-10-24 20:45 ` Hollis Blanchard
0 siblings, 0 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-24 20:45 UTC (permalink / raw)
To: The development of GRUB 2
On Tue, 2006-10-24 at 22:48 +0200, Johan Rydberg wrote:
> Hollis Blanchard <hollis@penguinppc.org> writes:
>
> >> The idea is very good. But I don't like that loaded areas are always allocated
> >> from the heap. GRUB has a staging area for OS images on i386-pc, and I prefer
> >> to load an image directly instead of consuming the heap.
> >
> > Actually I'm not using the heap, I'm just directly copying wherever
> > phdr->p_paddr says to. That's not a good thing actually; in the future
> > we should add some error checking to make sure we don't clobber GRUB
> > itself.
>
> Have you looked at how EFI solves this?
>
> They keep track of all memory regions, and with each region is a
> "memory type" associated. Whenever you allocate memory you change the
> type of the region (from "free") to some that makes sense (could be
> "loader data", "disk cache", ...). You can only allocate memory that
> is marked "conventional", meaning it is considered free. The memory
> region database is later feed to the operating system. We could do
> the same.
>
> Is this case we could allocate the regions specified by the ELF image.
> If any of the allocations fail we know there is something already
> loaded there, or the image is faulty.
That's a great point. Doing a "claim" (as described in my reply to
Tristan) will return an error if the area is already claimed, so that
will accomplish the check.
On x86, the load hook will manually check to make sure the address is
within the OS load area.
-Hollis
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] generic ELF loading
2006-10-24 20:03 ` Hollis Blanchard
2006-10-24 20:48 ` Johan Rydberg
@ 2006-10-25 5:53 ` Yoshinori K. Okuji
1 sibling, 0 replies; 11+ messages in thread
From: Yoshinori K. Okuji @ 2006-10-25 5:53 UTC (permalink / raw)
To: The development of GRUB 2
On Tuesday 24 October 2006 22:03, Hollis Blanchard wrote:
> Actually I'm not using the heap, I'm just directly copying wherever
> phdr->p_paddr says to. That's not a good thing actually; in the future
> we should add some error checking to make sure we don't clobber GRUB
> itself.
OK, then it's even worse. :(
You must not assume that GRUB can always load an OS image to an appropriate
location directly. I know this is the case for the current implementation of
the Multiboot loader, but it is a very bad idea, generally speaking.
What GRUB should do is first to load an image to somewhere then relocate it to
the right place at boot time. On i386-pc, the OS area is used for this very
purpose. The x86 Multiboot loader is just a mistake, and that's why we must
rewrite it.
Okuji
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: [PATCH] generic ELF loading
@ 2006-10-14 3:03 Mao, Bibo
2006-10-24 20:21 ` Hollis Blanchard
0 siblings, 1 reply; 11+ messages in thread
From: Mao, Bibo @ 2006-10-14 3:03 UTC (permalink / raw)
To: The development of GRUB 2
I do not know whether it is possible to add one element in structure
grub_elf_file structure to identify ELF type (ELFCLASS32/ELFCLASS64)
and ELF machine type, this element can be set at function grub_elf_open.
Thanks
Bibo,mao
>-----Original Message-----
>From: grub-devel-bounces+bibo.mao=intel.com@gnu.org
>[mailto:grub-devel-bounces+bibo.mao=intel.com@gnu.org] On Behalf Of Hollis
>Blanchard
>Sent: 2006年10月14日 6:38
>To: grub-devel
>Subject: [PATCH] generic ELF loading
>
>This patch adds generic ELF loading infrastructure for both 32-bit and
>64-bit ELF. It provides an "iterate" function for program headers, and a
>"load" function for convenience.
>
>I have converted the PowerPC Linux loader to use this infrastructure
>(see next mail), and possibly the i386 multiboot loader as well (though
>I will need others to test it). The module loader looks a little more
>annoying because it actually loads *sections*, not segments.
>
>I will be away next week but intend to commit this soon after, so please
>review.
>
>This code is literally duplicated, once for 32-bit and once for 64-bit.
>I'm trying to come up with a better way of doing that, and I'm
>considering something like this:
>
> elf32.c:
> #define Elf_Ehdr Elf32_Ehdr
> #define Elf_Phdr Elf32_Phdr
> #include "elfclass.c"
>
> elf64.c:
> #define Elf_Ehdr Elf64_Ehdr
> #define Elf_Phdr Elf64_Phdr
> #include "elfclass.c"
>
>If you strongly object to #including C files, or have a better way of
>doing this, please speak up.
>
>-Hollis
>
>diff -r b53dfa2812ad include/grub/elfload.h
>--- /dev/null Thu Jan 01 00:00:00 1970 +0000
>+++ b/include/grub/elfload.h Fri Oct 13 16:23:22 2006 -0500
>@@ -0,0 +1,57 @@
>+/*
>+ * GRUB -- GRand Unified Bootloader
>+ * Copyright (C) 2003, 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
>+ * 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.
>+ */
>+
>+#ifndef GRUB_ELFLOAD_HEADER
>+#define GRUB_ELFLOAD_HEADER 1
>+
>+#include <grub/err.h>
>+#include <grub/elf.h>
>+#include <grub/file.h>
>+#include <grub/symbol.h>
>+#include <grub/types.h>
>+
>+struct grub_elf_file
>+{
>+ grub_file_t file;
>+ union {
>+ Elf64_Ehdr ehdr64;
>+ Elf32_Ehdr ehdr32;
>+ } ehdr;
>+ void *phdrs;
>+};
>+typedef struct grub_elf_file *grub_elf_t;
>+
>+grub_elf_t EXPORT_FUNC(grub_elf_open) (const char *name);
>+grub_err_t EXPORT_FUNC(grub_elf_close) (grub_elf_t elf);
>+
>+int EXPORT_FUNC(grub_elf_is_elf32) (grub_elf_t elf);
>+grub_err_t EXPORT_FUNC(grub_elf32_phdr_iterate) (grub_elf_t elf,
>+ int (*hook) (grub_elf_t, Elf32_Phdr *, void *),
>+ void *hook_arg);
>+grub_err_t EXPORT_FUNC(grub_elf32_load) (grub_elf_t elf,
>+ int (*) (Elf32_Phdr *));
>+
>+int EXPORT_FUNC(grub_elf_is_elf64) (grub_elf_t elf);
>+grub_err_t EXPORT_FUNC(grub_elf64_phdr_iterate) (grub_elf_t elf,
>+ int (*hook) (grub_elf_t, Elf64_Phdr *, void *),
>+ void *hook_arg);
>+grub_err_t EXPORT_FUNC(grub_elf64_load) (grub_elf_t elf,
>+ int (*) (Elf64_Phdr *));
>+
>+#endif /* ! GRUB_ELFLOAD_HEADER */
>diff -r b53dfa2812ad kern/elf.c
>--- /dev/null Thu Jan 01 00:00:00 1970 +0000
>+++ b/kern/elf.c Fri Oct 13 16:23:22 2006 -0500
>@@ -0,0 +1,280 @@
>+/* elf.c - load ELF files */
>+/*
>+ * GRUB -- GRand Unified Bootloader
>+ * Copyright (C) 2003, 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
>+ * 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/err.h>
>+#include <grub/elf.h>
>+#include <grub/elfload.h>
>+#include <grub/file.h>
>+#include <grub/misc.h>
>+#include <grub/mm.h>
>+
>+/* Check if EHDR is a valid ELF header. */
>+static grub_err_t
>+grub_elf_check_header (grub_elf_t elf)
>+{
>+ Elf32_Ehdr *e = &elf->ehdr.ehdr32;
>+
>+ if (e->e_ident[EI_MAG0] != ELFMAG0
>+ || e->e_ident[EI_MAG1] != ELFMAG1
>+ || e->e_ident[EI_MAG2] != ELFMAG2
>+ || e->e_ident[EI_MAG3] != ELFMAG3
>+ || e->e_ident[EI_VERSION] != EV_CURRENT
>+ || e->e_version != EV_CURRENT)
>+ return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF
>magic");
>+
>+ return GRUB_ERR_NONE;
>+}
>+
>+grub_err_t
>+grub_elf_close (grub_elf_t elf)
>+{
>+ grub_file_t file = elf->file;
>+
>+ grub_free (elf->phdrs);
>+ grub_free (elf);
>+
>+ if (file)
>+ grub_file_close (file);
>+
>+ return grub_errno;
>+}
>+
>+grub_elf_t
>+grub_elf_open (const char *name)
>+{
>+ grub_elf_t elf;
>+
>+ elf = grub_malloc (sizeof (*elf));
>+ if (! elf)
>+ return 0;
>+
>+ elf->file = 0;
>+ elf->phdrs = 0;
>+
>+ elf->file = grub_file_open (name);
>+ if (! elf->file)
>+ goto fail;
>+
>+ if (grub_file_read (elf->file, (char *) &elf->ehdr, sizeof (elf->ehdr))
>+ != sizeof (elf->ehdr))
>+ {
>+ grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header.");
>+ goto fail;
>+ }
>+
>+ if (grub_elf_check_header (elf))
>+ goto fail;
>+
>+ return elf;
>+
>+fail:
>+ grub_elf_close (elf);
>+ return 0;
>+}
>+
>+
>
>
>+/* 32-bit */
>+
>+int
>+grub_elf_is_elf32 (grub_elf_t elf)
>+{
>+ return elf->ehdr.ehdr32.e_ident[EI_CLASS] == ELFCLASS32;
>+}
>+
>+typedef int (*grub_elf32_load_hook_t) (Elf32_Phdr *phdr);
>+
>+static int
>+grub_elf32_load_segment (grub_elf_t elf, Elf32_Phdr *phdr,
>+ void *hook)
>+{
>+ grub_elf32_load_hook_t load_hook = (grub_elf32_load_hook_t) hook;
>+
>+ if (phdr->p_type != PT_LOAD)
>+ return 0;
>+
>+ if (load_hook && load_hook (phdr))
>+ return 1;
>+
>+ grub_dprintf ("loader", "Loading segment at %llx, size 0x%llx\n",
>+ (unsigned long long) phdr->p_paddr,
>+ (unsigned long long) phdr->p_filesz);
>+
>+ if (grub_file_seek (elf->file, phdr->p_offset) == (grub_off_t) -1)
>+ {
>+ return grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program
>header");
>+ }
>+
>+ if (grub_file_read (elf->file, (void *) (long) phdr->p_paddr,
>phdr->p_filesz)
>+ != (grub_ssize_t) phdr->p_filesz)
>+ {
>+ return grub_error (GRUB_ERR_BAD_OS, "Couldn't load segment");
>+ }
>+
>+ if (phdr->p_filesz < phdr->p_memsz)
>+ grub_memset ((void *) (unsigned long) (phdr->p_paddr + phdr->p_filesz),
>+ 0, phdr->p_memsz - phdr->p_filesz);
>+
>+ return 0;
>+}
>+
>+static grub_err_t
>+grub_elf32_load_phdrs (grub_elf_t elf)
>+{
>+ grub_ssize_t phdrs_size;
>+
>+ phdrs_size = elf->ehdr.ehdr32.e_phnum * elf->ehdr.ehdr32.e_phentsize;
>+
>+ grub_dprintf ("elf", "loading program headers: offset 0x%llx, size 0x%x\n",
>+ (unsigned long long) elf->ehdr.ehdr32.e_phoff,
>+ phdrs_size);
>+
>+ elf->phdrs = grub_malloc (phdrs_size);
>+ if (! elf->phdrs)
>+ return grub_errno;
>+
>+ if ((grub_file_seek (elf->file, elf->ehdr.ehdr32.e_phoff) == (grub_off_t)
>-1)
>+ || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
>+ return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
>+
>+ return GRUB_ERR_NONE;
>+}
>+
>+grub_err_t
>+grub_elf32_phdr_iterate (grub_elf_t elf,
>+ int (*hook) (grub_elf_t, Elf32_Phdr *, void *),
>+ void *hook_arg)
>+{
>+ Elf32_Phdr *phdrs;
>+ unsigned int i;
>+
>+ if (! elf->phdrs)
>+ if (grub_elf32_load_phdrs (elf))
>+ return grub_errno;
>+
>+ phdrs = (Elf32_Phdr *) elf->phdrs;
>+ for (i = 0; i < elf->ehdr.ehdr32.e_phnum; i++)
>+ if (hook (elf, phdrs + i, hook_arg))
>+ break;
>+
>+ return grub_errno;
>+}
>+
>+/* Load every loadable segment into memory. */
>+grub_err_t
>+grub_elf32_load (grub_elf_t elf, int (*phdr_hook) (Elf32_Phdr *))
>+{
>+ return grub_elf32_phdr_iterate (elf, grub_elf32_load_segment,
>+ phdr_hook);
>+}
>+
>+
>
>
>+/* 64-bit */
>+
>+int
>+grub_elf_is_elf64 (grub_elf_t elf)
>+{
>+ return elf->ehdr.ehdr64.e_ident[EI_CLASS] == ELFCLASS64;
>+}
>+
>+typedef int (*grub_elf64_load_hook_t) (Elf64_Phdr *phdr);
>+
>+static int
>+grub_elf64_load_segment (grub_elf_t elf, Elf64_Phdr *phdr,
>+ void *hook)
>+{
>+ grub_elf64_load_hook_t load_hook = (grub_elf64_load_hook_t) hook;
>+
>+ if (phdr->p_type != PT_LOAD)
>+ return 0;
>+
>+ if (load_hook && load_hook (phdr))
>+ return 1;
>+
>+ grub_dprintf ("loader", "Loading segment at %llx, size 0x%llx\n",
>+ (unsigned long long) phdr->p_paddr,
>+ (unsigned long long) phdr->p_filesz);
>+
>+ if (grub_file_seek (elf->file, phdr->p_offset) == (grub_off_t) -1)
>+ {
>+ return grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program
>header");
>+ }
>+
>+ if (grub_file_read (elf->file, (void *) (long) phdr->p_paddr,
>phdr->p_filesz)
>+ != (grub_ssize_t) phdr->p_filesz)
>+ {
>+ return grub_error (GRUB_ERR_BAD_OS, "Couldn't load segment");
>+ }
>+
>+ if (phdr->p_filesz < phdr->p_memsz)
>+ grub_memset ((void *) (unsigned long) (phdr->p_paddr + phdr->p_filesz),
>+ 0, phdr->p_memsz - phdr->p_filesz);
>+
>+ return 0;
>+}
>+
>+static grub_err_t
>+grub_elf64_load_phdrs (grub_elf_t elf)
>+{
>+ grub_ssize_t phdrs_size;
>+
>+ phdrs_size = elf->ehdr.ehdr64.e_phnum * elf->ehdr.ehdr64.e_phentsize;
>+
>+ grub_dprintf ("elf", "loading program headers: offset 0x%llx, size 0x%x\n",
>+ (unsigned long long) elf->ehdr.ehdr64.e_phoff,
>+ phdrs_size);
>+
>+ elf->phdrs = grub_malloc (phdrs_size);
>+ if (! elf->phdrs)
>+ return grub_errno;
>+
>+ if ((grub_file_seek (elf->file, elf->ehdr.ehdr64.e_phoff) == (grub_off_t)
>-1)
>+ || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
>+ return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
>+
>+ return GRUB_ERR_NONE;
>+}
>+
>+grub_err_t
>+grub_elf64_phdr_iterate (grub_elf_t elf,
>+ int (*hook) (grub_elf_t, Elf64_Phdr *, void *),
>+ void *hook_arg)
>+{
>+ Elf64_Phdr *phdrs;
>+ unsigned int i;
>+
>+ if (! elf->phdrs)
>+ if (grub_elf64_load_phdrs (elf))
>+ return grub_errno;
>+
>+ phdrs = (Elf64_Phdr *) elf->phdrs;
>+ for (i = 0; i < elf->ehdr.ehdr64.e_phnum; i++)
>+ if (hook (elf, phdrs + i, hook_arg))
>+ break;
>+
>+ return grub_errno;
>+}
>+
>+/* Load every loadable segment into memory. */
>+grub_err_t
>+grub_elf64_load (grub_elf_t elf, int (*phdr_hook) (Elf64_Phdr *))
>+{
>+ return grub_elf64_phdr_iterate (elf, grub_elf64_load_segment,
>+ phdr_hook);
>+}
>
>
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 11+ messages in thread* RE: [PATCH] generic ELF loading
2006-10-14 3:03 Mao, Bibo
@ 2006-10-24 20:21 ` Hollis Blanchard
0 siblings, 0 replies; 11+ messages in thread
From: Hollis Blanchard @ 2006-10-24 20:21 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, 2006-10-14 at 11:03 +0800, Mao, Bibo wrote:
> I do not know whether it is possible to add one element in
> structure grub_elf_file structure to identify ELF type
> (ELFCLASS32/ELFCLASS64) and ELF machine type, this element can be set
> at function grub_elf_open.
I'm not sure it saves much, since you'd still want a wrapper function,
and the info is already present in `ehdr' anyways. It comes down to
int grub_elf_is_elf32 (grub_elf_t elf)
{
return elf->ehdr.ehdr32.e_ident[EI_CLASS] == ELFCLASS32;
}
vs
int grub_elf_is_elf32 (grub_elf_t elf)
{
return elf->class == ELFCLASS32;
}
-Hollis
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2006-10-25 5:53 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-13 22:37 [PATCH] generic ELF loading Hollis Blanchard
2006-10-13 22:40 ` [PATCH] ppc64 Linux ELF loader Hollis Blanchard
2006-10-14 15:33 ` [PATCH] generic ELF loading Yoshinori K. Okuji
2006-10-14 17:23 ` Tristan Gingold
2006-10-24 20:41 ` Hollis Blanchard
2006-10-24 20:03 ` Hollis Blanchard
2006-10-24 20:48 ` Johan Rydberg
2006-10-24 20:45 ` Hollis Blanchard
2006-10-25 5:53 ` Yoshinori K. Okuji
-- strict thread matches above, loose matches on Subject: below --
2006-10-14 3:03 Mao, Bibo
2006-10-24 20:21 ` Hollis Blanchard
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.