Fixed some issues reported by Vladimir:

Initial alignment value 1 instead of 0.
Verify error by returning address being -1 since 0 may be valid in memory allocated directly by the Open Firmware.
Use 'end' instead of (addr + len) to search for available memory.
change hardcoded value '1' to GRUB_MEMORY_AVAILABLE.

On 10/19/2010 11:46 AM, Manoel Rebelo Abraches wrote:
This is another version to the same fix.

The first patch 01_mem.patch creates a new function to allocate memory
using the "available" property in the "memory" node.
The second patch 02_offset.patch correctly finds the linux entry point,
also assumes that more segments can exist (made accordingly with sparc
implementation)

The patch was made passing  -Bbp to diff as suggested by Vladimir.
I tested with RHEL/SUSE images and some RHEL/SUSE kernel I had and
worked correctly. Before the images failed to boot.
Thank you for reviewing this.

On Mon, 2010-09-27 at 04:29 -0300, Manoel Rebelo Abraches wrote:
This Patch loads kernel LOAD segment at the address fixed by PhysAddr
with alignment Align at the ELF program header. Even if this address is
in use other address with the same alignment is found "linuxadr" (since
linux can relocate itself). The linux main function is then find in the
adress linuxaddr + entry + (PhysAddr- Entry), where Entry is  the Entry
point address in the ELF header. (PhysAddr- Entry) gives the offset
where the linux entry point is located after linuxaddr.


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

=== modified file 'grub-core/loader/powerpc/ieee1275/linux.c'
--- grub-core/loader/powerpc/ieee1275/linux.c	2010-09-05 11:05:36 +0000
+++ grub-core/loader/powerpc/ieee1275/linux.c	2010-11-03 19:55:00 +0000
@@ -26,6 +26,7 @@
 #include <grub/ieee1275/ieee1275.h>
 #include <grub/command.h>
 #include <grub/i18n.h>
+#include <grub/memory.h>
 
 #define ELF32_LOADMASK (0xc0000000UL)
 #define ELF64_LOADMASK (0xc000000000000000ULL)
@@ -45,6 +46,51 @@
 typedef void (*kernel_entry_t) (void *, unsigned long, int (void *),
 				unsigned long, unsigned long);
 
