设为首页 收藏本站
查看: 1156|回复: 0

[经验分享] KVM 虚拟机学习笔记

[复制链接]

尚未签到

发表于 2015-12-24 15:14:45 | 显示全部楼层 |阅读模式
  最近用一些零碎的时间学习KVM,算算大概也快有一个月了吧,进度还是很缓慢的,感觉该写一些类似读书笔记的东西了。欢迎大家来讨论,如果有错误,还请不吝赐教
  KVM 即 Kernel Based Virtual Machine, 是一个内核模块,使用它需要CPU支持虚拟化。加载KVM模块后,系统中会有一个/dev/kvm 设备,这个设备提供 ioctl 和 mmap操作。目前,KVM还必须和修改过的Qemu配合起来使用(这样说是不准确的,因为已经有一个叫 native kvm tool的东东了),KVM 使用Qemu做I/O模拟,虽然Qemu也提供CPU的模拟,但是KVM不用,也许这正是KVM+Qemu比单纯用Qemu进行虚拟化性能高的原因吧。
  运行在Qemu中的虚拟机被称为Guest,运行Qemu的物理机称为Host, 每一个guest是host上的一个进程,guest的每一个cpu对应进程中的一个线程。Qemu和KVM之间通过ioctl进行交互,KVM和guest之间通过VM Entry和VM Exit进行切换。
  那么什么时候会发生VM Entry和VM Exit呢? 说来话长!
  先从虚拟化这个概念说起,其实通常的进程/线程也是一种虚拟化。Intel把CPU的优先级分了4层,ring0完整的暴露了CPU的各个接口,运行在ring0的操作系统可以任意使用CPU提供的所有功能,相比之下,运行在ring3的应用程序只能看到较少的CPU接口。在这种情况下,操作系统担任的角色就是类似VMM(Virtual Machine Monitor)。运行在ring3的应用程序,自以为自己掌握所有的计算机资源,比如CPU资源,4GB的内存等等。众多傻乎乎的应用程序(用户态进程)在自己的虚拟世界里玩的不亦乐乎,而操作系统默默的在背后处理各个进程CPU相关的数据的保存和恢复,比如修改cr3寄存器,修改页表等等。
  所以,操作系统完成了对ring3环境下的CPU的虚拟化,而KVM则是实现了一个完整的CPU虚拟化(所以这种类型的虚拟化,能运行不经任过何修改操作系统)。
  kvm是一个内核模块,用kvm虚拟化技术创建的虚拟机,如果guest OS 执行的是与访问全局资源无关的指令,那么这些指令是直接运行在物理CPU上的;当执行到了访问全局资源的指令,比如产生缺页错误,或者设备I/O,则guest OS产生VM Exit退出到KVM中,然后KVM再根据退出的原因,决定是由自己来处理还是交给Qemu。当发生VM Entry和VM Exit 时必须要有一个结构体来保存当前CPU的上下文,这个结构就是VMCS (Virtual Machine Control Structure),而前面提到的,使用KVM必须要有CPU硬件上的支持,指的就是CPU硬件必须提供一种功能,能自动根据VMCS的内容完成VM和VMM之间的状态切换。
  
  KVM保证guest OS正确执行的手段就是当guest执行I/O指令或者其他特权指令时,引发处理器异常,从而进入到根操作模式(Intel 的VT-x技术)。
  当guest OS执行一些特权指令或者外部事件时,比如I/O访问,对控制寄存器的操作,对MSR(Machine Special Register)的读写操作、数据包的到达等,都会引起CPU发生 VM Exit,发生VM Exit后,KVM 会将guest OS 的状态保存到VMCS中,把Host的状态装入物理CPU,处理器进入根操作模式。接着KVM会读取保存的VMCS中 VM_EXIT_REASON字段的内容,从而知道虚拟机退出的原因。如果由于I/O信号到达,则退出到用户模式,交给Qemu来处理,处理完毕后,再通过KVM重新进入guest OS运行;如果是外部中断,则有KVM做一些必要的处理再返回。
  
  以上内容算是对 前一篇文章的回顾,前一篇文章在结尾处提到了VMCS,那么本文继续。
  不难看出,与异常处理机制相关的结构就是VMCS。VMCS占一页大小,该结构包含3个部分:版本标志、VMX退出原因、数据区。而数据区则包含大量与CPU状态和控制相关的信息,包括虚拟机状态保存区(各种寄存器)、宿主机状态保存区、VM Execution控制域、VM Entry控制域、VM Exit控制域、VM Exit信息域。Intel提供的一些指令可以用来直接操作这些域。
  VMX 指令集

  • VMPTRLD         加载一个VMCS结构体指针作为当前操作对象
  • VMPTRST         保存当前VMCS结构体指针
  • VMCLEAR       清除当前VMCS结构体
  • VMREAD          读VMCS结构体指定域
  • VMWRITE         写VMCS结构体指定域
  • VMCALL          引发一个VM Exit事件,返回到VMM
  • VMLAUNCH   启动一个虚拟机
  • VMRESUME   从VMM返回到虚拟机继续运行
  • VMXOFF          退出VMX操作模式
  • VMXON           进入VMX操作模
  唔。。。写道这里写不下去了,感觉也没什么可写的了,功力不够啊!!
  下一篇日志将会介绍KVM的内存管理部分。包括影子页表机制,EPT,嵌套MMU等等。(大牛请轻拍。)
  —————update————-
