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

Invalid-instruction dispatcher + trap-path seams (see emu_seams.h). More...

#include <capstone/capstone.h>
#include <stdio.h>
#include "emu_engine.h"
#include "emu_exc.h"
#include "emu_host_io_internal.h"
#include "emu_seams.h"
Include dependency graph for emu_insn_seams.c:

Go to the source code of this file.

Enumerations

enum  cs_op_field_t : uint32_t {
  k_cs_op_shift = 12U ,
  k_cs_op_mask = 0x3U
}
 Thumb halfword-two field decode for the conditional-select family. More...
enum  cond_select_t : uint32_t {
  k_cs_hw1_mask = 0xFFF0U ,
  k_cs_hw1_match = 0xEA50U ,
  k_cs_hw2_b15 = 0x8000U ,
  k_cs_hw2_b14 = 0x4000U ,
  k_cs_op_csel = 0U ,
  k_cs_op_csinc = 1U ,
  k_cs_op_csinv = 2U ,
  k_cs_op_csneg = 3U ,
  k_cs_insn_len = 4U ,
  k_cs_reg_sp = 13U ,
  k_cs_reg_pc = 15U
}
enum  apsr_bit_t : uint32_t {
  k_apsr_n = 31U ,
  k_apsr_z = 30U ,
  k_apsr_c = 29U ,
  k_apsr_v = 28U
}
enum  arm_cond_t : uint32_t {
  k_cond_eq = 0x0U ,
  k_cond_ne = 0x1U ,
  k_cond_cs = 0x2U ,
  k_cond_cc = 0x3U ,
  k_cond_mi = 0x4U ,
  k_cond_pl = 0x5U ,
  k_cond_vs = 0x6U ,
  k_cond_vc = 0x7U ,
  k_cond_hi = 0x8U ,
  k_cond_ls = 0x9U ,
  k_cond_ge = 0xAU ,
  k_cond_lt = 0xBU ,
  k_cond_gt = 0xCU ,
  k_cond_le = 0xDU ,
  k_cond_al = 0xEU
}
 ARM/Thumb 4-bit condition-code field encodings (cond[3:0]). More...
enum  : uint32_t {
  k_lob_dls_hw1 = 0xF040U ,
  k_lob_dls_h1m = 0xFFF0U ,
  k_lob_dls_hw2 = 0xE001U ,
  k_lob_le_hw1 = 0xF00FU ,
  k_lob_le_hw2 = 0xC000U ,
  k_lob_le_h2m = 0xF000U ,
  k_lob_le_imm10 = 0x03FFU ,
  k_lob_le_lsb = 11U ,
  k_lob_rn_mask = 0xFU ,
  k_lob_insn_len = 4U
}

Functions

static RA8_INTERNAL bool internal_cond_holds (uint32_t cond, uint32_t xpsr)
 Evaluate an ARM condition code against the APSR flags.
static RA8_INTERNAL bool internal_cs_reserved_reg (uint32_t reg)
 Report whether reg is reserved as a conditional-select operand.
static RA8_INTERNAL bool internal_emulate_cond_select (uc_engine *uc, uint32_t pc, const uint8_t *code)
 Emulate one Armv8.1-M conditional-select instruction if present at PC.
static RA8_INTERNAL bool internal_emulate_barrier (uc_engine *uc, uint32_t pc, const uint8_t *code)
 Emulate an Armv8-M memory barrier (DSB/DMB/ISB) as a NOP if present.
static RA8_INTERNAL bool internal_emulate_sec_scrub (uc_engine *uc, uint32_t pc, const uint8_t code[4])
 Emulate the Armv8-M security register-scrub ops as NOPs.
static RA8_INTERNAL bool internal_emulate_lob (uc_engine *uc, uint32_t pc, const uint8_t code[4])
 Emulate a DLS/LE Low-Overhead-Branch instruction; true iff handled.
static RA8_INTERNAL bool internal_dispatch_armv81_seam (uc_engine *uc, uint32_t pc, const uint8_t code[4])
 Emulate one Armv8.1-M instruction Unicorn's M33 core does not provide.
static RA8_INTERNAL bool internal_dispatch_insn_seam (uc_engine *uc, uint32_t pc, const uint8_t code[4])
 Try each Armv8.1-M / security seam in turn; true (and stop) if handled.
