KVM实现机制[3]

时间 : 14-06-14 栏目 : 虚拟化 作者 : 老薛 评论 : 0 点击 : 1,827 次

3.2.KVM实现
3.2.1.客户物理内存管理
每个虚拟机都需要拥有一定数量的物理内存。物理内存是宝贵的资源,为了提高物理内存的利用率,也为了在一台计算机上运行尽可能多的虚拟机,不能将一块物理内存固定划分给某个虚拟机使用,而应该采用按需分配的方式。下面简述KVM的内存管理原理,参见图3.3。
PC机的物理内存通常是不连续的,例如地址0xA0000至0xFFFFF、0xE0000000至0xFFFFFFFF等通常留给BIOS ROM和MMIO而不是物理内存。设虚拟机包括n块物理内存,分别记做P1, P2, …, Pn,每块物理内存的起始地址分别记做PB1, PB2, …, PBn,每块物理内存的大小分别为PS1, PS2, …, PSn。
在虚拟机创建之初,Qemu使用malloc()从其进程地址空间中申请了一块与虚拟机的物理内存大小相等的区域,设该区域的基地址为B。

 

k3

接下来,Qemu根据虚拟机的物理内存布局,将该区域划分成n个子区域,分别记做V1, V2, …, Vn,第i个子区域与第i块物理内存对应,每个子区域的起始线性地址记做VB1, VB2, …, VBn,每个子区域的大小等于对应的物理内存块的大小,仍是PS1, PS2, …, PSn。
然后,Qemu向KVM内核模块通告虚拟机的物理内存布局。KVM内核模块中使用slot结构来记录虚拟机的物理内存布局,每一个物理内存块对应一个 slot,其中记录着该物理内存块的起始物理地址PBi、大小PSi等信息,还记录了该物理内存块对应的在Qemu线性地址空间中的子区域的起始地址 VBi。
当发生由于页故障引发的VM exit时,VMM首先搜索客户页表,如果客户页表中本身就不存在客户线性地址GVA到客户物理地址GPA的映射,则将该异常事件回注给虚拟机,由客户软 件处理该页故障。如果在客户页表中存在GVA到GPA的映射,则从客户页表中得到该GPA,然后根据GPA得到其所属的slot,进而得到该GPA对应的 Qemu地址空间中的主机线性地址HVA,然后通过linux内核函数get_user_pages()确定HVA所对应的主机物理地址HPA,如果 HVA到HPA的映射不存在,get_user_pages()会分配物理内存,然后再建立HVA到HPA的映射。之后,VMM可以使用该HPA来构建影 子页表,即建立GVA到HPA的映射。因此,KVM系统中的虚拟机所使用的物理内存是最终还是由Linux内核来分配的。
3.2.2.VTLB实现
我们先来看一下VTLB的基本操作。客户真正的访存是通过影子页表进行的,如果影子页表中存在客户线性地址到物理地址的映射,那么访存操作就正常进行了。 如果影子页表中不存在客户线性地址到物理地址的映射,那么将引发一次页故障,从而导致一次VM exit。VMM获得控制后,将首先根据引发异常的客户线性地址去查找客户页表,如果客户页表本身限制这次访问,如到物理地址的映射不存在、违反页级保护 规则等,VMM将把异常事件回注给客户,由客户操作系统处理该页故障。如果客户页表允许本次访问,那么通常本次页故障是由于影子页表中不存在客户线性地址 到物理地址的映射引起的,此时就需要根据客户页表的内容来构建相应的影子页表,或称为对客户页表进行影射(Shadowing)。
如图所示,SPD是PD的影子页表,SPT1/SPT2是PT1/PT2的影子页表。由于客户PDE和PTE给出的页表基址和页基址并不是真正的物理地址,所以我们采用虚线表示PDE到客户页表以及PTE到普通客户页的映射关系。

k4

 

VMM中用于影子页表的内存是受限的,因此当内存紧张时,VMM可能回收一部分影子页表。例如,可能回收图中的影子页表SPT2,以后客户访问P1时将导致页故障,VMM将再次分配影子页表,查询客户页表,并修补客户线性地址到P1的映射。
如果完全模拟物理TLB的行为,客户机在切换CR3时,VMM需要清空整个VTLB,使所有影子页表的内容无效。在多进程客户操作系统中,CR3将被频繁 地切换,某些影子页表的内容可能很快就会被再次用到,而重建影子页表是一项十分耗时的工作。因此,采用完全模拟物理TLB行为的方法构建VTLB在效率上 是较差的。
提高效率的主要做法就是缓存影子页表,即客户切换CR3时不清空影子页表。例如,假设客户机上有两个进程A和B,参见图3,在T1时刻之前A正在运行,此 时CR3指向进程A的影子页表。在T1至T2时刻进程B运行,此时CR3指向进程B的影子页表,但并不丢弃进程A的影子页表。以后在T3时刻再次切换到进 程A时,原来A的影子页表还可以重用,这就避免了全部重新构建A的影子页表,提高了效率。
为了实现缓存影子页表的做法,必须意识到以下问题的存在:客户可能在不通知VMM的情况下,象修改普通内存一样修改影子页表。例如,在进程B运行时,客户 OS可能由于内存的紧张,将属于进程A的内存换出,并将相应的页表项的P位置0,而由于A不是当前进程,所以客户OS不会使用INVLPG指令刷新 TLB,VMM也就无从得知客户修改了进程A的页表。以后,当进程A恢复运行时,由于影子页表与客户页表不一致,将导致错误。
因此,在采用缓存影子页表的做法时,必须有某种机制保持客户页表与影子页表间的一致性,这可通过为客户页表所在的页设置写保护来实现。
首先必须区别普通客户内存和客户页表,因为效率上的考虑,不能对所有的客户页面进行写保护。当一个页表没有用于访存时,VMM是无从知道该页的身份的。例 如,客户操作系统在初始化某张页表时,VMM不能确定该页是普通客户内存还是客户页表,只有以后该表页用于访存时,由于在VTLB中没有影射,将导致一次 VTLB Fill,并触发VMM搜索客户页表结构,从而得知与引起页面故障的客户线性地址相关的客户页面的真实身份。
VTLB Fill操作实际上在客户页表和影子页表之间进行了一次同步,为了跟踪客户页表的后续变化,应该对客户页表进行写保护。注意,客户页表也是通过影子页表来 访问的,为了设置写保护就必须知道影子页表中访问客户页表所使用的PTE,为了做到这一点,KVM在影子页表中建立客户线性地址到物理地址的映射关系的同 时,还维护了物理地址到末级页表PTE间的逆向映射,即给定客户页面,能够方便地得到访问该客户页面的末级页表PTE。图中,红色箭头表示逆向映射。同 时,给定一个客户页面,如果其逆向映射存在,那么正向映射一定存在,即该客户页面可以通过影子页表被访问到。

 

k5

 

当VMM在VTLB Fill操作过程中识别一个客户页表,如PT1,就会通过逆向映射找到访问其所需的影子页表项,如SPT2中的某个PTE,将PTE的WP位置1。以后,客户对该客户页表的修改将导致VM exit,从而使VMM有机会与客户页表保持同步。

 

除非注明,文章均为( 老薛 )原创,转载请保留链接: http://www.bdkyr.com/uncategorized/127.html

随便看看

0