Kernel Bug - Nested MPU wrapper calls generate an exception

Hi,

I think I found a bug in the mpu_wrappers.c of the TI Hercules FreeRTOS port.

Context

I’m trying to use Tracealyzer in snapshot mode with the FreeRTOS Kernel 10.3.1 and a TI Hercules TMS570LS1224 microcontroller. Please note that this microcontroller has an MPU on it.

While doing so I encountered an unhandled prefetchEntry exception. Using the CP15 (AMR) register, I was able to conclude it was a permission fault that caused the exception.
Using my debugger, I was able to reproduce the bug.
Here’s the call stack that is causing the problem:

TO    MPU_ucQueueGetQueueType(struct QueueDefinition *)() 
      prvTraceGetQueueType(void *)() 
      prvInitialiseNewQueue(unsigned long, unsigned long, unsigned char *, int, struct QueueDefinition *)() 
      xQueueGenericCreate(unsigned long, unsigned long, int)() 
      MPU_xQueueGenericCreate(unsigned long, unsigned long, int)() 
FROM  my_freertos_task(void *)() 

As you can see, there are 2 calls to MPU_* API, which switch from user mode to privileged mode.

Problem (bug?)

When in privileged mode, the xPortRaisePrivilege() function returns 15 instead of pdTRUE (1).

This can cause problem when trying to reset to the correct mode.
As the vPortResetPrivilege() function is implemented has follows:

void vPortResetPrivilege( BaseType_t xRunningPrivileged )
{
	if( xRunningPrivileged != pdTRUE )
	{
	    portSWITCH_TO_USER_MODE();
	}
}

The nested MPU function will switch to user mode.
The expected behaviour would be to stay in a privileged mode, as we are in a nested MPU call.

Fix

I’m not good enough with assembly to explain why the function was not designed to return a bool, but here’s my quick fix:

void vPortResetPrivilege( BaseType_t xRunningPrivileged )
{
	if( xRunningPrivileged == pdFALSE)
	{
	    portSWITCH_TO_USER_MODE();
	}
}

With this, I don’t get any exception.

Closing

I would like to have yours thought on this bug and how to fix it.
Also, I’m not sure if this forum is the correct place to post this kind of bug, but I hope it’s helpful to somebody else.

Regards,
Gabriel

This definition of xIsPrivileged should only return 0 or 1: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/master/portable/GCC/ARM_CM4_MPU/port.c#L775.

Return value of 15 indicates something else going wrong. Let us find out the reason for that. Would you please tell me which FreeRTOS port (i.e. which port files in portable directory) are you using?

Thanks.

Thanks for your answer.

I’m using a modified version of the TI SDK generated by HALcodeGEN.
As the TI SDK only support FreeRTOS 9, we ported FreeRTOS to the 10.3.1 version.

Please note that we didn’t touch the assembly files. Therefore the portASM.asm is the same between the official TI FreeRTOS port and ours.

The specific function:

;-------------------------------------------------------------------------------
; swiRaisePrivilege

; Must return zero in R0 if caller was in user mode
        .asmfunc
swiRaisePrivilege
        mrs     r12, spsr
        ands    r0, r12, #0x0F      ; return value
        orreq   r12, r12, #0x1F
        msreq   spsr_c, r12
        bx      r14
        .endasmfunc

I’m not sure why we expect a bool considering the ands r0, r12, #0x0F line.

This explains the behavior you see. The above piece of assembly roughly is:

r12 = SPSR /* [SPSR=Saved Program Status Register] */
r0 = r0 & 0x0F;
if( r0 == 0 ) /* If the processor is not privileged. */
{
    r12 = r12 | 0x1F; /* Set last 5 bits. */
    CPSR = r12; /* [CPSR =Current Program Status Register] */
}
return r0;

Last 5 bits in Program Status Register tell the processor mode:

  • 0x10000 - user mode or unprivileged mode
  • 0x11111 - system mode or privileged mode

According to the above assembly, if the processor is privileged, the return value will be 0x0F (Decimal 15).

The expected behavior of portIS_PRIVILEGED is:

  • return 0 if the processor is not running privileged.
  • return 1 if the processor is running privileged.

This above assembly function does not implement it correctly in the second case when the processor is running privileged. It should be fixed in TI’s code.

However, the change you suggested above looks harmless to other ports and it will fix your problem. So I have incorporated it in this PR: https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/109

Thanks,
Gaurav

1 Like

Thanks for your support Gaurav.
I’m gonna report the potential bug to TI.

Regards,
Garbiel

Update:

TI engineers have been inform of the problem.
https://e2e.ti.com/support/microcontrollers/hercules/f/312/p/928049/3428925#3428925

Thank you for taking time to report the problem to TI.