一、前MMU时代:物理寻址的原始世界(1940s-1970s)
1. 早期计算机架构
直接物理寻址:CPU发出的地址信号直接连接到内存总线
+---------------------+
| CPU |
| 指令寄存器(IR) |--+
| 程序计数器(PC) | | 物理地址直通
+---------------------+ |
v
+---------------------+ |
| 内存 | |
| 物理地址0x0000-0xFFFF|<+
+---------------------+
致命缺陷:
- 无内存保护:一个程序可随意覆盖操作系统内核
- 无地址空间隔离:程序A可读写程序B的数据
- 碎片化严重:程序需连续物理内存(加载位置固定)
2. 原始解决方案
基址寄存器(Base Register):程序使用逻辑地址,硬件自动加上基址寄存器值。
IBM System/360 示例
LOAD R1, BASE_ADDR ; 加载基址
ADD R2, R1, OFFSET ; 计算物理地址
局限性:无法动态扩展,无法处理碎片。
二、MMU的诞生:虚拟内存革命(1960s)
1. 里程碑:Atlas Supercomputer(1962)
- 首次实现分页式虚拟内存: 发明页表(Page Table)
- 数据结构; 引入缺页异常(Page Fault)处理机制;
- 使用磁鼓存储器作为后备存储;
2. 核心技术创新
+---------------------+ +-----------------+
| CPU | | MMU |
| 逻辑地址(VA) ------>|------>| 页表查询(PTE) |
+---------------------+ | TLB缓存 |
| 物理地址(PA) ---> 内存
+-----------------+
分页机制:
- 内存划分为固定大小页(如4KB);
- 页表存储虚拟页到物理页帧的映射;
关键技术突破:
- 硬件加速转换:专用电路处理地址转换;
- 权限控制:页表项包含RWX权限位;
- 缺页中断:触发操作系统加载数据;
三、MMU的演进史:架构创新时间线
1. 段页式混合架构(1978:Intel 8086)
// 段寄存器 + 偏移量
uint32_t phys_addr = (segment_reg << 4) + offset;
16位实模式限制:
- 20位地址空间(1MB)
- 无内存保护
2. 保护模式革命(1985:Intel 80386)
选择子(Selector)
|
v
全局描述符表(GDT) ---> 段基址
|
v
线性地址(LA) ------> 分页单元 ---> 物理地址(PA)
两级转换:
- 段式转换:逻辑地址→线性地址
- 页式转换:线性地址→物理地址
关键创新:
- 4级权限环(Ring 0-3)
- 硬件任务切换
3. 纯分页时代(1995+:x86 PAE/AMD64)
- 放弃段式内存:设置CS/DS/ES/SS基址为0,偏移=线性地址。
- 物理地址扩展(PAE):36位物理地址(64GB支持)。
- x86-64架构:48位虚拟地址(256TB用户空间)和 4级页表(PML4→PDP→PD→PT)。
四、现代MMU核心技术解析
1. 多级页表工作流程(x86-64为例)
虚拟地址: 63-48 47-39 38-30 29-21 20-12 11-0
保留位 | PML4索引 | PDP索引 | PD索引 | PT索引 | 页内偏移
TIPS:为什么页内偏移是 bit11 - bit0 12位表示?4k对齐, 4096=0x100
MMU 硬件内部进行地址转换的简化版逻辑过程如下:
phys_addr_t translate(uint64_t va) {
pml4e_t *pml4 = get_cr3(); // 获取顶级页表地址
pml4e_t pml4e = pml4[va.pml4_idx]; // 读取PML4E
pdpe_t *pdpt = pml4e.pdp_base; // PDPT基址
pdpe_t pdpe = pdpt[va.pdp_idx]; // 读取PDPE
pde_t *pdt = pdpe.pd_base; // PDT基址
pde_t pde = pdt[va.pd_idx]; // 读取PDE
pte_t *pt = pde.pt_base; // PT基址
pte_t pte = pt[va.pt_idx]; // 读取PTE
return (pte.pfn << 12) | va.offset; // 组合物理地址
}
2. TLB(转换后备缓冲器)
工作原理
+-------------------+ +---------------------+
| CPU执行内存访问 | | 硬件MMU |
| 1. 检查TLB |--->| 2. TLB命中: 完成访问 |
| 3. TLB未命中 | | 4. 自动页表遍历 |
| | | 5. 转换失败触发#PF |
+-------------------+ +---------------------+
|
v
+-------------------+ +---------------------+
| 内核#PF处理程序 |<----| 6. 传递错误地址(CR2) |
| 7. 调用handle_mm_fault() | |
| 8. 软件模拟遍历修复页表 | |
+-------------------+ +---------------------+
关键技术:
- 全关联/组关联缓存:存储近期转换结果
- ASID(地址空间ID):区分进程上下文
- PCID(进程上下文ID):避免切换时TLB刷新
高级特性
- 大页支持(2MB/1GB):减少TLB Miss(1个TLB项覆盖更大范围)
- 内存保护密钥(Intel MPK):为内存页附加4-bit密钥,硬件强制隔离
- IOMMU(设备虚拟化):为DMA设备提供地址转换
+----------+ +-------+
| 设备DMA |----->| IOMMU |---> 物理内存
| 虚拟地址 | +-------+
+----------+
五、现代MMU架构对比
六、MMU与操作系统的协作
1. 关键内核操作
// 页表更新示例(Linux内核)
void update_mapping(unsigned long va, phys_addr_t pa) {
pte_t *pte = lookup_pte(va); // 查找PTE项
set_pte(pte, mk_pte(pa, PAGE_KERNEL)); // 设置物理地址+权限
flush_tlb_kernel_range(va, va+PAGE_SIZE); // 刷新TLB
}
2. 缺页异常处理流程
+---------------+
| CPU触发#PF异常 |
+---------------+
|
v
+---------------+
| 保存寄存器现场 |
+---------------+
|
v
+---------------+
| 调用do_page_fault() |
+---------------+
|
+-----------+-----------+
| |
用户态缺页(v) 内核态缺页(x)
| |
+-------------------+ +---------------------+
| 检查VMA权限 | | 检查内核地址合法性 |
| 分配物理页 | | 若是vmalloc区域 |
| 建立映射 | | 同步内核页表 |
| 返回用户空间 | | 否则触发Kernel Oops |
+-------------------+ +---------------------+
3. MMU 和 软件处理边界
- 完整处理流程
七、未来演进方向
- CXL内存池化:MMU需支持跨设备一致性内存访问
- 异构内存管理:统一管理DRAM、PMEM、GPU显存
- 安全增强:内存加密(Intel SGX, AMD SEV)、物理不可克隆功能(PUF)集成
- AI加速:专用硬件预测页表访问模式