我正在关注戈尔曼的虚拟内存管理书。
有一个关于内核表页面初始化的部分,据说分为两个阶段,自举和最终确定。
以下是有关自举阶段的内容。
汇编程序函数startup_32()负责启用分页单元 弓/ I386 /内核/ head.S中。虽然编译了 vmlinuz 中的所有正常内核代码 使用PAGE_OFFSET + 1MiB的基址,实际加载内核 在第一兆字节(0x00100000)的内存。使用第一兆字节 通过一些设备与BIOS通信并被跳过。 引导程序 此文件中的代码通过从中减去__PAGE_OFFSET将1MiB视为其基址 任何地址,直到寻呼单元被启用。因此在寻呼单元之前 启用后,必须建立一个页表映射,以转换 8MiB 物理内存到虚拟地址PAGE_OFFSET。
为什么我们要减去__PAGE_OFFEST?出于什么目的?
为什么我们必须在启用寻呼单元之前进行减法?是不是我们总是使用减法来将内核虚拟地址映射到物理内存地址?
为什么是8MB?
谢谢,
答案 0 :(得分:3)
由于x86代码通常与位置无关,如果它被编译为在地址X(__PAGE_OFFSET + 1MB)执行但在地址Y(1MB)处加载,则其内部的所有地址都需要递减YX(__PAGE_OFFSET +它可以工作1MB - 1MB = __PAGE_OFFSET。
例如,如果有一条指令从内核开始读取一个字节的内存,__PAGE_OFFSET + 1MB,则地址减少__PAGE_OFFSET,实际读取位置变为1MB,正好是内核在内存中启动的位置。
当最终启用页面转换时,__PAGE_OFFSET可以并且我相信,通过将一系列虚拟地址映射到一个较小的__PAGE_OFFSET物理地址范围(即,physical = virtual),页面转换机制可以有效地减去__PAGE_OFFSET -__ PAGE_OFFSET每页表格。)
除非涉及一些额外的内核重定位,否则8MB可能只是映射范围的大小,足以映射整个内核。