This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LC4357: HALCoGen FreeRTOS port cause prefetch or data abort due to dynamic MPU configuration

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

Hi,

Our software running on TMS570LC4357 will sometimes have prefetch/data abort exception, branch to interrupt vectors at HL_sys_intvecs.asm. But it wont branch to function _prefetch or _dabort function due to permission error. 

resetEntry
        b   _c_int00
        b   _undef
        b   vPortSWI
        b   _prefetch
        b   _dabort
        b   phantomInterrupt
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

After some debugging, we think it is due to MPU configuration problem because the issue always happen with the MPU Region Base Address Register=0x00000000 while MPU Region Size and Enable Register and MPU Region Access Control Register are values of dynamic MPU configuration of other tasks.

According to MPU Configuration Application Report by TI, MPU region should be disabled first before changing configuration but we don't find any code that disable the configurable MPU region in HALCoGen generated FreeRTOS code.

Hence, we added the snippet below into the function portSAVE_CONTEXT to disable configurable MPU regions before portRESTORE_CONTEXT change the MPU configuration. And then we tested it, the software run for a day without prefetch/data abort.

; Disable all configurable MPU region
mov r0, #12
mcr     p15, #0, r0, c6, c2, #0     ; Select region
mov r0, #0
mcr     p15, #0, r0, c6, c1, #2     ; Disable MPU
mov r0, #13
mcr     p15, #0, r0, c6, c2, #0     ; Select region
mov r0, #0
mcr     p15, #0, r0, c6, c1, #2     ; Disable MPU
mov r0, #14
mcr     p15, #0, r0, c6, c2, #0     ; Select region
mov r0, #0
mcr     p15, #0, r0, c6, c1, #2     ; Disable MPU
mov r0, #15
mcr     p15, #0, r0, c6, c2, #0     ; Select region
mov r0, #0
mcr     p15, #0, r0, c6, c1, #2     ; Disable MPU

Hence, we would like to ask:

  1. Is it an issue in HALCoGen or did we misconfigured our HALCoGen?
  2. Is the added snippet sufficient to covers the edge cases of dynamic MPU configuration during context switching?
  3. Is there better way to resolve the issue?

We used HALCoGen version=04.07.01, project device=TMS570LC4357ZWT_FREERTOS. And the HALCoGen configuration for MPU is as below:

Thanks

Jia Zhi.

  • Hello Jiazhi,

    The reason for Prefetch Abort can be analyzed by reading the Instruction Fault Status Register (IFSR) and Instruction Fault Address Register (IFAR). IFAR contains the address where the CPU was trying to fetch an instruction from. The contents of IFAR is always valid for a Prefetch Abort, because all Prefetch Aborts are synchronous.

    If a permission fault has occurred based on the IFSR status, it is possible that one of the following conditions has occurred:

    • An instruction is being fetched from a location for which “Execute Never” attribute is set (XN bit of MPU control register). The MPU region under which the address read from IFAR falls must be read.
    • The target address read from IFAR has “Device” or “Strongly-Ordered” memory attribute. This implicitly means that these areas do not have executable code
    • The target is in user mode which doesn't have permission to execute the code from the address read from IFAR

    The MPU APIs are defined in sys_mpu.asm generated by HALCOGen

  • Hi QJ,

    The ISFR and IFAR as as follow:

    The vector table, showing address 0x0000000C is instruction to branch to _prefetch abort function

    And the MPU configuration registers value are as follow:

    The software is stuck at interrupt vector because it's generating prefetch error when the CPU is trying to execute from the vector. Our tasks' configurable MPU are never configured in that way, it is caused by dynamic MPU configuration in portRESTORE_CONTEXT in os_portasm.asm.

    We are aware that sys_mpu.asm provide API to configure MPU, but isn't disabling the MPU region before dynamically configure the region should be part of the os_portasm.asm? We not experience in porting FreeRTOS, so we are wondering if there is suggested method to resolve this issue?

    Regards, Jia Zhi

  • Hello Jiazhi,

    You can also look at this application note (and included code example CCS project):
    www.ti.com/.../spna177.pdf

    A link to the CCS project is included in the document.

    Please check the value of the following registers:

    • SPSR_ABT:  holds the value of the CPSR before the abort exception occurs.
    • R13_ABT:  is the pointer to the top of the stack in CPU memory used by the abort handler
    • R14_ABT:  is the address of the Program Counter (PC) which points to the instruction that caused the abort + 8 bytes (due to CPU pipeline)

  • Hi QJ,

    Thank you for pointing to the application note.

    From the application note, i think we need to follow the section "1.5.3 Region Setup An Optimised Version" and "1.6 MPU Default Configuration", by setting MPU covering Kernel RAM & Flash to use higher region number to prevent FreeRTOS dynamic MPU regions to override MPU settings for Kernel. In this case, I don't need to disable dynamic MPU regions in portSAVE_CONTEXT, is this correct?

    Because HALCoGen MPU configuration for Flash and Kernel Flash(region 1 and region 2) cannot be changed(greyed out tickbox), seems like HALCoGen is suggesting using low priority MPU region to cover Flash and Kernel Flash which contradict the suggestion in the application note.

    The values of SPRS_ABT and R14_ABT indicated the prefetch abort was triggered by CPU trying to execute from interrupt vector in SYS mode. The software is stuck trying to execute from 0x0000000C, the software will branch back to 0x0000000C even using "Assembly Step Into" in CCS.

    This is the instruction fault registers and MPU registers on the same run for your information:

    Regards, Jia Zhi.

  • Hello JiaZhi,

    In the freeRTOS example generated by HALCoGen, the MPU is configured using _mpuInit_() function.

    You can enable MPU using: prvMpuEnable(), and set the MPU region, region, enable/disable region using "prvMpuSetRegion()"

    If you want to update the MPU settings for a region when the MPU is enabled, you need to be careful not to disturb the MPU region the code is currently executing from. You also need to disable the region before you modify the settings as you did in portSAVE_CONTEXT macro.