QEMU-KVM内核虚拟化概述

本文翻译自https://www.linux-kvm.org/page/Memory
主要内容为qemu/kvm的内存虚拟化的架构描述(的梗概)。

这是官网十年前的一篇文章,细节大家不要细扣,大概了解内存虚拟化和EPT的相关架构就行。

guest修改页表对host的影响

由于Linux内核的layz-mode得到策略, qemu/kvm会为guest分配虚拟内存空间,但直到访问时,才真正分配物理空间。
以前(指使用shadow page table时),每当guest修改页表, 必然会影响host. host会确认2点:

  1. guest放到页表中的entry是有效的
  2. entry没有访问不被允许访问的memory

为什么会影响host呢? 有2方面的机制影响.

  1. 虚拟化硬件使用的页表集和guest使用的页表是分离的.首先guest在自己的页表上做了修改,然后host发现了这个修改,确认该修改并在硬件访问的真实页表中做修改.guest不能直接访问和操作真实页表.这就是SPT(shadow page table).
  2. VMX/AMD-v扩展允许当guest尝试设置指向base page table(CR3)的指针时, 就trap(发生异常).

shadow page table机制的缺点

SPT机制下,缺点在于:

  1. 每次访问页表都必须经历guest+host都访问的过程
  2. guest访问一次,host可能要访问25次,成本极高
  3. 确认和维护SPT成本非常高

EPT/NPT的引入

AMD和Intel提出了EPT/NPT来解决这些问题(SPT的缺点). EPT/NPT在硬件层面提供了一系列结构,能够直接将GPA转化成HPA,而不用经历每次访问页表都必须guest+host访问的过程.

问题在于, 如果host把我们使用的page table 交换出去了,我们必须更新EPT/NPT里面的结构.

解决办法是Linux称为mmu_notifier的东西. 在kernel释放或交换出去这些内存之前,kvm/qemu guest会收到host的意图通知. kvm/qemu guest会将即将被host使用的page从SPT或EPT结构中移除, 在guest做完移除工作之后, host就可以对这些page做它想做的操作了.

Fault-in path(产生page fault的处理路径)

  1. QEMU调用malloc()并且为该page分配虚拟地址空间,但是没有对应的物理空间.(也就是就分配了个名头)
  2. guest访问了它认为是一个物理地址的东西, 但是因为没有分配对应的物理空间, traps into host
  3. host kernel看到了一个page fault, 对之前malloc()的区域调用do_page_fault()处理这个page fault,如果没什么问题,就分配一些memory给到该区域.
  4. host kernel 创建了pte_t连接malloc()好的虚拟地址和分配的物理地址, 在pte_t中创建rmap entry, 把pte_t放到LRU等
  5. mmu_notifier和change_pte()被调用,允许kvm为新的page创建一个EPT entry
  6. 完成处理page fault, VMRESUME, guest继续运行

Swap-out path(当host 内存不够用时)

如果host面临memory压力,会发生什么情况呢?
上面提到的,之前分配给guest的物理page发现自己已经上了待退休名单, kernel决定该page下岗,接下来会发生:

  1. host kernel使用rmap结构找出该物理page被映射到哪个VMA(vm_area_struct)中去了
  2. host kernel先寻找与该VMA关联的mm_struct,然后再遍历Linux page tables,寻找该page的host hardware page table entry(pte_t).
  3. host kernel 将该page交换出去,并清除了pte_t, 但是,在释放该page之前:
    1. host kernle 调用了mmu_notifier invalidate_page(). 这俩东西寻找EPT结构中的该page的entry,然后移除掉.
  4. 下次访问该page时,就会到fault-in path中去.

逻辑链

某个时刻guest访问某物理地址(它认为的) ==》 Page Fault ==》 trap into host ==》 为产生page fault的地址分配实际空间(Fault-in path) ==》 回到guest继续运行... 运行了一段时间 ==》 host的内存不够用了,要收回之前分配给guest的内存 ==》 给guest一个意图通知 ==》 guest会意,将EPT中的映射删除 ==》 host收回之前分配的物理空间 ==> 某个时刻guest访问某物理地址(它认为的)


__EOF__

本文作者EwanHai
本文链接https://www.cnblogs.com/haiyonghao/p/14440135.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   EwanHai  阅读(879)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示