KVM/QEMU和客户机操作系统如何处理页面错误

3
例如,我有一个宿主操作系统(比如Ubuntu),启用了KVM(虚拟机管理器)。我使用QEMU开始创建一个虚拟机,来运行一个客户操作系统(比如CentOS)。据说对于宿主操作系统而言,这个虚拟机只是一个进程。所以在宿主的角度看来,它会像往常一样处理页面错误(例如,根据需要分配页面框架,根据活跃/非活跃列表交换页面)。
以下是问题和我的理解。在客户操作系统内部,由于它仍然是一个完整的操作系统,我认为它仍然具备处理虚拟内存的所有机制。它看到了QEMU提供的某些虚拟化物理内存。所谓虚拟化的物理内存,我指的是客户操作系统不知道自己在一个虚拟机中,而是像在真实物理机器上一样工作,但它所拥有的确实是QEMU提供的一个抽象层。因此,即使分配了一个页面框架,如果该框架不在客户操作系统的页表中,客户操作系统仍然会触发页面错误,然后将某些页面映射到框架上。更糟糕的是,可能会出现双重页面错误,在此情况下,客户操作系统首先在页面错误时分配一些页面框架,然后触发宿主操作系统的页面错误。
然而,我也听说过像浅表(或影子)页表这样的东西,似乎可以优化这种不必要的双重页错误和双重页表问题。我还查看了一些其他内核实现,特别是unikernels,例如 OSvIncludeOS 等等。我没有找到与页面错误和页面表机制有关的任何内容。我确实看到了一些符号,如 page_fault_handler,但并不像在 Linux 内核代码中看到的那么庞大。这些unikernel实现中似乎内存管理并不是一个大问题。因此,我认为QEMU/KVM和一些英特尔的虚拟化技术已经处理了这个问题。
在这个主题上有什么想法吗?或者如果您有一些好的参考/论文/资源来解决这个问题,或者一些提示将非常有帮助。
1个回答

5
QEMU/KVM支持客户机物理内存的两种方式:EPT和影子页表。EPT是Intel定义的机制,其他处理器支持类似的机制,这里不做详述。
EPT代表“扩展页表”,它是CPU支持的第二级分页,除了常规的处理器页表外。当在虚拟机中运行时,常规页表用于将客户机虚拟地址转换为客户机物理地址,而EPT表用于将客户机物理地址转换为主机物理地址。对于客户机中的每个内存访问,都执行这种双层转换(处理器TLB隐藏大部分成本)。EPT表由VMM管理,而常规页表由客户机管理。如果在客户机页表中不存在一个页面,则会导致客户机内部的页面故障,就像你所描述的一样。如果在客户机页表中存在但在EPT中不存在一个页面,则会导致EPT违规VM退出,因此VMM可以处理缺失的页面。
当EPT不可用时,使用影子页表。影子页表是客户机页表的副本,其中包含单组页表中的GVA到GPA和GPA到HPA映射。当发生页面故障时,总是会导致VM退出。VMM检查缺失的页面是否映射到客户机页表中。如果没有,则VMM将页面故障注入到客户机中进行处理。如果页面映射到客户机页表中,则VMM将像对待EPT违规一样处理故障。有效地管理客户机内多个进程的影子页表可能会非常复杂。
对于大多数工作负载而言,EPT实现更简单,性能更好,因为页面故障直接生成到客户机操作系统,这通常是它们需要处理的地方。使用影子页表需要每次页面故障都产生一个VM退出。但是,对于一些很少引起页面故障的特定工作负载,影子页表可能具有更好的性能。

3
这个问题的回答更多地描述了影子页表是如何工作的:https://dev59.com/J2Yq5IYBdhLWcg3wzDzk - prl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接