虚拟化 · 2023年11月13日 0

内存虚拟化原理

内存虚拟化相关原理学习笔记

术语解释

VT(Virtualization Technology)

虚拟化技术,Intel VT技术主要分为三部分:

  • VT-x:针对处理器的虚拟化技术。包括Intel VTFlex Priority、Intel VTFlex Migration(Intel虚拟化灵活迁移技术)、Extended Page Tables(IntelVT扩展页表)。
  • VT-d:支持直接I/O访问的虚拟化技术,包括DMA重映射、中断重映射及Interrupt Posting。
  • VT-c:支持网络连接的虚拟化技术,包括虚拟机设备队列(VMDq)、虚拟机直接互连(VMDc)。

MMU(Memory management unit)

内存管理单元,负责检查内存总线上所有的内存引用,将虚拟内存地址转换为物理内存地址。

Intel架构将虚拟内存划分为划分为4KB-页(也支持其他大小),将物理内存划分为4KB-帧。MMU通常会包含一个TLB(translation lookaside buffer),将最后几个页表条目保存在TLB中,在需要访问物理内存中的页表之前,处理器会先在TLB中找相应的映射关系,避免从物理内存中直接读取。

VMM (Virtual Machine Manager)

虚拟机管理器,用于创建和运行虚拟机的软件、固件及硬件。

搭载虚拟机管理器来运行一个或多个虚拟机的计算机称为主机(Host),每个虚拟机称为客户机(Guest)。

SLAT(Second Level Address Translation)

二级地址转换,一种硬件辅助虚拟化技术。

AMD使用RVI技术支持SLAT,Intel使用EPT技术支持SLAT。

RVI(Rapid Virtualization Indexing)

快速虚拟化索引,是AMD第二代硬件辅助虚拟化技术。

EPT(Extended Page Tables)

扩展页表,是Intel第二代硬件辅助虚拟化技术。

物理内存和虚拟内存

物理内存存在于RAM上,是一种易失性存储。其大小就是内存条本身的大小。

可执行文件需要在进程执行之前映射到物理内存中。在理想情况下,运行程序所需的数据可以直接从硬盘映射到内存中,并由处理器快速访问处理数据。然而实际情况是内存空间不够将所有存储数据映射上去。

于是虚拟内存就出现了,虚拟内存是内存的次要形式,它利用硬盘等存储设备将其中一块区域划分为内存,供临时处理数据。

虚拟内存是一种内存管理技术,通过内存映射等方式,让程序认为它有一个连续可用的内存空间,但实际上它被划分了多个物理内存区域,还有部分暂时存储在硬盘中。

MTRR寄存器

当计算机开始引导时,在CPU上执行的代码可以直接访问物理内存(因为处理器在实模式下运行),实模式下的地址与其物理内存地址相对应。并且此时还有几个物理内存区域可以供操作系统或OS Loader使用。

在这个过程中,BIOS会对MTRR寄存器(Memory Type Range Registers)进行配置。这个寄存器能够将内存类型与系统内存中的物理地址范围关联起来,允许处理器优化不同类型内存的操作。

物理内存有范围,每个范围都有一个在系统初始化期间应用的缓存控制策略。

Intel CPU的内存类型编码表如下:

物理机上的MTRR映射如下:

内存分段与分页

x86体系结构中CPU看到的地址是逻辑地址,经过分段单元后逻辑地址被转换为线性地址,又叫虚拟地址,最后分页单元再将虚拟地址转换为物理地址。

分段提供了一种将处理器的可寻址内存空间(线性地址空间)划分为更小的受保护地址空间(也就是段)的机制。段可用于保护程序的代码、数据和堆栈,或保存系统数据结构。

多个程序运行时,处理器则为每个程序都分配一组段,并确保每个程序的段都是分离的不会互相干扰。

如图所示,系统中所有段都包含在处理器的线性地址空间中。要在特定段中定位字节,必须提供逻辑地址(也叫远指针)。

逻辑地址由段选择器和偏移量组成,段选择器是段的唯一标识符,并且它还提供描述符表(如全局描述符表GDT)到段描述符的偏移量。

每个段都有一个段描述符,用于指定段的大小、段的访问权限和特权级别、段类型及段基址。逻辑地址的偏移量被添加到段基址上来定位段内的数据。基址+偏移=线性地址。

如果不使用分页,则处理器的线性地址空间就直接映射到处理器的物理地址空间上。这里的物理地址空间定义为处理器可以在其地址总线上生成的地址范围。

