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

Cortex-M85 Memory Protection Unit configuration helper. More...

#include "ra8_mpu.h"
#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hw_intrinsics.h"
#include "ra8_mpu_regs.h"
Include dependency graph for ra8_mpu.c:

Go to the source code of this file.

Enumerations

enum  ra8_mpu_ap_t : uint8_t {
  k_ra8_mpu_ap_priv_rw_unpriv_none = 0U ,
  k_ra8_mpu_ap_priv_rw_unpriv_rw = 1U ,
  k_ra8_mpu_ap_priv_ro_unpriv_none = 2U ,
  k_ra8_mpu_ap_priv_ro_unpriv_ro = 3U ,
  k_ra8_mpu_ap_invalid = 0xFFU
}
 Encoded AP[1:0] values per the Cortex-M85 TRM. More...
enum  ra8_mpu_shcsr_addr_t : uintptr_t { k_ra8_mpu_shcsr_addr = 0xE000ED24U }
 SCB->SHCSR address + bits needed to dispatch MemManage faults. More...
enum  ra8_mpu_shcsr_bits_t : uint32_t { k_ra8_mpu_shcsr_memfaultena = (1U << 16U) }
enum  ra8_mpu_boot_base_t : uintptr_t {
  k_ra8_mpu_boot_base_mram = 0x02000000UL ,
  k_ra8_mpu_boot_base_sram = 0x22000000UL ,
  k_ra8_mpu_boot_base_sdram = 0x68000000UL ,
  k_ra8_mpu_boot_base_peri = 0x40000000UL ,
  k_ra8_mpu_boot_base_shram = 0x22100000UL
}
 Region base addresses for the canonical boot map. More...
enum  ra8_mpu_boot_size_t : uint32_t {
  k_ra8_mpu_boot_size_mram = 0x00100000UL ,
  k_ra8_mpu_boot_size_sram = 0x00100000UL ,
  k_ra8_mpu_boot_size_sdram = 0x04000000UL ,
  k_ra8_mpu_boot_size_peri = 0x08000000UL ,
  k_ra8_mpu_boot_size_shram = 0x000A0000UL
}
 Region byte sizes for the canonical boot map (base+size form). More...

Functions

static bool internal_is_pow2 (uint32_t value)
static uint8_t internal_encode_ap (ra8_mpu_perm_t priv, ra8_mpu_perm_t unpriv)
static uint8_t internal_dregion_count (void)
static ra8_err_t internal_validate_region (const ra8_mpu_region_t *r)
static uint32_t internal_build_rbar (const ra8_mpu_region_t *r)
static uint32_t internal_build_rlar (const ra8_mpu_region_t *r)
static void internal_program_region (uint8_t region, const ra8_mpu_region_t *r)
static void internal_clear_region (uint8_t region)
static void internal_write_ctrl (uint32_t ctrl)
static void internal_write_mair (uint32_t mair0, uint32_t mair1)
static uint32_t internal_build_ctrl (const ra8_mpu_cfg_t *cfg)
static ra8_err_t internal_validate_cfg (const ra8_mpu_cfg_t *cfg)
ra8_err_t ra8_mpu_configure (const ra8_mpu_cfg_t *cfg)
 Program every MPU region from a static configuration.
ra8_err_t ra8_mpu_enable (void)
 Set MPU_CTRL.ENABLE.
ra8_err_t ra8_mpu_disable (void)
 Clear MPU_CTRL.ENABLE.
ra8_err_t ra8_mpu_set_region (uint8_t region, const ra8_mpu_region_t *region_cfg)
 Program a single region without disabling the MPU.
const ra8_mpu_region_tra8_mpu_boot_map (uint8_t *out_count)
 Return the canonical boot memory-attribute map region table.
ra8_err_t ra8_mpu_apply_boot_map (void)
 Install the canonical 5-region boot memory-attribute map and enable the MPU.
