ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_elf.c File Reference

Streaming ELF32 segment, vector-base, and warm-reboot services. More...

#include "emu_elf.h"
#include <stdint.h>
#include <string.h>
#include "emu_elf_source_internal.h"
#include "emu_host_io_internal.h"
#include "emu_memory_access.h"
Include dependency graph for emu_elf.c:

Go to the source code of this file.

Data Structures

struct  emu_elf_program_table_t
 Decoded program-header table geometry. More...
struct  emu_elf_load_ctx_t
 Context for streaming PT_LOAD bytes into one Unicorn engine. More...
struct  emu_elf_vector_ctx_t
 Accumulator for the lowest executable segment VMA. More...

Enumerations

enum  emu_elf_stream_limit_t : uint32_t {
  k_elf_program_header_min = 32U ,
  k_elf_stream_scratch = 4096U ,
  k_elf_word_high_shift = 24U ,
  k_elf_data_offset = 5U
}
 Bounded parser and PT_LOAD transfer dimensions. More...

Functions

static uint16_t internal_u16 (const uint8_t *bytes)
 Decode one little-endian 16-bit ELF field.
static uint32_t internal_u32 (const uint8_t *bytes)
 Decode one little-endian 32-bit ELF field.
static bool internal_program_table (const emu_elf_source_t *source, emu_elf_program_table_t *table, uint16_t *machine)
 Read and validate the ELF32 ARM header and program-table geometry.
static bool internal_load_segment (const emu_elf_source_t *source, const emu_elf_program_table_t *table, uint16_t index, elf_exec_segment_t *segment)
 Decode one bounds-checked PT_LOAD entry.
uint32_t elf_foreach_load_segment (const emu_elf_source_t *elf, elf_exec_segment_fn fn, void *ctx)
 Walk every non-empty, bounds-checked PT_LOAD segment.
static bool internal_stream_segment (const elf_exec_segment_t *segment, void *opaque)
 Stream one PT_LOAD segment into Unicorn in bounded chunks.
int load_elf (uc_engine *uc, const emu_elf_source_t *elf)
 Load ELF32 PT_LOAD segments into emulated memory at their LMA.
uint32_t elf_foreach_exec_segment (const emu_elf_source_t *elf, elf_exec_segment_fn fn, void *ctx)
 Walk every executable PT_LOAD segment of an ELF32 image.
static bool internal_vector_segment (const elf_exec_segment_t *segment, void *opaque)
 Fold one executable segment into the lowest-VMA accumulator.
uint32_t elf_vector_base (const emu_elf_source_t *elf)
 Vector-table base of an ELF: lowest executable PT_LOAD VMA.

Detailed Description

Streaming ELF32 segment, vector-base, and warm-reboot services.

Program headers and PT_LOAD bytes are read from an independently owned raw descriptor through bounded stack scratch. No complete image is allocated, mapped, or retained in process memory.

Since
0.1.0

Definition in file emu_elf.c.

Enumeration Type Documentation

◆ emu_elf_stream_limit_t

enum emu_elf_stream_limit_t : uint32_t

Bounded parser and PT_LOAD transfer dimensions.

Enumerator
k_elf_program_header_min 

ELF32 program-header bytes consumed.

k_elf_stream_scratch 

Maximum transient segment bytes.

k_elf_word_high_shift 

Shift of byte three in a word.

k_elf_data_offset 

ELF identification data-byte offset.

Definition at line 23 of file emu_elf.c.

Function Documentation

◆ elf_foreach_exec_segment()

uint32_t elf_foreach_exec_segment ( const emu_elf_source_t * elf,
elf_exec_segment_fn fn,
void * ctx )

Walk every executable PT_LOAD segment of an ELF32 image.

Decodes the program-header table once, skips any segment that is not a non-empty executable PT_LOAD or that would run past the end of the image, and invokes fn for each survivor. Factored out because the seam installers and the profiler each need exactly this walk; duplicating it left the same twenty statements of bounds-checking in several functions, where a fix to one copy would silently miss the others.

Parameters
[in]elfOpen source; every read is bounded by its captured length.
[in]fnCallback invoked per executable segment.
[in,out]ctxOpaque pointer forwarded to fn.
Returns
The number of segments handed to fn.
Return values
0The image is too short, the header table is truncated, or the image carries no executable PT_LOAD segment.
Precondition
elf remains open for the complete walk.
fn is non-NULL.
Postcondition
No read touches a byte at or beyond elf->length.
The walk stops early once fn returns false.
Note
Independent source instances may be walked concurrently.
See also
div0_seam_install() Scans for UDIV/SDIV sites.
long_shift_seam_install() Scans for LSLL/LSRL/ASRL sites.
Since
0.1.0

Definition at line 265 of file emu_elf.c.

References emu_elf_program_table_t::count, elf_exec_segment_t::flags, internal_load_segment(), internal_program_table(), and k_elf_pf_x.

Referenced by div0_seam_install(), elf_vector_base(), and long_shift_seam_install().

◆ elf_foreach_load_segment()

uint32_t elf_foreach_load_segment ( const emu_elf_source_t * elf,
elf_exec_segment_fn fn,
void * ctx )

Walk every non-empty, bounds-checked PT_LOAD segment.

Decodes each usable load header and publishes only source offsets.

Parameters
[in]elfOpen immutable ELF source.
[in]fnCallback invoked for each segment.
[in,out]ctxOpaque callback context.
Returns
Number of load segments handed to fn.
Return values
0The header is malformed or no load segment was delivered.
Precondition
elf remains open for the complete walk.
fn is non-null.
Postcondition
No segment range crosses the source length.
Iteration stops when fn returns false.
Note
Segment descriptors borrow only the source context, never file bytes.
Since
0.1.0

Definition at line 172 of file emu_elf.c.

References emu_elf_program_table_t::count, internal_load_segment(), and internal_program_table().

Referenced by internal_cpu1_image_present(), and load_elf().

◆ elf_vector_base()

uint32_t elf_vector_base ( const emu_elf_source_t * elf)

Vector-table base of an ELF: lowest executable PT_LOAD VMA.

Walks the program headers and returns the lowest p_vaddr among non-empty, executable (PF_X) PT_LOAD segments. On Cortex-M the vector table is linked at the start of the executable text region, so this is the image's vector base: 0x32100000 for the RAM-resident NS layout (a single RWE segment runs from the NS_SRAM2 alias) and 0x90000000 for the OSPI-XIP layout (the R-E segment executes in place from the flash window). The executable filter is essential for XIP: that image also carries a writable .data segment whose VMA is 0x32100000 (its initialisers live in flash, copied to RAM at NS startup) – lower than the vectors – so a plain minimum-VMA scan would wrongly pick the RAM alias. ra8_emulator feeds the result to the TrustZone NS vector-base tracking so the BLXNS world switch reads the NS MSP/reset from wherever the loaded image placed them.

Parameters
[in]elfOpen ELF source (little-endian ELF32 ARM).
Returns
Lowest executable PT_LOAD p_vaddr, or 0 if none / the header is bad.
Return values
0No executable PT_LOAD segment, or a truncated header table.
Precondition
elf remains open throughout the bounded header walk.
The program-header table lies within elf->length.
Postcondition
The return value is the VMA of some executable PT_LOAD segment, or 0.
Note
Not thread-safe; ra8_emulator is single-threaded.
See also
elf_sym_addr() The symbol-level companion lookup.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 320 of file emu_elf.c.

References emu_elf_vector_ctx_t::base, elf_foreach_exec_segment(), emu_elf_vector_ctx_t::found, and internal_vector_segment().

Referenced by internal_main_load_ns().

◆ internal_load_segment()

bool internal_load_segment ( const emu_elf_source_t * source,
const emu_elf_program_table_t * table,
uint16_t index,
elf_exec_segment_t * segment )
static

Decode one bounds-checked PT_LOAD entry.

Reads only the fixed ELF32 header prefix and validates its payload range.