但实际上要处理多任务的系统不太可能直接映射物理内存来使用,为此需要使用“虚拟化”线性地址空间的方法,也就是分页机制来处理。

分页机制通过使用少量物理内存(RAM和ROM)和一些硬盘存储来模拟大型线性地址空间。分页机制将每个段分为页(一般为4KB大小)并将页存储在物理内存或磁盘上。

操作系统通过一组页表来跟踪对应的页数据,当程序尝试访问线性地址空间中的地址时,处理器使用页表将线性地址转换为物理地址,然后再内存中执行读写操作。

如果正在访问的页不在物理内存中,则处理器会中断程序的执行(通过generating a page-fault异常),然后操作系统将页从硬盘加载到物理内存并继续执行。

多级页表

为了节约内存空间又衍生了多级页表机制。在两级及其之后的页表可以不存放在内存里而是存放在磁盘里,需要的时候再交换回内存。

现代64位处理器大多采用四级页表模式,分别为:

  • 全局页目录项(Pege Global Directory,PGD)
  • 上层页目录项(Pege Upper Directory,PUD)
  • 中间页目录项(Pege Middle Directory,PMD)
  • 页表项(Pege Table Entry,PTE)

下图为4KB页面大小的四级页表模式:

内存虚拟化地址转换

地址缩写:

  • GVA – Guest Virtual Address
  • GPA – Guest Virtual Address
  • HVA – Host Physical Address
  • HPA – Host Physical Address

内存虚拟化要做的就是从GVA到HPA的转换,中间要经过GPA到HVA的转换,即:

GVA -> GPA -> HVA -> HPA

GVA->GPA的转换由虚拟机的系统页表完成,GPA->HVA的转换由VMM定义的映射表完成,HVA->HPA的转换由主机的系统页表完成。

但这个传统转换方式每次内存访问都需要VMM的介入,并进行多次地址转换,效率非常低。

在硬件辅助虚拟化技术出现之前,通过VMM来实现的影子页表技术,简化了地址转换过程,实现了GVA->HPA的直接映射。

Shadow page table

影子页表,简要来说其原理就是将GVA->GPA->HVA这一路的映射关系记录到影子页表中,把影子页表装入Host的MMU中,当Guest需要访问Host内存时,根据影子页表中存储的映射关系,完成GVA->HPA的直接映射。

但这种方式需要VMM为每个Guest都维护一套对应的影子页表,内存开销较大。为解决影子页表的CPU厂商提供了硬件辅助虚拟化技术。下面再讲Intel的EPT机制原理,先了解一下VMX相关知识。

VMX

针对处理器的虚拟化支持是通过VMX-虚拟化扩展技术来实现的。

VM Entry/VM Exit

VT-x为处理器增加了两种操作模式:VMX Root Operation和VMX non-root Operation。VMM运行VMX Root Operation模式,客户机运行VMX non-root Operation模式。

通过这两种操作模式,让vCPU直接运行在逻辑CPU上,在软件上省去了对vCPU运行的模拟,大大提升了性能。

VMX在VMX Root模式和VMX non-root模式之间的转换称为VMX transitions。

VMX transitions有两种:

  • VM Entry:进入VMX non-root 模式的转换为VM Entry。
  • VM Exit:从VMX non-root模式到VMX Root模式的转换为VM Exit。

VMM软件运行周期

VMM及其Guest的运行周期和交互流程如下:

  • 软件通过执行VMXON指令进入VMX操作
  • VMM通过VM entries来将Guest登录到虚拟机(一次一个)。VMM使用VMLAUNCH和VMRESUME指令来开启VM entry,并在需要时使用VM exits来重新获取控制权。
  • VM exits将控制权转移到VMM指定的入口点,VMM可以针对VM退出的原因采取相应的操作,然后使用VM Entry返回到VM。
  • 最后,VMM可以使用VMXOFF指令来关闭并结束VMX操作。

VMX地址转换支持

VMX操作包括两个支持地址转换的功能:虚拟处理器标识符(virtual-processor identifiers,VPIDs)和扩展页表(Extended Page Table,EPT)。

VPIDs是一种管理线性地址转换的机制,EPT则定义了一个地址转换层,增强了线性地址的转换。

VPIDs

逻辑处理器通过VPIDs机制来缓存多个线性地址空间的信息,当使用VPIDs时,VMX转换会保留缓存信息,而逻辑处理器会切换到不同的线性地址空间。

