ARM Cortex-M 内存保护单元(MPU)
MPU 的作用
MPU 可以将内存划分为不同的区域,并且可以设置每个区域的访问属性。提高系统的稳定性。典型应用如下:
划分特权用户访问区域和普通用户访问区域,在 OS 系统中提高系统稳定性。
设置只读区域,防止关键数据被意外修改。
检测堆、栈是否溢出。
MPU 相关寄存器
- 寄存器
寄存器名-------------- 类型 ----复位值 ----------寄存器功能描述
MPU_TYPE-----------RO --------------------------MPU 类型寄存器
MPU_CTRL --------- RW — 0x00000000------MPU 控制寄存器
MPU_RNR -----------RW — UNKNOWN-------MPU 区域号寄存器(region 号)
MPU_RBAR ---------RW — UNKNOWN-------MPU 区域基地址寄存器
MPU_RASR--------- RW — UNKNOWN-------MPU 区域属性和大小寄存器
MPU_RBAR_A1 — RW---------------------------MPU_RBAR 的别名 1
MPU_RASR_A1 ----RW---------------------------MPU_RASR 的别名 1
MPU_RBAR_A2 ----RW ---------------------------MPU_RBAR 的别名 2
MPU_RASR_A2 ----RW--------------------------- MPU_RASR 的别名 2
MPU_RBAR_A3 ----RW ---------------------------MPU_RBAR 的别名 3
MPU_RASR_A3 ----RW -------------------------- MPU_RASR 的别名 3
- 区域基地址寄存器(MPU_RBAR)
名称-------位段 功能描述
ADDR------bits[31:5]–区域的基地址
VALID------bit[4]-------决定 REGION 字段设置的区域编号是否覆盖 MPU_RNR 寄存器设置的区域 编号
REGION—bits[3:0]—MPU 区域编号复写字段
该寄存器提供了另外一种改变区域编号方法,即 REGION = 区域编号,VALID = 1。
使用这种方法设置区域编号更快捷。ADDR,保存区域基地址.
注意点:地址不能是任意地址.
代码:
/* 设置的地址,直接把底5bit给清零处理. 并且还会根据保护区域的大小还会进一步处理.
The ADDR field
The ADDR field is bits[31:N] of the MPU_RBAR. The region size, as specified by the SIZE
field in the MPU_RASR, defines the value of N:
N = Log2(Region size in bytes).
If the region size is configured to 4GB, in the MPU_RASR, there is no valid ADDR field. In
this case, the region occupies the complete memory map, and the base address is 0x00000000.
The base address is aligned to the size of the region. For example, a 64KB region must be
aligned on a multiple of 64KB, for example, at 0x00010000 or 0x00020000.
*/
#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */
#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */
#define ARM_MPU_RBAR(Region, BaseAddress) \
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
((Region) & MPU_RBAR_REGION_Msk) | \
(MPU_RBAR_VALID_Msk))
- 区域属性和大小寄存器(MPU_RASR)
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
((((DisableExec ) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
(((TypeExtField ) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
(((IsShareable ) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
(((IsCacheable ) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
(((IsBufferable ) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk) | \
(((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \
(((Size ) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \
(MPU_RASR_ENABLE_Msk))
举例:给内存的256byte区域设置只读属性
/*全局变量如果是需要 需要做对齐,
N = Log2(Region size in bytes) = Log2(256) = 8 :代表底8位是清零.也就是对齐256,
不然开始地址和保护区域地址不一致,会影响其他内存变量
*/
__align(256) char g_xxx_test[256];
/* Memory with Normal type, not shareable, non-cacheable */
MPU->RBAR = ARM_MPU_RBAR(8, g_xxx_test);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_256B);
/* 是能MPU */
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);