Parameters
[in]sourceOpen ELF source.
[in]tableValidated program-table geometry.
[in]indexEntry index below table->count.
[out]segmentReceives the decoded PT_LOAD descriptor.
Returns
True only for a non-empty, wholly bounded PT_LOAD entry.
Return values
trueA usable load segment was published.
falseThe entry is unreadable, not loadable, empty, or out of range.
Precondition
All pointers are non-null and index is in range.
source remains open during the exact read.
Postcondition
Success publishes no borrowed byte pointer.
Malformed/non-load entries leave segment untouched.
Note
Uses only 32 bytes of stack scratch.
Since
0.1.0

Definition at line 142 of file emu_elf.c.

References emu_elf_program_table_t::entry_size, internal_u32(), k_elf_ph_filesz_off, k_elf_ph_flags_off, k_elf_ph_offset_off, k_elf_ph_paddr_off, k_elf_ph_vaddr_off, k_elf_program_header_min, k_elf_pt_load, k_emu_elf_io_ok, emu_elf_source_t::length, emu_elf_program_table_t::offset, priv_emu_elf_read(), and RA8_INTERNAL.

Referenced by elf_foreach_exec_segment(), and elf_foreach_load_segment().

◆ internal_program_table()

bool internal_program_table ( const emu_elf_source_t * source,
emu_elf_program_table_t * table,
uint16_t * machine )
static

Read and validate the ELF32 ARM header and program-table geometry.

Rejects wrong magic, class, byte order, machine, and table bounds.

Parameters
[in]sourceOpen source to inspect.
[out]tableReceives validated program-header geometry.
[out]machineReceives e_machine when the fixed header was readable.
Returns
Whether the source is ELF32 ARM with a wholly bounded table.
Return values
trueBoth the fixed header and complete table geometry are valid.
falseThe source read or any validation failed.
Precondition
table and machine are non-null.
source remains open during the exact header read.
Postcondition
Success initializes both outputs.
Failure performs no out-of-range read.
Note
Uses only a 52-byte stack view.
Since
0.1.0

Definition at line 90 of file emu_elf.c.

References emu_elf_program_table_t::count, emu_elf_program_table_t::entry_size, internal_u16(), internal_u32(), k_elf_data_offset, k_elf_e_machine_off, k_elf_e_phentsize_off, k_elf_e_phnum_off, k_elf_e_phoff_off, k_elf_ehdr_size, k_elf_em_arm, k_elf_program_header_min, k_emu_elf_io_ok, emu_elf_source_t::length, memcmp(), emu_elf_program_table_t::offset, priv_emu_elf_read(), and RA8_INTERNAL.

Referenced by elf_foreach_exec_segment(), elf_foreach_load_segment(), and load_elf().

◆ internal_stream_segment()

bool internal_stream_segment ( const elf_exec_segment_t * segment,
void * opaque )
static

Stream one PT_LOAD segment into Unicorn in bounded chunks.

Alternates exact positioned reads and Unicorn writes until complete.

Parameters
[in]segmentBounds-checked load segment.
[in,out]opaqueemu_elf_load_ctx_t destination state.
Returns
True to continue, false on the first transfer failure.
Return values
trueEvery source byte was written successfully.
falseA source read or Unicorn write failed.
Precondition
Both pointers are non-null and the engine target is mapped.
segment source remains open.
Postcondition
Success writes every segment byte at its LMA.
Failure sets the sticky context flag and emits one diagnostic.
Note
Stack scratch is fixed at 4096 bytes regardless of segment size.
Since
0.1.0

Definition at line 218 of file emu_elf.c.

References emu_elf_view_t::bytes, emu_mem_write(), emu_elf_load_ctx_t::failed, elf_exec_segment_t::filesz, k_elf_stream_scratch, k_emu_elf_io_ok, emu_elf_load_ctx_t::loaded, elf_exec_segment_t::offset, elf_exec_segment_t::paddr, priv_emu_elf_read(), priv_emu_io_errf(), RA8_INTERNAL, elf_exec_segment_t::source, emu_elf_io_result_t::status, and emu_elf_load_ctx_t::uc.

Referenced by load_elf().

