在嵌入式系统开发中,内存保护单元(MPU)扮演着至关重要的角色。作为Arm CoreLink CMN-600AE互连架构的关键组件,MPU提供了硬件级别的内存访问控制机制。与传统的MMU不同,MPU不涉及地址转换,而是专注于内存区域的访问权限管理,这使得它在实时性要求高的场景中表现出色。
CMN-600AE的MPU模块支持多达12个独立可配置的内存保护区域,每个区域通过一对64位寄存器进行定义:
这种设计允许开发人员为不同的内存区域设置精细的访问权限,包括:
重要提示:所有MPU寄存器只能通过安全访问进行配置,在系统初始化阶段必须完成设置,之后任何非配置访问都将被MPU拦截。
PRBAR(Programmable Region Base Address Register)寄存器采用分段式设计,分为高32位和低32位两部分:
高32位(PRBARx_high)结构:
| 位域 | 字段名 | 描述 |
|---|---|---|
| 63:48 | 保留 | 必须保持为0 |
| 47:32 | regionX_base_addr | 基地址的高16位 |
低32位(PRBARx_low)结构:
| 位域 | 字段名 | 描述 |
|---|---|---|
| 31:12 | regionX_base_addr | 基地址的低20位 |
| 11:10 | 保留 | 必须保持为0 |
| 9 | regionX_br | 背景区域标识 |
| 8:6 | 保留 | 必须保持为0 |
| 5:2 | regionX_ap | 访问权限控制 |
| 1:0 | 保留 | 必须保持为0 |
regionX_base_addr(基地址)
c复制PRBARx_high = 0x00008000; // 高16位
PRBARx_low = 0x00000000; // 低20位
regionX_ap(访问权限)
c复制// 允许安全读写,非安全只读
regionX_ap = 0b1110;
// 完全禁止访问
regionX_ap = 0b0000;
regionX_br(背景区域)
PRLAR(Programmable Region Limit Address Register)同样采用高低32位分段结构:
高32位(PRLARx_high)结构:
| 位域 | 字段名 | 描述 |
|---|---|---|
| 63:48 | 保留 | 必须保持为0 |
| 47:32 | regionX_limit_addr | 限界地址的高16位 |
低32位(PRLARx_low)结构:
| 位域 | 字段名 | 描述 |
|---|---|---|
| 31:12 | regionX_limit_addr | 限界地址的低20位 |
| 11:1 | 保留 | 必须保持为0 |
| 0 | regionX_en | 区域使能位 |
保护区域的实际大小由基地址和限界地址共同决定:
code复制区域大小 = (limit_addr - base_addr) + 1
关键约束条件:
示例:配置1MB大小的保护区域(0x80000000-0x800FFFFF)
c复制// PRBAR配置
PRBARx_high = 0x00008000;
PRBARx_low = 0x00000000;
// PRLAR配置
PRLARx_high = 0x0000800F;
PRLARx_low = 0x000FFFF0; // 低20位为0xFFFFF,使能位置1
regionX_en位是PRLAR寄存器中最重要的控制位:
实际经验:建议先配置好所有寄存器后再统一使能,避免中间状态导致意外访问冲突。
c复制void mpu_init(void)
{
// 1. 禁用所有区域
for (int i = 0; i < 12; i++) {
PRLARx[i]_low = 0;
}
// 2. 配置区域0:ROM区(只读)
PRBAR0_high = ROM_BASE_HIGH;
PRBAR0_low = ROM_BASE_LOW | (0b1010 << 2); // 安全/非安全只读
PRLAR0_high = ROM_LIMIT_HIGH;
PRLAR0_low = ROM_LIMIT_LOW | 0x1;
// 3. 配置区域1:安全RAM区(读写)
PRBAR1_high = SECRAM_BASE_HIGH;
PRBAR1_low = SECRAM_BASE_LOW | (0b1111 << 2);
PRLAR1_high = SECRAM_LIMIT_HIGH;
PRLAR1_low = SECRAM_LIMIT_LOW | 0x1;
// 4. 配置背景区域(默认禁止访问)
PRBAR11_high = 0x0000;
PRBAR11_low = 0b1000000000; // BR=1, AP=0000
PRLAR11_high = 0xFFFF;
PRLAR11_low = 0xFFFFF | 0x1;
// 内存屏障确保配置生效
__DSB();
__ISB();
}
当地址空间被多个保护区域覆盖时,MPU按以下规则处理冲突:
建议配置策略:
对齐错误:
权限冲突:
区域重叠:
利用MPU故障状态寄存器识别违规访问:
渐进式配置法:
模拟测试:
c复制// 测试代码示例
void test_region_access(void)
{
// 尝试读取受保护区域
volatile uint32_t *ptr = (uint32_t *)0x80000000;
uint32_t val = *ptr; // 应触发MPU异常
// 验证异常处理流程
if (exception_occurred) {
printf("MPU protection working as expected\n");
}
}
在汽车电子等实时性要求高的场景中,我们通常会:
经过多年在嵌入式安全领域的实践,我发现MPU配置的质量直接影响系统的可靠性和安全性。特别是在ASIL-D应用中,建议采用以下防御性编程策略: