=== 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 + + 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 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);