KVM/QEMU 和 guest OS 如何处理页面错误

yua*_*ili 3 virtualization kernel kvm qemu linux-kernel

例如,我有一个启用了 KVM 的主机操作系统(例如 Ubuntu)。我使用 QEMU 启动虚拟机来运行来宾操作系统(例如 CentOS)。可以说,对于主机操作系统来说,这个VM只是一个进程。因此,从主机的角度来看,它像往常一样处理页面错误(例如,根据需要分配页面框架,根据需要根据活动/非活动列表交换页面)。

这是问题和我的理解。在来宾操作系统中,由于它仍然是一个成熟的操作系统,我认为它仍然具有处理虚拟内存的所有机制。它看到QEMU 提供的一些虚拟化物理内存。我所说的虚拟化物理内存是指客户操作系统不知道它在虚拟机中,并且仍然像在真实物理机上一样工作,但它所拥有的确实是 QEMU 给出的抽象。因此,即使分配了一个页框,如果该页框不在客户页表中,客户操作系统仍然会触发页面错误,然后将某些页面映射到该框架。更糟糕的是,可能会出现双页错误,即客户机在发生页错误时首先分配一些页框,这会触发主机操作系统的页错误。

然而,我也听说过类似浅(或影子)页表的东西,它似乎可以优化这种不必要的双页错误和双页表问题。我还查看了一些其他内核实现,特别是 unikernels,例如OSvIncludeOS等。我没有找到任何与页面错误和页表机制相关的内容。我确实看到了一些类似的符号page_fault_handler,但没有我在 Linux 内核代码中看到的那么大。在这些 un​​ikernel 实现中,内存管理似乎并不是什么大问题。所以我认为 QEMU/KVM 和一些 Intel 的虚拟化技术已经处理了这个问题。

对这个主题有什么想法吗?或者,如果您对这个问题有一些好的参考文献/论文/资源,或者一些提示将会非常有帮助。

prl*_*prl 5

QEMU/KVM 有两种方式支持 guest 物理内存:EPT 和影子页表。(EPT是Intel定义的机制,其他处理器也支持类似的东西,这里就不说了。)

EPT 代表扩展页表。它是除常规处理器页表之外 CPU 支持的第二级分页。在VM中运行时,常规页表用于将访客虚拟地址转换为访客物理地址,而EPT表用于将访客物理地址转换为主机物理地址。这种双层转换针对来宾内的每次内存访问执行。(处理器 TLB 隐藏了大部分成本。)EPT 表由 VMM 管理,而常规页表由来宾管理。如果某个页面不存在于来宾页表中,则会导致来宾内发生页面错误,正如您所描述的那样。如果某个页面存在于来宾页表中但不存在于 EPT 中,则会导致 EPT 违规 VM 退出,因此 VMM 可以处理丢失的页面。

当 EPT 不可用时,使用影子页表。影子页表是来宾页表的副本,它将 GVA 到 GPA 和 GPA 到 HPA 映射合并到一组页表中。当发生页面错误时,它总是会导致VM退出。VMM 检查丢失的页是否映射到来宾页表中。如果不是,则 VMM会将页面错误注入来宾系统中以供其处理如果该页映射到来宾页表中,则 VMM 会像处理 EPT 违规一样处理该故障。跨来宾内的多个进程有效管理影子页表可能非常复杂。

EPT 更容易实现,并且对于大多数工作负载具有更好的性能,因为页面错误是直接生成到客户操作系统的,而客户操作系统通常是需要处理页面错误的地方。使用影子页表需要在每次页面错误时退出虚拟机。然而,对于一些导致很少页面错误的特定工作负载,影子页表可能具有更好的性能。

  • 这个问题的答案有更多关于影子页表如何工作的描述:/sf/ask/992383311/ (3认同)