bool ra8_mpu_is_enabled (void)
 Report whether the core MPU is currently enabled.

Variables

static const char * s_tag = "MPU"
static const ra8_mpu_region_t s_ra8_mpu_boot_regions [k_ra8_mpu_boot_region_count]
 The canonical 5-region boot memory-attribute map.

Detailed Description

Cortex-M85 Memory Protection Unit configuration helper.

Implementation of the public API in ra8_mpu.h. Programmes the Armv8-M MPU register block documented in ra8_mpu_regs.h from a static region table. The register-level shape (RBAR / RLAR / MAIR0 / MAIR1) follows the Arm Cortex-M85 TRM "MPU register summary"; the helper adds power-of-two validation, AP[1:0] encoding from RO/RW/None pairs, and bounds checking against the implemented region count reported by MPU_TYPE.DREGION.

It also owns the canonical 5-region boot memory-attribute map (ra8_mpu_apply_boot_map()), the single source of truth the reset path routes through instead of hand-rolling MAIR/RBAR/RLAR/CTRL pokes in each app's system_init.c (issue #576).

Definition in file ra8_mpu.c.

Enumeration Type Documentation

◆ ra8_mpu_ap_t

enum ra8_mpu_ap_t : uint8_t

Encoded AP[1:0] values per the Cortex-M85 TRM.

Enumerator
k_ra8_mpu_ap_priv_rw_unpriv_none 

00: priv RW, unpriv -.

k_ra8_mpu_ap_priv_rw_unpriv_rw 

01: priv RW, unpriv RW.

k_ra8_mpu_ap_priv_ro_unpriv_none 

10: priv RO, unpriv -.

k_ra8_mpu_ap_priv_ro_unpriv_ro 

11: priv RO, unpriv RO.

k_ra8_mpu_ap_invalid 

Sentinel: not encodable.

Definition at line 40 of file ra8_mpu.c.

◆ ra8_mpu_boot_base_t

enum ra8_mpu_boot_base_t : uintptr_t

Region base addresses for the canonical boot map.

Each base is 32-byte aligned (the Armv8-M region quantum), asserted below. Addresses are 32-bit on the target; uintptr_t keeps the host build (64-bit) casts honest.

Enumerator
k_ra8_mpu_boot_base_mram 

MRAM code base.

k_ra8_mpu_boot_base_sram 

M85-private SRAM0+1 base.

k_ra8_mpu_boot_base_sdram 

External SDRAM base.

k_ra8_mpu_boot_base_peri 

Peripheral window base.

k_ra8_mpu_boot_base_shram 

Shared M85<->M33 SRAM base.

Definition at line 288 of file ra8_mpu.c.

◆ ra8_mpu_boot_size_t

enum ra8_mpu_boot_size_t : uint32_t

Region byte sizes for the canonical boot map (base+size form).

Region 4 (the shared M85<->M33 bank) is 640 KiB – deliberately NOT a power of two, so the size-checked ra8_mpu_set_region() rejects it, but the Armv8-M base+limit RBAR/RLAR pair encodes it exactly. Every size is a 32-byte multiple (asserted below).

Enumerator
k_ra8_mpu_boot_size_mram 

1 MiB MRAM code.

k_ra8_mpu_boot_size_sram 

1 MiB M85-private SRAM.

k_ra8_mpu_boot_size_sdram 

64 MiB SDRAM.

k_ra8_mpu_boot_size_peri 

128 MiB peripheral window.

k_ra8_mpu_boot_size_shram 

640 KiB shared SRAM (!pow2).

Definition at line 304 of file ra8_mpu.c.

◆ ra8_mpu_shcsr_addr_t

enum ra8_mpu_shcsr_addr_t : uintptr_t

SCB->SHCSR address + bits needed to dispatch MemManage faults.