这篇日志上周就写了,这几天看了一些影子页表,发现比想象中的难。KVM的代码(包括整个linux kernel的代码)函数调用关系非常复杂,加上目前KVM的资料非常少,所以很吃力,不过已经挖了这个坑了,再怎么样也要努力填吧。。。。
  今天把KVM的代码放下,读了读NoSQL数据库 Redis的代码,感觉比KVM要简单多了,不知道为什么会这样?
是因为本身redis的代码就清晰,还是因为我体系结构学得不好,而KVM的代码主要又是集中在CPU相关的硬件这一块,所以才会这么吃力? 求指点。。。。
  —————end——————

KVM 虚拟机学习笔记 三
  上篇博客里讲到要介绍KVM 影子页表和EPT, 于是尝试着去读源代码,发现很难读懂,所以第三篇学习笔记这么久才“写”出来。至于为什么难懂,我想原因应该是这样的:
  1、不知道为什么需要影子页表或者EPT,只是知道有这个概念然后去读代码,所以读得晕头转向,白费了很多功夫。 一个新的方案被提出来肯定是为了解决原有的代码无法解决的问题,所以在读源码之前一定要明白为什么要有影子页表,没有就不行吗?现有的MMU、内存分页机制又会产生哪些制约呢? EPT的出现又解决了影子页表的哪些缺点呢?这些都是预备知识,一定要搞清楚。
  2、对体系结构方面的知识理解不够深入,这个是硬伤,只能一边看一边补习了。
  
  在上网查资料的过程中,发现了这篇文档讲的非常好,原文地址在这里,几乎解决了我当时的所有疑惑,本来打算自己再写一篇,但是觉得这篇已经写的足够好了,即使我再写,大体上也是于这篇文档的内容相似的,所以决定转载过来算了,虽然极少会转载别人的文章的,这次破例吧,哈哈,当然我也会加一点自己的评注、划一些重点的。下面就是这篇文章。
  首先我们知道,KVM里面一个Guest OS在 Host OS看来是一个进程,既然是进程,那么它内部访问内存使用的是虚拟地址,但是具体对应到哪个物理地址?进程本身是不知道的,一切由Host OS来做,并且很有可能一段虚拟地址对应的物理页面是不连续的。
  为了让客户机使用一个隔离的、从零开始且具有连续的内存空间,KVM 引入一层新的地址空间,即客户机物理地址空间 (Guest Physical Address, GPA),这个地址空间并不是真正的物理地址空间,它只是宿主机虚拟地址空间在客户机地址空间的一个映射。对客户机来说,客户机物理地址空间都是从零开始的连续地址空间,但对于宿主机来说,客户机的物理地址空间并不一定是连续的,客户机物理地址空间有可能映射在若干个不连续的宿主机地址区间,如下图 1 所示:
