一、虚拟机指令集架构支持

如果在 ISA 设计期间就规划了 VM,那么减少 VMM 必须执行的指令数量以及模拟它们所需的时间就相对容易。 然而,由于虚拟机最近才被考虑用于桌面和基于 PC 的服务器应用程序,因此大多数指令集在创建时都没有考虑虚拟化。 

指令集虚拟化,是一种让不同的硬件平台能够运行相同的软件的技术。它通过软件来模拟一个虚拟的处理器,这个虚拟的处理器可以执行一种不同于真实硬件的指令集。如果想让一个用x86指令集编写的程序在ARM平台上运行,就需要用到指令集虚拟化。指令集虚拟化的过程就是将源指令集(比如x86)的二进制代码转换为目标指令集(比如ARM)的二进制代码。

如果一个体系结构满足了一些虚拟化要求,就可以用一种叫做陷阱和模拟的方法来实现虚拟化管理程序,这个管理程序可以在真实硬件上直接执行大部分指令,而只有少数敏感或特权的指令需要被捕获并模拟。这样可以保证虚拟机的效率,隔离和等效性。如果一个体系结构不满足这些要求,就需要用其他方法来实现虚拟化管理程序,比如解释执行或者硬件辅助。

由于VMM必须确保客户系统仅与虚拟资源交互,因此传统的客户操作系统作为用户模式程序运行在VMM之上。 然后,如果VM操作系统尝试通过特权指令访问或修改与硬件资源相关的信息(例如,读取或写入页表指针),它将捕获到 VMM。 然后,VMM 可以对相应的实际资源进行适当的更改。

因此,如果任何试图读取或写入此类敏感信息的指令在用户模式下执行时陷入trap,VMM 可以拦截它并支持VM操作系统期望的敏感信息的虚拟版本。 如果没有这种支持,就必须采取其他措施。 VMM 必须采取特殊的预防措施来定位所有有问题的指令并确保它们在由VM操作系统执行时正确运行,从而增加了 VMM 的复杂性并降低了运行 VM 的性能。

通过引入额外的权限级别,一些操作系统操作(例如,那些超出授予用户程序的权限但不需要 VMM 干预的操作(因为它们不会影响任何其他 VM))可以直接执行,而无需捕获和执行 调用VMM。 

二、虚拟机对虚拟内存和 I/O 的影响

另一个挑战是虚拟内存的虚拟化,因为每个虚拟机中的每个操作系统都管理自己的一组页表。 为了实现这一点,VMM 将真实内存和物理内存的概念(通常被视为同义词)分开,并使真实内存成为虚拟内存和物理内存之间的独立中间层。

客户操作系统通过其页表将虚拟内存映射到实际内存,VMM 页表将客户的实际内存映射到物理内存 。 虚拟内存体系结构可以通过页表指定,也可以通过 TLB 结构指定。

内存虚拟化是指让每个虚拟机都有自己的虚拟地址空间,而不是直接使用物理地址空间。为了实现这一点,需要用到页表和TLB(转换后备缓冲器)。

页表是用来记录虚拟地址和物理地址之间的对应关系的表格,

TLB是用来缓存页表中的部分条目的硬件,可以加快地址转换的速度。

虚拟化管理程序(VMM)是用来控制虚拟机和真实硬件之间的交互的软件,它需要保证每个虚拟机都能正确地访问内存,而不会影响其他虚拟机或者真实硬件。

为了做到这一点,有两种常见的方法:阴影页表和嵌套页表。阴影页表是指VMM维护一个从虚拟机的虚拟地址空间直接映射到真实硬件的物理地址空间的页表,这样就可以避免每次访问内存时都要经过两层页表的转换。但是这种方法需要VMM监测并捕获虚拟机对自己的页表或者页表指针的任何修改,并及时更新阴影页表。这通常是通过写保护虚拟机的页表和陷入对页表指针的访问来实现的。嵌套页表是指在硬件上增加一个额外的页表级别,由VMM管理,用来记录从虚拟机的物理地址空间到真实硬件的物理地址空间的映射关系。这样就可以让虚拟机保持自己的页表不变,而不需要阴影页表。但是这种方法需要硬件支持,并且可能增加地址转换的开销。

