/* 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 */