mirror of https://github.com/wolfSSL/wolfBoot.git
175 lines
5.2 KiB
C
175 lines
5.2 KiB
C
/* elf.c
|
|
*
|
|
* Copyright (C) 2023 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*
|
|
* Simple elf32 or elf64 loader support
|
|
*/
|
|
|
|
#ifdef WOLFBOOT_ELF
|
|
|
|
#include "wolfboot/wolfboot.h"
|
|
#include "printf.h"
|
|
#include "string.h"
|
|
#include "elf.h"
|
|
|
|
#ifdef ARCH_PPC
|
|
#include "hal/nxp_ppc.h"
|
|
#endif
|
|
|
|
/* support for elf parsing debug printf */
|
|
#if defined(DEBUG) || defined(ELF_PARSER)
|
|
#if defined(DEBUG_ELF) && DEBUG_ELF == 0
|
|
#undef DEBUG_ELF
|
|
#else
|
|
#undef DEBUG_ELF
|
|
#define DEBUG_ELF
|
|
#endif
|
|
#endif
|
|
|
|
/* support byte swapping if testing/reading an elf with different endianess */
|
|
#if defined(ELF_PARSER) || defined(ELF_ENDIAN_SUPPORT)
|
|
#ifdef BIG_ENDIAN_ORDER
|
|
#define GET16(x) (( is_le) ? __builtin_bswap16(x) : (x))
|
|
#define GET32(x) (( is_le) ? __builtin_bswap32(x) : (x))
|
|
#define GET64(x) (( is_le) ? __builtin_bswap64(x) : (x))
|
|
#else
|
|
#define GET16(x) ((!is_le) ? __builtin_bswap16(x) : (x))
|
|
#define GET32(x) ((!is_le) ? __builtin_bswap32(x) : (x))
|
|
#define GET64(x) ((!is_le) ? __builtin_bswap64(x) : (x))
|
|
#endif
|
|
#else
|
|
#define GET16(x) (x)
|
|
#define GET32(x) (x)
|
|
#define GET64(x) (x)
|
|
#endif
|
|
|
|
#define GET_H64(name) (is_elf32 ? GET32(h32->name) : GET64(h64->name))
|
|
#define GET_H32(name) (is_elf32 ? GET32(h32->name) : GET32(h64->name))
|
|
#define GET_H16(name) (is_elf32 ? GET16(h32->name) : GET16(h64->name))
|
|
#define GET_E64(name) (is_elf32 ? GET32(e32->name) : GET64(e64->name))
|
|
#define GET_E32(name) (is_elf32 ? GET32(e32->name) : GET32(e64->name))
|
|
|
|
/* Loader for elf32 or elf64 format program headers
|
|
* Returns the entry point function
|
|
*/
|
|
int elf_load_image_mmu(uint8_t *image, uintptr_t *entry, elf_mmu_map_cb mmu_cb)
|
|
{
|
|
elf32_header* h32 = (elf32_header*)image;
|
|
elf64_header* h64 = (elf64_header*)image;
|
|
uint16_t entry_count, entry_size;
|
|
uint8_t *entry_off;
|
|
int is_elf32, is_le, i;
|
|
|
|
#ifdef DEBUG_ELF
|
|
wolfBoot_printf("Loading elf at %p\r\n", (void*)image);
|
|
#endif
|
|
|
|
/* Verify ELF header */
|
|
if (memcmp(h32->ident, ELF_IDENT_STR, 4) != 0) {
|
|
return -1; /* not valid header identifier */
|
|
}
|
|
|
|
/* Load class and endianess */
|
|
is_elf32 = (h32->ident[4] == ELF_CLASS_32);
|
|
is_le = (h32->ident[5] == ELF_ENDIAN_LITTLE);
|
|
|
|
/* Verify this is an executable */
|
|
if (GET_H16(type) != ELF_HET_EXEC) {
|
|
return -2; /* not executable */
|
|
}
|
|
|
|
#ifdef DEBUG_ELF
|
|
wolfBoot_printf("Found valid elf%d (%s endian)\r\n",
|
|
is_elf32 ? 32 : 64, is_le ? "little" : "big");
|
|
#endif
|
|
|
|
/* programs */
|
|
entry_off = image + GET_H32(ph_offset);
|
|
entry_size = GET_H16(ph_entry_size);
|
|
entry_count = GET_H16(ph_entry_count);
|
|
#ifdef DEBUG_ELF
|
|
wolfBoot_printf("Program Headers %d (size %d)\r\n", entry_count, entry_size);
|
|
#endif
|
|
for (i = 0; i < entry_count; i++) {
|
|
uint8_t *ptr = ((uint8_t*)entry_off) + (i * entry_size);
|
|
elf32_program_header* e32 = (elf32_program_header*)ptr;
|
|
elf64_program_header* e64 = (elf64_program_header*)ptr;
|
|
uint32_t type = GET_E32(type);
|
|
uintptr_t paddr = GET_E64(paddr);
|
|
uintptr_t vaddr = GET_E64(vaddr);
|
|
uintptr_t mem_size = GET_E64(mem_size);
|
|
uintptr_t offset = GET_E64(offset);
|
|
uintptr_t file_size = GET_E64(file_size);
|
|
|
|
if (type != ELF_PT_LOAD || mem_size == 0) {
|
|
continue;
|
|
}
|
|
|
|
#ifdef DEBUG_ELF
|
|
if (file_size > 0) {
|
|
wolfBoot_printf(
|
|
"Load %u bytes (offset %p) to %p (p %p)\r\n",
|
|
(uint32_t)mem_size, (void*)offset, (void*)vaddr, (void*)paddr);
|
|
}
|
|
if (mem_size > file_size) {
|
|
wolfBoot_printf(
|
|
"Clear %u bytes at %p (p %p)\r\n",
|
|
(uint32_t)(mem_size - file_size), (void*)vaddr, (void*)paddr);
|
|
}
|
|
#endif
|
|
|
|
#ifndef ELF_PARSER
|
|
if (mmu_cb != NULL) {
|
|
if (mmu_cb(vaddr, paddr, mem_size) != 0) {
|
|
#ifdef DEBUG_ELF
|
|
wolfBoot_printf(
|
|
"Fail to map %u bytes to %p (p %p)\r\n",
|
|
(uint32_t)mem_size, (void*)vaddr, (void*)paddr);
|
|
#endif
|
|
continue;
|
|
}
|
|
}
|
|
|
|
memcpy((void*)(uintptr_t)vaddr, image + offset, file_size);
|
|
if (mem_size > file_size) {
|
|
memset((void*)(uintptr_t)(vaddr + file_size), 0,
|
|
mem_size - file_size);
|
|
}
|
|
#ifdef ARCH_PPC
|
|
flush_cache(paddr, mem_size);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
*entry = GET_H64(entry);
|
|
#ifdef DEBUG_ELF
|
|
wolfBoot_printf("Entry point %p\r\n", (void*)*entry);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int elf_load_image(uint8_t *image, uintptr_t *entry)
|
|
{
|
|
|
|
return elf_load_image_mmu(image, entry, NULL);
|
|
}
|
|
|
|
#endif /* WOLFBOOT_ELF */
|