首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

KVM 虚拟化技术在 AMD 平台上的实现(2)

KVM 虚拟化技术在 AMD 平台上的实现(2)

AMD-V 技术AMD-V 结构简介 AMD-V 在 AMD 传统的 x86-64 基础上引入了 “guest” 操作模式。 “guest”操作模式就是 CPU 在进入客操作系统运行时所处的模式。 “guest”操作模式为客操作系统设定了一个不同于 VMM 的运行环境而不需要改变客操作系统已有的 4 个特权级机制,也就是说在“guest”模式下,客操作系统的内核仍然运行在 Ring 0, 用户程序仍然在 Ring 3。  裸机上的操作系统和 VMM 所在的操作模式依然和传统的 x86 中一样,我们姑且称之为“host”操作模式。  VMM 通过执行 VMRUN 指令使 CPU 进入“guest”操作模式而执行客操作系统的代码; 客操作系统在运行时,遇到敏感指令或事件,硬件就执行 VMEXIT 行为,使 CPU 回到“host”模式而执行 VMM 的代码。 VMRUN 指令运行的参数是一个物理地址指针,其指向一个 Virtual Machine Control Block (VMCB) 的内存数据结构, 该数据结构包含了启动和控制一个虚拟机的全部信息。
“guest”模式的意义在于其让客操作系统处于完全不同的运行环境,而不需要改变客操作系统的代码。“guest”模式的设立在系统中建立了一个比 Ring 0 更强的特权控制,即客操作系统的 Ring 0 特权必须让位于 VMM 的 Ring 0 特权。 客操作系统上运行的那些特权指令,即便是在 Ring 0 上也变的可以被 VMM 截取的了, “Ring Deprivileging”由硬件自动搞定。 此外,VMM 还可以通过 VMCB 中的各种截取控制字段选择性的对指令和事情进行截取,或设置有条件的截取,所有的敏感的特权或非特权指令都在其控制之中。  有了“guest”模式,前面提到的 17 条敏感非特权指令问题和 “Ring Deprivileging”带来的三个问题被简单解决。
VMCB   VMCB 数据结构主要包含如下内容 :
1. 用于描述需要截取的指令或事件的字段列表。其中 :
  • 2 个 16 位的字段用于控制对 CR 类控制寄存器读写的截取
  • 2 个 16 位的字段用于控制对 DR 类调试寄存器的读写的截取
  • 一个 32 位的字段用于控制 exceptions 的截取
  • 一个 64 位的字段用于控制各种引起系统状态变化的事件或指令的截取,如 INTR, NMI, SMI 等事 件, HLT, CPUID,INVD/WBINVD, INVLPG/INVLPGA,MWAIT 等指令, 还包括两位分别标志是否对 IO 指令和 MSR 寄存器的读写进行控制
2. 指向IO端口访问控制位图和MSR读写控制位图的物理地址指针字段。该位图用于差别性地控制虚拟机对不同的 IO 端口和 MSR 寄存器进行读写访问。
3. 描述虚拟机CPU状态的信息。包含除通用寄存器外的大部分控制寄存器,段寄存器,描述符表寄存器,代码指针等。  RAX 寄存器也在其中,因为 RAX 在 VMM 执行 VMRUN 时是用来存放 VMCB 物理地址的。 对于段寄存器,该信息中还包含段寄存器对应的段描述符,也就那些传统 x86 上对软件隐藏的信息。
4. 对虚拟机的执行进行控制的字段。主要是控制虚拟机中断和 NPT 的字段。
5. 指示虚拟机进入“guest”模式后要执行的行动的字段。包括用来描述 VMM 向虚拟机注入的中断或异常的信息的字段。 注入的中断或异常在 VMRUN 进入“guest”模式后立即执行,就象完全发生在虚拟机内一样。
6. 提供VMEXIT信息的字段。包括导致 VMEXIT 的事件的代码,异常或中断的号码,page fault 的线性地址,被截获的指令的编码等。
   VMCB 以及其涉及的控制位图,完全通过物理地址进行指向,这就避免了“guest”和“host”模式切换的过程依赖于“guest”空间的线性地址 ( 传统操作系统内用户空间到内核的切换确实依赖于 IDT 中提供的目标的线性地址 ), 使得 VMM 可以采用和客操作系统完全不同的地址空间,避免了前面提到的“Address-space compression”问题。
   VMCB 的内容在物理上被分成了俩部分,其中用于保存虚拟机 CPU 状态的信息占据 2048 字节的后半部分,我们可称之为 VMCB.SAVE; 其他信息,占据前 1024 字节范围,我们可称之为 VMCB.CONTROL。
   VMRUN 命令以 VMCB 为参数,使 CPU 进入“guest”状态, 按 VMCB.SAVE 的内容恢复虚拟机的 CPU 寄存器状态,并按 VMCB.SAVE 中 CS:RIP 字段指示的地址开始执行虚拟机 的代码, 并将之前 VMM 的 CPU 状态保存在 MSR_VM_HSAVE_PA 寄存器所指向的物理内存区域中。VMRUN 所保存的 VMM 的 CPU 状态的 CS:RIP 实际上就是 VMM 的代码中 VMCB 的下一个指令, 当虚拟机因某种原因而导致 #VMEXIT 时,VMM 会从 VMRUN 后的一条指令开始执行。 CPU 执行 #VMEXIT 行为时,会自动将虚拟机的状态保存到 VMCB.SAVE 区,并从 MSR_VM_HSAVE_PA 指定的区域加载 VMM 的 CPU 状态。
  VMLOAD 和 VMSAVE 指令是对 VMRUN 的补充,他们用来加载和恢复一些并不需要经常使用的 CPU 状态,如 FS, GS, TR, LDTR 寄存器以及其相关的隐含的描述符寄存器的内容,VMLOAD 和 VMSAVE 可以让 VMM 的实现对 “guest”进入和退出的过程进行优化,让多数情况下只使用 VMRUN 进行最少的状态保存和恢复。