http://onexin.iyunv.com/source/plugin/onexin_bigdata/https://app.yinxiang.com/shard/s11/res/ac50908e-333b-49a3-b0e5-368e2c0a19c9.gif
  
  由于客户机物理地址不能直接用于宿主机物理 MMU 进行寻址,所以需要把客户机物理地址转换成宿主机虚拟地址 (Host Virtual Address, HVA),为此,KVM 用一个 kvm_memory_slot 数据结构来记录每一个地址区间的映射关系,此数据结构包含了对应此映射区间的起始客户机页帧号 (Guest Frame Number, GFN),映射的内存页数目以及起始宿主机虚拟地址。于是 KVM 就可以实现对客户机物理地址到宿主机虚拟地址之间的转换,也即首先根据客户机物理地址找到对应的映射区间,然后根据此客户机物理地址在此映射区间的偏移量就可以得到其对应的宿主机虚拟地址。进而再通过宿主机的页表也可实现客户机物理地址到宿主机物理地址之间的转换,也即 GPA 到 HPA 的转换。
  实现内存虚拟化,最主要的是实现客户机虚拟地址 (Guest Virtual Address, GVA) 到宿主机物理地址之间的转换。根据上述客户机物理地址到宿主机物理地址之间的转换以及客户机页表,即可实现客户机虚拟地址空间到客户机物理地址空间之间的映射,也即 GVA 到 HPA 的转换。显然通过这种映射方式,客户机的每次内存访问都需要 KVM 介入,并由软件进行多次地址转换,其效率是非常低的。因此,为了提高 GVA 到 HPA 转换的效率,KVM 提供了两种实现方式来进行客户机虚拟地址到宿主机物理地址之间的直接转换。其一是基于纯软件的实现方式,也即通过影子页表 (Shadow Page Table) 来实现客户虚拟地址到宿主机物理地址之间的直接转换。其二是基于硬件对虚拟化的支持,来实现两者之间的转换。下面就详细阐述两种方法在 KVM 上的具体实现。
影子页表
  由于宿主机 MMU 不能直接装载客户机的页表来进行内存访问,所以当客户机访问宿主机物理内存时,需要经过多次地址转换。也即首先根据客户机页表把客户机虚拟地址转传成客户机物理地址,然后再通过客户机物理地址到宿主机虚拟地址之间的映射转换成宿主机虚拟地址,最后再根据宿主机页表把宿主机虚拟地址转换成宿主机物理地址。而通过影子页表,则可以实现客户机虚拟地址到宿主机物理地址的直接转换。如下图所示:
http://onexin.iyunv.com/source/plugin/onexin_bigdata/https://app.yinxiang.com/shard/s11/res/21829c06-1980-4a64-928d-de10db44725c.gif
  影子页表简化了地址转换过程,实现了客户机虚拟地址空间到宿主机物理地址空间的直接映射。但是由于客户机中每个进程都有自己的虚拟地址空间,所以 KVM 需要为客户机中的每个进程页表都要维护一套相应的影子页表。在客户机访问内存时,真正被装入宿主机 MMU 的是客户机当前页表所对应的影子页表,从而实现了从客户机虚拟地址到宿主机物理地址的直接转换。而且,在 TLB 和 CPU 缓存上缓存的是来自影子页表中客户机虚拟地址和宿主机物理地址之间的映射,也因此提高了缓存的效率。
在影子页表中,每个页表项指向的都是宿主机的物理地址。这些表项是随着客户机操作系统对客户机页表的修改而相应地建立的。客户机中的每一个页表项都有一个影子页表项与之相对应。如下图 3 所示:
http://onexin.iyunv.com/source/plugin/onexin_bigdata/https://app.yinxiang.com/shard/s11/res/eba58043-4f3d-4159-a63e-a92bc9a53ef1.gif
  为了快速检索客户机页表所对应的的影子页表,KVM 为每个客户机都维护了一个哈希表,影子页表和客户机页表通过此哈希表进行映射。对于每一个客户机来说,客户机的页目录和页表都有唯一的客户机物理地址,通过页目录 / 页表的客户机物理地址就可以在哈希链表中快速地找到对应的影子页目录 / 页表。(注:不明白为什么这里要牵涉到客户机的物理地址,影子页表实现的是客户机虚拟地址到宿主机物理地址的直接映射呀!)    在检索哈希表时,KVM 把客户机页目录 / 页表的客户机物理地址低 10 位作为键值进行索引,根据其键值定位到对应的链表,然后遍历此链表找到对应的影子页目录 / 页表。当然,如果不能发现对应的影子页目录 / 页表,说明 KVM 还没有为其建立,于是 KVM 就为其分配新的物理页并加入此链表,从而建立起客户机页目录 / 页表和对应的影子页目录 / 页表之间的映射。当客户机切换进程时,客户机操作系统会把待切换进程的页表基址载入 CR3,而 KVM 将会截获这一特权指令,进行新的处理,也即在哈希表中找到与此页表基址对应的影子页表基址,载入客户机 CR3,使客户机在恢复运行时 CR3 实际指向的是新切换进程对应的影子页表。
  影子页表异常处理机制
