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

Armv8-M MPU enforcement implementation (see emu_mpu.h). More...

#include "emu_mpu.h"
#include "emu_engine.h"
#include "emu_exc.h"
Include dependency graph for emu_mpu.c:

Go to the source code of this file.

Data Structures

struct  mpu_region_t
 One captured MPU data region (base/limit + permission/enable). More...

Enumerations

enum  mpu_field_t : uint32_t {
  k_mpu_ctrl_enable_bit = 1U << 0U ,
  k_mpu_rbar_ap_ro_bit = 1U << 2U ,
  k_mpu_rlar_en_bit = 1U << 0U ,
  k_mpu_addr_mask = 0xFFFFFFE0U ,
  k_mpu_region_low_mask = 0x1FU ,
  k_mpu_rnr_mask = 0x7U ,
  k_mpu_max_regions = 8U ,
  k_cfsr_mmfsr_daccviol = 1U << 1U ,
  k_cfsr_mmfsr_mmarvalid = 1U << 7U
}
 Armv8-M MPU register field bits ra8_emulator enforces. More...

Functions

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.
static RA8_INTERNAL void internal_mpu_install_ro_hooks (uc_engine *uc)
 Install a write hook on every enabled, read-only MPU region.
static RA8_INTERNAL void internal_mpu_remove_ro_hooks (uc_engine *uc)
 Remove every installed RO-region write hook.
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.
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.
void mpu_synth_memmanage (uc_engine *uc, uint32_t vtor_base)
 Synthesise a MemManage (#4) fault for a trapped RO-region write.
void emu_mpu_install (uc_engine *uc)
 Implementation of emu_mpu_install() – RLAR capture + CTRL edges.
bool emu_mpu_fault_pending (void)
 Implementation of emu_mpu_fault_pending() – plain flag read.
void emu_mpu_clear_fault (void)
 Implementation of emu_mpu_clear_fault() – plain flag clear.

Variables

static mpu_region_t s_mpu_region [k_mpu_max_regions]
 Per-region shadow.
static bool s_mpu_enabled
 CTRL.ENABLE active.
static uc_hook s_mpu_ro_hook [k_mpu_max_regions]
 RO-range write hooks.
static uint32_t s_mpu_ro_hook_n
 Installed hook count.
static bool s_mpu_fault
 RO write trapped.
static uint32_t s_mpu_fault_pc
 PC of faulting store.
static uint32_t s_mpu_fault_addr
 Address written.

Detailed Description

Armv8-M MPU enforcement implementation (see emu_mpu.h).

Region capture at RLAR writes, RO-region write traps armed/disarmed on CTRL.ENABLE edges, and the MemManage synthesis – moved verbatim out of the ra8_emulator main translation unit.

Since
0.1.0

Definition in file emu_mpu.c.

Enumeration Type Documentation

◆ mpu_field_t

enum mpu_field_t : uint32_t

Armv8-M MPU register field bits ra8_emulator enforces.

The firmware programs the MPU via ra8_mpu (RNR -> RBAR -> RLAR per region, then CTRL). ra8_emulator watches those writes (no banked per-region storage in the flat-RAM PPB, so each region is captured at its RLAR write) and, while CTRL.ENABLE is set, faults a privileged store into any read-only region with a synthesised MemManage – the part Unicorn's core does not model. Inert unless the firmware enables the MPU.

Enumerator
k_mpu_ctrl_enable_bit 

MPU_CTRL.ENABLE.

k_mpu_rbar_ap_ro_bit 

RBAR.AP[2]=1 -> read-only.

k_mpu_rlar_en_bit 

RLAR.EN region-enable.

k_mpu_addr_mask 

BASE/LIMIT [31:5] (32-byte gran).

k_mpu_region_low_mask 

Low 5 bits of an inclusive limit.

k_mpu_rnr_mask 

8 regions -> 3-bit select.

k_mpu_max_regions 

Modelled data regions (DREGION).

k_cfsr_mmfsr_daccviol 

CFSR.MMFSR.DACCVIOL.

k_cfsr_mmfsr_mmarvalid 

CFSR.MMFSR.MMARVALID.

Definition at line 32 of file emu_mpu.c.

Function Documentation

◆ emu_mpu_clear_fault()

void emu_mpu_clear_fault ( void )

Implementation of emu_mpu_clear_fault() – plain flag clear.

Clear the latched MPU violation.

Definition at line 326 of file emu_mpu.c.

References s_mpu_fault.

Referenced by internal_run_inner_take_exception(), and warm_reboot().

◆ emu_mpu_fault_pending()

bool emu_mpu_fault_pending ( void )

Implementation of emu_mpu_fault_pending() – plain flag read.

Whether an RO-region write violation is latched.

Definition at line 320 of file emu_mpu.c.

References s_mpu_fault.

Referenced by internal_run_inner_take_exception().

◆ emu_mpu_install()

void emu_mpu_install ( uc_engine * uc)

Implementation of emu_mpu_install() – RLAR capture + CTRL edges.

Arm the MPU register watchers (RLAR capture + CTRL edge hooks).

Definition at line 295 of file emu_mpu.c.

References internal_on_mpu_ctrl_write(), internal_on_mpu_rlar_write(), k_mpu_ctrl, and k_mpu_rlar.

Referenced by internal_main_install_core_seams().

◆ internal_mpu_install_ro_hooks()

RA8_INTERNAL void internal_mpu_install_ro_hooks ( uc_engine * uc)
static

Install a write hook on every enabled, read-only MPU region.

Called when the firmware sets MPU_CTRL.ENABLE. Memory hooks are evaluated at access time, so a violating store anywhere in a region's [base, limit] range traps via internal_on_mpu_ro_write.

Parameters
[in,out]ucUnicorn engine.
Returns
Nothing.
Precondition
The per-region shadow s_mpu_region has been captured at RLAR writes.
No RO hooks are currently installed.
Postcondition
s_mpu_ro_hook_n hooks are installed (one per RO region).
Non-RO / disabled regions are left unhooked (writable).
Note
RW and background-region accesses are never hooked, so cost is nil for apps that do not lock down a region.
Since
0.1.0

Definition at line 127 of file emu_mpu.c.

References internal_on_mpu_ro_write(), k_mpu_max_regions, RA8_INTERNAL, s_mpu_region, s_mpu_ro_hook, and s_mpu_ro_hook_n.

Referenced by internal_on_mpu_ctrl_write().

◆ internal_mpu_remove_ro_hooks()

RA8_INTERNAL void internal_mpu_remove_ro_hooks ( uc_engine * uc)
static

Remove every installed RO-region write hook.

Called when the firmware clears MPU_CTRL.ENABLE, restoring plain read/write access to the formerly protected ranges.

Parameters
[in,out]ucUnicorn engine.
Returns
Nothing.
Precondition
s_mpu_ro_hook[0 .. s_mpu_ro_hook_n) hold live hook handles.
The engine is not mid-callback for one of those hooks.
Postcondition
All RO hooks are deleted and s_mpu_ro_hook_n is 0.
Subsequent writes to the ranges no longer trap.
Note
Idempotent when no hooks are installed.
Since
0.1.0

Definition at line 161 of file emu_mpu.c.

References RA8_INTERNAL, s_mpu_ro_hook, and s_mpu_ro_hook_n.

Referenced by internal_on_mpu_ctrl_write().

◆ internal_on_mpu_ctrl_write()

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 )
static

