You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核镜像与直接映射为何在物理地址空间存在重叠

内核镜像与直接映射的物理地址重叠是刻意设计的

先贴对应的内核地址转换实现代码:

unsigned long __phys_addr(unsigned long x)
{
    unsigned long y = x - __START_KERNEL_map;

    /* use the carry flag to determine if x was < __START_KERNEL_map */
    if (unlikely(x > y)) {
        x = y + phys_base;

        VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
    } else {
        x = y + (__START_KERNEL_map - PAGE_OFFSET);

        /* carry flag will be set if starting x was >= PAGE_OFFSET */
        VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x));
    }
}

这段逻辑覆盖了x86_64架构下内核空间两个独立的虚拟地址映射区间,两者映射到同一段内核镜像所在物理内存的设计完全是有意为之,根本不是映射错误:

  • 第一个分支处理__START_KERNEL_map起始的内核镜像固定映射区:这个区间的虚拟地址在编译内核时就写死到了内核镜像的符号表中,启动时只需要把这个区间和内核实际加载的物理基地址phys_base做固定偏移映射即可。哪怕开启KASLR让内核加载的物理地址随机化,也只需要更新phys_base值就能完成整个内核镜像的地址修正,不需要逐个修改内核符号的重定位表,启动早期页表还没完全初始化的时候,靠这段映射就能跑通最核心的启动流程。代码里的VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE)就是在做边界校验,保证这个区间的虚拟地址不会超出内核镜像的预留大小范围。
  • 第二个分支处理PAGE_OFFSET起始的全物理内存线性直接映射区:这个区间会把系统所有可用物理内存按固定偏移做一一映射,常规物理页分配、kmalloc申请的内核内存、DMA缓冲区都靠这个区间访问,默认用大页映射,访问开销极低,内存管理子系统可以靠固定偏移快速完成虚拟/物理地址转换,不需要逐页查页表。

两个区间重叠映射内核镜像所在物理内存的设计,核心是兼顾两个核心需求:

一是保证内核镜像本身的地址不随物理加载位置变化,减少启动阶段的重定位开销,同时可以给内核镜像的不同段(代码段、只读数据段、可写数据段)单独设置严格的页表权限,比如代码段设为可执行只读、只读数据段设为不可执行只读,阻断内核代码篡改类的攻击。
二是保证线性直接映射区可以覆盖100%的物理内存,不需要给内核镜像占用的物理页单独写特殊的地址转换逻辑,内存管理、DMA、内存热插拔等功能都可以用统一的线性映射规则处理所有物理页,大幅降低代码复杂度。

需要注意的是,虽然同一段物理内存有两个虚拟地址映射,但两个映射的页表权限完全不同,内核正常运行时不会出现地址访问冲突。

内容的提问来源于stack exchange,提问作者choxsword

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 08:27:20