C++ / a working model

119 / 163   ·   C11   ·   约 8 分钟

机制:地址转换

先记住这句话

本章介绍硬件地址转换如何让操作系统高效灵活地虚拟化内存。通过在每次访存时由硬件将虚拟地址映射到物理地址,进程获得从零开始的私有连续空间假象,同时操作系统保持隔离与保护。

本篇内容
  1. 内存虚拟化的核心需求
  2. 基址-界限动态重定位
  3. 操作系统如何配置硬件
  4. 运行示例
  5. 动手练习

官方章节 PDF

内存虚拟化的核心需求

内存虚拟化必须同时满足效率、控制与灵活性。效率意味着不能让软件在每次访存时介入;控制意味着任何进程都不能触及他人或内核的内存;灵活性意味着应用程序可以按自己喜欢的方式布局代码、堆和栈,仿佛独占从地址零开始的连续空间。硬件地址转换正是为这三项要求量身定做的机制。

基址-界限动态重定位

处理器提供一对特权寄存器:基址寄存器保存进程在物理内存中的起始位置,界限寄存器保存该进程地址空间的长度。每次取指、加载或存储时,硬件先把发出的虚拟地址与界限比较;若越界则立即产生保护异常,否则把虚拟地址加上基址得到真正的物理地址。整个过程对用户程序完全透明,程序仍然认为自己从零开始运行。

操作系统如何配置硬件

硬件只提供转换与检查的快速路径,真正的策略由操作系统决定。内核维护空闲物理区域列表,为新进程分配一块足够大的连续区间,把该区间的起始地址写入基址寄存器、把地址空间大小写入界限寄存器。每次上下文切换时这两个寄存器必须一起更新,否则新进程会看到错误的映射。越界异常被内核捕获后通常终止肇事进程,从而保证系统其余部分不受影响。

常见误区

  • 误以为只有数据访问才需要转换,忘记取指令同样经过基址-界限检查
  • 认为可以在纯软件里对每次访存做重定位,却忽略其巨大性能代价
  • 上下文切换时只更新页表指针而忘记同步基址与界限寄存器

运行一个例子

最低标准 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 界限。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录