UC_HOOK_MEM_WRITE handler for MPU_CTRL – arm / disarm enforcement.

On the ENABLE edge, install write hooks over every read-only region; on the disable edge, remove them. Edge-tracked via s_mpu_enabled so repeated writes of the same state are no-ops.

Parameters
[in,out]ucUnicorn engine.
[in]typeAccess type (write); unused.
[in]addrObserved address (MPU_CTRL); unused.
[in]sizeAccess width; unused.
[in]valueThe CTRL value being written.
[in]userHook user pointer; unused.
Returns
Nothing.
Precondition
The per-region shadow has been captured for the regions in use.
The engine permits uc_hook_add / uc_hook_del from a callback.
Postcondition
Enforcement hooks match the new ENABLE state.
s_mpu_enabled tracks the latest ENABLE bit.
Note
Apps that never enable the MPU install no hooks (zero overhead).
Since
0.1.0

Definition at line 237 of file emu_mpu.c.

References internal_mpu_install_ro_hooks(), internal_mpu_remove_ro_hooks(), k_mpu_ctrl_enable_bit, RA8_INTERNAL, and s_mpu_enabled.

Referenced by emu_mpu_install().

◆ internal_on_mpu_rlar_write()

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 )
static

UC_HOOK_MEM_WRITE handler for MPU_RLAR – capture one region.

ra8_mpu programs each region as RNR -> RBAR -> RLAR, so at the RLAR write the region's RNR and RBAR already sit in the (flat-RAM) PPB; read them back and record base / limit / permission / enable into the per-region shadow. The flat PPB has no banked per-region storage, so this capture-at-RLAR is how ra8_emulator reconstructs the table the real MPU keeps internally.

Parameters
[in,out]ucUnicorn engine.
[in]typeAccess type (write); unused.
[in]addrObserved address (MPU_RLAR); unused.
[in]sizeAccess width; unused.
[in]valueThe RLAR value being written.
[in]userHook user pointer; unused.
Returns
Nothing.
Precondition
RNR + RBAR for this region were written before this RLAR store.
The PPB RNR / RBAR words are mapped as RAM.
Postcondition
s_mpu_region[RNR] mirrors the region (en=0 for an RLAR=0 disable).
No enforcement changes until MPU_CTRL.ENABLE is (re)written.
Note
AP[2]=1 in RBAR marks the region read-only (no privileged store).
Since
0.1.0

Definition at line 194 of file emu_mpu.c.