+static grub_addr_t
+grub_linux_claimmap_iterate (grub_addr_t target, grub_size_t size,
+			     grub_size_t align)
+{
+  grub_addr_t found_addr = (grub_addr_t) -1;
+
+  auto int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len,
+				       grub_memory_type_t type);
+  int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len,
+				  grub_memory_type_t type)
+  {
+    grub_uint64_t end = addr + len;
+    addr = ALIGN_UP (addr, align);
+    target = ALIGN_UP (target, align);
+
+    /* Target above the memory chunk.  */
+    if (type != GRUB_MEMORY_AVAILABLE || target > end)
+      return 0;
+
+    /* Target inside the memory chunk.  */
+    if (target >= addr && target < end && size <= end - target)
+      {
+	if (grub_claimmap (target, size) == GRUB_ERR_NONE)
+	  {
+	    found_addr = target;
+	    return 1;
+	  }
+      }
+    /* Target below the memory chunk.  */
+    if (target < addr && addr + size <= end)
+      {
+	if (grub_claimmap (addr, size) == GRUB_ERR_NONE)
+	  {
+	    found_addr = addr;
+	    return 1;
+	  }
+      }
+    return 0;
+  }
+
+  grub_machine_mmap_iterate (alloc_mem);
+
+  return found_addr;
+}
+
 static grub_err_t
 grub_linux_boot (void)
 {
@@ -103,7 +149,6 @@
 grub_linux_load32 (grub_elf_t elf)
 {
   Elf32_Addr entry;
-  int found_addr = 0;
 
   /* Linux's entry point incorrectly contains a virtual address.  */
   entry = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK;
@@ -119,15 +164,8 @@
   /* 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)
+  linux_addr = grub_linux_claimmap_iterate (entry, linux_size, 0x100000);
+  if (linux_addr == (grub_addr_t) -1)
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
   /* Now load the segments into the area we claimed.  */
@@ -153,7 +191,6 @@
 grub_linux_load64 (grub_elf_t elf)
 {
   Elf64_Addr entry;
-  int found_addr = 0;
 
   /* Linux's entry point incorrectly contains a virtual address.  */
   entry = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK;
@@ -169,15 +206,8 @@
   /* 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)
+  linux_addr = grub_linux_claimmap_iterate (entry, linux_size, 0x100000);
+  if (linux_addr == (grub_addr_t) -1)
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
   /* Now load the segments into the area we claimed.  */
@@ -287,7 +317,6 @@
   grub_ssize_t size;
   grub_addr_t first_addr;
   grub_addr_t addr;
-  int found_addr = 0;
 
   if (argc == 0)
     {
@@ -311,20 +340,9 @@
 
   /* Attempt to claim at a series of addresses until successful in
      the same way that grub_rescue_cmd_linux does.  */
-  for (addr = first_addr; addr < first_addr + 200 * 0x100000; addr += 0x100000)
-    {
-      grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
-		    addr, size);
-      found_addr = grub_claimmap (addr, size);
-      if (found_addr != -1)
-	break;
-    }
-
-  if (found_addr == -1)
-    {
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot claim memory");
+  addr = grub_linux_claimmap_iterate (first_addr, size, 0x100000);
+  if (addr == (grub_addr_t) -1)
       goto fail;
-    }
 
   grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size);
 

=== modified file 'ChangeLog'
--- ChangeLog	2010-10-26 10:40:35 +0000
+++ ChangeLog	2010-11-03 19:55:14 +0000
@@ -1,3 +1,17 @@
+2010-10-18  Manoel Rebelo Abranches <mrab...@br.ibm.com>
+
+	* include/grub/elfload.h (grub_elf32_size): New parameter. All users updated.
+	Return maximum segments alignment.
+	(grub_elf64_size): Likewise.
+	* kern/elf.c (grub_elf32_size): New parameter. All users updated.
+	Return maximum segments alignment.
+	(grub_elf64_size): Likewise.
+	* grub-core/loader/powerpc/ieee1275/linux.c:
+	(grub_linux_claimmap_iterate): New function. Uses the "available"property 
+	in the "memory" node for memory allocation for kernel in the PowerPC loader.
+	(grub_linux_load32): Correctly find linux entry point offset.
+	(grub_linux_load64): Likewise.
+
 2010-10-26  Vladimir Serbinenko  <phco...@gmail.com>
 
 	* util/grub-setup.c (setup): Refuse to do a cross-disk embeddingless

=== modified file 'grub-core/kern/elf.c'
--- grub-core/kern/elf.c	2010-09-05 11:05:36 +0000
+++ grub-core/kern/elf.c	2010-11-03 19:55:14 +0000
@@ -171,11 +171,12 @@
 
 /* Calculate the amount of memory spanned by the segments.  */
 grub_size_t
-grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
+grub_elf32_size (grub_elf_t elf, Elf32_Addr *base, grub_uint32_t *max_align)
 {
   Elf32_Addr segments_start = (Elf32_Addr) -1;
   Elf32_Addr segments_end = 0;
   int nr_phdrs = 0;
+  grub_uint32_t curr_align = 1;
 
   /* Run through the program headers to calculate the total memory size we
    * should claim.  */
@@ -192,6 +193,8 @@
 	segments_start = phdr->p_paddr;
       if (phdr->p_paddr + phdr->p_memsz > segments_end)
 	segments_end = phdr->p_paddr + phdr->p_memsz;
+      if (curr_align < phdr->p_align)
+	curr_align = phdr->p_align;
       return 0;
     }
 
@@ -215,7 +218,8 @@
 
   if (base)
     *base = segments_start;
-
+  if (max_align)
+    *max_align = curr_align;
   return segments_end - segments_start;
 }
 
@@ -357,11 +360,12 @@
 
 /* Calculate the amount of memory spanned by the segments.  */
 grub_size_t
-grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
+grub_elf64_size (grub_elf_t elf, Elf64_Addr *base, grub_uint64_t *max_align)
 {
   Elf64_Addr segments_start = (Elf64_Addr) -1;
   Elf64_Addr segments_end = 0;
   int nr_phdrs = 0;
+  grub_uint64_t curr_align = 1;
 
   /* Run through the program headers to calculate the total memory size we
    * should claim.  */
@@ -378,6 +382,8 @@
 	segments_start = phdr->p_paddr;
       if (phdr->p_paddr + phdr->p_memsz > segments_end)
 	segments_end = phdr->p_paddr + phdr->p_memsz;
+      if (curr_align < phdr->p_align)
+	curr_align = phdr->p_align;
       return 0;
     }
 
@@ -401,7 +407,8 @@
 
   if (base)
     *base = segments_start;
-
+  if (max_align)
+    *max_align = curr_align;
   return segments_end - segments_start;
 }
 

