ModusToolbox Safety Test Library
Loading...
Searching...
No Matches
SMPU (CPUSS shared memory protection STL module)

General Description

Functional self-test for the CPUSS SMPU (shared memory protection unit) programmed through the PDL Cy_Prot_*SmpuSlaveStruct() API.

The SMPU denied write is reported by two independent mechanisms that the self-test relies on:

  1. a peripheral CPUSS_MPU_VIO SysFault latched in a FAULT_STRUCT (STATUS carries the source and DATA0 the violating address), which the self-test reads back by polling the fault structure directly - this proves the SMPU detected the violation, and
  2. a CPU BusFault, which the application-owned BusFault_Handler forwards to SelfTest_SMPU_HandleBusFault so execution recovers in place instead of escalating to a HardFault.

More Information

The self-test borrows one low, disabled SMPU slave struct and temporarily configures it over an application-provided 256-byte scratch block so that only a protection context different from the one the accessing bus master currently runs at is allowed. It then attempts a privileged write to the first word of that block and verifies that:

  1. the expected CPUSS_MPU_VIO SysFault source is observed, and
  2. the scratch word content is unchanged by the denied write.

Diagnostic coverage

Fault model: the SMPU fails to deny a write it is configured to deny, or fails to report the violation. One call checks one path end to end at startup:

  1. SMPU slave-struct evaluation for one struct and one 256-byte region: address/size match, ENABLED, and the PC_MASK check that denies the calling core's active protection context while one other context is allowed.
  2. Write blocking at the memory: the scratch word is unchanged.
  3. Violation reporting for the tested memory area: the stl_smpu_entry_t::expectedFault SysFault with DATA0 equal to the accessed address, and the bus error returned to the CPU as a BusFault.

Other cases are not covered, in particular: denial by the permission attributes (user/privileged read, write, execute), the secure attribute, pcMatch, subregions, other region sizes, the application's own SMPU slave structs and their priority, SMPU master structs, and accesses by other bus masters. Call SelfTest_SMPU() once per safety-related memory area, with a scratch block in that area and the matching stl_smpu_entry_t::expectedFault.

The self-test verifies the SMPU at startup only. Faults that occur after startup are not detected by this self-test.

Note
Non-cacheable scratch is mandatory. On a cache-enabled core (for example XMC7000 CM7, D-cache enabled at startup) a denied store to a cacheable buffer hits the D-cache and never reaches the bus, so the SMPU never sees it: the write appears to succeed and no fault is raised. The scratch word in stl_smpu_entry_t::testAddress MUST reside in non-cacheable memory; refer to the application linker script for the non-cacheable SRAM region.
The application owns BusFault_Handler. This module does not install a strong BusFault_Handler and does not override the application's vector table. The application must provide a small assembly-level trampoline that uses EXC_RETURN to pick the active exception stack (MSP or PSP) and forwards the frame pointer to a C dispatcher that calls SelfTest_SMPU_HandleBusFault():
// GCC / ARM
__attribute__((naked, noinline, used))
void BusFault_Handler(void)
{
__asm volatile(
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
"b Application_BusFault_Dispatch \n");
}
// IAR
#pragma required=Application_BusFault_Dispatch
#pragma inline=never
__stackless __root void BusFault_Handler(void)
{
asm volatile(
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
"b Application_BusFault_Dispatch \n");
}
// Portable C dispatcher (mark noinline so it is never merged into the naked
// trampoline above under LTO).
#if defined(__ICCARM__)
#pragma inline=never
#else
__attribute__((noinline))
#endif
void Application_BusFault_Dispatch(uint32_t* stack)
{
{
return; // STL consumed the deliberate SMPU-test fault
}
Application_UnexpectedBusFault(stack); // real application fault
}
bool SelfTest_SMPU_HandleBusFault(uint32_t *stack)
BusFault dispatch entry for the application's BusFault_Handler trampoline.

SelfTest_SMPU_HandleBusFault returns true only for the deliberate denied write driven by SelfTest_SMPU. For every other BusFault it returns false with CFSR and BFAR untouched, so the application's normal fault policy can inspect and handle it.

Note
LTO / link-time-optimization safeguards. Whole-program optimization can inline, reorder, or discard code around naked functions in ways that silently break exception handling. Refer to your toolchain manual for details. Suggested attributes/pragmas:
  1. noinline / inline=never on both the trampoline and its C dispatcher.
  2. used (GCC / ARM) or __root (IAR) on the trampoline so the linker keeps it even when the vector-table reference is a pure data relocation that LTO does not see as a code reference.
  3. #pragma required=<dispatcher-name> (IAR only) to keep the C dispatcher from being dead-code-eliminated when nothing but the naked trampoline references it.

API Reference

 Macros
 
 Data Structures
 
 Functions