Armv8-M ARM B3.2.10 "SHCSR, System Handler Control and State Register" / Cortex-M85 TRM SCB+0x24. Bit 16 MEMFAULTENA enables the MemManage exception; without it any MPU permission violation escalates to HardFault and the strong MemManage_Handler the application installed never runs.

Enumerator
k_ra8_mpu_shcsr_addr 

SCB->SHCSR (Armv8-M B3.2.10).

Definition at line 59 of file ra8_mpu.c.

◆ ra8_mpu_shcsr_bits_t

enum ra8_mpu_shcsr_bits_t : uint32_t
Enumerator
k_ra8_mpu_shcsr_memfaultena 

SHCSR.MEMFAULTENA bit.

Definition at line 63 of file ra8_mpu.c.

Function Documentation

◆ internal_build_ctrl()

uint32_t internal_build_ctrl ( const ra8_mpu_cfg_t * cfg)
static

◆ internal_build_rbar()

◆ internal_build_rlar()

◆ internal_clear_region()

void internal_clear_region ( uint8_t region)
static

◆ internal_dregion_count()

◆ internal_encode_ap()

◆ internal_is_pow2()

bool internal_is_pow2 ( uint32_t value)
inlinestatic

Definition at line 68 of file ra8_mpu.c.

References RA8_INTERNAL.

Referenced by internal_validate_region().

◆ internal_program_region()

void internal_program_region ( uint8_t region,
const ra8_mpu_region_t * r )
static

◆ internal_validate_cfg()

◆ internal_validate_region()

◆ internal_write_ctrl()

void internal_write_ctrl ( uint32_t ctrl)
static

Definition at line 159 of file ra8_mpu.c.

References r_mpu_regs_t::CTRL, RA8_INTERNAL, and ra8_mpu_regs().

Referenced by ra8_mpu_apply_boot_map(), and ra8_mpu_configure().

◆ internal_write_mair()

void internal_write_mair ( uint32_t mair0,
uint32_t mair1 )
static

◆ ra8_mpu_apply_boot_map()

ra8_err_t ra8_mpu_apply_boot_map ( void )
nodiscard

Install the canonical 5-region boot memory-attribute map and enable the MPU.

Programs the fixed attribute map every RA8D2 image needs out of reset – RO+executable cacheable MRAM code, RW/XN cacheable M85-private SRAM and SDRAM, RW/XN Device-nGnRE peripherals, and RW/XN Normal-non-cacheable shared M85<->M33 SRAM – then enables the MPU with PRIVDEFENA so anything the map does not cover keeps the privileged default memory map. This is the boot-usable entry point that replaces the hand-rolled MAIR/RBAR/RLAR/CTRL pokes each app's system_init.c used to duplicate: the boot path routes its attribute map through this one driver exactly as it already calls ra8_cache_dcache_invalidate_all().

Callable from SystemInit() before .data/.bss are initialised: it reads only the driver-owned const region table (in .rodata) and MMIO, writes no .data/.bss, and never logs. The shared M85<->M33 bank is 640 KiB, which is not a power of two and so cannot be expressed through the size-checked ra8_mpu_set_region(); this entry point encodes it by base+limit directly, which the Armv8-M PMSAv8 RBAR/RLAR pair supports natively.

Returns
ra8_err_t error code.
Return values
k_ra8_okMap installed; MPU enabled with PRIVDEFENA.
k_ra8_err_invalid_argMPU_TYPE.DREGION reports fewer than k_ra8_mpu_boot_region_count implemented regions; the MPU is left disabled.
Precondition
Caller is privileged (true out of reset in the Secure state).
The core MPU is idle (freshly reset or previously disabled).
Postcondition
On k_ra8_ok, MPU_CTRL.ENABLE == 1 and MPU_CTRL.PRIVDEFENA == 1.
On failure the MPU is left disabled; no partial map is enabled.
Note
Not thread-safe; single-threaded boot / init context only.
Does not touch SHCSR.MEMFAULTENA – the boot path enables the configurable-fault handlers separately; a runtime caller wanting MemManage delivery uses ra8_mpu_configure() instead.
See also
ra8_mpu_boot_map() Inspect the region table this installs.
ra8_mpu_configure() Full runtime configuration from a caller table.
Since
0.1.0

