diff options
author | ian <ian@FreeBSD.org> | 2013-02-26 03:24:45 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2013-02-26 03:24:45 +0000 |
commit | d2e4d8580db5e670ed6869f86477e4081350e6e1 (patch) | |
tree | 8bbb78af033867df467a94f798d6e6695a1c4cb5 /sys/boot/common | |
parent | 6eb36900d3b68eef8de23beb09bb58794733617f (diff) | |
download | FreeBSD-src-d2e4d8580db5e670ed6869f86477e4081350e6e1.zip FreeBSD-src-d2e4d8580db5e670ed6869f86477e4081350e6e1.tar.gz |
Adjust the arm kernel entry point address properly regardless of whether the
e_entry field holds a physical or a virtual address. Add a comment block
that explains the assumptions being made by the adjustment code.
Diffstat (limited to 'sys/boot/common')
-rw-r--r-- | sys/boot/common/load_elf.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index e1e6de7..d712b3d 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -290,14 +290,25 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) } else off = 0; #elif defined(__arm__) - if (off & 0xf0000000u) { - off = -(off & 0xf0000000u); - ehdr->e_entry += off; + /* + * The elf headers in some kernels specify virtual addresses in all + * header fields. More recently, the e_entry and p_paddr fields are the + * proper physical addresses. Even when the p_paddr fields are correct, + * the MI code below uses the p_vaddr fields with an offset added for + * loading (doing so is arguably wrong). To make loading work, we need + * an offset that represents the difference between physical and virtual + * addressing. ARM kernels are always linked at 0xC0000000. Depending + * on the headers, the offset value passed in may be physical or virtual + * (because it typically comes from e_entry), but we always replace + * whatever is passed in with the va<->pa offset. On the other hand, we + * only adjust the entry point if it's a virtual address to begin with. + */ + off = -0xc0000000u; + if ((ehdr->e_entry & 0xc0000000u) == 0xc000000u) + ehdr->e_entry += off; #ifdef ELF_VERBOSE - printf("Converted entry 0x%08x\n", ehdr->e_entry); + printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); #endif - } else - off = 0; #else off = 0; /* other archs use direct mapped kernels */ #endif |