Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea46a13e authored by Sven Schnelle's avatar Sven Schnelle Committed by Helge Deller
Browse files

kexec_elf: support 32 bit ELF files



The powerpc version only supported 64 bit. Add some
code to switch decoding of fields during runtime so
we can kexec a 32 bit kernel from a 64 bit kernel and
vice versa.

Signed-off-by: default avatarSven Schnelle <svens@stackframe.org>
Reviewed-by: default avatarThiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent 571ceb7d
Loading
Loading
Loading
Loading
+42 −15
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@
#include <linux/slab.h>
#include <linux/types.h>

#define elf_addr_to_cpu	elf64_to_cpu

static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
{
	return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
@@ -152,9 +150,6 @@ static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
	ehdr->e_type      = elf16_to_cpu(ehdr, buf_ehdr->e_type);
	ehdr->e_machine   = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
	ehdr->e_version   = elf32_to_cpu(ehdr, buf_ehdr->e_version);
	ehdr->e_entry     = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry);
	ehdr->e_phoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff);
	ehdr->e_shoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff);
	ehdr->e_flags     = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
	ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
	ehdr->e_phnum     = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
@@ -162,6 +157,24 @@ static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
	ehdr->e_shnum     = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);

	switch (ehdr->e_ident[EI_CLASS]) {
	case ELFCLASS64:
		ehdr->e_entry = elf64_to_cpu(ehdr, buf_ehdr->e_entry);
		ehdr->e_phoff = elf64_to_cpu(ehdr, buf_ehdr->e_phoff);
		ehdr->e_shoff = elf64_to_cpu(ehdr, buf_ehdr->e_shoff);
		break;

	case ELFCLASS32:
		ehdr->e_entry = elf32_to_cpu(ehdr, buf_ehdr->e_entry);
		ehdr->e_phoff = elf32_to_cpu(ehdr, buf_ehdr->e_phoff);
		ehdr->e_shoff = elf32_to_cpu(ehdr, buf_ehdr->e_shoff);
		break;

	default:
		pr_debug("Unknown ELF class.\n");
		return -EINVAL;
	}

	return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
}

@@ -192,6 +205,7 @@ static int elf_read_phdr(const char *buf, size_t len,
{
	/* Override the const in proghdrs, we are the ones doing the loading. */
	struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
	const struct elfhdr *ehdr = elf_info->ehdr;
	const char *pbuf;
	struct elf_phdr *buf_phdr;

@@ -199,18 +213,31 @@ static int elf_read_phdr(const char *buf, size_t len,
	buf_phdr = (struct elf_phdr *) pbuf;

	phdr->p_type   = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
	phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset);
	phdr->p_paddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr);
	phdr->p_vaddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr);
	phdr->p_flags  = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);

	/*
	 * The following fields have a type equivalent to Elf_Addr
	 * both in 32 bit and 64 bit ELF.
	 */
	phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
	phdr->p_memsz  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
	phdr->p_align  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
	switch (ehdr->e_ident[EI_CLASS]) {
	case ELFCLASS64:
		phdr->p_offset = elf64_to_cpu(ehdr, buf_phdr->p_offset);
		phdr->p_paddr  = elf64_to_cpu(ehdr, buf_phdr->p_paddr);
		phdr->p_vaddr  = elf64_to_cpu(ehdr, buf_phdr->p_vaddr);
		phdr->p_filesz = elf64_to_cpu(ehdr, buf_phdr->p_filesz);
		phdr->p_memsz  = elf64_to_cpu(ehdr, buf_phdr->p_memsz);
		phdr->p_align  = elf64_to_cpu(ehdr, buf_phdr->p_align);
		break;

	case ELFCLASS32:
		phdr->p_offset = elf32_to_cpu(ehdr, buf_phdr->p_offset);
		phdr->p_paddr  = elf32_to_cpu(ehdr, buf_phdr->p_paddr);
		phdr->p_vaddr  = elf32_to_cpu(ehdr, buf_phdr->p_vaddr);
		phdr->p_filesz = elf32_to_cpu(ehdr, buf_phdr->p_filesz);
		phdr->p_memsz  = elf32_to_cpu(ehdr, buf_phdr->p_memsz);
		phdr->p_align  = elf32_to_cpu(ehdr, buf_phdr->p_align);
		break;

	default:
		pr_debug("Unknown ELF class.\n");
		return -EINVAL;
	}

	return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
}