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.


-- 
Best Regards,

Manoel Rebelo Abranches
Software engineer
IBM - Linux Technology Center - Brazil
=== modified file 'ChangeLog'
--- ChangeLog	2010-09-26 14:11:33 +0000
+++ ChangeLog	2010-09-27 09:19:23 +0000
@@ -1,3 +1,14 @@
+2010-09-27  Manoel Rebelo Abranches <mrab...@br.ibm.com>
+	
+	Correct allocate kernel segment and entry point address. That corrects
+	booting of some images, like RHEL and SLES.
+
+	* grub-core/loader/powerpc/ieee1275/linux.c (grub_linux_load32):
+	Allocate the kernel segment of type LOAD  at the PhysAddr address and
+	using alignment in the program header. Also uses ELF header entry point
+	minus PhysAddr as offset to linux main function.
+	(grub_linux_load64): Likewise.
+
 2010-09-26  Robert Millan  <r...@gnu.org>
 
 	Support degraded ZFS arrays in "grub-probe -t device" resolution.

=== 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-09-27 09:03:05 +0000
@@ -102,48 +102,49 @@
 static grub_err_t
 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;
-  if (entry == 0)
-    entry = 0x01400000;
-
-  linux_size = grub_elf32_size (elf, 0);
-  if (linux_size == 0)
-    return grub_errno;
-  /* Pad it; the kernel scribbles over memory beyond its load address.  */
-  linux_size += 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, "couldn't claim memory");
-
-  /* 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)
     {
+      int found_addr = 0;
+      grub_addr_t physaddr;
+
       if (phdr->p_type != PT_LOAD)
-	{
-	  *do_load = 0;
-	  return 0;
+        {
+          *do_load = 0;
+          return 0;
 	}
       *do_load = 1;
 
+      linux_size = grub_elf32_size (elf, 0);
+      if (linux_size == 0)
+        return grub_errno;
+
+      /* Pad it; the kernel scribbles over memory beyond its load address.  */
+      linux_size += 0x10000;
+
       /* 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;
+      physaddr = (phdr->p_paddr & ~ELF32_LOADMASK);
+      if (physaddr == 0)
+        physaddr = 0x01400000;
+
+      /* 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 (*addr = physaddr; *addr < physaddr + 200 * 0x100000; *addr += phdr->p_align)
+        {
+          grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
+		        *addr, linux_size);
+          found_addr = grub_claimmap (*addr, linux_size);
+          if (found_addr != -1)
+	    break;
+        }
+  
+      if (found_addr == -1)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
+
+      linux_addr = elf->ehdr.ehdr32.e_entry - phdr->p_paddr + *addr;
       return 0;
     }
   return grub_elf32_load (elf, offset_phdr, 0, 0);
@@ -152,47 +153,49 @@
 static grub_err_t
 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;
-  if (entry == 0)
-    entry = 0x01400000;
-
-  linux_size = grub_elf64_size (elf, 0);
-  if (linux_size == 0)
-    return grub_errno;
-  /* Pad it; the kernel scribbles over memory beyond its load address.  */
-  linux_size += 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, "couldn't claim memory");
-
-  /* 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)
     {
+      int found_addr = 0;
+      grub_addr_t physaddr;
+
       if (phdr->p_type != PT_LOAD)
-	{
-	  *do_load = 0;
-	  return 0;
+        {
+          *do_load = 0;
+          return 0;
 	}
       *do_load = 1;
+
+      linux_size = grub_elf64_size (elf, 0);
+      if (linux_size == 0)
+        return grub_errno;
+
+      /* Pad it; the kernel scribbles over memory beyond its load address.  */
+      linux_size += 0x10000;
+      
       /* 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;
+      physaddr = (phdr->p_paddr & ~ELF64_LOADMASK);
+      if (physaddr == 0)
+        physaddr = 0x01400000;
+
+      /* 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 (*addr = physaddr; *addr < physaddr + 200 * 0x100000; *addr += phdr->p_align)
+        {
+          grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n",
+		        *addr, linux_size);
+          found_addr = grub_claimmap (*addr, linux_size);
+          if (found_addr != -1)
+	    break;
+        }
+  
+      if (found_addr == -1)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory");
+
+      linux_addr = elf->ehdr.ehdr64.e_entry - phdr->p_paddr + *addr;
       return 0;
     }
   return grub_elf64_load (elf, offset_phdr, 0, 0);

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

Reply via email to