20#include <capstone/capstone.h>
29typedef enum : uint32_t {
42typedef enum : uint32_t {
57typedef enum : uint32_t {
68typedef enum : uint32_t {
101 const bool n = ((xpsr >> (uint32_t)
k_apsr_n) & 1U) != 0U;
102 const bool z = ((xpsr >> (uint32_t)
k_apsr_z) & 1U) != 0U;
103 const bool c = ((xpsr >> (uint32_t)
k_apsr_c) & 1U) != 0U;
104 const bool v = ((xpsr >> (uint32_t)
k_apsr_v) & 1U) != 0U;
131 return !z && (n == v);
133 return z || (n != v);
185 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << 8));
186 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << 8));
191 const uint32_t rn = (uint32_t)(hw1 & (uint32_t)
k_lo4_mask);
193 const uint32_t rd = (uint32_t)((hw2 >> 8) & (uint32_t)
k_lo4_mask);
194 const uint32_t cond = (uint32_t)((hw2 >> 4) & (uint32_t)
k_lo4_mask);
195 const uint32_t rm = (uint32_t)(hw2 & (uint32_t)
k_lo4_mask);
211 (void)uc_reg_read(uc, UC_ARM_REG_XPSR, &xpsr);
227 result = (uint32_t)(-(int32_t)vm);
237 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
268 k_barrier_hw1 = 0xF3BFU,
269 k_barrier_hw2_mask = 0xFF00U,
270 k_barrier_hw2_match = 0x8F00U,
271 k_barrier_op_mask = 0x00F0U,
272 k_barrier_op_dsb = 0x0040U,
273 k_barrier_op_dmb = 0x0050U,
274 k_barrier_op_isb = 0x0060U,
275 k_barrier_len = 0x0004U,
277 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << 8));
278 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << 8));
279 if ((hw1 != (uint16_t)k_barrier_hw1) ||
280 ((hw2 & (uint16_t)k_barrier_hw2_mask) != (uint16_t)k_barrier_hw2_match)) {
283 const uint16_t op = (uint16_t)(hw2 & (uint16_t)k_barrier_op_mask);
284 if ((op != (uint16_t)k_barrier_op_dsb) && (op != (uint16_t)k_barrier_op_dmb) &&
285 (op != (uint16_t)k_barrier_op_isb)) {
288 const uint32_t next = pc + (uint32_t)k_barrier_len;
289 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
318 const uint16_t hw0 = (uint16_t)(((uint16_t)code[1] << (uint16_t)
k_byte_bits) | (uint16_t)code[0]);
324 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
370 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << (uint16_t)
k_byte_bits));
371 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << (uint16_t)
k_byte_bits));
382 (void)uc_reg_write(uc, UC_ARM_REG_LR, &v);
384 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
392 (void)uc_reg_read(uc, UC_ARM_REG_LR, &lr);
394 (void)uc_reg_write(uc, UC_ARM_REG_LR, &lr);
404 const uint32_t imm10 = ((uint32_t)hw2 >> 1U) & (uint32_t)
k_lob_le_imm10;
405 const uint32_t lsb = ((uint32_t)hw2 >> (uint32_t)
k_lob_le_lsb) & 1U;
406 next -= ((imm10 << 2U) | (lsb << 1U));
408 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
506 (void)uc_emu_stop(uc);
513 (void)uc_emu_stop(uc);
518 (void)uc_emu_stop(uc);
536 (void)
priv_emu_io_errf(
" INVALID INSN @ 0x%08X: bytes %02X %02X %02X %02X\n",
544 if (cs_open(CS_ARCH_ARM, (cs_mode)(CS_MODE_THUMB | CS_MODE_MCLASS), &cs) == CS_ERR_OK) {
545 cs_insn* insn =
nullptr;
548 const size_t n = cs_disasm(cs, code, (
size_t)
k_cs_insn_len, pc, 1, &insn);
550 (void)
priv_emu_io_errf(
" disasm: %s %s\n", insn[0].mnemonic, insn[0].op_str);
564 (void)uc_reg_read(uc, UC_ARM_REG_PC, &pc);
565 uint8_t code[4] = {};
577 (void)uc_emu_stop(uc);
588 static uc_hook s_h_invalid;
589 (void)uc_hook_add(uc, &s_h_invalid, UC_HOOK_INSN_INVALID, (
void*)
on_invalid_insn,
nullptr, 1, 0);
Shared Unicorn engine access utilities for the board emulator.
const int k_arm_reg_id[16]
ARM register index (0..15) -> Unicorn register id.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_thumb2_insn_bytes
32-bit Thumb-2 instruction width.
@ k_vscclrm_hw0_s
VSCCLRM {s..,VPR} first halfword.
@ k_lo4_mask
Low nibble (register / cond field).
@ k_vscclrm_hw0_d
VSCCLRM {d..,VPR} first halfword.
@ k_byte_bits
Bits per byte (SHPR field width).
@ k_clrm_hw0
CLRM {regs} first halfword.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
static RA8_INTERNAL bool internal_cs_reserved_reg(uint32_t reg)
Report whether reg is reserved as a conditional-select operand.
cs_op_field_t
Thumb halfword-two field decode for the conditional-select family.
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.
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.
void emu_insn_seams_install(uc_engine *uc)
Implementation of emu_insn_seams_install() – arm the dispatcher.
bool on_invalid_insn(uc_engine *uc, void *user)
Disassemble + report an instruction the core could not decode.
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 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 uint64_t s_lob_emulated
Count of LOB instructions emulated this run (run-end telemetry).
static RA8_INTERNAL bool internal_cond_holds(uint32_t cond, uint32_t xpsr)
Evaluate an ARM condition code against the APSR flags.
@ k_lob_le_hw1
LE lr,label first half-word.
@ 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.
@ k_lob_dls_hw2
DLS second half-word (fully fixed).
@ k_lob_le_imm10
LE offset high bits hw2[10:1] (#233).
@ k_lob_le_h2m
Mask isolating the fixed LE hw2 bits.
@ k_lob_le_hw2
LE second half-word fixed bits.
@ k_lob_dls_h1m
Mask isolating the fixed DLS hw1 bits.
@ k_lob_dls_hw1
DLS lr,Rn first half-word (Rn in [3:0]).
arm_cond_t
ARM/Thumb 4-bit condition-code field encodings (cond[3:0]).
@ k_cond_ls
Unsigned lower or same.
@ k_cond_ne
Not equal (Z==0).
@ k_cond_cs
Carry set / unsigned >=.
@ k_cond_vc
Overflow clear.
@ k_cond_hi
Unsigned higher.
@ k_cond_pl
Positive or zero.
@ k_cond_cc
Carry clear / unsigned <.
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_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.
uint64_t emu_lob_emulated_count(void)
Implementation of emu_lob_emulated_count() – plain counter read.
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.
@ k_cs_op_csinv
op == 10: Rd = c ?
@ k_cs_op_csel
op == 00: Rd = c ?
@ k_cs_insn_len
Both halfwords: 4 bytes.
@ k_cs_op_csneg
op == 11: Rd = c ?
@ k_cs_op_csinc
op == 01: Rd = c ?
@ k_cs_hw1_match
hw1[15:4] == 0xEA5 for this family.
@ k_cs_hw2_b14
hw2 bit14 must be 0.
@ k_cs_reg_pc
PC: reserved as a CSEL operand.
@ k_cs_hw1_mask
hw1 high 12 bits identify the group.
@ k_cs_reg_sp
SP: reserved as a CSEL operand.
@ k_cs_hw2_b15
hw2 bit15 must be 1.
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
@ k_cs_op_shift
CSEL-family op = hw2[13:12].
@ k_cs_op_mask
2-bit op field.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
bool on_invalid_insn(uc_engine *uc, void *user)
UC_HOOK_INSN_INVALID dispatcher: service or report a trapped opcode.
bool emu_mve_nocp_spurious(uint32_t pc)
Report whether an invalid-instruction trap at pc is the bogus one Unicorn raises just after the MVE s...
bool emulate_div0_patched(uc_engine *uc, uint32_t pc, const uint8_t code[4])
Service an undefined-instruction trap that landed on an armed divide.
bool emulate_long_shift_reg(uc_engine *uc, uint32_t pc, const uint8_t code[4])
Emulate a register-form Armv8.1-M long shift (LSLL/ASRL) that trapped.
bool emulate_mve(uc_engine *uc, uint32_t pc0, const uint8_t code0[4])
Emulate a run of consecutive auto-vectoriser MVE instructions.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).