我试图了解 Linux 3/1 分割(或 2/2、1/3 等)以及映射到物理内存的工作原理。我们假设 x86。
我特别不明白的是为什么内核的 va[3GiB, 4GiB) 中的 1GiB 总是映射到 pa[0, 1GiB]。分割位置为 (virtual) PAGE_OFFSET
。
如果我有更多内存怎么办?如果我少了怎么办?用户空间的所有内存都去哪里了?
从 TLDP 我了解到底部物理 1GiB 始终用于内核(为什么?)。使用高内存(通过这篇文章)当虚拟地址空间小于物理地址空间时,因为内存很多,否则会浪费(对吧?);在 x86-64 中,它没有被使用,因为虚拟地址空间是异常的。
始终保持内核的一件事可能是在上下文切换时current
保持不变并且无需更改cr3
。
这个答案说:
高内存是用户空间程序可以寻址的内存段。它不能触及低内存。
低内存是 Linux 内核可以直接寻址的内存段。如果内核必须访问高端内存,它必须首先将其映射到自己的地址空间。
人们是否过度使用了“低记忆力”和“高记忆力”这两个术语?
最后,LDD3 说:
内核无法直接操作未映射到内核地址空间的内存。换句话说,内核需要它自己的虚拟地址来存储它必须直接接触的任何内存。因此,多年来,内核可以处理的最大物理内存量是可以映射到虚拟地址空间的内核部分的量,减去内核代码本身所需的空间。因此,基于 x86 的 Linux 系统最多可以使用略低于 1 GB 的物理内存。
p
这是否指的是内核中的指针必须保存虚拟地址,而不是物理地址,就像映射总是适用的那样?为什么会有“1GiB 物理内存”限制?
答案1
如今,32 位 x86 几乎与 20 世纪 90 年代初 Linux 诞生时的 16 位 8086 一样过时。当时 386 提供的 4 GB 虚拟地址空间已经足够了,因为典型的台式机只有几十个兆字节内存。
Linus 决定分割虚拟地址空间,以便为内核保留较高的 1 GB(从地址 0xc0000000 开始),而较低的 3 GB(从地址 0 开始)可供用户空间进程使用。然后,所有物理 RAM 都从 PAGE_OFFSET 开始映射,即从 3 GB 开始的地址。 1 GB 在当时就足够了,因为(正如我之前提到的)物理 RAM 的典型数量远小于此,并且这种划分为用户空间留下了舒适的 3 GB 空间。
在打开分页(即虚拟到物理地址映射)之前,包含内核代码和静态数据的内核映像被加载到物理内存的开头。 (嗯,不完全是,但由于 PC 平台的一些怪癖,通常从 2 MB 开始。)当分页打开时,物理地址 N 处的内存最终位于虚拟地址 N + PAGE_OFFSET 处。这意味着内核映像占据内核内存区域的较低部分,通常只有几兆字节。
请注意,到目前为止我已经讨论了虚拟地址空间,这些空间是预订的对于某些事情。要实际使用这些地址,您必须将物理 RAM 页框映射到虚拟地址。早期,只映射了一小部分内核虚拟地址空间,因为可供映射的物理 RAM 太少了,但是当更大的 RAM 变得可以承受时,这种情况很快就发生了巨大变化,导致 1 GB 空间不足以满足寻址所有 RAM。因此引入了“高内存”机制,它提供了一个窗口,可以根据需要映射部分额外的 RAM。
那么为什么内核需要在其虚拟地址空间中拥有 RAM。问题是 CPU 只能(以编程方式)通过虚拟(映射)地址访问内存。寄存器中的指针是指向虚拟地址空间的指针,指导程序流程的指令指针也是如此。内核需要能够自由访问 RAM,例如将稍后提供给用户空间进程的缓冲区清零。
内核将整个 RAM 存储到其地址空间中并不意味着用户空间无法访问它。可以存在多个到 RAM 页框的映射;当选择执行进程时,它既可以永久映射到内核内存空间,也可以映射到用户空间的某个地址。