=== modified file 'grub-core/loader/mips/linux.c'
--- grub-core/loader/mips/linux.c	2010-09-18 22:04:31 +0000
+++ grub-core/loader/mips/linux.c	2010-11-03 19:55:14 +0000
@@ -83,7 +83,7 @@
   /* Linux's entry point incorrectly contains a virtual address.  */
   entry_addr = elf->ehdr.ehdr32.e_entry;
 
-  linux_size = grub_elf32_size (elf, &base);
+  linux_size = grub_elf32_size (elf, &base, 0);
   if (linux_size == 0)
     return grub_errno;
   target_addr = base;
@@ -138,7 +138,7 @@
   /* Linux's entry point incorrectly contains a virtual address.  */
   entry_addr = elf->ehdr.ehdr64.e_entry;
 
-  linux_size = grub_elf64_size (elf, &base);
+  linux_size = grub_elf64_size (elf, &base, 0);
   if (linux_size == 0)
     return grub_errno;
   target_addr = base;

=== modified file 'grub-core/loader/powerpc/ieee1275/linux.c'
--- grub-core/loader/powerpc/ieee1275/linux.c	2010-11-03 19:55:00 +0000
+++ grub-core/loader/powerpc/ieee1275/linux.c	2010-11-03 19:55:14 +0000
@@ -148,26 +148,30 @@
 static grub_err_t
 grub_linux_load32 (grub_elf_t elf)
 {
-  Elf32_Addr entry;
+  Elf32_Addr base_addr;
+  grub_addr_t seg_addr;
+  grub_uint32_t align;
+  int offset;
 
-  /* Linux's entry point incorrectly contains a virtual address.  */
-  entry = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK;
-  if (entry == 0)
-    entry = 0x01400000;
-
-  linux_size = grub_elf32_size (elf, 0);
+  linux_size = grub_elf32_size (elf, &base_addr, &align);
   if (linux_size == 0)
     return grub_errno;
   /* Pad it; the kernel scribbles over memory beyond its load address.  */
   linux_size += 0x100000;
 
+  offset = elf->ehdr.ehdr32.e_entry - base_addr;
+  /* Linux's incorrectly contains a virtual address.  */
+  base_addr &= ~ELF32_LOADMASK;
+
   /* 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.  */
-  linux_addr = grub_linux_claimmap_iterate (entry, linux_size, 0x100000);
-  if (linux_addr == (grub_addr_t) -1)
+  seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF32_LOADMASK, linux_size, align);
+  if (seg_addr == (grub_addr_t) -1)
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
+  linux_addr = seg_addr + offset;
+
   /* Now load the segments into the area we claimed.  */
   auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load);
   grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load)
@@ -179,9 +183,7 @@
 	}
       *do_load = 1;
 
