76 lines
3.2 KiB
C
76 lines
3.2 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/**
|
|
* @file ft_tt_elf.h
|
|
* @brief Parse an in-memory ELF32 little-endian RISC-V executable (a Tensix kernel or
|
|
* firmware image) into the list of segments a loader writes into L1.
|
|
*
|
|
* The parser copies nothing: segment file_data points into the caller's blob, which must
|
|
* outlive the image. Anything the loader could not place safely is refused with
|
|
* FT_TT_EINVAL (ft_tt_device.h) and a reason logged through ft_tt_log_error():
|
|
*
|
|
* - not ELF / not ELFCLASS32 / not little-endian / not ET_EXEC / not EM_RISCV;
|
|
* - a missing, misaligned or out-of-bounds program-header table;
|
|
* - a PT_LOAD whose file offset, virtual or physical address is not 4-byte aligned,
|
|
* whose file size is not a multiple of 4, or whose file bytes leave the blob;
|
|
* - more than FT_TT_ELF_MAX_SEGMENTS PT_LOADs;
|
|
* - an entry point that is not the start of the first PT_LOAD (the text);
|
|
* - a `.segments` section (written by fw/ft_tensix_*.ld) that disagrees with the
|
|
* PT_LOADs: a different execution address, or a memory size over the region limit.
|
|
*
|
|
* @status Clean-room rewrite. Oracle: tests/test_launch.c (`make check-launch`).
|
|
* @issues None
|
|
* @todo None
|
|
*/
|
|
|
|
#ifndef FT_TT_ELF_H
|
|
#define FT_TT_ELF_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
/** Most PT_LOAD segments an image may carry (text, data, and headroom). */
|
|
#define FT_TT_ELF_MAX_SEGMENTS 4u
|
|
|
|
/** One PT_LOAD segment. */
|
|
typedef struct ft_tt_elf_segment {
|
|
uint32_t exec_address; /**< p_vaddr: where the core sees it when running */
|
|
uint32_t load_address; /**< p_paddr: where its initial image is staged */
|
|
const uint8_t *file_data; /**< p_filesz bytes inside the caller's blob */
|
|
uint32_t file_bytes; /**< p_filesz */
|
|
uint32_t memory_bytes; /**< p_memsz (file bytes plus zero-filled tail) */
|
|
} ft_tt_elf_segment;
|
|
|
|
/** A parsed image: PT_LOADs in program-header order, text first. */
|
|
typedef struct ft_tt_elf_image {
|
|
uint32_t entry_address; /**< e_entry == segments[0].exec_address */
|
|
ft_tt_elf_segment segments[FT_TT_ELF_MAX_SEGMENTS];
|
|
unsigned segment_count; /**< 1..FT_TT_ELF_MAX_SEGMENTS */
|
|
uint32_t loaded_bytes; /**< sum of file_bytes over segments */
|
|
} ft_tt_elf_image;
|
|
|
|
/**
|
|
* Parse and validate `blob`.
|
|
*
|
|
* @param blob ELF file contents.
|
|
* @param blob_size Bytes in `blob`.
|
|
* @param out_image Filled on success; unspecified on failure.
|
|
* @return FT_TT_OK, or FT_TT_EINVAL (reason logged).
|
|
*/
|
|
int ft_tt_elf_parse(const void *blob, size_t blob_size, ft_tt_elf_image *out_image);
|
|
|
|
/**
|
|
* The text segment (the first PT_LOAD), or NULL for a NULL or empty image.
|
|
*/
|
|
const ft_tt_elf_segment *ft_tt_elf_text_segment(const ft_tt_elf_image *image);
|
|
|
|
/**
|
|
* The span of load addresses a load writes: `*out_low` is the lowest load address of a
|
|
* segment with file bytes, `*out_high` the highest load_address + file_bytes. With no
|
|
* file bytes at all, both are the text segment's load address.
|
|
*
|
|
* @return FT_TT_OK, or FT_TT_EINVAL on NULL arguments or an empty image.
|
|
*/
|
|
int ft_tt_elf_load_extent(const ft_tt_elf_image *image, uint32_t *out_low, uint32_t *out_high);
|
|
|
|
#endif
|