References k_mpu_addr_mask, k_mpu_rbar, k_mpu_rbar_ap_ro_bit, k_mpu_region_low_mask, k_mpu_rlar_en_bit, k_mpu_rnr, k_mpu_rnr_mask, RA8_INTERNAL, rd32(), and s_mpu_region.

Referenced by emu_mpu_install().

◆ internal_on_mpu_ro_write()

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 )
static

UC_HOOK_MEM_WRITE handler for a write into an enforced RO MPU region.

Installed (only while the MPU is enabled) on the exact [base, limit] range of each read-only region. A privileged store into that range is an MPU permission violation; record the faulting PC + address and stop the chunk so the run loop can synthesise a MemManage exception at this boundary – Unicorn's core models no MPU, so this is the software stand-in.

Parameters
[in,out]ucUnicorn engine.
[in]typeAccess type (write); unused.
[in]addrAddress being written (the violating address).
[in]sizeAccess width; unused.
[in]valueValue being written; unused.
[in]userHook user pointer; unused.
Returns
Nothing.
Precondition
The MPU is enabled and addr lies in a read-only region.
The PPB CFSR / MMFAR words are mapped as RAM.
Postcondition
s_mpu_fault is set with the PC / address latched; emulation stopped.
At most one pending MPU fault is tracked at a time.
Note
PC is captured here (the store instruction) so the run loop stacks it.
Since
0.1.0

Definition at line 88 of file emu_mpu.c.

References RA8_INTERNAL, reg_get(), s_mpu_fault, s_mpu_fault_addr, and s_mpu_fault_pc.

Referenced by internal_mpu_install_ro_hooks().

◆ mpu_synth_memmanage()

void mpu_synth_memmanage ( uc_engine * uc,
uint32_t vtor_base )

Synthesise a MemManage (#4) fault for a trapped RO-region write.

Called by the run loop after internal_on_mpu_ro_write latched a violation. Latches CFSR.MMFSR.DACCVIOL + MMARVALID and MMFAR (so a fault handler – and the HIL alive probe – see the architectural status), forces PC back to the faulting store so exc_enter stacks that address (a recovering handler skips exactly one store), and vectors into the application's MemManage_Handler. If no handler is installed the violation is dropped (no escalation modelled).

Parameters
[in,out]ucUnicorn engine.
[in]vtor_baseFallback vector base if VTOR reads as 0.
Returns
Nothing.
Precondition
s_mpu_fault_pc / s_mpu_fault_addr hold the trapped store.
The PPB CFSR / MMFAR words and the vector table are mapped as RAM.
Postcondition
On a valid vector, the core is in the MemManage handler with the basic frame stacked (stacked PC == the faulting store).
CFSR.MMFSR and MMFAR reflect a data-access violation.
Note
Faithful to the recovering-handler contract of mpu_partition_simple.
Since
0.1.0

Definition at line 281 of file emu_mpu.c.

References exc_enter(), exc_vector(), k_cfsr_mmfsr_daccviol, k_cfsr_mmfsr_mmarvalid, k_exc_memmanage, k_scb_cfsr, k_scb_mmfar, rd32(), s_mpu_fault_addr, s_mpu_fault_pc, and wr32().

Referenced by internal_run_inner_take_exception().

Variable Documentation

◆ s_mpu_enabled

bool s_mpu_enabled
static

CTRL.ENABLE active.

Definition at line 56 of file emu_mpu.c.

Referenced by internal_on_mpu_ctrl_write().

◆ s_mpu_fault

bool s_mpu_fault
static

RO write trapped.

Definition at line 59 of file emu_mpu.c.

Referenced by emu_mpu_clear_fault(), emu_mpu_fault_pending(), and internal_on_mpu_ro_write().

◆ s_mpu_fault_addr

uint32_t s_mpu_fault_addr
static

Address written.

Definition at line 61 of file emu_mpu.c.

Referenced by internal_on_mpu_ro_write(), and mpu_synth_memmanage().

◆ s_mpu_fault_pc

uint32_t s_mpu_fault_pc
static

PC of faulting store.

Definition at line 60 of file emu_mpu.c.

Referenced by internal_on_mpu_ro_write(), and mpu_synth_memmanage().

◆ s_mpu_region

mpu_region_t s_mpu_region[k_mpu_max_regions]
static

Per-region shadow.

Definition at line 55 of file emu_mpu.c.

Referenced by internal_mpu_install_ro_hooks(), and internal_on_mpu_rlar_write().

◆ s_mpu_ro_hook

uc_hook s_mpu_ro_hook[k_mpu_max_regions]
static

RO-range write hooks.

Definition at line 57 of file emu_mpu.c.

Referenced by internal_mpu_install_ro_hooks(), and internal_mpu_remove_ro_hooks().

◆ s_mpu_ro_hook_n

uint32_t s_mpu_ro_hook_n
static

Installed hook count.

Definition at line 58 of file emu_mpu.c.

Referenced by internal_mpu_install_ro_hooks(), and internal_mpu_remove_ro_hooks().