static RA8_INTERNAL void internal_report_unhandled_insn (uint32_t pc, const uint8_t code[4])
 Report + capstone-disassemble an instruction no seam could decode.
bool on_invalid_insn (uc_engine *uc, void *user)
 Disassemble + report an instruction the core could not decode.
void emu_insn_seams_install (uc_engine *uc)
 Implementation of emu_insn_seams_install() – arm the dispatcher.
uint64_t emu_lob_emulated_count (void)
 Implementation of emu_lob_emulated_count() – plain counter read.

Variables

static uint64_t s_lob_emulated = 0U
 Count of LOB instructions emulated this run (run-end telemetry).

Detailed Description

Invalid-instruction dispatcher + trap-path seams (see emu_seams.h).

The UC_HOOK_INSN_INVALID dispatcher and the seams that ride it: the armed div-0 UDF service, the Armv8-M security register scrubs (CLRM / VSCCLRM), the Armv8.1-M conditional-select family (CSEL/CSINC/CSINV/CSNEG), the DSB/DMB/ISB barriers old Unicorn builds trap, the MVE run consumer, and the low-overhead-branch (DLS/LE) hardware loops. Every handled seam edits PC and stops the engine so the chunked run loop relaunches on valid code (editing PC and continuing in-place corrupts Unicorn's block/Thumb state). Moved verbatim out of the ra8_emulator main translation unit.

Since
0.1.0

Definition in file emu_insn_seams.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum : uint32_t
Enumerator
k_lob_dls_hw1 

DLS lr,Rn first half-word (Rn in [3:0]).

k_lob_dls_h1m 

Mask isolating the fixed DLS hw1 bits.

k_lob_dls_hw2 

DLS second half-word (fully fixed).

k_lob_le_hw1 

LE lr,label first half-word.

k_lob_le_hw2 

LE second half-word fixed bits.

k_lob_le_h2m 

Mask isolating the fixed LE hw2 bits.

k_lob_le_imm10 

LE offset high bits hw2[10:1] (#233).

k_lob_le_lsb 

LE offset LSB scattered to hw2[11].

k_lob_rn_mask 

Rn field (4 bits) in hw1[3:0].

k_lob_insn_len 

LOB instructions are 32-bit Thumb-2.

Definition at line 340 of file emu_insn_seams.c.

◆ apsr_bit_t

enum apsr_bit_t : uint32_t
Enumerator
k_apsr_n 

Negative.

k_apsr_z 

Zero.

k_apsr_c 

Carry.

k_apsr_v 

Overflow.

Definition at line 57 of file emu_insn_seams.c.

◆ arm_cond_t

enum arm_cond_t : uint32_t

ARM/Thumb 4-bit condition-code field encodings (cond[3:0]).

Enumerator
k_cond_eq 

Equal (Z==1).

k_cond_ne 

Not equal (Z==0).

k_cond_cs 

Carry set / unsigned >=.

k_cond_cc 

Carry clear / unsigned <.

k_cond_mi 

Negative.

k_cond_pl 

Positive or zero.

k_cond_vs 

Overflow set.

k_cond_vc 

Overflow clear.

k_cond_hi 

Unsigned higher.

k_cond_ls 

Unsigned lower or same.

k_cond_ge 

Signed >=.

k_cond_lt 

Signed <.

k_cond_gt 

Signed >.

k_cond_le 

Signed <=.

k_cond_al 

Always.

Definition at line 68 of file emu_insn_seams.c.

◆ cond_select_t

enum cond_select_t : uint32_t
Enumerator
k_cs_hw1_mask 

hw1 high 12 bits identify the group.

k_cs_hw1_match 

hw1[15:4] == 0xEA5 for this family.

k_cs_hw2_b15 

hw2 bit15 must be 1.

k_cs_hw2_b14 

hw2 bit14 must be 0.

k_cs_op_csel 

op == 00: Rd = c ?

Rn : Rm.

k_cs_op_csinc 

op == 01: Rd = c ?

Rn : Rm + 1.

k_cs_op_csinv 

op == 10: Rd = c ?

Rn : ~Rm.

k_cs_op_csneg 

op == 11: Rd = c ?

Rn : -Rm.

k_cs_insn_len 

Both halfwords: 4 bytes.

k_cs_reg_sp 

SP: reserved as a CSEL operand.

k_cs_reg_pc 

PC: reserved as a CSEL operand.

Definition at line 42 of file emu_insn_seams.c.

◆ cs_op_field_t

enum cs_op_field_t : uint32_t

Thumb halfword-two field decode for the conditional-select family.

Enumerator
k_cs_op_shift 

CSEL-family op = hw2[13:12].

k_cs_op_mask 

2-bit op field.

Definition at line 29 of file emu_insn_seams.c.

Function Documentation

◆ emu_insn_seams_install()

void emu_insn_seams_install ( uc_engine * uc)

Implementation of emu_insn_seams_install() – arm the dispatcher.

Arm the invalid-instruction dispatcher on the engine.

Definition at line 586 of file emu_insn_seams.c.

References on_invalid_insn().

Referenced by internal_main_install_core_seams().

◆ emu_lob_emulated_count()

uint64_t emu_lob_emulated_count ( void )

Implementation of emu_lob_emulated_count() – plain counter read.

Count of LOB (DLS/LE) instructions emulated this run (telemetry).

Definition at line 593 of file emu_insn_seams.c.

References s_lob_emulated.

Referenced by internal_run_print_stop_summary().

◆ internal_cond_holds()

RA8_INTERNAL bool internal_cond_holds ( uint32_t cond,
uint32_t xpsr )
static

Evaluate an ARM condition code against the APSR flags.

Parameters
[in]cond4-bit ARM condition code (0..15).
[in]xpsrCurrent xPSR (APSR flags live in the top nibble).
Returns
true if the condition holds.

Evaluate an arm condition code against the apsr flags; this step is contained within the emu insn seams model and uses bounded caller or module-owned storage.

Return values
trueThe cond holds condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for cond holds.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 99 of file emu_insn_seams.c.

References k_apsr_c, k_apsr_n, k_apsr_v, k_apsr_z, k_cond_cc, k_cond_cs, k_cond_eq, k_cond_ge, k_cond_gt, k_cond_hi, k_cond_le, k_cond_ls, k_cond_lt, k_cond_mi, k_cond_ne, k_cond_pl, k_cond_vc, k_cond_vs, k_lo4_mask, and RA8_INTERNAL.

Referenced by internal_emulate_cond_select().

◆ internal_cs_reserved_reg()

RA8_INTERNAL bool internal_cs_reserved_reg ( uint32_t reg)
static

Report whether reg is reserved as a conditional-select operand.

SP and PC make CSEL/CSINC/CSINV/CSNEG UNPREDICTABLE, so no compiler emits them and their presence means the decode window landed on a different instruction entirely.

Parameters
[in]regRegister index [0, 15].
Returns
true when reg is SP or PC.
Return values
truereg is SP (13) or PC (15).
falsereg is a general-purpose operand register.
Precondition
reg was masked to four bits by the caller.
Postcondition
No state is modified (pure predicate).
Note
Not thread-safe by inheritance only; the predicate itself is pure.
Since
0.1.0
Precondition
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 157 of file emu_insn_seams.c.

References k_cs_reg_pc, k_cs_reg_sp, and RA8_INTERNAL.

Referenced by internal_emulate_cond_select().

◆ internal_dispatch_armv81_seam()

RA8_INTERNAL bool internal_dispatch_armv81_seam ( uc_engine * uc,
uint32_t pc,
const uint8_t code[4] )
static

Emulate one Armv8.1-M instruction Unicorn's M33 core does not provide.

The RA8D2 firmware is built for Cortex-M85 (Armv8.1-M) but the nearest core Unicorn offers is M33 (Armv8-M), so the conditional selects, the barriers, Helium, the register-form long shifts and the hardware loops all arrive as undefined instructions. Each handler writes its result and advances PC; the caller stops the engine so the chunked run loop relaunches from the new PC. Split out of internal_dispatch_insn_seam, which keeps the two seams that are about ra8_emulator's own machinery (a patched divide, a security scrub) rather than a missing instruction.

Parameters
[in,out]ucUnicorn engine.
[in]pcAddress of the trapping instruction.
[in]codeThe 4 instruction bytes at pc.
Returns
true when a handler claimed and emulated the instruction.
Return values
truePC has advanced; the caller must stop and relaunch.
falseNo handler recognised code.
Precondition
code holds the bytes the core failed to decode at pc.
uc is stopped inside the invalid-instruction hook.
Postcondition
On true, PC points past the emulated instruction.
Note
Not thread-safe; called from the single-threaded run loop.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 442 of file emu_insn_seams.c.

References emulate_long_shift_reg(), emulate_mve(), internal_emulate_barrier(), internal_emulate_cond_select(), and internal_emulate_lob().

Referenced by internal_dispatch_insn_seam().

◆ internal_dispatch_insn_seam()

RA8_INTERNAL bool internal_dispatch_insn_seam ( uc_engine * uc,
uint32_t pc,
const uint8_t code[4] )
static

Try each Armv8.1-M / security seam in turn; true (and stop) if handled.

Try each armv8.1-m / security seam in turn; true (and stop) if handled; this step is contained within the emu insn seams model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]pcGuest program-counter value associated with the operation.
[in]codeInstruction, status, or command code decoded by the operation.
Returns
The dispatch insn seam result produced by the emu insn seams model.
Return values
trueThe dispatch insn seam condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for dispatch insn seam.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 499 of file emu_insn_seams.c.

References emulate_div0_patched(), internal_dispatch_armv81_seam(), and internal_emulate_sec_scrub().

Referenced by on_invalid_insn().

◆ internal_emulate_barrier()

RA8_INTERNAL bool internal_emulate_barrier ( uc_engine * uc,
uint32_t pc,
const uint8_t * code )
static

Emulate an Armv8-M memory barrier (DSB/DMB/ISB) as a NOP if present.

Some Unicorn builds – e.g. 2.0.1, as packaged on the Linux CI runner – do not decode the self-synchronising barrier instructions DSB / DMB / ISB and trap them as invalid, where a newer build executes them. They have no architectural effect in this single-threaded, in-order emulator (there is no real memory ordering or pipeline to enforce), so recognising the encoding and advancing PC past the 4-byte instruction is a faithful NOP. This keeps the firmware's boot-path barriers (e.g. after a clock / SDRAM register write) from faulting regardless of the host Unicorn version. Anything else is left untouched.

Parameters
[in,out]ucUnicorn engine.
[in]pcAddress of the trapped instruction.
[in]codeThe 4 instruction bytes already read at pc.
Returns
true if a DSB/DMB/ISB barrier was recognised and PC advanced past it.
Return values
trueThe emulate barrier condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for emulate barrier.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

< First half-word of DSB/DMB/ISB.

< Fixed high byte of the second h-word.

< 0x8F: the barrier group.

< Barrier subtype field, bits [7:4].

< DSB.

< DMB.

< ISB.

< Thumb-2 barrier instruction length.

Definition at line 265 of file emu_insn_seams.c.

References RA8_INTERNAL.

Referenced by internal_dispatch_armv81_seam().

◆ internal_emulate_cond_select()

RA8_INTERNAL bool internal_emulate_cond_select ( uc_engine * uc,
uint32_t pc,
const uint8_t * code )
static

Emulate one Armv8.1-M conditional-select instruction if present at PC.

Decodes the CSEL/CSINC/CSINV/CSNEG encoding (see cond_select_t), evaluates the condition against the APSR, computes Rd, writes it back, and advances PC past the 4-byte instruction. This lets Unicorn's M33 core execute the M85 firmware's branchless index math instead of trapping on an opcode it does not implement. Anything that is not this family is left untouched.

Parameters
[in,out]ucUnicorn engine.
[in]pcAddress of the trapped instruction.
[in]codeThe 4 instruction bytes already read at pc.
Returns
true if a conditional-select was recognised, executed, and PC advanced.
Return values
trueThe emulate cond select condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for emulate cond select.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 183 of file emu_insn_seams.c.

References internal_cond_holds(), internal_cs_reserved_reg(), k_arm_reg_id, k_cs_hw1_mask, k_cs_hw1_match, k_cs_hw2_b14, k_cs_hw2_b15, k_cs_insn_len, k_cs_op_csel, k_cs_op_csinc, k_cs_op_csinv, k_cs_op_csneg, k_cs_op_mask, k_cs_op_shift, and k_lo4_mask.

Referenced by internal_dispatch_armv81_seam().

◆ internal_emulate_lob()

RA8_INTERNAL bool internal_emulate_lob ( uc_engine * uc,
uint32_t pc,
const uint8_t code[4] )
static

Emulate a DLS/LE Low-Overhead-Branch instruction; true iff handled.

Emulate a dls/le low-overhead-branch instruction; true iff handled; this step is contained within the emu insn seams model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]pcGuest program-counter value associated with the operation.
[in]codeInstruction, status, or command code decoded by the operation.
Returns
The emulate lob result produced by the emu insn seams model.
Return values
trueThe emulate lob condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for emulate lob.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 368 of file emu_insn_seams.c.