TLB也需要被虚拟化,因为不同的虚拟机可能有相同的虚拟地址,但是对应不同的物理地址。为了解决这个问题,有两种常见的方法:刷新TLB和使用进程标识符(PID)。刷新TLB是指在每次切换虚拟机时,清空TLB中所有的条目,这样就可以避免混淆不同虚拟机的地址转换。但是这种方法会降低TLB命中率,并且增加切换开销。使用PID是指在TLB中加入一个标识符字段,用来区分不同虚拟机或者进程的地址转换。这样就可以在TLB中同时保存多个虚拟机或者进程的条目,并且在切换时不需要刷新TLB。但是这种方法也需要硬件支持,并且需要VMM维护一个从虚拟机或者进程的PID到真实硬件PID的映射关系。

I/O设备虚拟化是指让每个虚拟机都能够使用真实硬件上连接的各种输入输出设备,如磁盘、网络接口、键盘、鼠标等。这是系统虚拟化中最困难的部分,因为I/O设备的数量和类型非常多,并且需要考虑如何在多个虚拟机之间共享一个真实设备,以及如何支持各种设备驱动程序,特别是当不同的虚拟机运行不同的操作系统时。维持虚拟机幻觉的一种方法是给每个虚拟机提供一些通用的设备驱动程序,然后由VMM来处理真实的I/O操作。不同类型的I/O设备可能需要不同的映射方法。例如,物理磁盘通常被VMM划分为多个虚拟磁盘,分配给不同的虚拟机,并且VMM维护虚拟磁盘和物理磁盘之间的扇区映射关系。网络接口通常被VMM在很短的时间片内在多个虚拟机之间切换,并且VMM负责根据虚拟网络地址来过滤和转发消息,确保虚拟机只收到发给它们的消息。

三、扩展指令集以实现高效虚拟化和更好的安全性

虚拟化的效率主要受到内存和I/O的影响,因此指令集扩展主要针对这两个方面进行优化。

内存方面,指令集扩展可以避免不必要的TLB刷新,并且使用嵌套页表机制来代替阴影页表,从而减少地址转换的开销。

I/O方面,指令集扩展可以允许设备直接使用DMA来传输数据(省去了VMM的一次拷贝),并且允许设备中断和命令直接被虚拟机处理,而不需要经过VMM的转发。这些扩展在内存管理或者I/O密集的应用中可以显示出显著的性能提升。

虚拟化的安全性主要受到恶意代码的威胁,如果恶意代码能够访问比敏感数据更高的特权级别,就可能破坏系统的安全。通过使用虚拟化,我们可以防止外部用户访问不同虚拟机中的数据,这比多道程序设计环境提供了更大的保护。但是这可能还不够,如果攻击者能够入侵VMM或者通过在另一个VMM中观察来获取信息。例如,假设攻击者渗透了VMM;攻击者就可以重新映射内存,从而访问任何部分的数据。注意单纯加密并不能防止这种攻击。如果内存中的数据是未加密的,那么攻击者就可以访问所有这些数据。而且,如果攻击者知道加密密钥存储在哪里,攻击者就可以自由地访问密钥,然后访问任何加密过的数据。

最近,Intel引入了一组指令集扩展,叫做软件防护扩展(SGX),它允许用户程序创建一些隔离区域(enclave),这些区域包含了一些始终加密并且只有在使用时才用用户提供的密钥解密的代码和数据。因为隔离区域总是加密的,所以标准的操作系统操作(如虚拟内存或I/O)可以访问隔离区域(比如移动一个页面),但是不能提取任何信息。要想让隔离区域工作,所有需要的代码和数据都必须是隔离区域的一部分。

虽然细粒度保护的话题已经存在了几十年,但是它没有得到很多关注,因为它的开销很高,而且有一些更有效和更不侵入的解决方案是可以接受的。网络攻击的增加和在线保密信息的数量导致了对改进细粒度安全性的技术的重新审视。像Intel的SGX一样,IBM和AMD最近的处理器也提供了一些指令集扩展,用来支持细粒度保护。