在嵌入式系统开发中,内存保护机制是确保系统稳定性和安全性的基石。ARM Protected Memory System Architecture version 7(PMSAv7)定义了一套完整的内存保护方案,特别适合对实时性和确定性要求较高的应用场景。与MMU(Memory Management Unit)不同,PMSAv7采用的MPU(Memory Protection Unit)方案更轻量级,不需要地址转换,而是直接对物理内存进行访问控制和属性管理。
PMSAv7的核心设计哲学体现在三个方面:
提示:PMSAv7通常应用于Cortex-R系列实时处理器和部分Cortex-M系列微控制器,而带有MMU的VMSAv7则多见于Cortex-A应用处理器。
MPU通过三组寄存器管理每个内存区域:
DRBAR (Data Region Base Address Register)
assembly复制MOV r0, #0x20000000 ; 基地址0x20000000
MCR p15, 0, r0, c6, c1, 0 ; 写入DRBAR
DRSR (Data Region Size and Enable Register)
DRACR (Data Region Access Control Register)
MPU通过AP[2:0]三位字段实现精细的权限控制:
| AP[2:0] | 特权模式(PL1) | 用户模式(PL0) | 典型应用场景 |
|---|---|---|---|
| 000 | 无访问 | 无访问 | 保护区域 |
| 001 | 读写 | 无访问 | 内核数据结构 |
| 010 | 读写 | 只读 | 只读共享数据 |
| 011 | 读写 | 读写 | 完全共享区域 |
| 101 | 只读 | 无访问 | 固件代码区 |
| 110 | 只读 | 只读 | 常量数据区 |
XN(Execute Never)位提供了额外的安全防护:
经验:在配置外设寄存器区域时,务必设置XN=1,防止通过代码注入操控硬件行为。
PMSAv7定义了三种基本内存类型:
普通内存(Normal)
设备内存(Device)
强序内存(Strongly-ordered)
TEX[2:0], C, B位的组合决定了详细的内存属性:
| TEX[2:0] | C | B | 内存类型 | 缓存策略 |
|---|---|---|---|---|
| 000 | 0 | 0 | 强序 | 无缓存 |
| 000 | 0 | 1 | 共享设备 | 无缓存 |
| 001 | 0 | 0 | 普通 | 非缓存 |
| 001 | 1 | 1 | 普通 | 回写写分配 |
| 010 | 0 | 0 | 非共享设备 | 无缓存 |
| 1BB | A | A | 普通(缓存) | 内外缓存策略独立配置 |
注意:当TEX[2]=1时,TEX[1:0]定义外部缓存属性,C/B定义内部缓存属性。
确定区域布局
c复制// 示例内存布局
const struct mpu_region regions[] = {
{0x00000000, 1MB, MPU_ATTR_FLASH}, // 固件区
{0x20000000, 256KB, MPU_ATTR_RAM}, // 主内存
{0x40000000, 1MB, MPU_ATTR_PERIPH}, // 外设
{0x60000000, 16MB, MPU_ATTR_EXT_RAM} // 外部SDRAM
};
计算DRSR大小编码
python复制def encode_size(size):
# 计算2^(n+1) >= size的最小n
import math
return int(math.log2(size) - 1)
配置完整流程
assembly复制; 配置区域0
LDR r0, =0x20000000 ; 基地址
LDR r1, =0x00000013 ; 使能+256KB(0x13=19→2^20=1MB)
LDR r2, =0x00000303 ; 全读写权限,普通内存,回写写分配
MCR p15, 0, r0, c6, c1, 0 ; DRBAR
MCR p15, 0, r1, c6, c1, 2 ; DRSR
MCR p15, 0, r2, c6, c1, 4 ; DRACR
修改MPU属性时必须遵循严格的缓存维护序列:
修改属性前的准备
c复制// 1. 将目标区域改为非缓存
set_mpu_attr(base, size, NC_ATTR);
// 2. 数据同步屏障
__DSB();
// 3. 清理+无效化缓存
clean_invalidate_dcache_range(base, size);
应用新属性
c复制// 4. 设置新属性
set_mpu_attr(base, size, NEW_ATTR);
// 5. 再次同步
__DSB();
__ISB(); // 指令缓存同步
PMSAv7定义了严格的异常处理层级:
对齐错误(Alignment Fault)
MPU故障
外部中止(External Abort)
异常优先级规则:
关键状态寄存器:
DFSR (Data Fault Status Register)
| 位域 | 说明 |
|---|---|
| FS[3:0] | 故障类型编码 |
| WnR | 写操作标志(1=写,0=读) |
| ExT | 外部中止扩展信息 |
典型FS编码:
DFAR (Data Fault Address Register)
实时操作系统常利用MPU实现任务隔离:
c复制void switch_context(struct task *new) {
// 1. 保存当前任务MPU配置
save_mpu_regs(current_task);
// 2. 配置新任务内存区域
for (int i=0; i<new->region_count; i++) {
configure_region(i, new->regions[i]);
}
// 3. 数据同步
__DSB();
__ISB();
}
Bootloader阶段MPU配置示例:
assembly复制; 保护Bootloader区域
MPU_SetRegion(0, 0x00000000, 64KB,
RO_PRIV_ONLY | STRONGLY_ORDERED);
; 配置SRAM为全访问
MPU_SetRegion(1, 0x20000000, 128KB,
RW_PRIV_USER | WB_WA_CACHEABLE);
; 关键外设为仅特权访问
MPU_SetRegion(2, 0x40000000, 1MB,
RW_PRIV_ONLY | DEVICE_SHAREABLE);
性能关键路径:
外设访问:
代码保护:
c复制// 将关键函数放在独立section
__attribute__((section(".secure_code")))
void secure_function() {
// ...
}
// 链接脚本中配置MPU属性
.secure_code {
*(.secure_code)
} > FLASH ATTR(RO_PRIV_ONLY)
权限错误循环
缓存一致性问题
c复制// 强制同步
__DSB();
__ISB();
clean_dcache_range(addr, size);
区域重叠冲突
Keil MDK:
GDB脚本:
python复制def mpu_dump():
for i in range(8):
drbar = gdb.execute(f"monitor mcr p15 0 {i} c6 c1 0", to_string=True)
print(f"Region {i}: BASE={drbar}")
Trace32:
javascript复制// 检查MPU配置
MPU.DumpAllRegions()
// 捕获权限错误
ONERROR "MPU" (
PRINT "Fault at PC:", Register(PC)
PRINT "DFSR:", HEX(Data.DFSR)
BREAK
)
通过深入理解PMSAv7的MPU机制,开发者可以构建既安全又高效的嵌入式系统。实际项目中建议结合RTOS的MPU抽象层(如FreeRTOS-MPU)来简化配置管理。当出现内存相关异常时,系统化的排查流程(检查DFSR→DFAR→回溯调用栈)能快速定位问题根源。