References k_arm_reg_id, k_byte_bits, k_lob_dls_h1m, k_lob_dls_hw1, k_lob_dls_hw2, k_lob_insn_len, k_lob_le_h2m, k_lob_le_hw1, k_lob_le_hw2, k_lob_le_imm10, k_lob_le_lsb, k_lob_rn_mask, RA8_INTERNAL, and s_lob_emulated.

Referenced by internal_dispatch_armv81_seam().

◆ internal_emulate_sec_scrub()

RA8_INTERNAL bool internal_emulate_sec_scrub ( uc_engine * uc,
uint32_t pc,
const uint8_t code[4] )
static

Emulate the Armv8-M security register-scrub ops as NOPs.

CLRM {regs} and VSCCLRM {s..,VPR} zero caller-saved core / FP registers on a Non-Secure-Callable return so Secure data cannot leak to the Non-Secure caller. ra8_emulator is a single flat domain with one register/FP bank, so the scrub has no observable effect on a correct caller (the cleared registers are already caller-saved/clobbered) – model them as NOPs so the cmse veneer epilogue runs. Unicorn's M33 rejects both as invalid.

Parameters
[in,out]ucUnicorn engine.
[in]pcAddress of the instruction.
[in]codeFour instruction bytes at pc.
Returns
true if code was a scrub op (PC advanced past it); false otherwise.
Precondition
code holds the 4 bytes at pc.
uc is running.
Postcondition
On true, PC is advanced one 32-bit instruction.
On false, no state changes.
Note
Not thread-safe.
Since
0.1.0
Return values
trueThe emulate sec scrub condition holds or completed successfully; false otherwise.