在通过影子页表进行寻址的过程中,有两种原因会引起影子页表的缺页异常,一种是由客户机本身所引起的缺页异常,具体来说就是客户机所访问的客户机页表项存在位 (Present Bit) 为 0,或者写一个只读的客户机物理页,再者所访问的客户机虚拟地址无效等。另一种异常是由客户机页表和影子页表不一致引起的异常。
  当缺页异常发生时,KVM 首先截获该异常,然后对发生异常的客户机虚拟地址在客户机页表中所对应页表项的访问权限进行检查,并根据引起异常的错误码,确定出此异常的原因,进行相应的处理。如果该异常是由客户机本身引起的,KVM 则直接把该异常交由客户机的缺页异常处理机制来进行处理。如果该异常是由客户机页表和影子页表不一致引起的,KVM 则根据客户机页表同步影子页表。为此,KVM 要建立起相应的影子页表数据结构,填充宿主机物理地址到影子页表的页表项,还要根据客户机页表项的访问权限修改影子页表对应页表项的访问权限。
  由于影子页表可被载入物理 MMU 为客户机直接寻址使用, 所以客户机的大多数内存访问都可以在没有 KVM 介入的情况下正常执行,没有额外的地址转换开销,也就大大提高了客户机运行的效率。但是影子页表的引入也意味着 KVM 需要为每个客户机的每个进程的页表都要维护一套相应的影子页表,这会带来较大内存上的额外开销,此外,客户机页表和和影子页表的同步也比较复杂。因此,Intel 的 EPT(Extent Page Table) 技术和 AMD 的 NPT(Nest Page Table) 技术都对内存虚拟化提供了硬件支持。这两种技术原理类似,都是在硬件层面上实现客户机虚拟地址到宿主机物理地址之间的转换。下面就以 EPT 为例分析一下 KVM 基于硬件辅助的内存虚拟化实现。
EPT 页表
  EPT 技术在原有客户机页表对客户机虚拟地址到客户机物理地址映射的基础上,又引入了 EPT 页表来实现客户机物理地址到宿主机物理地址的另一次映射,这两次地址映射都是由硬件自动完成。(为什么前者也是由硬件自动完成?)客户机运行时,客户机页表被载入 CR3,而 EPT 页表被载入专门的 EPT 页表指针寄存器 EPTP。EPT 页表对地址的映射机理与客户机页表对地址的映射机理相同,(注意了,EPT实现的是guest的物理地址到 host 的物理地址的映射,与影子页表是不一样的)下图 出示了一个页面大小为 4K 的映射过程:
  
http://onexin.iyunv.com/source/plugin/onexin_bigdata/https://app.yinxiang.com/shard/s11/res/74ceb24c-b4ae-4bde-8b89-30c27a526217.gif
  在客户机物理地址到宿主机物理地址转换的过程中,由于缺页、写权限不足等原因也会导致客户机退出,产生 EPT 异常。对于 EPT 缺页异常,KVM 首先根据引起异常的客户机物理地址,映射到对应的宿主机虚拟地址,然后为此虚拟地址分配新的物理页,最后 KVM 再更新 EPT 页表,建立起引起异常的客户机物理地址到宿主机物理地址之间的映射。对 EPT 写权限引起的异常,KVM 则通过更新相应的 EPT 页表来解决。
  由此可以看出,EPT 页表相对于前述的影子页表,其实现方式大大简化。而且,由于客户机内部的缺页异常也不会致使客户机退出,因此提高了客户机运行的性能。此外,KVM 只需为每个客户机维护一套 EPT 页表,也大大减少了内存的额外开销。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-155824-1-1.html 上篇帖子: PIO and MMIO on KVM/QEMU 下篇帖子: KVM源代码分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表