在嵌入式系统开发中,内存管理单元(MMU)和内存保护单元(MPU)是处理器架构的核心组件。作为ARM体系结构的重要组成部分,它们负责实现虚拟地址到物理地址的转换以及内存访问权限控制。不同于x86架构的统一内存管理设计,ARM针对不同应用场景提供了灵活的配置方案。
MMU(Memory Management Unit)是完整的内存管理单元,主要特性包括:
MPU(Memory Protection Unit)则是简化版的内存保护机制:
以ARM920T为例,其MMU支持两种页表格式:
RealView Instruction Set Simulator(RVISS)作为ARM官方仿真工具,其pagetable模块解决了开发初期的一个关键痛点:在硬件平台就绪前,开发者需要验证内存相关代码的正确性。传统做法需要手动编写复杂的初始化代码,而RVISS通过预置配置实现了开箱即用的内存管理环境。
技术实现上,pagetable模块在仿真器启动时自动完成以下工作:
在工程实践中,通过三种方式控制pagetable模块:
在ARMulator Configuration对话框中选择:
定位到安装目录下的default.ami文件:
bash复制{RVISS安装目录}/RVARMulator/ARMulator/.../platform/default.ami
修改PAGETAB参数:
ini复制{PAGETAB=Default_Pagetables} # 启用默认页表
{PAGETAB=No_Pagetables} # 禁用模块
在peripherals.ami中可定义详细的页表属性:
ini复制{Default_Pagetables=PageTables
MMU=Yes
Cache=Yes
PageTableBase=0xA0000000
Region[0]{
VirtualBase=0
PhysicalBase=0
Size=4GB
Cacheable=No
}
}
pagetable模块会初始化以下关键寄存器:
| 标志位 | 功能描述 | 典型值 |
|---|---|---|
| MMU | 启用MMU/MPU | 1 |
| Cache | 数据缓存启用 | 1 |
| WriteBuffer | 写缓冲启用 | 1 |
| ICache | 指令缓存启用 | 1 |
| BranchPredict | 分支预测启用(ARM810特有) | 0 |
存储一级页表的物理基地址,必须16KB对齐。例如:
c复制PageTableBase = 0xA0000000; // 页表位于256MB位置
控制16个内存域的访问权限,默认配置:
c复制DAC = 0x00000001; // 所有域设置为Client模式
默认配置包含两个典型区域:
ini复制Region[0]{
VirtualBase=0
PhysicalBase=0
Size=4GB
Cacheable=No
Bufferable=No
AccessPermissions=3 // 读写权限
}
ini复制Region[1]{
VirtualBase=0
PhysicalBase=0
Size=128MB
Cacheable=Yes
Bufferable=Yes
}
实际开发中建议添加更精细的配置:
ini复制Region[2]{
VirtualBase=0x30000000 // SDRAM区域
PhysicalBase=0x30000000
Size=64MB
Cacheable=Yes
}
Region[3]{
VirtualBase=0x48000000 // 外设区域
PhysicalBase=0x48000000
Size=1MB
Cacheable=No
}
以ARM920T为例的典型初始化序列:
关键差异点:
ARM1156T2-S处理器的MPU配置:
ini复制PhysicalBase=0
Size=4GB
Cacheable=Yes
AccessPermissions=3 // 完全访问权限
TEX=0 // 类型扩展字段
在启用缓存时需特别注意:
RVISS通过以下标志控制缓存行为:
ini复制Cache=Yes // 全局缓存启用
WriteBuffer=Yes // 写缓冲启用
Updateable=Yes // ARM610特有属性
症状:Prefetch Abort或Data Abort
排查步骤:
症状:读取到过期数据或DMA传输错误
解决方案:
c复制// 清理数据缓存
void clean_cache_range(unsigned long start, unsigned long end)
{
unsigned long addr;
for (addr = start; addr < end; addr += 32) {
__asm__ __volatile__ (
"mcr p15, 0, %0, c7, c10, 1" :: "r" (addr));
}
}
内存映射可视化:
缓存命中率分析:
bash复制monitor cache_stats on # 启用缓存统计
run # 运行测试代码
monitor cache_stats off # 查看命中率
页表内容检查:
bash复制x/16 0xA0000000 # 查看一级页表内容
通过修改peripherals.ami的Pagetables段实现:
ini复制{Default_Pagetables=PageTables
Region[4]{
VirtualBase=0xC0000000
PhysicalBase=0x30000000 // 重映射SDRAM
Size=16MB
Domain=1
}
}
模拟Linux MMU上下文切换:
c复制// 上下文切换示例
void switch_mmu_context(unsigned int new_pgd)
{
__asm__ __volatile__(
"mcr p15, 0, %0, c2, c0, 0" // 设置TTBR0
:: "r" (new_pgd | 0x1A) // 带ASID标记
);
}
ARM TrustZone技术模拟:
ini复制Region[5]{
VirtualBase=0x80000000
PhysicalBase=0x80000000
Size=16MB
AccessPermissions=1 // 仅特权访问
S=Yes // 安全区域标记
}
在实际项目开发中,我们曾遇到一个典型案例:在移植u-boot到ARM926EJ-S平台时,通过RVISS的pagetable模块快速验证了NOR Flash和SDRAM的映射方案。具体做法是在peripherals.ami中预先配置:
ini复制Region[0]{
VirtualBase=0x00000000
PhysicalBase=0x00000000 // NOR Flash
Size=2MB
Cacheable=No
}
Region[1]{
VirtualBase=0x30000000
PhysicalBase=0x30000000 // SDRAM
Size=32MB
Cacheable=Yes
}
这样在硬件平台就绪前,就能提前验证启动代码的内存访问逻辑,显著缩短了开发周期。