ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_mpu.c
Go to the documentation of this file.
1
14
15#include "emu_mpu.h"
16
17#include "emu_engine.h"
18#include "emu_exc.h"
19
43
48typedef struct {
49 uint32_t base;
50 uint32_t limit;
51 bool ro;
52 bool en;
54
56static bool s_mpu_enabled;
58static uint32_t s_mpu_ro_hook_n;
59static bool s_mpu_fault;
60static uint32_t s_mpu_fault_pc;
61static uint32_t s_mpu_fault_addr;
62
88RA8_INTERNAL static void internal_on_mpu_ro_write(uc_engine* uc,
89 uc_mem_type type,
90 uint64_t addr,
91 int size,
92 int64_t value,
93 void* user)
94{
95 (void)type;
96 (void)size;
97 (void)value;
98 (void)user;
99 if (s_mpu_fault) {
100 return; /* one pending fault is enough; the run loop takes it next */
101 }
102 s_mpu_fault = true;
103 s_mpu_fault_addr = (uint32_t)addr;
104 s_mpu_fault_pc = reg_get(uc, UC_ARM_REG_PC);
105 (void)uc_emu_stop(uc);
106}
107
128{
129 s_mpu_ro_hook_n = 0U;
130 for (uint32_t i = 0U; i < (uint32_t)k_mpu_max_regions; i++) {
131 if (!s_mpu_region[i].en || !s_mpu_region[i].ro) {
132 continue;
133 }
134 (void)uc_hook_add(uc,
136 UC_HOOK_MEM_WRITE,
138 nullptr,
139 (uint64_t)s_mpu_region[i].base,
140 (uint64_t)s_mpu_region[i].limit);
142 }
143}
144
162{
163 for (uint32_t i = 0U; i < s_mpu_ro_hook_n; i++) {
164 (void)uc_hook_del(uc, s_mpu_ro_hook[i]);
165 }
166 s_mpu_ro_hook_n = 0U;
167}
168
194RA8_INTERNAL static void internal_on_mpu_rlar_write(uc_engine* uc,
195 uc_mem_type type,
196 uint64_t addr,
197 int size,
198 int64_t value,
199 void* user)
200{
201 (void)type;
202 (void)addr;
203 (void)size;
204 (void)user;
205 const uint32_t rnr = rd32(uc, (uint64_t)k_mpu_rnr) & (uint32_t)k_mpu_rnr_mask;
206 const uint32_t rbar = rd32(uc, (uint64_t)k_mpu_rbar);
207 const uint32_t rlar = (uint32_t)value;
208 s_mpu_region[rnr].base = rbar & (uint32_t)k_mpu_addr_mask;
209 s_mpu_region[rnr].limit = (rlar & (uint32_t)k_mpu_addr_mask) | (uint32_t)k_mpu_region_low_mask;
210 s_mpu_region[rnr].ro = (rbar & (uint32_t)k_mpu_rbar_ap_ro_bit) != 0U;
211 s_mpu_region[rnr].en = (rlar & (uint32_t)k_mpu_rlar_en_bit) != 0U;
212}
213
237RA8_INTERNAL static void internal_on_mpu_ctrl_write(uc_engine* uc,
238 uc_mem_type type,
239 uint64_t addr,
240 int size,
241 int64_t value,
242 void* user)
243{
244 (void)type;
245 (void)addr;
246 (void)size;
247 (void)user;
248 const bool enable = ((uint32_t)value & (uint32_t)k_mpu_ctrl_enable_bit) != 0U;
249 if (enable && !s_mpu_enabled) {
251 s_mpu_enabled = true;
252 } else if (!enable && s_mpu_enabled) {
254 s_mpu_enabled = false;
255 }
256}
257
281void mpu_synth_memmanage(uc_engine* uc, uint32_t vtor_base)
282{
283 const uint32_t cfsr = rd32(uc, (uint64_t)k_scb_cfsr) | (uint32_t)k_cfsr_mmfsr_daccviol |
284 (uint32_t)k_cfsr_mmfsr_mmarvalid;
285 wr32(uc, (uint64_t)k_scb_cfsr, cfsr);
286 wr32(uc, (uint64_t)k_scb_mmfar, s_mpu_fault_addr);
287 (void)uc_reg_write(uc, UC_ARM_REG_PC, &s_mpu_fault_pc);
288 const uint32_t handler = exc_vector(uc, vtor_base, (uint32_t)k_exc_memmanage);
289 if (handler != 0U) {
290 exc_enter(uc, (uint32_t)k_exc_memmanage, handler);
291 }
292}
293
295void emu_mpu_install(uc_engine* uc)
296{
297 /* Armv8-M MPU enforcement: capture each region at its RLAR write, then arm /
298 * disarm read-only-region write traps on MPU_CTRL.ENABLE edges. Inert unless
299 * the firmware programs and enables the MPU (mpu_partition_simple); a trapped
300 * store synthesises MemManage in the run loop (see internal_on_mpu_ro_write). */
301 static uc_hook s_h_mpu_rlar;
302 static uc_hook s_h_mpu_ctrl;
303 (void)uc_hook_add(uc,
304 &s_h_mpu_rlar,
305 UC_HOOK_MEM_WRITE,
307 nullptr,
308 (uint64_t)k_mpu_rlar,
309 (uint64_t)k_mpu_rlar + 3U);
310 (void)uc_hook_add(uc,
311 &s_h_mpu_ctrl,
312 UC_HOOK_MEM_WRITE,
314 nullptr,
315 (uint64_t)k_mpu_ctrl,
316 (uint64_t)k_mpu_ctrl + 3U);
317}
318
321{
322 return s_mpu_fault;
323}
324
327{
328 s_mpu_fault = false;
329}
Shared Unicorn engine access utilities for the board emulator.
static uint32_t reg_get(uc_engine *uc, int reg)
Read a Unicorn 32-bit register by its UC_ARM_REG_* id.
Definition emu_engine.h:113
static uint32_t rd32(uc_engine *uc, uint64_t addr)
Read a 32-bit little-endian word from emulated memory.
Definition emu_engine.h:67
static void wr32(uc_engine *uc, uint64_t addr, uint32_t v)
Write a 32-bit little-endian word to emulated memory.
Definition emu_engine.h:91
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_scb_cfsr
Config Fault Status (MMFSR low byte).
Definition emu_exc.h:52
@ k_scb_mmfar
MemManage Fault Address Register.
Definition emu_exc.h:53
@ k_mpu_rbar
MPU_RBAR (BASE[31:5]|SH|AP[2:1]|XN).
Definition emu_exc.h:48
@ k_exc_memmanage
MemManage exception / vector index.
Definition emu_exc.h:57
@ k_mpu_ctrl
MPU_CTRL (ENABLE in bit 0).
Definition emu_exc.h:46
@ k_mpu_rnr
MPU_RNR (region number select).
Definition emu_exc.h:47
@ k_mpu_rlar
MPU_RLAR (LIMIT[31:5]|AttrIdx|EN).
Definition emu_exc.h:49
uint32_t exc_vector(uc_engine *uc, uint32_t vtor_base, uint32_t exc_num)
Read the handler address for an exception from the vector table.
Definition emu_exc.c:417
void exc_enter(uc_engine *uc, uint32_t exc_num, uint32_t handler)
Enter a Cortex-M exception: stack the basic frame and vector in.
Definition emu_exc.c:210
static uint32_t s_mpu_ro_hook_n
Installed hook count.
Definition emu_mpu.c:58
static uc_hook s_mpu_ro_hook[k_mpu_max_regions]
RO-range write hooks.
Definition emu_mpu.c:57
static RA8_INTERNAL void internal_on_mpu_ctrl_write(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
UC_HOOK_MEM_WRITE handler for MPU_CTRL – arm / disarm enforcement.
Definition emu_mpu.c:237
static mpu_region_t s_mpu_region[k_mpu_max_regions]
Per-region shadow.
Definition emu_mpu.c:55
bool emu_mpu_fault_pending(void)
Implementation of emu_mpu_fault_pending() – plain flag read.
Definition emu_mpu.c:320
static RA8_INTERNAL void internal_mpu_remove_ro_hooks(uc_engine *uc)
Remove every installed RO-region write hook.
Definition emu_mpu.c:161
static bool s_mpu_enabled
CTRL.ENABLE active.
Definition emu_mpu.c:56
static uint32_t s_mpu_fault_pc
PC of faulting store.
Definition emu_mpu.c:60
static RA8_INTERNAL void internal_on_mpu_ro_write(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
UC_HOOK_MEM_WRITE handler for a write into an enforced RO MPU region.
Definition emu_mpu.c:88
static RA8_INTERNAL void internal_mpu_install_ro_hooks(uc_engine *uc)
Install a write hook on every enabled, read-only MPU region.
Definition emu_mpu.c:127
void emu_mpu_clear_fault(void)
Implementation of emu_mpu_clear_fault() – plain flag clear.
Definition emu_mpu.c:326
void mpu_synth_memmanage(uc_engine *uc, uint32_t vtor_base)
Synthesise a MemManage (#4) fault for a trapped RO-region write.
Definition emu_mpu.c:281
static RA8_INTERNAL void internal_on_mpu_rlar_write(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
UC_HOOK_MEM_WRITE handler for MPU_RLAR – capture one region.
Definition emu_mpu.c:194
static bool s_mpu_fault
RO write trapped.
Definition emu_mpu.c:59
mpu_field_t
Armv8-M MPU register field bits ra8_emulator enforces.
Definition emu_mpu.c:32
@ k_mpu_rlar_en_bit
RLAR.EN region-enable.
Definition emu_mpu.c:35
@ k_mpu_max_regions
Modelled data regions (DREGION).
Definition emu_mpu.c:39
@ k_mpu_rnr_mask
8 regions -> 3-bit select.
Definition emu_mpu.c:38
@ k_mpu_region_low_mask
Low 5 bits of an inclusive limit.
Definition emu_mpu.c:37
@ k_mpu_ctrl_enable_bit
MPU_CTRL.ENABLE.
Definition emu_mpu.c:33
@ k_mpu_rbar_ap_ro_bit
RBAR.AP[2]=1 -> read-only.
Definition emu_mpu.c:34
@ k_mpu_addr_mask
BASE/LIMIT [31:5] (32-byte gran).
Definition emu_mpu.c:36
@ k_cfsr_mmfsr_mmarvalid
CFSR.MMFSR.MMARVALID.
Definition emu_mpu.c:41
@ k_cfsr_mmfsr_daccviol
CFSR.MMFSR.DACCVIOL.
Definition emu_mpu.c:40
void emu_mpu_install(uc_engine *uc)
Implementation of emu_mpu_install() – RLAR capture + CTRL edges.
Definition emu_mpu.c:295
static uint32_t s_mpu_fault_addr
Address written.
Definition emu_mpu.c:61
Armv8-M MPU enforcement model for ra8_emulator.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
One captured MPU data region (base/limit + permission/enable).
Definition emu_mpu.c:48
uint32_t limit
Inclusive region top.
Definition emu_mpu.c:50
bool en
RLAR.EN set.
Definition emu_mpu.c:52
bool ro
AP encodes read-only (no privileged write).
Definition emu_mpu.c:51
uint32_t base
Inclusive region base (32-byte aligned).
Definition emu_mpu.c:49