[Skiboot] [PATCH v2] Allow ELF executables with function descriptor entrypoint to be skiboot payloads
Benjamin Herrenschmidt
benh at kernel.crashing.org
Thu Jan 29 16:30:45 AEDT 2015
On Tue, 2015-01-27 at 17:00 -0800, Nathan Whitehorn wrote:
> Big-endian ELF64 ELF executables normally (the Linux kernel is an
> exception) have their entry point refer to a function descriptor instead
> of the first instruction. Distinguish between the Linux case and the
> function descriptor case, which is used for the FreeBSD kernel, by
> checking whether the entry point points into an executable section or
> not. This allows use of the FreeBSD kernel as a skiboot payload.
Thanks !
I did a closer review and all I found was a minor style nit,
Stewart can probably fix it up while applying (see below).
Note also that in *theory* there can be ABI v1 LE kernels but
I wouldn't make a fuss here, I doubt that will concern freebsd.
> Signed-off-by: Nathan Whitehorn <nwhitehorn at freebsd.org>
> ---
> core/init.c | 22 ++++++++++++++++++++++
> include/elf.h | 17 +++++++++++++++++
> 2 files changed, 39 insertions(+)
>
> diff --git a/core/init.c b/core/init.c
> index 2c7e30c..e75b5a3 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -111,6 +111,7 @@ static bool try_load_elf64(struct elf_hdr *header)
> struct elf64_hdr *kh = (struct elf64_hdr *)header;
> uint64_t load_base = (uint64_t)kh;
> struct elf64_phdr *ph;
> + struct elf64_shdr *sh;
> unsigned int i;
>
> /* Check it's a ppc64 LE ELF */
> @@ -152,6 +153,27 @@ static bool try_load_elf64(struct elf_hdr *header)
> prerror("INIT: Failed to find kernel entry !\n");
> return false;
> }
> +
> + /* For the normal big-endian ELF ABI, the kernel entry points
> + * to a function descriptor in the data section. Linux instead
> + * has it point directly to code. Test whether it is pointing
> + * into an executable section or not to figure this out. Default
> + * to assuming it obeys the ABI.
> + */
> + sh = (struct elf64_shdr *)(load_base + kh->e_shoff);
> + for (i = 0; i < kh->e_shnum; i++, sh++) {
> + if (sh->sh_addr > kh->e_entry ||
> + (sh->sh_addr + sh->sh_size) <= kh->e_entry)
> + continue;
I would reverse the test polarity and break instead of continuing, thus
avoiding the line below:
> + break;
> + }
> + if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) {
> + kernel_entry = *(uint64_t *)(kernel_entry + load_base);
> + kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset;
> + }
> +
> kernel_entry += load_base;
> kernel_32bit = false;
>
> diff --git a/include/elf.h b/include/elf.h
> index 0a52f3e..c600f7f 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -76,6 +76,23 @@ struct elf64_phdr {
> uint64_t p_align;
> };
>
> +/* 64-bit ELF section header */
> +struct elf64_shdr {
> + uint32_t sh_name;
> + uint32_t sh_type;
> + uint64_t sh_flags;
> +#define ELF_SFLAGS_X 0x4
> +#define ELF_SFLAGS_A 0x2
> +#define ELF_SFLAGS_W 0x1
> + uint64_t sh_addr;
> + uint64_t sh_offset;
> + uint64_t sh_size;
> + uint32_t sh_link;
> + uint32_t sh_info;
> + uint64_t sh_addralign;
> + uint64_t sh_entsize;
> +};
> +
> /* Some relocation related stuff used in relocate.c */
> struct elf64_dyn {
> int64_t d_tag;
>
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
More information about the Skiboot
mailing list