◆ internal_u16()

uint16_t internal_u16 ( const uint8_t * bytes)
static

Decode one little-endian 16-bit ELF field.

Combines bytes explicitly so host byte order is irrelevant.

Parameters
[in]bytesAt least two readable bytes.
Returns
Decoded host value.
Return values
uint16_tThe decoded unsigned field.
Precondition
bytes is non-null and two-byte bounded.
The source field uses ELF little-endian encoding.
Postcondition
No state changes.
The input bytes remain unchanged.
Note
Pure and alignment-independent.
Since
0.1.0

Definition at line 50 of file emu_elf.c.

References RA8_INTERNAL.

Referenced by internal_program_table().

◆ internal_u32()

uint32_t internal_u32 ( const uint8_t * bytes)
static

Decode one little-endian 32-bit ELF field.

Combines bytes explicitly so host byte order is irrelevant.

Parameters
[in]bytesAt least four readable bytes.
Returns
Decoded host value.
Return values
uint32_tThe decoded unsigned field.
Precondition
bytes is non-null and four-byte bounded.
The source field uses ELF little-endian encoding.
Postcondition
No state changes.
The input bytes remain unchanged.
Note
Pure and alignment-independent.
Since
0.1.0

Definition at line 68 of file emu_elf.c.

References k_elf_word_high_shift, and RA8_INTERNAL.

Referenced by internal_load_segment(), and internal_program_table().

◆ internal_vector_segment()

bool internal_vector_segment ( const elf_exec_segment_t * segment,
void * opaque )
static

Fold one executable segment into the lowest-VMA accumulator.

Replaces the candidate only when this segment has a lower VMA.

Parameters
[in]segmentBounds-checked executable segment.
[in,out]opaqueemu_elf_vector_ctx_t accumulator.
Returns
Whether the executable-segment walk should continue.
Return values
trueEvery valid segment is accepted for comparison.
Precondition
segment is non-null.
opaque points to a writable accumulator.
Postcondition
The accumulator retains the lowest VMA seen so far.
No source or emulator state changes.
Note
Pure apart from the caller-owned accumulator.
Since
0.1.0

Definition at line 310 of file emu_elf.c.

References emu_elf_vector_ctx_t::base, emu_elf_vector_ctx_t::found, RA8_INTERNAL, and elf_exec_segment_t::vaddr.

Referenced by elf_vector_base().

◆ load_elf()

int load_elf ( uc_engine * uc,
const emu_elf_source_t * elf )

Load ELF32 PT_LOAD segments into emulated memory at their LMA.

Validates the ELF magic, class (ELFCLASS32) and machine (EM_ARM), then walks the program headers and writes each non-empty PT_LOAD segment's file bytes to its physical load address (p_paddr) in uc memory – exactly what a flash programmer does with the image. One loaded ... @ ... injected error sink line is emitted per segment. .bss is untouched (the firmware's own Reset_Handler zeroes it), matching real boot.

Parameters
[in,out]ucUnicorn engine whose memory receives the segments.
[in]elfOpen immutable ELF source.
Returns
0 on success, -1 on a malformed image or a failed memory write.
Return values
0At least one PT_LOAD segment was written.
-1Not a 32-bit ARM ELF, or a segment write failed, or no segment was loadable.
Precondition
uc has every segment's target region mapped.
elf remains open for the complete segment walk.
Postcondition
On success, every non-empty PT_LOAD segment is resident at its LMA.
On failure, a diagnostic has been printed to injected error sink.
Note
Not thread-safe; call during single-threaded setup or a warm reboot.
See also
priv_emu_elf_source_open() Acquires the source this consumes.
Since
0.1.0

Definition at line 248 of file emu_elf.c.

References elf_foreach_load_segment(), emu_elf_load_ctx_t::failed, internal_program_table(), internal_stream_segment(), k_elf_em_arm, emu_elf_load_ctx_t::loaded, and priv_emu_io_errf().

Referenced by internal_cpu1_engine_init(), internal_main_load_ns(), internal_main_load_primary(), and warm_reboot().