From fc682f0337b42372a8d7311efbae35867fa803ca Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Wed, 12 Jan 2022 13:58:10 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@15346 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- os/sb/host/sbelf_old.c | 577 +++++++++++++++++++++++++++++++++++++++++ os/sb/host/sbelf_old.h | 77 ++++++ 2 files changed, 654 insertions(+) create mode 100644 os/sb/host/sbelf_old.c create mode 100644 os/sb/host/sbelf_old.h diff --git a/os/sb/host/sbelf_old.c b/os/sb/host/sbelf_old.c new file mode 100644 index 000000000..360861445 --- /dev/null +++ b/os/sb/host/sbelf_old.c @@ -0,0 +1,577 @@ +/* + ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, + 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS 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 version 3 of the License. + + ChibiOS 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, see . +*/ + +/** + * @file sb/host/sbelf.c + * @brief ARM SandBox ELF loader code. + * + * @addtogroup ARM_SANDBOX_ELF + * @{ + */ + +#include + +#include "ch.h" +#include "sb.h" + +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/* Relevant section types.*/ +#define SHT_PROGBITS 1U +#define SHT_SYMTAB 2U +#define SHT_NOBITS 8U +#define SHT_REL 9U + +/* Relevant section flags.*/ +#define SHF_WRITE (1U << 0) +#define SHF_ALLOC (1U << 1) +#define SHF_EXECINSTR (1U << 2) +#define SHF_INFO_LINK (1U << 6) + +/* Special section indices.*/ +#define SHN_UNDEF 0U + +/* Supported relocation types.*/ +#define R_ARM_ABS32 2U +#define R_ARM_THM_PC22 10U +#define R_ARM_THM_JUMP24 30U + +#define ELF32_R_SYM(v) ((v) >> 8) +#define ELF32_R_TYPE(v) ((v) & 0xFFU) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/** + * @brief Type of a section number. + */ +typedef unsigned elf_secnum_t; + +/** + * @brief Type of a symbol number. + */ +typedef unsigned elf_symnum_t; + +/** + * @brief Type of a loadable section info structure. + */ +typedef struct { + elf_secnum_t section; + uint32_t address; + size_t bits_size; + vfs_offset_t bits_off; + size_t rel_size; + vfs_offset_t rel_off; +} elf_loadable_info_t; + +/** + * @brief Type of an ELF loader context. + */ +typedef struct elf_load_context { + vfs_file_node_c *fnp; + const memory_area_t *map; + uint8_t *next; + + uint32_t entry; + elf_secnum_t sections_num; + vfs_offset_t sections_off; + elf_symnum_t symbols_num; + vfs_offset_t symbols_off; + elf_loadable_info_t loadable_code; + elf_loadable_info_t loadable_const; + elf_loadable_info_t loadable_data; +#if 0 +// vfs_offset_t strings_off; +#endif +} elf_load_context_t; + +/** + * @brief Type of an ELF32 header. + */ +typedef struct { + unsigned char e_ident[16]; + 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; +} elf32_header_t; + +typedef struct { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +} elf32_section_header_t; + +typedef struct { + uint32_t r_offset; + uint32_t r_info; +} elf32_rel_t; + +typedef struct { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; +} elf32_symbol_t; + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if 0 +static msg_t read_section_name(elf_load_context_t *ctxp, + elf32_section_header_t *shp, + char *buf, size_t buflen) { + msg_t ret; + + if (shp->sh_name == 0U) { + *buf = '\0'; + return CH_RET_SUCCESS; + } + + ret = vfsSetFilePosition(ctxp->fnp, + ctxp->stringsoff + (vfs_offset_t)shp->sh_name, + VFS_SEEK_SET); + CH_RETURN_ON_ERROR(ret); + ret = vfsReadFile(ctxp->fnp, (void *)buf, buflen); + CH_RETURN_ON_ERROR(ret); + + return CH_RET_SUCCESS; +} +#endif + +static msg_t read_section_header(elf_load_context_t *ctxp, + elf32_section_header_t *shp, + elf_secnum_t index) { + msg_t ret; + + ret = vfsSetFilePosition(ctxp->fnp, + ctxp->sections_off + ((vfs_offset_t)index * + (vfs_offset_t)sizeof (elf32_section_header_t)), + VFS_SEEK_SET); + CH_RETURN_ON_ERROR(ret); + return vfsReadFile(ctxp->fnp, (void *)shp, sizeof (elf32_section_header_t)); +} + +static msg_t allocate_section(elf_load_context_t *ctxp, + elf32_section_header_t *shp) { + uint8_t *load_address; + + /* Checking if the section can fit into the destination memory area.*/ + load_address = ctxp->map->base + shp->sh_addr; + if (!chMemIsSpaceWithinX(ctxp->map, + (const void *)load_address, + (size_t)shp->sh_size)) { + return CH_RET_ENOMEM; + } + + return CH_RET_SUCCESS; +} + +static elf_loadable_info_t *find_loaded_section(elf_load_context_t *ctxp, + elf_secnum_t sn) { + + if (sn == ctxp->loadable_code.section) { + /* Executable code section.*/ + return &ctxp->loadable_code; + } + if (sn == ctxp->loadable_data.section) { + /* Writable data section.*/ + return &ctxp->loadable_data; + } + if (sn == ctxp->loadable_const.section) { + /* Constants data section.*/ + return &ctxp->loadable_const; + } + + return NULL; +} + +#if 0 +static msg_t reloc_jump(uint32_t relocation_address, + uint32_t destination_address) { + + uint32_t ins = (((uint32_t *)relocation_address)[0] << 16) | + (((uint32_t *)relocation_address)[1] << 0); + uint32_t s = (ins >> 26) & 1U; + uint32_t j1 = (ins >> 13) & 1U; + uint32_t j2 = (ins >> 11) & 1U; + uint32_t off = (s << 24) | + ((~(j1 ^ s) & 1U) << 23) | + ((~(j2 ^ s) & 1U) << 22) | + ((ins & 0x03FF0000U) >> 4) | + ((ins & 0x000007FFU) << 1); +} +#endif + +static msg_t reloc_entry(elf_load_context_t *ctxp, + elf_loadable_info_t *lip, + elf32_rel_t *rp) { + vfs_offset_t symoff; + elf_symnum_t symnum; + uint32_t relocation_address; + elf_loadable_info_t *symbol_lip; + elf32_symbol_t symbol; + msg_t ret; + + /* Checking for a symbol number overflow.*/ + symnum = (elf_symnum_t)ELF32_R_SYM(rp->r_info); + if (symnum > ctxp->symbols_num) { + return CH_RET_ENOEXEC; + } + + /* Moving file pointer to the symbol then reading it.*/ + symoff = ctxp->symbols_off + ((vfs_offset_t)symnum * + (vfs_offset_t)sizeof (elf32_symbol_t)); + ret = vfsSetFilePosition(ctxp->fnp, symoff, VFS_SEEK_SET); + CH_RETURN_ON_ERROR(ret); + ret = vfsReadFile(ctxp->fnp, (void *)&symbol, sizeof (elf32_symbol_t)); + CH_RETURN_ON_ERROR(ret); + + /* Undefined symbols are not handled, this is a loader not a linker.*/ + if (symbol.st_shndx == SHN_UNDEF) { + return CH_RET_ENOEXEC; + } + + /* Symbols must be associated to an already loaded section.*/ + symbol_lip = find_loaded_section(ctxp, (elf_symnum_t)symbol.st_shndx); + if (symbol_lip == NULL) { + return CH_RET_ENOEXEC; + } + + /* Relocation point address.*/ + relocation_address = (uint32_t)ctxp->map->base + + lip->address + + rp->r_offset; + if (!chMemIsSpaceWithinX(ctxp->map, + (const void *)relocation_address, + sizeof (uint32_t))) { + return CH_RET_ENOMEM; + } + + /* Handling the various relocation point types.*/ + switch (ELF32_R_TYPE(rp->r_info)) { + case R_ARM_ABS32: + *((uint32_t *)relocation_address) += (uint32_t)ctxp->map->base + + symbol_lip->address + + symbol.st_value; + break; + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: +// return reloc_jump(relocation_address, symbol_lip->address); + /* TODO */ + break; + default: + return CH_RET_ENOEXEC; + } + + return CH_RET_SUCCESS; +} + +static msg_t reloc_section(elf_load_context_t *ctxp, + elf_loadable_info_t *lip) { + elf32_rel_t *rbuf; + size_t size, done_size, remaining_size; + msg_t ret; + + rbuf = (elf32_rel_t *)(void *)vfs_buffer_take(); + + /* Reading the relocation section data.*/ + remaining_size = lip->rel_size; + done_size = 0U; + while (remaining_size > 0U) { + unsigned i, n; + + /* Reading relocation data using buffers in order to not make continuous + calls to the FS which could be unbuffered.*/ + if (remaining_size > VFS_BUFFERS_SIZE) { + size = VFS_BUFFERS_SIZE; + } + else { + size = remaining_size; + } + + /* Reading a buffer-worth of relocation data.*/ + ret = vfsSetFilePosition(ctxp->fnp, + lip->rel_off + (vfs_offset_t)done_size, + VFS_SEEK_SET); + CH_BREAK_ON_ERROR(ret); + ret = vfsReadFile(ctxp->fnp, (void *)rbuf, size); + CH_BREAK_ON_ERROR(ret); + + /* Number of relocation entries in the buffer.*/ + n = (unsigned)ret / (unsigned)sizeof (elf32_rel_t); + for (i = 0U; i < n; i++) { + ret = reloc_entry(ctxp, lip, &rbuf[i]); + CH_BREAK_ON_ERROR(ret); + } + CH_BREAK_ON_ERROR(ret); + + remaining_size -= size; + done_size += size; + } + + vfs_buffer_release((char *)rbuf); + + return ret; +} + +static msg_t load_relocate_section(elf_load_context_t *ctxp, + elf_loadable_info_t *lip) { + uint8_t *load_address; + msg_t ret; + + if (lip->rel_size > 0U) { + + /* Checking if the section can fit into the destination memory area.*/ + load_address = ctxp->map->base + lip->address; + if (!chMemIsSpaceWithinX(ctxp->map, + (const void *)load_address, + lip->bits_size)) { + return CH_RET_ENOMEM; + } + + /* Loading the section data into the final memory area.*/ + if (lip->bits_size > 0U) { + ret = vfsSetFilePosition(ctxp->fnp, lip->bits_off, VFS_SEEK_SET); + CH_RETURN_ON_ERROR(ret); + ret = vfsReadFile(ctxp->fnp, (void *)load_address, lip->bits_size); + CH_RETURN_ON_ERROR(ret); + } + + ret = reloc_section(ctxp, lip); + CH_RETURN_ON_ERROR(ret); + } + + return CH_RET_SUCCESS; +} + +static msg_t init_elf_context(elf_load_context_t *ctxp, + vfs_file_node_c *fnp, + const memory_area_t *map) { + static uint8_t elf32_header[16] = { + 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + elf32_header_t h; + msg_t ret; + + /* Context fully cleared.*/ + memset((void *)ctxp, 0, sizeof (elf_load_context_t)); + + /* Initializing the fixed part of the context.*/ + ctxp->fnp = fnp; + ctxp->map = map; + ctxp->next = map->base; + + /* Reading the main ELF header.*/ + ret = vfsSetFilePosition(ctxp->fnp, (vfs_offset_t)0, VFS_SEEK_SET); + CH_RETURN_ON_ERROR(ret); + ret = vfsReadFile(ctxp->fnp, (void *)&h, sizeof (elf32_header_t)); + CH_RETURN_ON_ERROR(ret); + + /* Checking for the expected header.*/ + if (memcmp(h.e_ident, elf32_header, 16) != 0) { + return CH_RET_ENOEXEC; + } + + /* TODO more consistency checks.*/ + + /* Storing info required later.*/ + ctxp->entry = h.e_entry; + ctxp->sections_num = (unsigned)h.e_shnum; + ctxp->sections_off = (vfs_offset_t)h.e_shoff; + + return CH_RET_SUCCESS; +} + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +msg_t sbElfLoad(vfs_file_node_c *fnp, const memory_area_t *map) { + msg_t ret; + + do { + elf_load_context_t ctx; + elf_loadable_info_t *lip; + elf_secnum_t i; + + ret = init_elf_context(&ctx, fnp, map); + CH_BREAK_ON_ERROR(ret); + + /* Discovery phase, scanning section headers and gathering data.*/ + for (i = 0U; i < ctx.sections_num; i++) { + elf32_section_header_t sh; + + /* Reading the header.*/ + ret = read_section_header(&ctx, &sh, i); + CH_BREAK_ON_ERROR(ret); + + /* Empty sections are not processed.*/ + if (sh.sh_size == 0U) { + continue; + } + + /* Deciding what to do with the section depending on type.*/ + switch (sh.sh_type) { + case SHT_PROGBITS: + /* Loadable section type, we allow for one executable, one data and + one constants sections.*/ + if ((sh.sh_flags & SHF_ALLOC) != 0U) { + + if ((sh.sh_flags & SHF_EXECINSTR) != 0U) { + /* Executable code section.*/ + lip = &ctx.loadable_code; + } + else if ((sh.sh_flags & SHF_WRITE) != 0U) { + /* Writable data section.*/ + lip = &ctx.loadable_data; + } + else { + /* Constants data section.*/ + lip = &ctx.loadable_const; + } + + /* Multiple sections of same kind.*/ + if (lip->section != 0U) { + return CH_RET_ENOEXEC; + } + + lip->section = i; + lip->address = sh.sh_addr; + lip->bits_size = (size_t)sh.sh_size; + lip->bits_off = (vfs_offset_t)sh.sh_offset; + + } + break; + + case SHT_NOBITS: + /* Uninitialized data section, we can have more than one, just checking + address ranges.*/ + if ((sh.sh_flags & SHF_ALLOC) != 0U) { + ret = allocate_section(&ctx, &sh); + CH_RETURN_ON_ERROR(ret); + } + break; + + case SHT_REL: + if ((sh.sh_flags & SHF_INFO_LINK) != 0U) { + + lip = find_loaded_section(&ctx, (elf_secnum_t)sh.sh_info); + if (lip == NULL) { + /* Ignoring other relocation sections.*/ + break; + } + + /* Multiple relocation sections associated to the same section.*/ + if (lip->rel_size != 0U) { + return CH_RET_ENOEXEC; + } + + lip->rel_size = sh.sh_size; + lip->rel_off = (vfs_offset_t)sh.sh_offset; + } + break; + + case SHT_SYMTAB: + /* Symbols section, this is required for relocation.*/ + + if (ctx.symbols_num != 0U) { + /* Multiple symbol sections.*/ + return CH_RET_ENOEXEC; + } + + ctx.symbols_num = (elf_symnum_t)sh.sh_size / + (elf_symnum_t)sizeof (elf32_symbol_t); + ctx.symbols_off = (vfs_offset_t)sh.sh_offset; + break; + + default: + /* Ignoring other section types.*/ + break; + } + } + + /* Loading phase.*/ + ret = load_relocate_section(&ctx, &ctx.loadable_code); + CH_RETURN_ON_ERROR(ret); + ret = load_relocate_section(&ctx, &ctx.loadable_data); + CH_RETURN_ON_ERROR(ret); + ret = load_relocate_section(&ctx, &ctx.loadable_const); + CH_RETURN_ON_ERROR(ret); + } while (false); + + return ret; +} + +msg_t sbElfLoadFile(vfs_driver_c *drvp, + const char *path, + const memory_area_t *map) { + vfs_file_node_c *fnp; + msg_t ret; + + ret = vfsDrvOpenFile(drvp, path, VO_RDONLY, &fnp); + CH_RETURN_ON_ERROR(ret); + + do { + ret = sbElfLoad(fnp, map); + CH_BREAK_ON_ERROR(ret); + + } while (false); + + vfsClose((vfs_node_c *)fnp); + + return ret; +} + +#endif /* SB_CFG_ENABLE_VFS == TRUE */ + +/** @} */ diff --git a/os/sb/host/sbelf_old.h b/os/sb/host/sbelf_old.h new file mode 100644 index 000000000..62ca61c9e --- /dev/null +++ b/os/sb/host/sbelf_old.h @@ -0,0 +1,77 @@ +/* + ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, + 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS 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 version 3 of the License. + + ChibiOS 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, see . +*/ + +/** + * @file sb/host/sbloader.h + * @brief ARM SandBox ELF loader macros and structures. + * + * @addtogroup sbhost.h + * @{ + */ + +#ifndef SBELF_H +#define SBELF_H + +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + msg_t sbElfLoad(vfs_file_node_c *fnp, + const memory_area_t *map); + msg_t sbElfLoadFile(vfs_driver_c *drvp, + const char *path, + const memory_area_t *map); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* SB_CFG_ENABLE_VFS == TRUE */ + +#endif /* SBELF_H */ + +/** @} */