[2008] 2009-02-27 Robert Millan <[email protected]>

Robert Millan <[email protected]>
Newsgroups gmane.comp.boot-loaders.grub.cvs
Message-ID <[email protected]>
Revision: 2008
          http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=2008
Author:   robertmh
Date:     2009-02-27 23:04:46 +0000 (Fri, 27 Feb 2009)
Log Message:
-----------
2009-02-27  Robert Millan  <[email protected]>

        Factorize elf32 / elf64 code in Multiboot loader.  This will
        prevent it from getting out of sync again.

        * loader/i386/multiboot.c (grub_multiboot_is_elf32,
        grub_multiboot_load_elf32, grub_multiboot_is_elf64,
        grub_multiboot_load_elf64): Move from here ...
        * loader/i386/multiboot_elfxx.c (grub_multiboot_is_elf,
        grub_multiboot_load_elf): ... to here (new file).

Modified Paths:
--------------
    trunk/grub2/ChangeLog
    trunk/grub2/loader/i386/multiboot.c

Added Paths:
-----------
    trunk/grub2/loader/i386/multiboot_elfxx.c

Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog	2009-02-27 21:37:07 UTC (rev 2007)
+++ trunk/grub2/ChangeLog	2009-02-27 23:04:46 UTC (rev 2008)
@@ -1,5 +1,16 @@
 2009-02-27  Robert Millan  <[email protected]>
 
+	Factorize elf32 / elf64 code in Multiboot loader.  This will
+	prevent it from getting out of sync again.
+
+	* loader/i386/multiboot.c (grub_multiboot_is_elf32,
+	grub_multiboot_load_elf32, grub_multiboot_is_elf64,
+	grub_multiboot_load_elf64): Move from here ...
+	* loader/i386/multiboot_elfxx.c (grub_multiboot_is_elf,
+	grub_multiboot_load_elf): ... to here (new file).
+
+2009-02-27  Robert Millan  <[email protected]>
+
 	* util/grub.d/10_linux.in: Rename "single-user mode" to
 	"recovery mode".
 

Modified: trunk/grub2/loader/i386/multiboot.c
===================================================================
--- trunk/grub2/loader/i386/multiboot.c	2009-02-27 21:37:07 UTC (rev 2007)
+++ trunk/grub2/loader/i386/multiboot.c	2009-02-27 23:04:46 UTC (rev 2008)
@@ -124,181 +124,14 @@
   grub_machine_mmap_iterate (hook);
 }
 
-/* Check if BUFFER contains ELF32.  */
-static int
-grub_multiboot_is_elf32 (void *buffer)
-{
-  Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
+#define MULTIBOOT_LOAD_ELF64
+#include "multiboot_elfxx.c"
+#undef MULTIBOOT_LOAD_ELF64
 
-  return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
-}
+#define MULTIBOOT_LOAD_ELF32
+#include "multiboot_elfxx.c"
+#undef MULTIBOOT_LOAD_ELF32
 
