vTaskAllocateMPURegions() usage?

freddie-chopin wrote on Tuesday, June 26, 2012:

Am I right to think that a context switch is required for vTaskAllocateMPURegions() to become effective? My tests seem to confirm that, also inspecting that function shows that indeed the settings are only stored in TCB, not “applied” in any way to the MPU.

If I’m right then is that a flaw in design or maybe that’s intended? There is no function to perform such “apply” other than yielding or sth like that (delay, API call, …).

BTW - I think that a feature that would allow “restoring” previous settings of regions would be nice - sometimes you need to change the regions and than change them back, but there is no way to “get” current settings so that these could be used later. One needs to use the same array as used for defining a task, and that sometimes is not desireable (scope of variables).

BTW2 - I’m having a really hard time trying to learn how to use MPU (; Having all tasks in privileged mode doesn’t seem like a good answer, neither does continuous reconfigurations of MPU regions…


rtel wrote on Wednesday, June 27, 2012:

1) You can call taskYIELD() after the call to vTaskAllocateMPURegions() to apply the setting right away.

2) You can have local copies of various MPU setting in xMemoryRegion structures, then just pass the one you want to use as a pointer into vTaskAllocateMPURegions().

3) Creating an application that uses the MPU is more complex than one without, naturally.  The fine grain control of the MPU allowed by FreeRTOS-MPU allows you to have an extremely secure application if you so wish, but writing tasks in a completely locked down system requires a lot of planning.

One extreme is to allocate two memory regions, one used by the kernel, and one by every task - so every task has access to every other task (all their MPU region settings are the same) but cannot corrupt the kernel.  That makes the tasks easy to write (because they don’t have to consider what it is they are accessing) but provides only limited safety.  The other extreme is to allow each task to only have access to its own private RAM (every task has its own MPU settings), and only communicate with other tasks through kernel primitives (queues, semaphores, etc.).  That makes the tasks harder to write because writing code that only accesses certain amounts of RAM is not what most people are used to - but the system is very safe as nothing can corrupt anything else.

Most applications will do something in between these too extremes.  If the code is a task is trusted and tested to the n’th degree, you may open up its MPU regions, while code that is not trusted (who wrote it?  how has it been tested?) might want to be locked down so as not to disrupt the rest of the system.


freddie-chopin wrote on Wednesday, June 27, 2012:

Thx for your answer.

If that behavior is “by design” I think a clarification in the docs would be most welcome, as in the example at the bottom of the page http://www.freertos.org/vTaskAllocateMPURegions.html it’s said as if calling this function changes MPU settings “right away”.

One more question
Wouldn’t having a function to “apply” these settings (or vTaskAllocateMPURegions() doing it automatically) be faster than doing a context switch (I don’t even take the time waiting for the task to be resumed while another one is running into account)?

I don’t have a good idea how to deal with queueing larger pieces of data with random size. When the queue holds the pointers to buffers that were obtained with malloc() you would have to reconfigure MPU before copying data to this buffer (while sending) and from this buffer (while receiving). If you use fixed size large buffers and partition the data to fit there (for example the queue can hold 64bytes in one element) you waste memory, as the buffers are there forever and sometimes you need 3 bytes, not whole 64… Any hints?


freddie-chopin wrote on Wednesday, June 27, 2012:

I’ve found a nice idea to deal with most of the problems - make whole RAM read-only for the task, but unfortunatelly it does not work. If whole RAM is read only in region 8, and task stack is read-write in region 5, any stack operation in task ends with a fault, as region 8 is more important than region 5…

Wouldn’t that be better to have user regions “below” system regions? instead of 1-4 for system, 5-8 for user - 1-4 for user, 5-8 for system? Or maybe it would be a good idea to ALSO have whole RAM read-only as a default? Something like this:
1-3 t- ask defineable regions
4 - task stack
5 - whole RAM read-only
6 - privileged RAM read-write for privileged mode
7 - whole ROM read-only
8 - privileged ROM read-only for privileged mode

I think such inverted priority would work better (assuming you don’t consider giving access to privileged data by user code, as that would not be possible)…