MPU Port in Cortex-M33 hits a halt when the stack is allocated from heap (10.3.1)

Hi,
I am facing an issue, when I try to allocate a stack for the task from the heap, and configure MPU region for the tasks to provide access to the heap.
The MPU regions get overlapped and thus causes the fault the moment we try to write these setting into MPU in vRestoreContextOfFirstTask.

The whole problem happens because the stack of the task will be with in the heap and thus the heap MPU region and task stack region overlaps and causes this issue.

The work around could be that have separate section from where stack can be allocated, but still i want to see if we have more options on fixing this

My task configuration would look like below
.xRegions = {
{ (void *)unprivileged_sram_start,
region_size_ram,
tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER},
{ (void *)heap_start,
region_size_heap,
tskMPU_REGION_READ_WRITE },
{ 0, 0, 0},
}

Looks like i the above thing is not possible based on the documentation in the kernel
if portUSING_MPU_WRAPPERS=1 & configSUPPORT_DYNAMIC_ALLOCATION=1
The possible things are

  1. xTaskCreate = TCB - Dynamic, Stack - Dynamic
  2. xTaskCreateRestricted = TCB - Dynamic, Stack - Static

Which FreeRTOS version are you using?

Hi Richard,
Am using 10.3.0.
It looks like I cannot opt for dynamic stack allocation in MPU ports.

Is it not possible to allocate MPU regions for tasks created using xTaskCreate call ?

Also why do we have a restriction that allocate MPU regions to be called in tasks run time?

Please use the latest FreeRTOS release: https://github.com/FreeRTOS/FreeRTOS-Kernel/releases/tag/V10.4.1-kernel-only

The reason I ask you to use the latest release is because there is a fix which is not in 10.3.0: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/master/portable/GCC/ARM_CM33/non_secure/port.c#L1081

Heap is now placed in the privileged region and therefore cannot be accessed from unprivileged tasks. Would you please share your use case?

Thanks.

It looks like I cannot opt for dynamic stack allocation in MPU ports.

You can not use dynamic stack allocation (i.e. xTaskCreate) in MPU ports for creating unprivileged tasks. This is mentioned here: https://www.freertos.org/FreeRTOS-MPU-memory-protection-unit.html

Is it not possible to allocate MPU regions for tasks created using xTaskCreate call ?

You can allocate MPU regions. However, you cannot grant a task access to memory from heap as heap is all privileged.

Also why do we have a restriction that allocate MPU regions to be called in tasks run time?

I am not sure I understand this one. Would you please elaborate?

Thanks.

Hi Gaurav,
Currently we are not in the state to upgrade to 10.4.1.
My use case is,
I have to create threads which should be having access to Global unprivileged ram, Some Secure side of the memory and the heap. All this can be achieved by using linker markers and configuring the same in MPU setting structure during the task creation.
But at the same time, i didnt wanted to allocate the stack statically as its shown in demo. So i allocated the stack from the heap !!! Now the problem occurs, as the Task Stack is a part of heap and heap has its own MPU settings and thus during the task dispatch, these areas collide and MPU makes the code to hit the fault.
Anyways there are multiple ways to solve the problem, but the point is in the kernel documentation you say xTaskCreate can have dynamic stack allocation, which is wrong is what i believe.
The above given link is updates recently after you guys have released the 10.4.1. But we are using 10.3.0 from quite a long time.
Thanks,
Sachin

To me, the whole concept of making a task restricted means it should have absolute minimum privileges of access, and a broad category like ‘the heap’ runs counter to that, especially if you are dynamically allocating tasks, so it has the ability to interfere with almost any task (any that aren’t statically allocated).

The premise for the request sounds a bit like the concept of a restricted tasks sounds good, so lets make the task restricted, but we can’t work out the details well enough to fit the requirements.

Also, unless you are making a variable number of these tasks, or the stack size needs to be changed at run time, statically allocation the task is a very easy thing to do.

To allow dynamically allocating the task stack will basically REQUIRE that the task has access to the heap, or at least part of it, including stuff that you can not be sure what it is (malloc has no way to specify you need a ‘page’ aligned block), which goes against the general specification of what a restricted task should have access to, so it seems that your described use is very non-standard.

Now the problem occurs, as the Task Stack is a part of heap and heap has its own MPU settings and thus during the task dispatch, these areas collide and MPU makes the code to hit the fault.

This issue was fixed in this PR: https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/85

The above given link is updates recently after you guys have released the 10.4.1. But we are using 10.3.0 from quite a long time.

Yes, this documentation was updated recently after the above fix.

I have to create threads which should be having access to Global unprivileged ram, Some Secure side of the memory and the heap.

That seems like a lot for an unprivileged task to have access to. Is it possible to have more granular division to minimize what an unprivileged task can access? What is the use case requiring an unprivileged task to have access to heap?

Thanks.

Hi Gaurav,
Thanks for the insights, Yes we can have a restriction of unprivileged tasks not using the heap.
Thanks,
Sachin

Hello Gaurav,
Based on your recommendation, went through the pull request and noticed that the fix provides is, if the stack is allocated from the privileged_sram you basically avoid the overlap and leave the permission to the level which is assigned for privileged_sram.
Does this fix not potentially cause issues like any other privileged task can by default access the task stack of others?
Thanks,
Sachin

Privileged tasks have access to all the memory and therefore can access the stack the stack of other tasks. The stack limit registers in Cortex-M33 provide protection against stack overflow though - so a task cannot overflow its stack and write into someone else’s.

In a memory protected system, you should minimize (ideally zero) the number of privileged tasks - only Idle and Timer tasks should be privileged.

Thanks.

Ok. I agree that the system must have minimum privileged tasks. But any developer would prefer that the OS must provide basic mechanism of Freedom From Interference on at least the task stacks.
The issue of stack overflow is detected by hardware provided limit registers, but OS also must ensure that the stack variables of any task be at privileged/ Unprivileged must be isolated and protected.

You are right that the OS should provide the maximum isolation but there are some hardware limitations. We use Memory Protection Unit (MPU) to provide isolation. The way MPU works is that you define a memory region and the associated permissions.

        +------------+
        |            |
        | Region 1   |
        |            |
        +------------+
        |            |
        | Unmapped   |
        |            |
        +------------+
        |            |
        | Region 2   |
        |            |
        +------------+
        |            |
        | Unmapped   |
        |            |
        +------------+

The Idle task (which is part of OS) needs to legitimately access TCBs and other internal structures of all the application tasks. Since MPU has limited number of regions, we cannot use one region per application task to grant Idle task access to these internal structures of all tasks. We, therefore, enable background region which allows privileged code to access everything including unmapped regions. As a result, all the privileged tasks can access all memories.

To be sure that application tasks cannot corrupt each other, the application should never create any privileged task and should only grant the minimal access required to each unprivileged task. This would have been difficult to achieve with ARMv7-M (Cortex-M3, Cortex-M4) MPU because of the size and alignment restrictions but ARMv8-M (Cortex-M23, Coretx-M33) MPU is much more flexible and it should be achievable.

Thanks.