-static grub_err_t
-grub_multiboot_load_elf32 (grub_file_t file, void *buffer)
-{
-  Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer;
-  char *phdr_base;
-  int lowest_segment = 0, highest_segment = 0;
-  int i;
-
-  if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
-    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
-
-  if (grub_dl_check_header (ehdr, sizeof(Elf32_Ehdr)))
-    return grub_error (GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
-
-  if (ehdr->e_type != ET_EXEC)
-    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
-
-  /* FIXME: Should we support program headers at strange locations?  */
-  if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
-    return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
-
-  phdr_base = (char *) buffer + ehdr->e_phoff;
-#define phdr(i)			((Elf32_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
-
-  for (i = 0; i < ehdr->e_phnum; i++)
-    if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
-      {
-	if (phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr)
-	  lowest_segment = i;
-	if (phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
-	  highest_segment = i;
-      }
-  grub_multiboot_payload_size += (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
-  grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
-
-  playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
-  if (! playground)
-    return grub_errno;
-
-  grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward);
-
-  /* Load every loadable segment in memory.  */
-  for (i = 0; i < ehdr->e_phnum; i++)
-    {
-      if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
-        {
-	  char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr));
-
-	  grub_dprintf ("multiboot_loader", "segment %d: paddr=%p, memsz=0x%x\n",
-			i, (void *) phdr(i)->p_paddr, phdr(i)->p_memsz);
-
-	  if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
-	      == (grub_off_t) -1)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "invalid offset in program header");
-
-          if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
-              != (grub_ssize_t) phdr(i)->p_filesz)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "couldn't read segment from file");
-
-          if (phdr(i)->p_filesz < phdr(i)->p_memsz)
-            grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
-			 phdr(i)->p_memsz - phdr(i)->p_filesz);
-        }
-    }
-
-  grub_multiboot_payload_entry_offset = ehdr->e_entry - phdr(lowest_segment)->p_vaddr;
-
-#undef phdr
-
-  return grub_errno;
-}
-
-/* Check if BUFFER contains ELF64.  */
-static int
-grub_multiboot_is_elf64 (void *buffer)
-{
-  Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
-
-  return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
-}
-
-static grub_err_t
-grub_multiboot_load_elf64 (grub_file_t file, void *buffer)
-{
-  Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
-  char *phdr_base;
-  grub_addr_t physical_entry_addr = 0;
-  int i;
-
-  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
-    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
-
-  if (ehdr->e_ident[EI_MAG0] != ELFMAG0
-      || ehdr->e_ident[EI_MAG1] != ELFMAG1
-      || ehdr->e_ident[EI_MAG2] != ELFMAG2
-      || ehdr->e_ident[EI_MAG3] != ELFMAG3
-      || ehdr->e_version != EV_CURRENT
-      || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
-      || ehdr->e_machine != EM_X86_64)
-    return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
-
-  if (ehdr->e_type != ET_EXEC)
-    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
-
-  /* FIXME: Should we support program headers at strange locations?  */
-  if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
-    return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
-
-  /* We still in 32-bit mode */
-  if (ehdr->e_entry > 0xffffffff)
-    return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64");
-
-  entry = ehdr->e_entry;
-
-  phdr_base = (char *) buffer + ehdr->e_phoff;
-#define phdr(i)			((Elf64_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
-
-  /* Load every loadable segment in memory.  */
-  for (i = 0; i < ehdr->e_phnum; i++)
-    {
-      if (phdr(i)->p_type == PT_LOAD)
-        {
-          /* The segment should fit in the area reserved for the OS.  */
-          if (phdr(i)->p_paddr < (grub_uint64_t) grub_os_area_addr)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
-			       phdr(i)->p_paddr, (grub_uint64_t) grub_os_area_addr);
-          if (phdr(i)->p_paddr + phdr(i)->p_memsz
-		  > (grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
-			       phdr(i)->p_paddr + phdr(i)->p_memsz,
-			       (grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size);
-
-	  if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
-	      == (grub_off_t) -1)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "invalid offset in program header");
-
-	  if (grub_file_read (file, (void *) ((grub_uint32_t) phdr(i)->p_paddr),
-			      phdr(i)->p_filesz)
-              != (grub_ssize_t) phdr(i)->p_filesz)
-	    return grub_error (GRUB_ERR_BAD_OS,
-			       "couldn't read segment from file");
-
-          if (phdr(i)->p_filesz < phdr(i)->p_memsz)
-	    grub_memset (((char *) ((grub_uint32_t) phdr(i)->p_paddr)
-			  + phdr(i)->p_filesz),
-			 0,
-			 phdr(i)->p_memsz - phdr(i)->p_filesz);
-
-	  if ((entry >= phdr(i)->p_vaddr) &&
-	      (entry < phdr(i)->p_vaddr + phdr(i)->p_memsz))
-	    physical_entry_addr = entry + phdr(i)->p_paddr - phdr(i)->p_vaddr;
-        }
-    }
-#undef phdr
-
-  if (physical_entry_addr)
-    entry = physical_entry_addr;
-
-  return grub_errno;
-}
-
 /* Load ELF32 or ELF64.  */
 static grub_err_t
 grub_multiboot_load_elf (grub_file_t file, void *buffer)
@@ -460,7 +293,7 @@
 
   grub_multiboot_payload_size = ALIGN_UP (grub_multiboot_payload_size, MULTIBOOT_INFO_ALIGN);
 