VMMCALL 指令是 AMD-V 为客操作系统内核提供的明确的功能调用接口,类似于 syscall 指令 ( 从 Ring 3 到 Ring 0), VMMCALL 让客操作系统直接执行 #VMEXIT 而进入 VMM,请求 VMM 的服务。
中断的虚拟化  AMD-V 对中断的虚拟化有如下支持 :
虚拟中断
虚拟中断是指由虚拟机的 EFLAGS.IF 标志控制的中断。 AMD-V 在 VMCB.CONTROL 中加入了一个 V_INTR_MASKING 字段, 当 V_INTR_MASKING 设置为 0 时, EFLAGS.IF 同时控制虚拟中断和物理中断; 当 V_INTR_MASKING 设置为 1 时,ELAGS.IF 值只控制虚拟中断,而 VMM 在执行 VMRUN 时保存的主机的 EFLAGS.IF 则控制物理中断。  VMCB 还提供了几个字段 V_IRQ, V_INTR_PRIO, V_INTR_VECTOR 及 V_TPR。  其中 V_TPR 代表虚拟 CPU 的 TPR,  当 V_INTR_MASKING 为 1 时,虚拟机上对 CR8 寄存器的访问被映射到对 V_TPR 字段的访问, 并由 V_TPR 和 V_INTR_PRIO 一起决定是否产生虚拟中断。  V_IRQ 表示当前存在虚拟中断请求,V_INTR_PRIO 是当前虚拟中断的优先级,如果 V_INTR_PRIO 比 V_TPR 高,则当虚拟机的 EFLAGS.IF 变为 1 时,虚拟中断就可被递交,V_INTR_VECTOR 就是中断的向量号。VMM 可以通过设置 VMCB 的 V_IRQ, V_INTR_PRIO, V_INTR_VECTOR 字段向虚拟机发起一个虚拟中断。 虚拟中断的机制扩展了中断的概念,不需要物理设备的存在,VMM 可以代表其仿真的虚拟设备,向虚拟机发起中断请求。
全局的中断控制
AMD-V 的硬件扩展包含一个标志位 GIF 可用来对物理中断和虚拟中断进行统一控制,当 GIF 被清 0 时,物理中断和虚拟中断均被屏蔽,当 GIF 被设置时,物理中断和虚拟中断才能按各自的控制机制进行递交。  STGI 指令设置 GIF, CLGI 指令清除 GIF。
中断截取
通过 VMCB.CONTROL 的 5 个控制位,物理的、虚拟的、NMI、SMI、 INIT 类型的中断都可以被截取或不截取,以便于 VMM 来控制中断相关的行为。一般来说,固定的低优先级的虚拟中断可不被截取由客操作系统自己处理, 高优先级的虚拟中断一般需要截取,以便 VMM 能快速的应答或通过 IER 关闭该中断以避免该中断延迟更低优先级的中断。
事件注入
VMCB.CONTROL 提供一个 EVENTINJ 字段,在执行 VMRUN 之前,VMM 通过设置该字段,向虚拟机注入一个异常或中断 .  被注入的事件完全在虚拟机的环境执行,就象完全发生在客操作系统中一样。被注入的事件是虚拟机返回“guest”模式后最先执行的代码,在 VMCB.SAVE 的 CS:RIP 字段指定的返回代码之前执行。
扩展的 APIC 特征
增加了 IER 控制寄存器和 SEOI 寄存器。IER 可被 VMM 软件用来控制 Local APIC 上 Pending 的中断,让某 Pending 中断不参与优先级的裁决,每个中断在 IER 中都有一个对应的控制位。SEOI 可被 VMM 软件用来结束中断的 Pending 状态,软件将需要结束的中断的向量号写入 SEOI 的 Vector 字段即可。
返回列表