内核页表如何初始化?
我正在关注戈尔曼的虚拟内存管理书。
有一节是关于内核表页初始化的,据说分为两个阶段,bootstrapping 和 Finalizing。
以下是关于引导阶段的内容。
汇编器函数startup_32()负责启用分页单元 arch/i386/kernel/head.S。当 vmlinuz 中的所有正常内核代码都已编译时 基地址位于 PAGE_OFFSET + 1MiB,内核实际上是从开始加载的 在内存的第一个兆字节 (0x00100000) 处。第一个兆字节已使用 由某些设备与 BIOS 通信并被跳过。 引导程序 该文件中的代码通过减去 __PAGE_OFFSET 将 1MiB 视为其基地址 启用分页单元之前的任何地址。因此在分页单元启用之前 启用后,必须建立页表映射来转换 8MiB 物理内存到虚拟地址PAGE_OFFSET。
为什么我们要减去__PAGE_OFFEST?出于什么目的?
为什么我们必须在启用分页单元之前进行减法?我们不是总是使用减法来将内核虚拟地址映射到物理内存地址吗?
为什么是8MB?
谢谢,
I am following Gorman's virtual memory management book.
There is a section about kernel table page initialization which is said to be divided into two phases, bootstrapping and finalizing.
Here is what it says about the bootstrapping phase.
The assembler function startup_32() is responsible for enabling the paging unit in
arch/i386/kernel/head.S. While all normal kernel code in vmlinuz is compiled
with the base address at PAGE_OFFSET + 1MiB, the kernel is actually loaded beginning
at the first megabyte (0x00100000) of memory. The first megabyte is used
by some devices for communication with the BIOS and is skipped. The bootstrap
code in this file treats 1MiB as its base address by subtracting __PAGE_OFFSET from
any address until the paging unit is enabled. Therefore before the paging unit is
enabled, a page table mapping has to be established that translates the 8MiB of
physical memory to the virtual address PAGE_OFFSET.
Why we want to subtract __PAGE_OFFEST? For what purpose?
Why we have to do subtracting before the paging unit is enabled? Isn't that we always use subtracting for mapping kernel virtual address to physical memory address?
Why it is 8MB?
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于 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 per页表)。
除非涉及一些额外的内核重定位,否则 8MB 可能只是映射范围的大小,足以映射整个内核。
Since x86 code isn't generally position-independent, if it's compiled to execute at address X (__PAGE_OFFSET + 1MB) but loaded at address Y (1MB), all addresses inside of it need to be decremented by Y-X (__PAGE_OFFSET + 1MB - 1MB = __PAGE_OFFSET) for it to work.
For example, if there's an instruction to read a byte of memory from the beginning of the kernel, __PAGE_OFFSET + 1MB, the address is reduced by __PAGE_OFFSET and the actual read location becomes 1MB, exactly where the kernel starts in the memory.
When page translation is finally enabled, __PAGE_OFFSET can and, I believe, is effectively subtracted by the page translation mechanism by mapping a range of virtual addresses to a range of physical addresses that are smaller by __PAGE_OFFSET (that is, physical=virtual-__PAGE_OFFSET per the page tables).
Unless there's some additional kernel relocation involved, 8MB is likely just the size of the mapping range, sufficient to map the entire kernel.