-  mbi = grub_multiboot_payload_orig + grub_multiboot_payload_size - mmap_length - sizeof (struct grub_multiboot_info);
+  mbi = (void *) (grub_multiboot_payload_orig + grub_multiboot_payload_size - mmap_length - sizeof (struct grub_multiboot_info));
   grub_memset (mbi, 0, sizeof (struct grub_multiboot_info));
   mbi->mmap_length = mmap_length;
       

Added: trunk/grub2/loader/i386/multiboot_elfxx.c
===================================================================
--- trunk/grub2/loader/i386/multiboot_elfxx.c	                        (rev 0)
+++ trunk/grub2/loader/i386/multiboot_elfxx.c	2009-02-27 23:04:46 UTC (rev 2008)
@@ -0,0 +1,137 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009  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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(MULTIBOOT_LOAD_ELF32)
+# define XX		32
+# define E_MACHINE	EM_386
+# define ELFCLASSXX	ELFCLASS32
+# define Elf_Ehdr	Elf32_Ehdr
+# define Elf_Phdr	Elf32_Phdr
+#elif defined(MULTIBOOT_LOAD_ELF64)
+# define XX		64
+# define E_MACHINE	EM_X86_64
+# define ELFCLASSXX	ELFCLASS64
+# define Elf_Ehdr	Elf64_Ehdr
+# define Elf_Phdr	Elf64_Phdr
+#else
+#error "I'm confused"
+#endif
+
+#define CONCAT(a,b)	CONCAT_(a, b)
+#define CONCAT_(a,b)	a ## b
+
+/* Check if BUFFER contains ELF32 (or ELF64).  */
+static int
+CONCAT(grub_multiboot_is_elf, XX) (void *buffer)
+{
+  Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
+
+  return ehdr->e_ident[EI_CLASS] == ELFCLASSXX;
+}
+
+static grub_err_t
+CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer)
+{
+  Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer;
+  char *phdr_base;
+  int lowest_segment = 0, highest_segment = 0;
+  int i;
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX)
+    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
+
+  if (ehdr->e_ident[EI_MAG0] != ELFMAG0
+      || ehdr->e_ident[EI_MAG1] != ELFMAG1
+      || ehdr->e_ident[EI_MAG2] != ELFMAG2
+      || ehdr->e_ident[EI_MAG3] != ELFMAG3
+      || ehdr->e_version != EV_CURRENT
+      || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
+      || ehdr->e_machine != E_MACHINE)
+    return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
+
+  if (ehdr->e_type != ET_EXEC)
+    return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
+
+  /* FIXME: Should we support program headers at strange locations?  */
+  if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
+    return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
+
+#ifdef MULTIBOOT_LOAD_ELF64
+  /* We still in 32-bit mode.  */
+  if (ehdr->e_entry > 0xffffffff)
+    return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64");
+#endif
+
+  phdr_base = (char *) buffer + ehdr->e_phoff;
+#define phdr(i)			((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
+
+  for (i = 0; i < ehdr->e_phnum; i++)
+    if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
+      {
+	if (phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr)
+	  lowest_segment = i;
+	if (phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
+	  highest_segment = i;
+      }
+  grub_multiboot_payload_size += (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
+  grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
+
+  playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
+  if (! playground)
+    return grub_errno;
+
+  grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward);
+
+  /* Load every loadable segment in memory.  */
+  for (i = 0; i < ehdr->e_phnum; i++)
+    {
+      if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0)
+        {
+	  char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (long) (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr));
+
+	  grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx\n",
+			i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz);
+
+	  if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
+	      == (grub_off_t) -1)
+	    return grub_error (GRUB_ERR_BAD_OS,
+			       "invalid offset in program header");
+
+          if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
+              != (grub_ssize_t) phdr(i)->p_filesz)
+	    return grub_error (GRUB_ERR_BAD_OS,
+			       "couldn't read segment from file");
+
+          if (phdr(i)->p_filesz < phdr(i)->p_memsz)
+            grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
+			 phdr(i)->p_memsz - phdr(i)->p_filesz);
+        }
+    }
+
+  grub_multiboot_payload_entry_offset = ehdr->e_entry - phdr(lowest_segment)->p_vaddr;
+
+#undef phdr
+
+  return grub_errno;
+}
+
+#undef XX
+#undef E_MACHINE
+#undef ELFCLASSXX
+#undef Elf_Ehdr
+#undef Elf_Phdr
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.