QEMU KVM系列三: 使用EPT 模拟内存。

来源:互联网 发布:聚合数据接口怎么用呀 编辑:程序博客网 时间:2024/06/07 15:50

一,Memory

为了简化问题,这里只总结一下使用intel EPT的情况。不讨论影子页表。

1.1 首先需要一点背景知识,intel CPU的内存管理

Intel CPU的内存管理由两部分组成,segmentation 和page。segmentation是必须的,page是可选的。


图一:

<图一>引入了三个概念:logical address,linear address,physical address。

logical address是我们用来访问内存时用的。它由segment selector和offset组成。通过它我们可以得到linear address,如果没有使用page,那么linear address就是physical address。如果使用了page,那么CPU就需要使用页表把linear addree转成physic address,physical address CPU最终用来访问内存的地址了。

因为现代的操作系统基本都需要使用虚拟内存,那么page就是必须了。所以就以guest 使用了page的情况为例。

1.2 Guest OS如何访问内存。

上一节提到了几个和CPU内存管理的概念。接下来需要引入和虚拟化内存有关的几个概念。

GVA,Guest Virtual Address客户机进程的线性地址
GPA,Guest Physical Address客户机的物理地址
HVA,Host Virtual Address宿主机进程的线性地址
HPA,Host Physical Address宿主机的物理地址

因为Guest OS 是无法分清它是在physical 还是virtual machine上面运行。那么它会按照正常的流程,对内存进行分段,分页。只有当需要访问到physcial address的时候,才需要内存模拟。也就是说Guest OS首先自己把地址转成GPA。

那么EPT是怎么做的呢

图二(转)

如,图二,如果没有内存虚拟化,那么CR3里面应该是physical address. 但是现在这个地址是GPA,那么这个GPA就需要通过ETP table转成HPA了。整个内存虚拟化的过程就是这样,一级一级地把GPA 转成HPA.

EPT把GPA转化成HPA的过程和页表机制完全一样。这也是大家也把EPT转化机制称为二维转化的原因:

这里只简单的介绍一下第一级转化:

图三



首先VMCS里面有一个EPTP的指针,它指向一个EPT PML4 table,这个table包含512个64 bit的Enetry。通过如下方式选中其中的一个entry,

Bits 63:52 are all 0.
— Bits 51:12 are from the EPTP.
— Bits 11:3 are bits 47:39 of the guest-physical address.
— Bits 2:0 are all 0.

图四,



图四是PML4  enntry的数据结构。它的51:12 bit指向了一个EPT page-directory-pointer table,然后下一级转化就以这个table开始了,直到这个GVA 转化成HPA。


1.3 EPT 页表的建立(转)

看完上节后,下一个问题就是:EPT页表是如何建立的?

与宿主机页表建立过程相似,EPT页表结构也是通过对缺页异常的处理完成的。Guset处在非根模式下运行,加载新的客户进程时,将VMCS客户域CR3的值加载到gCR3寄存器(保存的是GPA),非根模式下的CPU根据EPT表寻址该GPA->HPA的映射,EPT页表的基址在VMCS域的EPTP保存。初始情况下客户页表、EPT页表均为空,映射未建立,发生EPT_VIOLATION,切换到根模式下,由KVM负责建立该GPA到宿主内存地址HPA的映射,此时映射已建立,取得该内存单元中的值(一条GPA),返回给客户机,切换到非根模式继续运行。VCPU的mmu查询客户页表,发现为空,客户机产生缺页,不发生VM_Exit,由客户系统的缺页处理函数捕获该异常,创建客户页表,根据GVA的偏移产生一条新的GPA,客户机寻址该GPA,产生缺页异常,此时该GPA对应的EPT页表项不存在,发生EPT_VIOLATION,切换到根模式下,由KVM负责建立该GPA->HPA映射,再切换回非根模式,如此往复,直到非根模式下GVA最后的偏移建立最后一级客户页表,获得GPA,缺页异常退出到根模式建立最后一级EPT页表项,完成整个EPT页表的建立。

KVM对客户机缺页异常的处理,此处以Intel EPT为例,处理流程如图:


客户机运行过程中,首先获得gCR3的客户页帧号(右移PAGE_SIZE),根据其所在memslot区域获得其对应的HVA,再由HVA转化为HPA,得到宿主页帧号。若GPA->HPA的映射不存在,将会触发VM-Exit,KVM负责捕捉该异常,并交由KVM的缺页中断机制进行相应的缺页处理。kvm_vmx_exit_handlers函数数组中,保存着全部VM-Exit的处理函数,它由kvm_x86_ops的vmx_handle_exit负责调用。缺页异常的中断号为EXIT_REASON_EPT_VIOLATION,对应由handle_ept_violation函数进行处理。

tdp_page_fault是EPT的缺页处理函数,负责完成GPA->HPA转化。而传给tdp_page_fault的GPA是通过vmcs_read64函数(VMREAD指令)获得的。
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);



0 0