119 / 163 · C11 · 约 8 分钟
机制:地址转换
本章介绍硬件地址转换如何让操作系统高效灵活地虚拟化内存。通过在每次访存时由硬件将虚拟地址映射到物理地址,进程获得从零开始的私有连续空间假象,同时操作系统保持隔离与保护。
内存虚拟化的核心需求
内存虚拟化必须同时满足效率、控制与灵活性。效率意味着不能让软件在每次访存时介入;控制意味着任何进程都不能触及他人或内核的内存;灵活性意味着应用程序可以按自己喜欢的方式布局代码、堆和栈,仿佛独占从地址零开始的连续空间。硬件地址转换正是为这三项要求量身定做的机制。
基址-界限动态重定位
处理器提供一对特权寄存器:基址寄存器保存进程在物理内存中的起始位置,界限寄存器保存该进程地址空间的长度。每次取指、加载或存储时,硬件先把发出的虚拟地址与界限比较;若越界则立即产生保护异常,否则把虚拟地址加上基址得到真正的物理地址。整个过程对用户程序完全透明,程序仍然认为自己从零开始运行。
操作系统如何配置硬件
硬件只提供转换与检查的快速路径,真正的策略由操作系统决定。内核维护空闲物理区域列表,为新进程分配一块足够大的连续区间,把该区间的起始地址写入基址寄存器、把地址空间大小写入界限寄存器。每次上下文切换时这两个寄存器必须一起更新,否则新进程会看到错误的映射。越界异常被内核捕获后通常终止肇事进程,从而保证系统其余部分不受影响。
常见误区
- 误以为只有数据访问才需要转换,忘记取指令同样经过基址-界限检查
- 认为可以在纯软件里对每次访存做重定位,却忽略其巨大性能代价
- 上下文切换时只更新页表指针而忘记同步基址与界限寄存器
运行一个例子
最低标准 C11 · 完整程序 · 下载 .c
#include <stdio.h>
#include <stdint.h>
int main(void) {
const uint32_t base = 40960; /* 40 KB */
const uint32_t bound = 16384; /* 16 KB */
printf("Simulating hardware address translation\n");
printf("Base register: %u (0x%x)\n", base, base);
printf("Bounds register: %u (0x%x)\n\n", bound, bound);
uint32_t test_vas[] = {0, 8192, 16383, 16384, 20480};
int n = 5;
for (int i = 0; i < n; ++i) {
uint32_t va = test_vas[i];
printf("Virtual address %u (0x%x): ", va, va);
if (va >= bound) {
printf("OUT OF BOUNDS - exception raised\n");
} else {
uint32_t pa = va + base;
printf("translates to physical %u (0x%x)\n", pa, pa);
}
}
return 0;
}
在本地编译
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-15-address-translation.c -o example && ./example预期结果
Simulating hardware address translation
Base register: 40960 (0xa000)
Bounds register: 16384 (0x4000)
Virtual address 0 (0x0): translates to physical 40960 (0xa000)
Virtual address 8192 (0x2000): translates to physical 49152 (0xc000)
Virtual address 16383 (0x3fff): translates to physical 57343 (0xdfff)
Virtual address 16384 (0x4000): OUT OF BOUNDS - exception raised
Virtual address 20480 (0x5000): OUT OF BOUNDS - exception raised
CHECK YOUR UNDERSTANDING
合上答案,试着解释。
某进程拥有 16 KB 地址空间,被操作系统放到物理地址 40 KB 处。虚拟地址 8 KB 对应的物理地址是多少?若该进程访问虚拟地址 20 KB,硬件会怎样反应?
查看参考答案
物理地址为 48 KB。访问 20 KB 会立即触发保护异常,因为 20 KB 已经超出 16 KB 界限。
继续查证
标准草案与官方章节会更新;版本标记只说明示例最低要求。