我知道虚拟地址如何变成物理的映射机制。
如下所示,线性地址包含三个部分
以下是插图:
现在,当我在memorylayout.h中查看Xv6的源代码时
#define V2P(a) (((uint) (a)) - KERNBASE)
#define P2V(a) (((void *) (a)) + KERNBASE)
#define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts
#define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts
如果不执行地址转换过程,V2P或P2V如何正常工作?
答案 0 :(得分:1)
V2P和P2V宏的功能并不像你想象的那么多。它们只是减去并添加KERNBASE常量,标记为2 GB。
您似乎正确理解了MMU的硬件映射机制。 映射规则由每个进程页表保存。这些表格形成了流程的虚拟空间。
具体来说,在XV6中,正在构建进程的虚拟空间结构(通过适当的映射),如下所示:virtual address space layout
如上图所示,XV6专门构建了进程的虚拟地址空间,以便2GB - 4GB虚拟地址(分别)映射到0到PHYSTOP物理地址。正如XV6官方评论中所解释的那样:
Xv6包含内核在每个进程的页表中运行所需的所有映射; 这些映射都出现在KERNBASE之上。它映射虚拟地址KERNBASE:KERNBASE + PHYSTOP 到0:PHYSTOP。
还明确了这一决定的动机:
这种映射的一个原因是这样的 内核可以使用自己的指令和数据。另一个原因是内核有时候 需要能够写入给定的物理内存页面,例如何时 创建页表页面;让每个物理页面都出现在可预测的虚拟页面上 地址使这很方便。
换句话说,因为内核使所有页表都将2GB虚拟映射到0物理(并且高达PHYSTOP),我们可以很容易地找到超过2GB的虚拟地址的物理地址。 例如:虚拟地址0x10001000的物理地址很容易找到:它是0x00001000,我们只减去2GB,因为我们将它映射为。
这"解决方法"可以帮助内核轻松完成转换,例如,构建和操作页表(需要计算物理地址并将其写入内存)。
当然,以上"解决方法"不是免费的,因为这会浪费宝贵的虚拟地址空间(2GB),因为现在每个物理地址至少已经有1个虚拟地址。即使我们永远不会使用它。离开整个虚拟地址只留下2GB的实际进程(总共4GB,因为我们使用32位来计算地址)。这也在XV6官方评论中得到了解释:
这种安排的缺点是xv6无法制作 使用超过2 GB的物理内存
我建议你在"流程地址空间"下的XV6评论中阅读更多关于这种方式的内容。头。 XV6 Commentary