Definition at line 316 of file emu_insn_seams.c.

References k_byte_bits, k_clrm_hw0, k_thumb2_insn_bytes, k_vscclrm_hw0_d, and k_vscclrm_hw0_s.

Referenced by internal_dispatch_insn_seam().

◆ internal_report_unhandled_insn()

RA8_INTERNAL void internal_report_unhandled_insn ( uint32_t pc,
const uint8_t code[4] )
static

Report + capstone-disassemble an instruction no seam could decode.

Report + capstone-disassemble an instruction no seam could decode; this step is contained within the emu insn seams model and uses bounded caller or module-owned storage.

Parameters
[in]pcGuest program-counter value associated with the operation.
[in]codeInstruction, status, or command code decoded by the operation.
Precondition
Arguments satisfy the ranges documented for report unhandled insn.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu insn seams model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 534 of file emu_insn_seams.c.

References k_cs_insn_len, priv_emu_io_errf(), and RA8_INTERNAL.

Referenced by on_invalid_insn().

◆ on_invalid_insn()

bool on_invalid_insn ( uc_engine * uc,
void * user )

Disassemble + report an instruction the core could not decode.

UC_HOOK_INSN_INVALID dispatcher: service or report a trapped opcode.

Definition at line 560 of file emu_insn_seams.c.

References emu_mem_read(), emu_mve_nocp_spurious(), internal_dispatch_insn_seam(), and internal_report_unhandled_insn().

Referenced by emu_insn_seams_install().

Variable Documentation

◆ s_lob_emulated

uint64_t s_lob_emulated = 0U
static

Count of LOB instructions emulated this run (run-end telemetry).

Definition at line 353 of file emu_insn_seams.c.

Referenced by emu_lob_emulated_count(), and internal_emulate_lob().