Good evening everyone,
We recently enabled OCRAM on our Cortex-M7 (on a Verdin iMX8M Plus module) and moved some non-critical text and data into it. However, since we made this change, we have been getting some unpredictable crashes on our M7. What I mean is, while developing, depending on the changes we just added, it sometimes never crashes (uptime of >8h), it crashes after around 1h, and then sometimes even after 5min. We are currently analysing our code for UB and races, and have finally added serial print-outs to all FreeRTOS configAssertsand newlibs asserts, but we have not yet been able to pin down our mistake.
While we are still analysing our code, I wanted to double-check our OCRAM setup in the linker file and its MPU settings, because what I really don’t understand is why it never happened (~1.5 years!) when all the code was still in ITCM & DTCM. Also, we use OCRAM on a Cortex-M4 on Colibri iMX7 just fine. However, TBH, I still suspect some bad usage of FreeRTOS Kernel APIs, for which in slower code the configAsserts fire, but anyways I would be really thankful if you could glance over our setup
.
Our main questions would be:
- Do you know of others that had issues with OCRAM on M7-Cortex
- Do you note some unusual things with our setup below?
- Might Linux use OCRAM at the same time as M7 does? I thought it was already declared
no-mapin imx8mp.dtsi#L213- We are building our own Linux using torizon minimal (still on the
7.4.0tag with very minimal customisations)
- We are building our own Linux using torizon minimal (still on the
I added the full linker, startup and MPU config file (board.c) as an attachment, but quickly cover the most important sections here:
We use remoteproc, and as far as I know, the driver splits OCRAM into three regions (c.f. imx_rproc.c#L189), so our linker file adds those three sections and adds the data & text accordingly:
MEMORY
{
m_itcm_isr (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400
m_itcm_text (RX) : ORIGIN = 0x00000400, LENGTH = 0x0001FC00
m_dtcm_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00020000
m_ocram_data (RW) : ORIGIN = 0x20200000, LENGTH = 0x00020000 /* 128 KB, fits ATT entry 1 */
m_ocram_text_lo (RWX) : ORIGIN = 0x20220000, LENGTH = 0x00020000 /* 128 KB, fits ATT entry 2 */
m_ocram_text_hi (RWX) : ORIGIN = 0x20240000, LENGTH = 0x00010000 /* 64 KB inside ATT entry 3, ends below the lowest BL31 base */
/* 16MB DDR reserved in the Linux device-tree: https://git.toradex.com/cgit/device-tree-overlays.git/tree/overlays/verdin-imx8mp_hmp_overlay.dts?h=toradex_6.6-2.1.x-imx#n47 */
m_ddr_data (RW) : ORIGIN = 0x80000000, LENGTH = 0x01000000
}
/* Non-critical code pre-diverted to OCRAM before the ITCM wildcard below. */
.text_ocram_lo :
{
. = ALIGN(4);
*/rtos_tasks/communication/*.c.obj(.text* .rodata*)
*/rtos_tasks/monitor/*.c.obj(.text* .rodata*)
*/rtos_tasks/worker/*.c.obj(.text* .rodata*)
*/rtos_tasks/fsm/*.c.obj(.text* .rodata*)
. = ALIGN(4);
__ocram_text_lo_end__ = .;
} > m_ocram_text_lo
.text_ocram_hi :
{
. = ALIGN(4);
*/rtos_tasks/input_output/*.c.obj(.text* .rodata*)
*/rtos_tasks/linear_motor/*.c.obj(.text* .rodata*)
*/rtos_tasks/pose_control/*.c.obj(.text* .rodata*)
*/drivers/linear_motor/*.c.obj(.text* .rodata*)
. = ALIGN(4);
__ocram_text_hi_end__ = .;
} > m_ocram_text_hi
/* Non-critical data pre-diverted to OCRAM before the DTCM wildcard below
* .bss* is intentionally omitted because the startup zero loop in startup_MIMX8ML8_cm7.S
* only covers __bss_start__/__bss_end__ (DTCM), so BSS from these modules fall through to
* .bss in DTCM and is zeroed there.
* NOTE: we don't care anyway as we hardly use any BSS
*/
.data_ocram :
{
. = ALIGN(4);
*/rtos_tasks/communication/*.c.obj(.data*)
*/rtos_tasks/monitor/*.c.obj(.data*)
*/rtos_tasks/worker/*.c.obj(.data*)
*/rtos_tasks/fsm/*.c.obj(.data*)
*/rtos_tasks/input_output/*.c.obj(.data*)
*/rtos_tasks/linear_motor/*.c.obj(.data*)
*/rtos_tasks/pose_control/*.c.obj(.data*)
*/drivers/linear_motor/*.c.obj(.data*)
. = ALIGN(4);
__ocram_data_end__ = .;
} > m_ocram_data
In board.c we set the MPU like this (cachable):
/* Region 7 OCRAM[0x2020_0000 - 0x2024_FFFF]: Normal, non-shareable, write-back/write-allocate.
* Overrides Region 0 (Device/XN) to enable instruction fetch from OCRAM.
*
* 512KB base (smallest power-of-2 ≥ 320KB, aligned at 0x2020_0000). SRD=0xE0 disables
* sub-regions 5-7 (64KB each), fencing off the OCRAM range 0x2025_0000-0x2027_FFFF that
* holds ATF BL31 (and BL2, if NEED_BL2 is enabled). This is defensive across the full set
* of TF-A configurations we might encounter on a Toradex BSP bump:
* NEED_BL2 unset (current, TF-A lf_v2.10_6.6.52_2.2.x): BL31_BASE = U(0x970000)
* → M7-local 0x2027_0000-0x2028_FFFF (128KB)
* NEED_BL2 set: BL31_BASE = U(0x950000), BL2 at U(0x970000)
* → M7-local 0x2025_0000-0x2028_FFFF (256KB)
* https://github.com/nxp-imx/imx-atf/blob/lf_v2.10/plat/imx/imx8m/imx8mp/include/platform_def.h
*
* Older TF-A versions also placed BL31 inside sub-regions 5 or 6 (lf_v2.4: 0x960000,
* lf_v2.6: 0x960000 regression). SRD=0xE0 covers all of these:
* https://www.mail-archive.com/barebox@lists.infradead.org/msg41959.html
*
* Sub-region map (disabled regions fall back to Region 0, Device/XN):
* enabled 0-4: 0x2020_0000-0x2024_FFFF (320KB: m_ocram_data + m_ocram_text_lo + m_ocram_text_hi)
* disabled 5-7: 0x2025_0000-0x2027_FFFF (BL2/BL31 across all known TF-A configurations) */
MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 1, 1, 0xE0, ARM_MPU_REGION_SIZE_512KB);
Thank you very much for your support, and let me know if you need any other info.
Sincerely,
Chris & Team
board-minimal.c (13.7 KB)
MIMX8ML8xxxLZ_ram-minimal.ld (9.8 KB)
startup_MIMX8ML8_cm7-minimal.S (66.0 KB)