intel vmm笔记一
intel vmm笔记一
1处理器对虚拟化的支持操作成为VMX operation.这里有两种VMX operation,一种是root的,另外一种是非root的。 从root到非root成为vm entry(进入虚拟机) 反之为 vm exit
2通过VMXON激活虚拟化,开启VMX操作。 通过VMXOFF关闭虚拟化,关闭VMX操作。在VMX操作中通过VMLAUNCH 和VMRESUME 实现vm entry, VMM也可以捕获不同的vm exit.
3 VMX的非root operation 和VMX两种operation之间的转换,通过 VMCS配置,这个结构的地址,由VMPTRST 和VMPTRLD来读写。VMCS内部内容由VMREAD 和VMWRITE VMCLEAR来读写。 每个guest的每个逻辑(虚拟)处理器都应该有1个VMCS,vmcs要求4kb对齐的回写内存, intel cpu在未开启ept的时候取决于cr0.cd cr0.pg 和IA32_PAT MSR。(windows 内核api 有多种内存可供分配)
4在进入VMX之前,先要检测支不支持CPUID.1.ECX.VMX[bit5]=1表示支持。VMX的一些feature是不是支持由一系列MSR寄存器描述
5进入VMX之前的配置:
①set CR4.VMXE[bit13]=1, 一旦该位设置成1,除了关机,没法清0.
②IA32_FEATURE_CONTROL(3ah) bit0必须置set 1 bit 1 和bit 2都set 1.(跟smx也有关,不过设置1就ok了)
③每个逻辑处理器在进入VMX之前,都有一个配置VMX的结构,VMXON region, 这个结构的地址通过 VMXON指令配置,该结构必须4k对齐
④执行VMXON之前,处理器必须要固定cr0和cr4的某些位置,而且进入后再更改会报错,这些固定位到底是哪些由某些msr决定(这些位置由cpu在执行VMXON后自动固定,之后不让修改,也不需要提前修改)
6在虚拟化环境中,可能会有多个虚拟机同时运行,并且每个虚拟机可能有多个虚拟处理器。这就意味着(物理)处理器可能需要在多个VMCS之间进行切换。”active” 状态允许处理器在多个VMCS之间进行快速切换,因为这些VMCS都已被加载并准备好使用。然而,处理器在任何时候只能处理一个VMCS,这就是 “current” 状态的作用。这样设计可以帮助处理器有效地管理和切换多个VMCS,从而提高虚拟化的效率和性能。而是launched表示该VMCS是否已经被启动。current是针对当前物理处理器来说是current的,而launched是标记这个VMCS是否被启动过的。
7关于VMM内存管理。为了确保VMM对硬件的全权管理,必须对guest的地址翻译做出修改,让guest不直接访问物理地址。有两个办法spt和ept:
shadows page tables; 维护一套影子page table (PML4到PT四级),每次guest地址映射的时候,拦截一下,使用影子pt,每次往guest pt写入的时候,影子pt也同时写入,不过guest不知道影子pt的存在,也不知道影子pt条目的内容。也就是实际映射是看影子pt
extended page tables;在guest的映射上再套一层映射,因此再建立了一套分页机制,用于把guest转换后的物理地址转成VMM物理地址(真实物理地址)。 因此转换步骤很长。
spt和ept相比:
spt 每次guest修改pt,都需要断下,触发VM exit,切换到VMM root,来修改spt,开销很大
ept主要问题是访问内存延迟大了一点,但是全程都是硬件直接实现。
目前主流方案是ept。
ept机制下下,guest的所有vpa物理地址都需要转换成mpa(注意这里vmm自身不需要ept,自身只用传统pat就)。
上图是ept机制下的guest虚拟地址到真实物理地址的流程。之所以这么长,原因是guest中的每步物理地址,还得经过ept转换,又是一个四级结构。如果把中间ept省略,就还原出来了cr3->PML4->PDPT->PD->PT->PA 。
还有一个机制跟tlb有关,在未开启虚拟化时,tlb缓存va到pa的转换,cr3切换会刷新tlb。开启虚拟化时,为了支持切换虚拟机不刷新或者多个虚拟机同时运行,tlb支持多个虚拟机相同的va同时缓存,转换到不同pa,实现方式是,由va->pa的转换,改为va+guestid->pa,这样就不会混了。这个机制称为VPIDs
8EPT机制是否开启,在VMCSdata区域的vm ecxcution control fields
9关于虚拟化技术,我们高屋建瓴的看,vmm和vm基于硬件的关系,是不是跟os和app的关系一样?前者直接管理硬件资源,为后者虚拟出来了硬件。当然区别是,app需要的硬件只是cpu 内存 io并且他明确知道自己在虚拟环境下,主动配合os帮助来获取硬件资源,因此os需要虚拟的东西反而没那么多。但是vm不需要知道自己在虚拟环境下,因此vmm需要给vm全部的硬件虚拟,从cpu(各种寄存器,包括cpuid msr) 内存,io。这就表现在,对于有状态的硬件资源,我们需要为每个vm保存状态,无状态的,但是我们想hook的,都要在vmcs设置vm exit。
10 MSR bitmaps和IO bitmaps正是后者的体现, 表明那些msr和io的操作会导致vm exit.
11开启ept后,内存的缓存分为两块:
1:针对ept分页结构有关的内存的缓存机制,受cr0.cd的影响和 eptp的 paging struct cache type的影响
2:其他内存的缓存机制:受到cr0.cd 和ept最后一级页表的属性设置影响
注意:guest仍然可以设置传统页表的读写权限和缓存。但如果同一个页面即设置了传统PAT,有设置了EPT页面,那cpu缓存以EPT设置为主。
INVVPID 和 INVEPT 的目标都是无效化某些特定的内存地址映射。在处理器中,有一个叫做 TLB(Translation Lookaside Buffer)的硬件缓存,它用来存储最近使用的虚拟地址到物理地址的映射,以加速内存访问。当操作系统或虚拟机管理器(VMM)更改了内存的分页结构(即改变了虚拟地址到物理地址的映射)后,TLB 中可能会存留一些过时的映射,这时就需要使用 INVVPID 或 INVEPT 指令来告诉处理器,让它丢弃这些过时的映射。
接下来,我们来看看这两个指令的具体用法:
INVVPID(Invalidate Translations Based on VPID):这个指令可以视为一个"清洁工",它可以清理掉与特定虚拟处理器(VPID)相关的过时映射。你可以告诉这个"清洁工"清理掉与某个 VPID 相关的所有映射,或者仅清理掉与某个 VPID 和特定线性地址相关的映射。这就像是你告诉清洁工清理整个房子,或者只清理房子中的某个房间。
INVEPT(Invalidate Translations Based on EPT):这个指令也是一个"清洁工",但是它清理的是与特定扩展页表(EPT)相关的过时映射。你可以告诉这个"清洁工"清理掉与某个 EPT 相关的所有映射,或者清理掉所有 EPT 的所有映射。这就像是你告诉清洁工清理掉整个办公楼,或者清理掉整个办公园区。
以下是有关例子:
INVVPID(Invalidate Virtual-Processor Identifier):假设你有一个虚拟机监视器(VMM),它为每个虚拟机(VM)分配了一个唯一的 VPID。现在,你修改了一个 VM 的页表。为了确保此 VM 的所有映射都是最新的,你需要无效化与该 VM 的 VPID 相关的所有映射。你可以使用 INVVPID 指令来完成这个操作:
Individual-address:假设你知道修改了哪个线性地址的页表条目,你可以使用 INVVPID 指令的 Individual-address 类型,只无效化与该线性地址相关的映射。例如,如果你修改了线性地址 0x1000 的页表条目,并且该地址的 VPID 是 1,你可以执行 INVVPID 0, (1, 0x1000)。
Single-context:如果你不知道修改了哪些线性地址的页表条目,或者修改了很多页表条目,你可以使用 INVVPID 指令的 Single-context 类型,无效化与该 VM 的所有映射。例如,如果 VM 的 VPID 是 1,你可以执行 INVVPID 1, (1)。
All-context:如果你想无效化所有 VM 的所有映射,你可以使用 INVVPID 指令的 All-context 类型。例如,你可以执行 INVVPID 2, ()。
Single-context-retaining-globals:如果你想无效化与某个 VPID 相关的所有映射,但保留全局映射,你可以使用 INVVPID 指令的 Single-context-retaining-globals 类型。例如,如果 VM 的 VPID 是 1,你可以执行 INVVPID 3, (1)。
INVEPT(Invalidate Translations Derived from EPT):假设你有一个 VMM,它为每个 VM 分配了一个唯一的 EPTP。现在,你修改了一个 VM 的扩展页表(EPT)。为了确保此 VM 的所有映射都是最新的,你需要无效化与该 VM 的 EPTP 相关的所有映射。你可以使用 INVEPT 指令来完成这个操作:
Single-context:如果你只修改了与一个特定 EPTP 相关的 EPT,你可以使用 INVEPT 指令的 Single-context 类型。例如,如果 VM 的 EPTP 是 0x1000,你可以执行 INVEPT 1, (0x1000)。
All-context:如果你修改了与多个 EPTP 相关的 EPT,或者你不知道修改了哪些 EPT,你可以使用 INVEPT 指令的 All-context 类型。例如,你可以执行 INVEPT 2, ()。
在这些示例中,括号内的参数是 INVVPID 或 INVEPT 指令的描述符,描述符中的值是 VPID、线性地址或 EPTP 的值。这些值取决于你的具体应用场景和内存管理策略。
13 vmcs是内存里的区域,处理器只保存vmcs指针。
14关于vmm作为驱动程序加载,此时vmm继承了windows的各种上下文(比如各种寄存器,分页cr3)