Xv6中P2V、V2P宏背后的机制是什么
What's the mechanism behind P2V, V2P macro in Xv6
我知道虚拟地址如何变成物理地址有一个映射机制。
就像下面这样,一个线性地址包含三部分
- 页面目录索引
- 页Table索引
- 偏移量
插图如下:
现在,当我在 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不做地址转换怎么能正常工作呢?
V2P 和 P2V 宏的功能并没有您想象的那么多。它们只是减去并添加标记为 2 GB 的 KERNBASE 常量。
看来你对MMU的硬件映射机制理解正确。
映射规则由每个进程页表保存。这些表构成了进程的虚拟 space.
具体来说,在 XV6 中,进程的虚拟 space 结构正在构建(通过适当的映射)如下:virtual address space layout
如上图所示,XV6 专门构建了进程的虚拟地址space,以便 2GB - 4GB 虚拟地址映射到 0 到 PHYSTOP 物理地址(分别)。正如XV6官方评论中解释的那样:
Xv6 includes all mappings needed for the kernel to run in every process’s page table;
these mappings all appear above KERNBASE. It maps virtual addresses KERNBASE:KERNBASE+PHYSTOP
to 0:PHYSTOP.
还说明了做出此决定的动机:
One reason for this mapping is so that the
kernel can use its own instructions and data. Another reason is that the kernel sometimes
needs to be able to write a given page of physical memory, for example when
creating page table pages; having every physical page appear at a predictable virtual
address makes this convenient.
换句话说,因为内核使所有页表将2GB虚拟映射到0物理(直到PHYSTOP),我们可以很容易地找到2GB以上的虚拟地址的物理地址。
例如:虚拟地址0x10001000的物理地址很容易找到:它是0x00001000我们只是减去2GB,因为我们是这样映射的。
这"workaround"可以帮助内核轻松地进行转换,例如,用于构建和操作页表(需要计算物理地址并写入内存)。
当然上面的"workaround"不是免费的,因为这让我们浪费了宝贵的虚拟地址space(2GB),因为现在每个物理地址至少已经有1个虚拟地址了。即使我们永远不会使用它。这样真正的进程就只剩下整个虚拟地址剩下的2GB了(一共是4GB,因为我们是用32bit来统计地址的)。这个在XV6官方解说中也有解释:
A defect of this arrangement is that xv6 cannot make
use of more than 2 GB of physical memory
我建议您在 "Process address space" header 下的 XV6 评论中阅读更多关于这种方式的信息。 XV6 Commentary
我知道虚拟地址如何变成物理地址有一个映射机制。
就像下面这样,一个线性地址包含三部分
- 页面目录索引
- 页Table索引
- 偏移量
插图如下:
现在,当我在 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不做地址转换怎么能正常工作呢?
V2P 和 P2V 宏的功能并没有您想象的那么多。它们只是减去并添加标记为 2 GB 的 KERNBASE 常量。
看来你对MMU的硬件映射机制理解正确。 映射规则由每个进程页表保存。这些表构成了进程的虚拟 space.
具体来说,在 XV6 中,进程的虚拟 space 结构正在构建(通过适当的映射)如下:virtual address space layout
如上图所示,XV6 专门构建了进程的虚拟地址space,以便 2GB - 4GB 虚拟地址映射到 0 到 PHYSTOP 物理地址(分别)。正如XV6官方评论中解释的那样:
Xv6 includes all mappings needed for the kernel to run in every process’s page table; these mappings all appear above KERNBASE. It maps virtual addresses KERNBASE:KERNBASE+PHYSTOP to 0:PHYSTOP.
还说明了做出此决定的动机:
One reason for this mapping is so that the kernel can use its own instructions and data. Another reason is that the kernel sometimes needs to be able to write a given page of physical memory, for example when creating page table pages; having every physical page appear at a predictable virtual address makes this convenient.
换句话说,因为内核使所有页表将2GB虚拟映射到0物理(直到PHYSTOP),我们可以很容易地找到2GB以上的虚拟地址的物理地址。 例如:虚拟地址0x10001000的物理地址很容易找到:它是0x00001000我们只是减去2GB,因为我们是这样映射的。
这"workaround"可以帮助内核轻松地进行转换,例如,用于构建和操作页表(需要计算物理地址并写入内存)。
当然上面的"workaround"不是免费的,因为这让我们浪费了宝贵的虚拟地址space(2GB),因为现在每个物理地址至少已经有1个虚拟地址了。即使我们永远不会使用它。这样真正的进程就只剩下整个虚拟地址剩下的2GB了(一共是4GB,因为我们是用32bit来统计地址的)。这个在XV6官方解说中也有解释:
A defect of this arrangement is that xv6 cannot make use of more than 2 GB of physical memory
我建议您在 "Process address space" header 下的 XV6 评论中阅读更多关于这种方式的信息。 XV6 Commentary