Summary
The Zephyr RRAM driver drivers/flash/soc_flash_nrf_rram.c does not pass NS-side reads of TF-M secure flash through soc_secure_mem_read when the device tree uses the modern, pure-DTS partition layout. Any NS code issuing a flash_area_read() whose physical address falls inside the TF-M secure sub-partition (i.e. between slot0_partition start and slot0_ns_partition start) hits an SAU/IDAU attribution-unit violation and SecureFaults the application core.
The legacy Partition Manager path is already handled correctly by an existing PM_APP_ADDRESS guard. The DTS-only path was never ported when NCS deprecated PM in favour of DTS partitioning, so any NS+TFM nRF54L15 build that follows the recommended flow crashes the moment a host queries slot state.
Reproducer
- Build any *_cpuapp/ns application on nrf54l15 with TF-M, MCUboot sub-partitioned slots (slot0_partition spans slot0_s_partition + slot0_ns_partition), MCUmgr image group enabled, pure-DTS partitioning (no PM).
- Boot the NS app, attach mcumgr-cli over SMP.
- Run: mcumgr --conntype serial --connstring "dev=/dev/ttyACM0,baud=115200" image list
- Host times out. Device log: os: ***** SECURE FAULT ***** os: Address: 0xc000 os: Attribution unit violation os: r0/a1: 0x2002d588 r1/a2: 0x0000c000 r2/a3: 0x0000c020 os: Faulting instruction address (r15/pc): 0x0008f6fc os: >>> ZEPHYR FATAL ERROR 41: Unknown error on CPU 0
0xc000 is slot0_partition base = first byte of slot0_s_partition (TF-M, MPC-locked). The 32-byte read (r2 - r1 == 0x20) is the standard MCUboot image_header fetch in zephyr_img_mgmt.c::img_mgmt_read_info().
I think its caused by:
In drivers/flash/soc_flash_nrf_rram.c, nrf_rram_read() currently does:
#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER && PM_APP_ADDRESS if (addr < PM_APP_ADDRESS) { return soc_secure_mem_read(data, (void *)addr, len); }#endif memcpy(data, (void *)addr, len);
The legacy drivers/flash/soc_flash_nrf.c (nRF52/nRF53) already has a parallel #elif arm for the DTS-only case using slot0_ns_partition. The RRAM driver was never given the equivalent.
#if CONFIG_TRUSTED_EXECUTION_NONSECURE#if USE_PARTITION_MANAGER && PM_APP_ADDRESS if (addr < PM_APP_ADDRESS) { return soc_secure_mem_read(data, (void *)addr, len); }#elif !USE_PARTITION_MANAGER && DT_NODE_EXISTS(DT_NODELABEL(slot0_ns_partition)) if ((uintptr_t)addr < DT_REG_ADDR(DT_NODELABEL(slot0_ns_partition))) { return soc_secure_mem_read(data, (void *)addr, len); }#endif#endif
And relax the soc_secure.h include guard so it's pulled in for both PM and DTS-only NS builds:
#if CONFIG_TRUSTED_EXECUTION_NONSECURE
#include <soc_secure.h>
#if USE_PARTITION_MANAGER
#include <pm_config.h>
#endif
#endif
This is what my patching is currently doing.
Many thanks and hope this help.
Dom