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