Definition at line 417 of file ra8_mpu.c.

References internal_clear_region(), internal_dregion_count(), internal_program_region(), internal_write_ctrl(), internal_write_mair(), k_ra8_err_invalid_arg, k_ra8_mpu_boot_mair0, k_ra8_mpu_boot_mair1, k_ra8_mpu_boot_region_count, k_ra8_mpu_ctrl_enable, k_ra8_mpu_ctrl_privdefena, k_ra8_ok, ra8_hw_dsb(), ra8_hw_isb(), and s_ra8_mpu_boot_regions.

Referenced by SystemInit().

◆ ra8_mpu_boot_map()

const ra8_mpu_region_t * ra8_mpu_boot_map ( uint8_t * out_count)

Return the canonical boot memory-attribute map region table.

Read-only view of the exact region descriptors ra8_mpu_apply_boot_map() installs, so callers (a boot self-test, the host unit tests) can inspect or cross-check the map without re-encoding it. The pointer targets a driver-owned static const table in .rodata; the entries are immutable.

Parameters
[out]out_countReceives the region count (k_ra8_mpu_boot_region_count). Must be non-NULL.
Returns
Pointer to the first of *out_count region descriptors, or NULL when out_count is NULL.
Return values
NULLout_count was NULL; *out_count is not written.
Precondition
out_count != NULL.
Postcondition
On non-NULL return, *out_count == k_ra8_mpu_boot_region_count.
The referenced table is not modified.
Note
Thread-safe: returns a pointer to immutable data.
See also
ra8_mpu_apply_boot_map()
Since
0.1.0

Definition at line 408 of file ra8_mpu.c.

References k_ra8_mpu_boot_region_count, and s_ra8_mpu_boot_regions.

Referenced by mpu_boot_test_map().

◆ ra8_mpu_configure()

ra8_err_t ra8_mpu_configure ( const ra8_mpu_cfg_t * cfg)
nodiscard

Program every MPU region from a static configuration.

Disables the MPU, writes MAIR0/MAIR1, walks the region table, clears any unused regions above region_count, then re-enables the MPU with the requested CTRL flags.

Parameters
[in]cfgConfiguration block.
Returns
ra8_err_t error code.
Return values
k_ra8_okRegion table programmed and MPU enabled.
k_ra8_err_null_ptrcfg == NULL or cfg->regions == NULL.
k_ra8_err_invalid_argregion_count > DREGION, or a region has non-power-of-two size, misaligned base, or unrepresentable AP pair.
Precondition
cfg != NULL.
Caller is in privileged mode.
Postcondition
On success MPU_CTRL.ENABLE == 1.
On failure no MPU state is changed.
Note
Not thread-safe.
See also
Arm Cortex-M85 TRM "MPU register summary".
Since
0.1.0

Definition at line 206 of file ra8_mpu.c.

References internal_build_ctrl(), internal_clear_region(), internal_dregion_count(), internal_program_region(), internal_validate_cfg(), internal_write_ctrl(), internal_write_mair(), k_ra8_mpu_shcsr_addr, k_ra8_mpu_shcsr_memfaultena, k_ra8_ok, ra8_mpu_cfg_t::mair0, ra8_mpu_cfg_t::mair1, RA8_CHECK_NULL_PTR, ra8_mpu_cfg_t::region_count, ra8_mpu_cfg_t::regions, and s_tag.

Referenced by main().

◆ ra8_mpu_disable()

ra8_err_t ra8_mpu_disable ( void )
nodiscard

Clear MPU_CTRL.ENABLE.

Returns
ra8_err_t error code.
Return values
k_ra8_okAlways.
Precondition
Caller is privileged.
Postcondition
MPU_CTRL.ENABLE == 0.
Note
Not thread-safe.
Since
0.1.0

Definition at line 251 of file ra8_mpu.c.

References r_mpu_regs_t::CTRL, k_ra8_mpu_ctrl_enable, k_ra8_ok, and ra8_mpu_regs().

◆ ra8_mpu_enable()

ra8_err_t ra8_mpu_enable ( void )
nodiscard

Set MPU_CTRL.ENABLE.

Returns
ra8_err_t error code.
Return values
k_ra8_okAlways.
Precondition
Caller is privileged.
Postcondition
MPU_CTRL.ENABLE == 1.
Note
Not thread-safe.
Since
0.1.0

Definition at line 243 of file ra8_mpu.c.

References r_mpu_regs_t::CTRL, k_ra8_mpu_ctrl_enable, k_ra8_ok, and ra8_mpu_regs().

◆ ra8_mpu_is_enabled()

bool ra8_mpu_is_enabled ( void )
nodiscard

Report whether the core MPU is currently enabled.

Reads MPU_CTRL.ENABLE (Armv8-M "MPU_CTRL"). Lets application code confirm the boot attribute map came up without poking the register block directly – the whole point of routing MPU access through this driver.

Returns
Whether MPU_CTRL.ENABLE is set.
Return values
trueThe MPU is enabled.
falseThe MPU is disabled.
Precondition
Caller is privileged (or RA8_OFF_TARGET, where the register is faked).
Postcondition
No MPU state is modified (pure read).
Note
Not thread-safe with respect to a concurrent enable/disable.
See also
ra8_mpu_enable()
ra8_mpu_apply_boot_map()
Since
0.1.0

Definition at line 450 of file ra8_mpu.c.

References k_ra8_mpu_ctrl_enable, and ra8_mpu_regs().

Referenced by mpu_boot_test_enabled().

◆ ra8_mpu_set_region()

ra8_err_t ra8_mpu_set_region ( uint8_t region,
const ra8_mpu_region_t * region_cfg )
nodiscard

Program a single region without disabling the MPU.

Parameters
[in]regionRegion index, 0..MPU_TYPE.DREGION - 1.
[in]region_cfgNew descriptor.
Returns
ra8_err_t error code.
Return values
k_ra8_okRegion updated.
k_ra8_err_null_ptrregion_cfg == NULL.
k_ra8_err_invalid_argregion >= DREGION, or region_cfg has non-power-of-two size, misaligned base, or unrepresentable AP pair.
Precondition
region_cfg != NULL.
Caller is privileged.
Postcondition
On success the addressed region holds the new descriptor.
Note
Not thread-safe.
Since
0.1.0

Definition at line 259 of file ra8_mpu.c.

References internal_dregion_count(), internal_program_region(), internal_validate_region(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Variable Documentation

◆ s_ra8_mpu_boot_regions

const ra8_mpu_region_t s_ra8_mpu_boot_regions[k_ra8_mpu_boot_region_count]
static

The canonical 5-region boot memory-attribute map.

Region 0 maps MRAM code RO+executable cacheable; regions 1-2 map the M85-private SRAM and SDRAM RW/XN cacheable; region 3 maps the peripheral window RW/XN Device-nGnRE; region 4 maps the shared M85<->M33 SRAM RW/XN Normal non-cacheable so cross-core hand-offs stay coherent with the M85 D-cache on. Lives in .rodata, so it is readable from SystemInit() before the .data copy.

Note
Const; installed verbatim by ra8_mpu_apply_boot_map().
Warning
Never modify at run time; exposed read-only via ra8_mpu_boot_map().
Since
0.1.0

Definition at line 325 of file ra8_mpu.c.

Referenced by ra8_mpu_apply_boot_map(), and ra8_mpu_boot_map().

◆ s_tag

const char* s_tag = "MPU"
static

Definition at line 34 of file ra8_mpu.c.