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: Sven Schnelle <svens@stackframe.org> Reviewed-by: Thiago Jung Bauermann <bauerman@linux.ibm.com> Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
parent
571ceb7d96
commit
ea46a13ebf
|
@ -21,8 +21,6 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#define elf_addr_to_cpu elf64_to_cpu
|
|
||||||
|
|
||||||
static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
|
static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
|
||||||
{
|
{
|
||||||
return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
|
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_type = elf16_to_cpu(ehdr, buf_ehdr->e_type);
|
||||||
ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
|
ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
|
||||||
ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version);
|
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_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
|
||||||
ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
|
ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
|
||||||
ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
|
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_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
|
||||||
ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
|
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;
|
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. */
|
/* Override the const in proghdrs, we are the ones doing the loading. */
|
||||||
struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
|
struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
|
||||||
|
const struct elfhdr *ehdr = elf_info->ehdr;
|
||||||
const char *pbuf;
|
const char *pbuf;
|
||||||
struct elf_phdr *buf_phdr;
|
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;
|
buf_phdr = (struct elf_phdr *) pbuf;
|
||||||
|
|
||||||
phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
|
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);
|
phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
|
||||||
|
|
||||||
/*
|
switch (ehdr->e_ident[EI_CLASS]) {
|
||||||
* The following fields have a type equivalent to Elf_Addr
|
case ELFCLASS64:
|
||||||
* both in 32 bit and 64 bit ELF.
|
phdr->p_offset = elf64_to_cpu(ehdr, buf_phdr->p_offset);
|
||||||
*/
|
phdr->p_paddr = elf64_to_cpu(ehdr, buf_phdr->p_paddr);
|
||||||
phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
|
phdr->p_vaddr = elf64_to_cpu(ehdr, buf_phdr->p_vaddr);
|
||||||
phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
|
phdr->p_filesz = elf64_to_cpu(ehdr, buf_phdr->p_filesz);
|
||||||
phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
|
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;
|
return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue