diff --git a/core/flash.c b/core/flash.c index 4e10229d52ee..de748641fa9c 100644 --- a/core/flash.c +++ b/core/flash.c @@ -523,24 +523,38 @@ const char *flash_map_resource_name(enum resource_id id) static size_t sizeof_elf_from_hdr(void *buf) { - struct elf_hdr *elf = (struct elf_hdr*) buf; + struct elf_hdr *elf = (struct elf_hdr *)buf; size_t sz = 0; BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf_hdr)); - BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf64_hdr)); - BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf32_hdr)); + BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf64be_hdr)); + BUILD_ASSERT(SECURE_BOOT_HEADERS_SIZE > sizeof(struct elf32be_hdr)); if (elf->ei_ident == ELF_IDENT) { if (elf->ei_class == ELF_CLASS_64) { - struct elf64_hdr *elf64 = (struct elf64_hdr*) buf; - sz = le64_to_cpu(elf64->e_shoff) + - ((uint32_t)le16_to_cpu(elf64->e_shentsize) * - (uint32_t)le16_to_cpu(elf64->e_shnum)); + if (elf->ei_data == ELF_DATA_LSB) { + struct elf64le_hdr *kh = (struct elf64le_hdr *)buf; + sz = le64_to_cpu(kh->e_shoff) + + ((uint32_t)le16_to_cpu(kh->e_shentsize) * + (uint32_t)le16_to_cpu(kh->e_shnum)); + } else { + struct elf64be_hdr *kh = (struct elf64be_hdr *)buf; + sz = be64_to_cpu(kh->e_shoff) + + ((uint32_t)be16_to_cpu(kh->e_shentsize) * + (uint32_t)be16_to_cpu(kh->e_shnum)); + } } else if (elf->ei_class == ELF_CLASS_32) { - struct elf32_hdr *elf32 = (struct elf32_hdr*) buf; - sz = le32_to_cpu(elf32->e_shoff) + - (le16_to_cpu(elf32->e_shentsize) * - le16_to_cpu(elf32->e_shnum)); + if (elf->ei_data == ELF_DATA_LSB) { + struct elf32le_hdr *kh = (struct elf32le_hdr *)buf; + sz = le32_to_cpu(kh->e_shoff) + + (le16_to_cpu(kh->e_shentsize) * + le16_to_cpu(kh->e_shnum)); + } else { + struct elf32be_hdr *kh = (struct elf32be_hdr *)buf; + sz = be32_to_cpu(kh->e_shoff) + + (be16_to_cpu(kh->e_shentsize) * + be16_to_cpu(kh->e_shnum)); + } } } diff --git a/core/init.c b/core/init.c index a7083456e5cb..d90695c1601b 100644 --- a/core/init.c +++ b/core/init.c @@ -89,9 +89,9 @@ static void checksum_romem(void); static bool try_load_elf64_le(struct elf_hdr *header) { - struct elf64_hdr *kh = (struct elf64_hdr *)header; + struct elf64le_hdr *kh = (struct elf64le_hdr *)header; uint64_t load_base = (uint64_t)kh; - struct elf64_phdr *ph; + struct elf64le_phdr *ph; unsigned int i; printf("INIT: 64-bit LE kernel discovered\n"); @@ -103,7 +103,7 @@ static bool try_load_elf64_le(struct elf_hdr *header) * to work for the Linux Kernel because it's a fairly dumb ELF * but it will not work for any ELF binary. */ - ph = (struct elf64_phdr *)(load_base + le64_to_cpu(kh->e_phoff)); + ph = (struct elf64le_phdr *)(load_base + le64_to_cpu(kh->e_phoff)); for (i = 0; i < le16_to_cpu(kh->e_phnum); i++, ph++) { if (le32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD) continue; @@ -137,23 +137,24 @@ static bool try_load_elf64_le(struct elf_hdr *header) static bool try_load_elf64(struct elf_hdr *header) { - struct elf64_hdr *kh = (struct elf64_hdr *)header; + struct elf64be_hdr *kh = (struct elf64be_hdr *)header; + struct elf64le_hdr *khle = (struct elf64le_hdr *)header; uint64_t load_base = (uint64_t)kh; - struct elf64_phdr *ph; - struct elf64_shdr *sh; + struct elf64be_phdr *ph; + struct elf64be_shdr *sh; unsigned int i; /* Check it's a ppc64 LE ELF */ - if (kh->ei_ident == ELF_IDENT && - kh->ei_data == ELF_DATA_LSB && - kh->e_machine == le16_to_cpu(ELF_MACH_PPC64)) { + if (khle->ei_ident == ELF_IDENT && + khle->ei_data == ELF_DATA_LSB && + le16_to_cpu(khle->e_machine) == ELF_MACH_PPC64) { return try_load_elf64_le(header); } /* Check it's a ppc64 ELF */ if (kh->ei_ident != ELF_IDENT || kh->ei_data != ELF_DATA_MSB || - kh->e_machine != ELF_MACH_PPC64) { + be16_to_cpu(kh->e_machine) != ELF_MACH_PPC64) { prerror("INIT: Kernel doesn't look like an ppc64 ELF\n"); return false; } @@ -165,16 +166,18 @@ static bool try_load_elf64(struct elf_hdr *header) * to work for the Linux Kernel because it's a fairly dumb ELF * but it will not work for any ELF binary. */ - ph = (struct elf64_phdr *)(load_base + kh->e_phoff); - for (i = 0; i < kh->e_phnum; i++, ph++) { - if (ph->p_type != ELF_PTYPE_LOAD) + ph = (struct elf64be_phdr *)(load_base + be64_to_cpu(kh->e_phoff)); + for (i = 0; i < be16_to_cpu(kh->e_phnum); i++, ph++) { + if (be32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD) continue; - if (ph->p_vaddr > kh->e_entry || - (ph->p_vaddr + ph->p_memsz) < kh->e_entry) + if (be64_to_cpu(ph->p_vaddr) > be64_to_cpu(kh->e_entry) || + (be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_memsz)) < + be64_to_cpu(kh->e_entry)) continue; /* Get our entry */ - kernel_entry = kh->e_entry - ph->p_vaddr + ph->p_offset; + kernel_entry = be64_to_cpu(kh->e_entry) - + be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_offset); break; } @@ -189,23 +192,27 @@ static bool try_load_elf64(struct elf_hdr *header) * 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) + sh = (struct elf64be_shdr *)(load_base + be64_to_cpu(kh->e_shoff)); + for (i = 0; i < be16_to_cpu(kh->e_shnum); i++, sh++) { + if (be64_to_cpu(sh->sh_addr) <= be64_to_cpu(kh->e_entry) && + (be64_to_cpu(sh->sh_addr) + be64_to_cpu(sh->sh_size)) > + be64_to_cpu(kh->e_entry)) break; } - if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) { + if (i == be16_to_cpu(kh->e_shnum) || + !(be64_to_cpu(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 = kernel_entry - + be64_to_cpu(ph->p_vaddr) + be64_to_cpu(ph->p_offset); } kernel_entry += load_base; kernel_32bit = false; - kernel_size = kh->e_shoff + - ((uint32_t)kh->e_shentsize * (uint32_t)kh->e_shnum); + kernel_size = be64_to_cpu(kh->e_shoff) + + ((uint32_t)be16_to_cpu(kh->e_shentsize) * + (uint32_t)be16_to_cpu(kh->e_shnum)); printf("INIT: 64-bit kernel entry at 0x%llx, size 0x%lx\n", kernel_entry, kernel_size); @@ -215,9 +222,9 @@ static bool try_load_elf64(struct elf_hdr *header) static bool try_load_elf32_le(struct elf_hdr *header) { - struct elf32_hdr *kh = (struct elf32_hdr *)header; + struct elf32le_hdr *kh = (struct elf32le_hdr *)header; uint64_t load_base = (uint64_t)kh; - struct elf32_phdr *ph; + struct elf32le_phdr *ph; unsigned int i; printf("INIT: 32-bit LE kernel discovered\n"); @@ -229,7 +236,7 @@ static bool try_load_elf32_le(struct elf_hdr *header) * to work for the Linux Kernel because it's a fairly dumb ELF * but it will not work for any ELF binary. */ - ph = (struct elf32_phdr *)(load_base + le32_to_cpu(kh->e_phoff)); + ph = (struct elf32le_phdr *)(load_base + le32_to_cpu(kh->e_phoff)); for (i = 0; i < le16_to_cpu(kh->e_phnum); i++, ph++) { if (le32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD) continue; @@ -259,22 +266,23 @@ static bool try_load_elf32_le(struct elf_hdr *header) static bool try_load_elf32(struct elf_hdr *header) { - struct elf32_hdr *kh = (struct elf32_hdr *)header; + struct elf32be_hdr *kh = (struct elf32be_hdr *)header; + struct elf32le_hdr *khle = (struct elf32le_hdr *)header; uint64_t load_base = (uint64_t)kh; - struct elf32_phdr *ph; + struct elf32be_phdr *ph; unsigned int i; /* Check it's a ppc32 LE ELF */ - if (header->ei_ident == ELF_IDENT && - header->ei_data == ELF_DATA_LSB && - header->e_machine == le16_to_cpu(ELF_MACH_PPC32)) { + if (khle->ei_ident == ELF_IDENT && + khle->ei_data == ELF_DATA_LSB && + le16_to_cpu(khle->e_machine) == ELF_MACH_PPC32) { return try_load_elf32_le(header); } /* Check it's a ppc32 ELF */ - if (header->ei_ident != ELF_IDENT || - header->ei_data != ELF_DATA_MSB || - header->e_machine != ELF_MACH_PPC32) { + if (kh->ei_ident != ELF_IDENT || + kh->ei_data != ELF_DATA_MSB || + be16_to_cpu(kh->e_machine) != ELF_MACH_PPC32) { prerror("INIT: Kernel doesn't look like an ppc32 ELF\n"); return false; } @@ -286,16 +294,18 @@ static bool try_load_elf32(struct elf_hdr *header) * to work for the Linux Kernel because it's a fairly dumb ELF * but it will not work for any ELF binary. */ - ph = (struct elf32_phdr *)(load_base + kh->e_phoff); - for (i = 0; i < kh->e_phnum; i++, ph++) { - if (ph->p_type != ELF_PTYPE_LOAD) + ph = (struct elf32be_phdr *)(load_base + be32_to_cpu(kh->e_phoff)); + for (i = 0; i < be16_to_cpu(kh->e_phnum); i++, ph++) { + if (be32_to_cpu(ph->p_type) != ELF_PTYPE_LOAD) continue; - if (ph->p_vaddr > kh->e_entry || - (ph->p_vaddr + ph->p_memsz) < kh->e_entry) + if (be32_to_cpu(ph->p_vaddr) > be32_to_cpu(kh->e_entry) || + (be32_to_cpu(ph->p_vaddr) + be32_to_cpu(ph->p_memsz)) < + be32_to_cpu(kh->e_entry)) continue; /* Get our entry */ - kernel_entry = kh->e_entry - ph->p_vaddr + ph->p_offset; + kernel_entry = be32_to_cpu(kh->e_entry) - + be32_to_cpu(ph->p_vaddr) + be32_to_cpu(ph->p_offset); break; } diff --git a/include/elf.h b/include/elf.h index 93524bb99a4a..f3e071de1928 100644 --- a/include/elf.h +++ b/include/elf.h @@ -5,11 +5,16 @@ #define __ELF_H #include +#include /* Generic ELF header */ struct elf_hdr { uint32_t ei_ident; +#if HAVE_BIG_ENDIAN #define ELF_IDENT 0x7F454C46 +#else +#define ELF_IDENT 0x464C457F +#endif uint8_t ei_class; #define ELF_CLASS_32 1 #define ELF_CLASS_64 2 @@ -18,68 +23,190 @@ struct elf_hdr { #define ELF_DATA_MSB 2 uint8_t ei_version; uint8_t ei_pad[9]; - uint16_t e_type; - uint16_t e_machine; +}; + #define ELF_MACH_PPC32 0x14 #define ELF_MACH_PPC64 0x15 - uint32_t e_version; + +/* 64-bit ELF header */ +struct elf64be_hdr { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + __be16 e_type; + __be16 e_machine; + __be32 e_version; + __be64 e_entry; + __be64 e_phoff; + __be64 e_shoff; + __be32 e_flags; + __be16 e_ehsize; + __be16 e_phentsize; + __be16 e_phnum; + __be16 e_shentsize; + __be16 e_shnum; + __be16 e_shstrndx; +}; + +/* 64-bit ELF program header */ +struct elf64be_phdr { + __be32 p_type; +#define ELF_PTYPE_LOAD 1 + __be32 p_flags; +#define ELF_PFLAGS_R 0x4 +#define ELF_PFLAGS_W 0x2 +#define ELF_PFLAGS_X 0x1 + __be64 p_offset; + __be64 p_vaddr; + __be64 p_paddr; + __be64 p_filesz; + __be64 p_memsz; + __be64 p_align; +}; + +/* 64-bit ELF section header */ +struct elf64be_shdr { + __be32 sh_name; + __be32 sh_type; + __be64 sh_flags; +#define ELF_SFLAGS_X 0x4 +#define ELF_SFLAGS_A 0x2 +#define ELF_SFLAGS_W 0x1 + __be64 sh_addr; + __be64 sh_offset; + __be64 sh_size; + __be32 sh_link; + __be32 sh_info; + __be64 sh_addralign; + __be64 sh_entsize; +}; + +/* 32-bit ELF header */ +struct elf32be_hdr { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + __be16 e_type; + __be16 e_machine; + __be32 e_version; + __be32 e_entry; + __be32 e_phoff; + __be32 e_shoff; + __be32 e_flags; + __be16 e_ehsize; + __be16 e_phentsize; + __be16 e_phnum; + __be16 e_shentsize; + __be16 e_shnum; + __be16 e_shstrndx; +}; + +/* 32-bit ELF program header*/ +struct elf32be_phdr { + __be32 p_type; + __be32 p_offset; + __be32 p_vaddr; + __be32 p_paddr; + __be32 p_filesz; + __be32 p_memsz; + __be32 p_flags; + __be32 p_align; }; /* 64-bit ELF header */ -struct elf64_hdr { +struct elf64le_hdr { uint32_t ei_ident; uint8_t ei_class; uint8_t ei_data; uint8_t ei_version; uint8_t ei_pad[9]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint64_t e_entry; - uint64_t e_phoff; - uint64_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; + __le16 e_type; + __le16 e_machine; + __le32 e_version; + __le64 e_entry; + __le64 e_phoff; + __le64 e_shoff; + __le32 e_flags; + __le16 e_ehsize; + __le16 e_phentsize; + __le16 e_phnum; + __le16 e_shentsize; + __le16 e_shnum; + __le16 e_shstrndx; }; /* 64-bit ELF program header */ -struct elf64_phdr { - uint32_t p_type; +struct elf64le_phdr { + __le32 p_type; #define ELF_PTYPE_LOAD 1 - uint32_t p_flags; + __le32 p_flags; #define ELF_PFLAGS_R 0x4 #define ELF_PFLAGS_W 0x2 #define ELF_PFLAGS_X 0x1 - uint64_t p_offset; - uint64_t p_vaddr; - uint64_t p_paddr; - uint64_t p_filesz; - uint64_t p_memsz; - uint64_t p_align; + __le64 p_offset; + __le64 p_vaddr; + __le64 p_paddr; + __le64 p_filesz; + __le64 p_memsz; + __le64 p_align; }; /* 64-bit ELF section header */ -struct elf64_shdr { - uint32_t sh_name; - uint32_t sh_type; - uint64_t sh_flags; +struct elf64le_shdr { + __le32 sh_name; + __le32 sh_type; + __le64 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; - int64_t sh_entsize; + __le64 sh_addr; + __le64 sh_offset; + __le64 sh_size; + __le32 sh_link; + __le32 sh_info; + __le64 sh_addralign; + __le64 sh_entsize; +}; + +/* 32-bit ELF header */ +struct elf32le_hdr { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + __le16 e_type; + __le16 e_machine; + __le32 e_version; + __le32 e_entry; + __le32 e_phoff; + __le32 e_shoff; + __le32 e_flags; + __le16 e_ehsize; + __le16 e_phentsize; + __le16 e_phnum; + __le16 e_shentsize; + __le16 e_shnum; + __le16 e_shstrndx; +}; + +/* 32-bit ELF program header*/ +struct elf32le_phdr { + __le32 p_type; + __le32 p_offset; + __le32 p_vaddr; + __le32 p_paddr; + __le32 p_filesz; + __le32 p_memsz; + __le32 p_flags; + __le32 p_align; }; + /* Some relocation related stuff used in relocate.c */ struct elf64_dyn { int64_t d_tag; @@ -101,39 +228,5 @@ struct elf64_rela { /* relocs we support */ #define R_PPC64_RELATIVE 22 -/* 32-bit ELF header */ -struct elf32_hdr { - uint32_t ei_ident; - uint8_t ei_class; - uint8_t ei_data; - uint8_t ei_version; - uint8_t ei_pad[9]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint32_t e_entry; - uint32_t e_phoff; - uint32_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; -}; - -/* 32-bit ELF program header*/ -struct elf32_phdr { - uint32_t p_type; - uint32_t p_offset; - uint32_t p_vaddr; - uint32_t p_paddr; - uint32_t p_filesz; - uint32_t p_memsz; - uint32_t p_flags; - uint32_t p_align; -}; - #endif /* __ELF_H */ diff --git a/include/stack.h b/include/stack.h index 09d22adb61de..b0d6df17d31f 100644 --- a/include/stack.h +++ b/include/stack.h @@ -11,7 +11,11 @@ #define STACK_ENTRY_RESET 0x0100 /* System reset */ #define STACK_ENTRY_SOFTPATCH 0x1500 /* Soft patch (denorm emulation) */ +#if HAVE_BIG_ENDIAN #define STACK_TOC_OFFSET 40 +#else +#define STACK_TOC_OFFSET 24 +#endif /* Safety/ABI gap at top of stack */ #define STACK_TOP_GAP 0x100 diff --git a/include/types.h b/include/types.h index a7a45f5cb4ec..e7660f6b7e25 100644 --- a/include/types.h +++ b/include/types.h @@ -11,5 +11,9 @@ typedef beint16_t __be16; typedef beint32_t __be32; typedef beint64_t __be64; +typedef leint16_t __le16; +typedef leint32_t __le32; +typedef leint64_t __le64; + #endif /* __TYPES_H */