ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_tz.c
Go to the documentation of this file.
1
14
15#include "emu_tz.h"
16
17#include <stdio.h>
18
19#include "emu_console.h"
20#include "emu_elf.h"
21#include "emu_exc.h"
23#include "emu_memory_access.h"
24
41static uint32_t s_ns_vector_base = (uint32_t)k_ns_sram2_base;
42
44typedef enum : uint64_t {
45 k_scb_vtor_ns_addr = 0xE002ED08UL,
47
55typedef enum : uint32_t {
56 k_blxns_mask = 0xFF87U,
57 k_blxns_match = 0x4784U,
59
87RA8_INTERNAL static void
88internal_on_blxns(uc_engine* uc, uint64_t address, uint32_t size, void* user)
89{
90 (void)address;
91 (void)size;
92 (void)user;
93 /* Prefer the live VTOR_NS: ra8_tz_secure_boot_jump_ns stores the NS vector
94 * base to the 0xE002ED08 alias (plain PPB RAM here) right before its BLXNS,
95 * so this resolves the NS table wherever the app placed it (MRAM-resident
96 * 0x02080000, SRAM2 run alias 0x32100000, or OSPI XIP) with no per-app
97 * knowledge. Fall back to ::s_ns_vector_base when the app never wrote it. */
98 uint32_t vector_base = 0U;
99 (void)emu_mem_read(uc, (uint64_t)k_scb_vtor_ns_addr, &vector_base, sizeof(vector_base));
100 if (vector_base == 0U) {
101 vector_base = s_ns_vector_base;
102 }
103 uint32_t ns_msp = 0U;
104 uint32_t ns_reset = 0U;
105 (void)emu_mem_read(uc, (uint64_t)vector_base, &ns_msp, sizeof(ns_msp));
106 (void)emu_mem_read(uc,
107 (uint64_t)vector_base + (uint64_t)sizeof(uint32_t),
108 &ns_reset,
109 sizeof(ns_reset));
110 const uint32_t ns_pc = ns_reset & ~1U; /* mask the Thumb bit for the PC write */
111 (void)uc_reg_write(uc, UC_ARM_REG_SP, &ns_msp);
112 (void)uc_reg_write(uc, UC_ARM_REG_PC, &ns_pc);
113 (void)uc_emu_stop(uc);
114}
115
137RA8_INTERNAL static uint32_t internal_emu_tz_find_blxns(uc_engine* uc, uint32_t from, uint32_t size)
138{
139 for (uint32_t a = from; (a + (uint32_t)k_thumb_hw_bytes) <= (from + size);
140 a += (uint32_t)k_thumb_hw_bytes) {
141 uint16_t hw = 0U;
142 (void)emu_mem_read(uc, (uint64_t)a, &hw, sizeof(hw));
143 if (((uint32_t)hw & (uint32_t)k_blxns_mask) == (uint32_t)k_blxns_match) {
144 return a;
145 }
146 }
147 return 0U;
148}
149
152void emu_tz_install(uc_engine* uc, const emu_elf_source_t* elf)
153{
154 /* TrustZone S->NS boot seams -- armed whenever the firmware links the secure
155 * boot's ra8_tz_secure_boot_jump_ns: a two-image --ns app, OR a single-image
156 * app whose NS half is embedded at its MRAM LMA (cpu1_pingpong_ipc). The
157 * Secure boot bails to its fallback main() unless SAU_TYPE.SREGION >= 4/5;
158 * ra8_emulator maps the PPB as plain RAM (SAU_TYPE reads 0), so seed the
159 * M85's 8-region count to let the real SAU programming + NS-image copy +
160 * BLXNS run. Firmware without the symbol keeps its current (all-Secure) path.
161 */
162 uint32_t jn_size = 0U;
163 const uint32_t jump_ns = elf_sym_addr(elf, "ra8_tz_secure_boot_jump_ns", &jn_size);
164 if ((jump_ns == 0U) || (jn_size < (uint32_t)k_thumb_hw_bytes)) {
165 return; /* Not a TrustZone image: keep the all-Secure path. */
166 }
167 const uint32_t sau_type = (uint32_t)k_sau_type_regs;
168 (void)emu_mem_write(uc, (uint64_t)k_sau_type_addr, &sau_type, sizeof(sau_type));
169
170 /* Hand-emulate the Secure->NS BLXNS in ra8_tz_secure_boot_jump_ns.
171 * Unicorn's all-Secure M33 cannot really switch worlds, so resolve the
172 * BLXNS site from the Secure symtab (scan the function for the BLXNS
173 * opcode) and hook it to enter NS manually (see internal_on_blxns). Without this
174 * the BLXNS stalls and the NS world never runs. */
175 const uint32_t blxns_at = internal_emu_tz_find_blxns(uc, jump_ns, jn_size);
176 if (blxns_at == 0U) {
177 (void)priv_emu_io_errf("ra8_emulator: TZ warning: no BLXNS found in "
178 "ra8_tz_secure_boot_jump_ns\n");
179 return;
180 }
181 uc_hook h_blxns;
182 (void)uc_hook_add(uc,
183 &h_blxns,
184 UC_HOOK_CODE,
185 (void*)internal_on_blxns,
186 nullptr,
187 (uint64_t)blxns_at,
188 (uint64_t)blxns_at);
189 (void)priv_emu_io_errf("ra8_emulator: TZ BLXNS seam armed @ 0x%08X\n", blxns_at);
190}
191
194void emu_tz_patch_cmse(uc_engine* uc, const emu_elf_source_t* elf)
195{
196 /* TrustZone NSC pointer validation. The Non-Secure-Callable veneers guard
197 * their pointer args with cmse_check_address_range(), which issues Armv8-M
198 * `TT`/`TTA` (Test Target) instructions to read an address's security/MPU
199 * attribution and then checks the Non-Secure read/write bit. Unicorn's M33
200 * has no SAU/IDAU configured (ra8_emulator maps the PPB as plain RAM, so the
201 * core's internal SAU stays at its reset all-Secure state); a native TT thus
202 * reports every address as Secure, the NS range-check fails, and the veneer
203 * returns k_ra8_err_invalid_arg -- stalling CGC/SD bring-up. ra8_emulator
204 * collapses the Secure/Non-Secure split into one flat, fully-accessible
205 * domain, so every NS pointer the veneers pass (each already null-checked
206 * before the range check) is valid. Model that by patching the routine's
207 * entry to `BX LR`: r0 still holds the first argument (the pointer `p`) at
208 * entry, so an immediate return yields p != NULL == "address OK". This is a
209 * one-time 2-byte memory patch (the function image is already copied into
210 * Unicorn memory by load_elf), not a UC_HOOK_CODE -- a code hook forces
211 * Unicorn to single-step the whole run
212 * (~10x slower), whereas the patch has zero steady-state cost. Absent in
213 * non-TZ firmware (symbol not found -> no patch). */
214 const uint32_t cmse_check_addr = elf_sym_addr(elf, "cmse_check_address_range", nullptr);
215 if (cmse_check_addr != 0U) {
216 const uint16_t bx_lr = (uint16_t)k_thumb_bx_lr;
217 (void)emu_mem_write(uc, (uint64_t)cmse_check_addr, &bx_lr, sizeof(bx_lr));
218 }
219}
220
222void emu_tz_set_ns_vector_base(uint32_t base)
223{
224 s_ns_vector_base = base;
225}
226
229{
230 return s_ns_vector_base;
231}
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
@ k_sau_type_regs
SAU_TYPE.SREGION: M85 implements 8.
Definition emu_console.h:76
@ k_sau_type_addr
SAU_TYPE (SREGION = implemented regs).
Definition emu_console.h:53
@ k_ns_sram2_base
SRAM2 Non-secure alias (bit[28]=1).
Definition emu_console.h:54
ELF32 image services for the board emulator (load / symbols / vectors).
uint32_t elf_sym_addr(const emu_elf_source_t *elf, const char *name, uint32_t *size_out)
Resolve a function symbol's entry address from the ELF .symtab.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_thumb_bx_lr
BX LR (stub a function to return).
Definition emu_exc.h:122
@ k_thumb_hw_bytes
Bytes per Thumb halfword.
Definition emu_exc.h:123
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.
Central first-party Unicorn memory access seam.
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
static void internal_on_blxns(uc_engine *uc, uint64_t address, uint32_t size, void *user)
UC_HOOK_CODE at the Secure->NS BLXNS – hand-emulate the world switch.
Definition emu_tz.c:88
uint32_t emu_tz_ns_vector_base(void)
Implementation of emu_tz_ns_vector_base() – plain state read.
Definition emu_tz.c:228
void emu_tz_install(uc_engine *uc, const emu_elf_source_t *elf)
Implementation of emu_tz_install() – SAU seed + BLXNS scan/hook.
Definition emu_tz.c:152
static uint32_t s_ns_vector_base
Fallback NS vector-table base for the BLXNS world switch.
Definition emu_tz.c:41
void emu_tz_set_ns_vector_base(uint32_t base)
Implementation of emu_tz_set_ns_vector_base() – –ns override.
Definition emu_tz.c:222
void emu_tz_patch_cmse(uc_engine *uc, const emu_elf_source_t *elf)
Implementation of emu_tz_patch_cmse() – flat-domain range check.
Definition emu_tz.c:194
vtor_ns_addr_t
SCB VTOR_NS alias address (ARMv8-M B3.2.4; Secure-state view).
Definition emu_tz.c:44
@ k_scb_vtor_ns_addr
VTOR_NS: NS vector-table base.
Definition emu_tz.c:45
static uint32_t internal_emu_tz_find_blxns(uc_engine *uc, uint32_t from, uint32_t size)
Scan a Thumb function image for its first BLXNS instruction.
Definition emu_tz.c:137
blxns_op_t
Thumb encoding of the BLXNS instruction (scanned in jump_ns).
Definition emu_tz.c:55
@ k_blxns_mask
Mask isolating the BLXNS fixed bits.
Definition emu_tz.c:56
@ k_blxns_match
BLXNS fixed-bit pattern (any Rm).
Definition emu_tz.c:57
TrustZone Secure/Non-Secure seams for ra8_emulator.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One independently owned immutable raw-descriptor ELF source.
Definition emu_elf.h:91