From: H. Peter Anvin Date: Mon, 4 May 2009 01:35:46 +0000 (-0700) Subject: mboot: handle ELF Multiboot kernel where paddr != vaddr X-Git-Tag: syslinux-3.80~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=de1ecabd369a2105f7822f4f8be10fb1937b9f86;p=profile%2Fivi%2Fsyslinux.git mboot: handle ELF Multiboot kernel where paddr != vaddr The way Grub handles ELF Multiboot kernels where paddr != vaddr is to load at the paddr, but to also adjust the entry point (e_entry) so that the previous vaddr becomes a paddr. Since the Multiboot spec is pretty much "Grub wins", follow this behavior. Signed-off-by: H. Peter Anvin --- diff --git a/com32/mboot/map.c b/com32/mboot/map.c index a84fc23..15e3a28 100644 --- a/com32/mboot/map.c +++ b/com32/mboot/map.c @@ -161,19 +161,26 @@ int map_image(void *ptr, size_t len) * useless, but at least Solaris apparently depends on this behavior. */ if (eh && !(opt.aout && mbh_len && (mbh->flags & MULTIBOOT_AOUT_KLUDGE))) { - regs.eip = eh->e_entry; + regs.eip = eh->e_entry; /* Can be overridden further down... */ ph = (Elf32_Phdr *)(cptr+eh->e_phoff); for (i = 0; i < eh->e_phnum; i++) { if (ph->p_type == PT_LOAD || ph->p_type == PT_PHDR) { - /* This loads at p_paddr, which is arguably the correct semantics. - The SysV spec says that SysV loads at p_vaddr (and thus Linux does, - too); that is, however, a major brainfuckage in the spec. */ + /* + * This loads at p_paddr, which matches Grub. However, if + * e_entry falls within the p_vaddr range of this PHDR, then + * adjust it to match the p_paddr range... this is how Grub + * behaves, so it's by definition correct (it doesn't have to + * make sense...) + */ addr_t addr = ph->p_paddr; addr_t msize = ph->p_memsz; addr_t dsize = min(msize, ph->p_filesz); + if (eh->e_entry >= ph->p_vaddr && eh->e_entry < ph->p_vaddr + msize) + regs.eip = eh->e_entry + (ph->p_paddr - ph->p_vaddr); + dprintf("Segment at 0x%08x data 0x%08x len 0x%08x\n", addr, dsize, msize);