Changeset View
Standalone View
stand/common/load_elf.c
Show First 20 Lines • Show All 449 Lines • ▼ Show 20 Lines | __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off) | ||||
Elf_Sym sym; | Elf_Sym sym; | ||||
Elf_Addr p_start, p_end; | Elf_Addr p_start, p_end; | ||||
dp = NULL; | dp = NULL; | ||||
shdr = NULL; | shdr = NULL; | ||||
ret = 0; | ret = 0; | ||||
firstaddr = lastaddr = 0; | firstaddr = lastaddr = 0; | ||||
ehdr = ef->ehdr; | ehdr = ef->ehdr; | ||||
#ifdef __powerpc__ | |||||
if (ef->kernel) { | |||||
#else | |||||
if (ehdr->e_type == ET_EXEC) { | if (ehdr->e_type == ET_EXEC) { | ||||
#endif | |||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
#if __ELF_WORD_SIZE == 64 | #if __ELF_WORD_SIZE == 64 | ||||
/* x86_64 relocates after locore */ | /* x86_64 relocates after locore */ | ||||
off = - (off & 0xffffffffff000000ull); | off = - (off & 0xffffffffff000000ull); | ||||
#else | #else | ||||
/* i386 relocates after locore */ | /* i386 relocates after locore */ | ||||
off = - (off & 0xff000000u); | off = - (off & 0xff000000u); | ||||
#endif | #endif | ||||
#elif defined(__powerpc__) | #elif defined(__powerpc__) | ||||
/* | /* | ||||
* On the purely virtual memory machines like e500, the kernel | * On the purely virtual memory machines like e500, the kernel | ||||
* is linked against its final VA range, which is most often | * is linked against its final VA range, which is most often | ||||
* not available at the loader stage, but only after kernel | * not available at the loader stage, but only after kernel | ||||
* initializes and completes its VM settings. In such cases we | * initializes and completes its VM settings. In such cases we | ||||
* cannot use p_vaddr field directly to load ELF segments, but | * cannot use p_vaddr field directly to load ELF segments, but | ||||
* put them at some 'load-time' locations. | * put them at some 'load-time' locations. | ||||
*/ | */ | ||||
if (off & 0xf0000000u) { | if (off & 0xf0000000u) { | ||||
jhibbits: I don't think this block should really be here, but I'm not sure enough to remove it. Since… | |||||
off = -(off & 0xf0000000u); | off = -(off & 0xf0000000u); | ||||
/* | /* | ||||
* XXX the physical load address should not be | * XXX the physical load address should not be | ||||
* hardcoded. Note that the Book-E kernel assumes that | * hardcoded. Note that the Book-E kernel assumes that | ||||
* it's loaded at a 16MB boundary for now... | * it's loaded at a 16MB boundary for now... | ||||
*/ | */ | ||||
off += 0x01000000; | off += 0x01000000; | ||||
} | |||||
ehdr->e_entry += off; | ehdr->e_entry += off; | ||||
Not Done Inline Actionsand why not adjust it here? imp: and why not adjust it here? | |||||
Done Inline ActionsLook above and you see this block is for type ET_EXEC. PowerPC kernels are ET_DYN now. This block looks really weird, and I would love to remove it. Not sure if we can, though, because I don't know if any "supported" older release kernels are being booted with a modern loader. Otherwise, yes, I could muck with the condition above and muck with this as well. Or completely remove this block for PowerPC, and do the work below where I added, only. jhibbits: Look above and you see this block is for type ET_EXEC. PowerPC kernels are ET_DYN now. This… | |||||
#ifdef ELF_VERBOSE | #ifdef ELF_VERBOSE | ||||
printf("Converted entry 0x%jx\n", (uintmax_t)ehdr->e_entry); | printf("Converted entry 0x%jx\n", (uintmax_t)ehdr->e_entry); | ||||
#endif | #endif | ||||
} else | |||||
off = 0; | |||||
#elif defined(__arm__) && !defined(EFI) | #elif defined(__arm__) && !defined(EFI) | ||||
/* | /* | ||||
* The elf headers in arm kernels specify virtual addresses in | * The elf headers in arm kernels specify virtual addresses in | ||||
* all header fields, even the ones that should be physical | * all header fields, even the ones that should be physical | ||||
* addresses. We assume the entry point is in the first page, | * addresses. We assume the entry point is in the first page, | ||||
* and masking the page offset will leave us with the virtual | * and masking the page offset will leave us with the virtual | ||||
* address the kernel was linked at. We subtract that from the | * address the kernel was linked at. We subtract that from the | ||||
* load offset, making 'off' into the value which, when added | * load offset, making 'off' into the value which, when added | ||||
Show All 14 Lines | #ifdef ELF_VERBOSE | ||||
printf("ehdr->e_entry 0x%jx, va<->pa off %llx\n", | printf("ehdr->e_entry 0x%jx, va<->pa off %llx\n", | ||||
(uintmax_t)ehdr->e_entry, off); | (uintmax_t)ehdr->e_entry, off); | ||||
#endif | #endif | ||||
#else | #else | ||||
off = 0; /* other archs use direct mapped kernels */ | off = 0; /* other archs use direct mapped kernels */ | ||||
#endif | #endif | ||||
} | } | ||||
ef->off = off; | ef->off = off; | ||||
Not Done Inline ActionsThis should move up to where I tagged it above (though maybe not in that if) since we already have a powerpc ifdef there. imp: This should move up to where I tagged it above (though maybe not in that if) since we already… | |||||
Not Done Inline ActionsOkay, that's two of us who thought this needed to move up. We were wrong, but clearly the current code structure is going to fool people. Maybe it would be better to move this block up so that the overall structure is: if (ehdr->e_type == ET_DYN) { #ifdef powerpc // new stuff #endif } else if (ehdr->e_type == ET_EXEC) { // existing stuff } ian: Okay, that's two of us who thought this needed to move up. We were wrong, but clearly the… | |||||
Not Done Inline Actionsor just make it an else if here for the new stuff. but why then is this powerpc specific if other platforms aren't currently doing it? Will there be harm to them? imp: or just make it an else if here for the new stuff.
but why then is this powerpc specific if… | |||||
if (ef->kernel) | if (ef->kernel) | ||||
__elfN(relocation_offset) = off; | __elfN(relocation_offset) = off; | ||||
if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { | if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { | ||||
printf("elf" __XSTRING(__ELF_WORD_SIZE) | printf("elf" __XSTRING(__ELF_WORD_SIZE) | ||||
"_loadimage: program header not within first page\n"); | "_loadimage: program header not within first page\n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 696 Lines • Show Last 20 Lines |
I don't think this block should really be here, but I'm not sure enough to remove it. Since the current idea is that we typically load in the first 256MB, I don't see a problem enough to fix it.