2010-11-08 Manoel Rebelo Abranches <mrabran@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.
This commit is contained in:
parent
d2bf06bf34
commit
9c4cf53bfe
6 changed files with 110 additions and 67 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2010-11-08 Manoel Rebelo Abranches <mrabran@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-11-07 Robert Millan <rmh@gnu.org>
|
||||
|
||||
On mips-yeeloong, build with -march=loongson2f when this flag is
|
||||
|
|
|
@ -171,11 +171,12 @@ grub_elf32_phdr_iterate (grub_elf_t elf,
|
|||
|
||||
/* 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 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
|
|||
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 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
|
|||
|
||||
if (base)
|
||||
*base = segments_start;
|
||||
|
||||
if (max_align)
|
||||
*max_align = curr_align;
|
||||
return segments_end - segments_start;
|
||||
}
|
||||
|
||||
|
@ -290,7 +294,6 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 64-bit */
|
||||
|
||||
|
@ -357,16 +360,17 @@ grub_elf64_phdr_iterate (grub_elf_t elf,
|
|||
|
||||
/* 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. */
|
||||
auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
|
||||
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
|
||||
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
|
||||
Elf64_Phdr *phdr,
|
||||
void *_arg __attribute__ ((unused)))
|
||||
{
|
||||
|
@ -378,6 +382,8 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
|
|||
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,11 +407,11 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
|
|||
|
||||
if (base)
|
||||
*base = segments_start;
|
||||
|
||||
if (max_align)
|
||||
*max_align = curr_align;
|
||||
return segments_end - segments_start;
|
||||
}
|
||||
|
||||
|
||||
/* Load every loadable segment into memory specified by `_load_hook'. */
|
||||
grub_err_t
|
||||
grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
|
||||
|
|
|
@ -91,7 +91,7 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size)
|
|||
/* 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;
|
||||
|
@ -146,7 +146,7 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size)
|
|||
/* 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;
|
||||
|
|
|
@ -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 @@ static char *linux_args;
|
|||
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)
|
||||
{
|
||||
|
@ -102,34 +148,30 @@ grub_linux_unload (void)
|
|||
static grub_err_t
|
||||
grub_linux_load32 (grub_elf_t elf)
|
||||
{
|
||||
Elf32_Addr entry;
|
||||
int found_addr = 0;
|
||||
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. */
|
||||
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)
|
||||
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)
|
||||
|
@ -141,9 +183,7 @@ grub_linux_load32 (grub_elf_t elf)
|
|||
}
|
||||
*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);
|
||||
|
@ -152,34 +192,30 @@ grub_linux_load32 (grub_elf_t elf)
|
|||
static grub_err_t
|
||||
grub_linux_load64 (grub_elf_t elf)
|
||||
{
|
||||
Elf64_Addr entry;
|
||||
int found_addr = 0;
|
||||
Elf64_Addr base_addr;
|
||||
grub_addr_t seg_addr;
|
||||
grub_uint64_t align;
|
||||
int offset;
|
||||
|
||||
/* 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);
|
||||
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. */
|
||||
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)
|
||||
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)
|
||||
|
@ -190,9 +226,8 @@ grub_linux_load64 (grub_elf_t elf)
|
|||
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);
|
||||
|
@ -287,7 +322,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_ssize_t size;
|
||||
grub_addr_t first_addr;
|
||||
grub_addr_t addr;
|
||||
int found_addr = 0;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
|
@ -311,20 +345,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
/* 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");
|
||||
goto fail;
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ grub_linux_load64 (grub_elf_t elf)
|
|||
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;
|
||||
|
||||
|
|
|
@ -46,12 +46,12 @@ grub_elf_t grub_elf_file (grub_file_t);
|
|||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue