armv7-m/arm_mpu.c: MPU regions >= 2GB cannot be configured
- Dominant language
- C
- Stars
- 4k
- Forks
- 1.7k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 237
Description
Hi, minor bug to report regarding the MPU configuration in armv7-m:
The cortex-M7 MPU supports configuring regions up to 4GB in size (_see ARMv7-M Arch. Reference Manual, System Address Map :: B3.5 Protected Memory System Architecture_). ([Download link here](https://developer.arm.com/documentation/ddi0403/latest/))

In [arm_mpu.c](https://github.com/apache/nuttx/blob/master/arch/arm/src/armv7-m/arm_mpu.c#L369), say you want to configure a 2 GiB sized region 2GiB offset from address 0:
```c
const size_t SIZE_2_GiB = 2 * 1024 * 1024 *1024; /* 0x80000000 */
mpu_configure_region(/*base = */ SIZE_2_GiB,
/*size = */ SIZE_2_GiB,
/*flags =*/ );
```
When we make it to the `DEBUG_ASSERT`s in the function, we'll have:
```c
l2size = 31;
alignedbase = SIZE_2_GiB;
```
The first assert, `DEBUGASSERT(alignedbase + (1 << l2size) >= base + size);`,
will expand to `DEBUGASSERT( 0 >= 0)` (due to unsigned integer overflow) and pass. The second assert, however,
```c
DEBUGASSERT(l2size == 5 ||
alignedbase + (1 << (l2size - 1)) < base + size);
```
will expand to
```c
DEBUGASSERT(false ||
SIZE_2_GiB + (1 << (30)) < 0);
```
and fail because only the right-hand-side will overflow. The workaround for this would be:
- saying we only allow regions of 1GiB max size to be configured,
- using uint64_t for our arguments and arithmetic in this entire file,
- just have a special case where values for `base` and `size` >= 2GiB are handled differently, or
- just telling users to program the MPU registers directly themselves rather than relying on this convenience function
Contributor guide
Assessment
This issue has not been assessed yet.