以下情况下当前VPID为0000H:

  • 外部VMX操作中(包括在SMI和SMM系统管理模式下使用VMX操作)
  • VMX root操作模式中。
  • VMX non-root操作模式下,”enable VPID” VM-execution控制符为0时。

如处理器在VMX non-root操作模式下,”enable VPID” VM-execution控制符为1时,当前VPID的值为VMCS中VPID VM-execution字段的值。

HLAT

HLAT(Hypervisor-managed linear-address translation)是一种改变VMX non-root操作中线性地址转换方式的功能。

当“enable HLAT”的VM-execution控制符为1时,启用HLAT分页功能。

HLAT分页仅用于分页模式的4级分页和5级分页。

EPT

系统通过使用一组EPT分页结构来支持GPA到HPA的地址转换。

如果开启EPT模式,当Guest和Host访问同一个物理地址时,Guest只能对“虚拟的”物理内存进行读写,只有Host才能访问到真正的物理内存。

在使用EPT机制的VMM中,实现GVA-> HPA的地址转换只需两步,首先根据Guest的系统页表完成GVA->GPA的转换,然后根据EPT页表完成GPA->HPA的地址转换。

在VMCS结构中有一个EPTP的指针,其中的12-51位指向EPT页表的一级目录即PML4 Table。这样根据客户机物理地址的首个9位就可以定位一个PML4 entry,一个PML4 entry理论上可以控制512GB的区域。PML4E的格式如下:

EPT页表的转换流程如下图:

除了将GPA转换为HPA之外,EPT 还能指定软件在访问该地址时的权限。未经允许的访问会触发EPT violations并导致 VM 退出。

VMCS

为了对vCPU的状态进行记录,Intel还引入了VMCS(Virtual Machine Control Structure)虚拟机控制数据结构。

对 VMCS 的访问是通过称为 VMCS 指针(每个逻辑处理器一个)的处理器状态组件进行管理的。 

  • VMCS指针的值是VMCS的64位地址。 
  • VMCS 指针的读写使用指令 VMPTRST 和 VMPTRLD。 
  • VMM 使用 VMREAD、VMWRITE 和 VMCLEAR 指令配置 VMCS。

VMCS实际上是一个物理内存区域,用于保存或恢复VMM和客户机执行的上下文。

其中又包含Guest-State Area、Host-State Area、VM-execution control fields、VM-exit control fields、VM-entry control fields、VM-Exit Infomation Fields几个区域。

各区域字段的值可查看Intel开发手册3卷B附录。

  • Host State Area:用于记录部分CPU的状态信息,VMCS即要记录主机CPU的状态,也要记录客户机CPU的状态。
  • 下图为64位Host State Fields字段的值,VM exit从这些字段加载处理器状态:
  • VM Control Fields:用于控制虚拟机行为,如中断方式、是否启用EPT、启用I/O端口、MSR访问限制等。
  • Guest State Area: VM entry从该区域的字段中加载处理器状态,VM exit将处理器状态存储到这里的字段中。
  • VM Exit Infomation Fields:该区域是一个只读区域。主要用于存储VM exit的错误信息。

中断与异常

IDT(interrupt descriptor table 中断描述符表)是x86架构用来实现中断向量表的数据结构。处理器使用IDT来确定对中断和异常的正确响应。

IDT由三类事件触发:硬件中断、软件中断和处理器异常。IDT由256个中断向量组成,其中(0~31)用于处理器异常,(32~255)为用户自定义外部中断。

异常类型如下表所示:

IDT可以驻留在线性地址空间中的任意位置。如图所示,处理器使用IDTR寄存器来定位IDT。该寄存器保存IDT的32位基址和16位Limit。

当处理器从中断控制器收到中断号后,就可以通过IDTR来找到IDT中对应的中断门。通过这个中断门可以在全局描述符中找到对应的描述符,最后找到对应的中断处理函数的逻辑地址,再结合分段与分页机制找到中断处理函数的实际物理地址跳转执行。

IDT可以包含三种门描述符中的任意一种:

  • Task-gate descriptor(任务门描述符)
  • Interrupt-gate descriptor(中断门描述符)
  • Trap-gate descriptor(陷阱门描述符)

下图为三种门描述符的格式:

任务门包含用于异常和中断处理程序任务的TSS的段选择器。

中断门和陷阱门包含一个远指针(指向段选择器),处理器使用该远指针将程序执行转移到异常或中断处理程序代码段中进行处理。

参考