-      /* Linux's program headers incorrectly contain virtual addresses.
-       * Translate those to physical, and offset to the area we claimed.  */
-      *addr = (phdr->p_paddr & ~ELF32_LOADMASK) + linux_addr;
+      *addr = (phdr->p_paddr - base_addr) + seg_addr;
       return 0;
     }
   return grub_elf32_load (elf, offset_phdr, 0, 0);
@@ -190,26 +192,30 @@
 static grub_err_t
 grub_linux_load64 (grub_elf_t elf)
 {
-  Elf64_Addr entry;
-
-  /* Linux's entry point incorrectly contains a virtual address.  */
-  entry = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK;
-  if (entry == 0)
-    entry = 0x01400000;
+  Elf64_Addr base_addr;
+  grub_addr_t seg_addr;
+  grub_uint64_t align;
+  int offset;
 
-  linux_size = grub_elf64_size (elf, 0);
+  linux_size = grub_elf64_size (elf, &base_addr, &align);
   if (linux_size == 0)
     return grub_errno;
   /* Pad it; the kernel scribbles over memory beyond its load address.  */
   linux_size += 0x100000;
 
+  offset = elf->ehdr.ehdr64.e_entry - base_addr;
+  /* Linux's incorrectly contains a virtual address.  */
+  base_addr &= ~ELF64_LOADMASK;
+
   /* 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.  */
-  linux_addr = grub_linux_claimmap_iterate (entry, linux_size, 0x100000);
-  if (linux_addr == (grub_addr_t) -1)
+  seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF64_LOADMASK, linux_size, align);
+  if (seg_addr == (grub_addr_t) -1)
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
 
+  linux_addr = seg_addr + offset;
+
   /* Now load the segments into the area we claimed.  */
   auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load);
   grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load)
@@ -220,9 +226,8 @@
 	  return 0;
 	}
       *do_load = 1;
-      /* Linux's program headers incorrectly contain virtual addresses.
-       * Translate those to physical, and offset to the area we claimed.  */
-      *addr = (phdr->p_paddr & ~ELF64_LOADMASK) + linux_addr;
+
+      *addr = (phdr->p_paddr - base_addr) + seg_addr;
       return 0;
     }
   return grub_elf64_load (elf, offset_phdr, 0, 0);

=== modified file 'grub-core/loader/sparc64/ieee1275/linux.c'
--- grub-core/loader/sparc64/ieee1275/linux.c	2010-09-18 22:04:31 +0000
+++ grub-core/loader/sparc64/ieee1275/linux.c	2010-11-03 19:55:14 +0000
@@ -247,7 +247,7 @@
   linux_entry = elf->ehdr.ehdr64.e_entry;
   linux_addr = 0x40004000;
   off = 0x4000;
-  linux_size = grub_elf64_size (elf, 0);
+  linux_size = grub_elf64_size (elf, 0, 0);
   if (linux_size == 0)
     return grub_errno;
 

=== modified file 'include/grub/elfload.h'
--- include/grub/elfload.h	2010-01-20 10:48:36 +0000
+++ include/grub/elfload.h	2010-11-03 19:55:14 +0000
@@ -46,12 +46,12 @@
 grub_err_t grub_elf_close (grub_elf_t);
 
 int grub_elf_is_elf32 (grub_elf_t);
-grub_size_t grub_elf32_size (grub_elf_t, Elf32_Addr *);
+grub_size_t grub_elf32_size (grub_elf_t, Elf32_Addr *, grub_uint32_t *);
 grub_err_t grub_elf32_load (grub_elf_t, grub_elf32_load_hook_t, grub_addr_t *,
 			    grub_size_t *);
 
 int grub_elf_is_elf64 (grub_elf_t);
-grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *);
+grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *, grub_uint64_t *);
 grub_err_t grub_elf64_load (grub_elf_t, grub_elf64_load_hook_t, grub_addr_t *,
 			    grub_size_t *);
 grub_err_t

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to