2024-12-10 02:16 PM - edited 2024-12-10 02:16 PM
There's a bug in the standard MPU_AdjustRegionAddressSize which appears everywhere in the sample code. My reference is the H7RS, it's in the Template and virtually all examples: H7RS Github example The net result is that it's likely noncacheable regions (particularly large ones) will NOT be properly marked as noncacheable.
There are two sections to this function--the first, where the size is rounded to the next greater power of 2, works just fine. As an example, I have a memory region of 207,712 bytes. It correctly turns this into a "17" which is the code for MPU_REGION_SIZE_256KB (0x11 -- see stm32h7rsxx_hal_cortext.h).
HOWEVER, the second section is incorrect. It does not adjust the base address of the region to be on a matching size boundary. Further, after the adjustment, it's possible that the size no longer encapsulates the region you're targeting.
For example, assume my start address is 0x24032000. This is not valid because it's not an even multiple of 256k that was computed in step 1. It needs adjustment.
The reference code computes:
uint32_t Modulo = Address % (1 << (pInit->Size - 1))
In this example, this becomes:
Modulo = 0x24032000 % (1 << (17 - 1))
->
Modulo = 0x24032000 % (1 << 16)
->
Modulo = 0x24032000 % 0x10000
∴
Modulo = 0x2000
This moves my BaseAddress down to 0x24030000, which is not a 256k boundary! The MPU will silently discard the 0x30000 bits to align with a 256k boundary. Even worse, because my memory extends ~200k ABOVE the 0x32000 address, after the MPU silently discards the irrelevant bits, my memory is actually *outside* of the region that was created. In my case, I was trying to mark the region is uncacheable, and it made my regular ram uncacheable and my DMA buffers cacheable because it fell outside of the resulting region.
At the very least, the code should be:
uint32_t Modulo = Address % (1 << (pInit->Size + 1))
->
Modulo = 0x24032000 % (1 << 18)
->
Modulo = 0x24032000 % 0x40000
∴
Modulo = 0x32000
This puts the memory at the correct start address at least.
However, the second part of the bug remains. After the adjustment occurs, it's possible the region no longer contains the memory you were originally trying to encapsulate.
So, this code probably should then recompute the region size to ensure that the new BaseAddress + (1<<pInitSize+1) is <= original Address + Size, and if not, compute again.
Compounding this problem is the standard linker map which places RAM_NONCACHEABLEBUFFER *after* standard RAM adjusting downwards from the top of available memory. This makes it highly likely noncacheable buffers will not be properly aligned, and after adjustment, will be outside the noncacheable zone.
In my case, I have a 256k noncachable buffer, which it stuck at 0x24032000 (because it subtracted 256k from the memory size of 0x72000).
2024-12-11 06:53 AM
Hello @FA1234
Thank you for rising this up.
I escalated this issue internally via ticket number 198335 to take a closer look at the problem.
I'll make sure to post here as soon as there is an update.
(PS: Ticket number 198335 is an internal tracking number and is not accessible outside of ST).