虚拟化与云计算硬核技术内幕 (8) —— “饭圈互撕”的末路

2022-09-08 16:53:03 浏览数 (1)

上一期《虚拟化与云计算硬核技术内幕 (7) —— 花名与破冰》中,我们经过研究《Intel64 & IA32 Architectures Software Developer Manual》,发现Intel通过给内存起“花名”(虚拟地址)实现了内存虚拟地址与物理地址解耦,但如果缺乏对VM root和VM Non-root状态下对内存地址访问的区分,会发生类似“破冰”的侵犯他人界限的现象。

为了避免虚拟机工作在ring0下的Guest OS操作系统内核随意访问其他虚拟机或宿主机的内存空间,需要实现这两点:

  1. 识别目前是哪个虚拟机;
  2. CPU的MMU,要根据当前是哪个虚拟机,去TLB中将虚拟地址翻译为真实的物理地址。

举一个栗子:

如果虚拟机A访问线性地址0x8001A360,映射到物理地址0xA871A360;同时,虚拟机B也访问线性地址0x8001A360,应当映射到哪里呢?当然是与虚拟机A不同的一个物理地址了。

也就是,TLB中保存的映射关系表格,其Key除了虚拟地址外,还需要一个标识虚拟机的字段。

Intel在VMX扩展中,管这个字段叫VPID (Virtual Processor Identifiers,虚拟处理器标识)。VPID是一个16bit的数,因此,理论上每个物理CPU最多只可以虚拟出65536个VM(敲黑板)。在VM Root下,这个数为0。如果这个数不为0,说明目前在虚拟机中。

同时,Intel还引入了新的页表机制:EPT(Extended Page Table)。从字面上理解,EPT是对原有页表机制的扩展。实质上,它是实现了从虚拟机内存地址到物理地址的映射。

EPT的基本原理如下图:

虚拟化环境下,虚拟机使用的是客户机虚拟地址GVA(Guest Virtual Address)。在虚拟机的程序指令访问这个地址时,实际上CPU的MMU会进行两次查表:

第一次是根据虚拟机的CR3寄存器指向的页表,得到虚拟机的GPA(Guest Physical Address),第二次再根据EPT Base Pointer进行查表,将GPA转化为HPA(Host Physical Address),也就是宿主机上的物理地址。

EPT查表的Key,除了GPA以外,另一个字段就是VPID —— 如果没有VPID,是无法区分两个不同的虚拟机发出的同一个GPA的。

EPT的翻译机制如下图:

假设处理器工作在IA32e模式,也就是64位模式下。

GPA的长度为48位,也就是每台虚拟机最多可寻址248=281.5TB内存。

EPT页表是4级页表,查表分为五个步骤:

  1. MMU会根据GPA的bit 47~bit39,在EPTP(EPT Pointer)寄存器指向的PML4表中找到EPT Page directory pointer table的基址;
  2. 根据EPT Page directory pointer table的基址,加上bit38~bit28作为偏移量找到EPT Page Directory Pointer,取出其中Page Directory Table的基址;
  3. 在Page Directory Table中,根据bit29~bit21的偏移量的Page Directory Entry,找到EPT Page Table的基址;
  4. 在EPT Page Table中,根据bit20~bit12的偏移量,找到EPT Page Entry,提取里面bit51~bit12得到Page的基址;
  5. 拿到Page Table基址,与bit11~bit0的偏移量相加得到最终的物理地址;

在EPT机制加持之下,Intel的处理器就可以有效隔离不同虚拟机的内存地址,避免多个虚拟机发出的同一个逻辑地址发生混淆了。

EPT从根本上解决了类似“饭圈互撕”的虚拟机之间直接互访内存或虚拟机访问宿主机内存的可能性,使得虚拟化的Intel处理器从原理上而言,真正能够用于生产场景。

想一想,我们还有什么问题没有解决呢?

对了,是虚拟机的输入和输出。

在经典的冯·诺伊曼架构中,计算机除了处理器(CPU),存储器(RAM)外,还有IO设备。最常见的IO设备是磁盘和网络适配器。如何让虚拟机能够使用磁盘和网络适配器呢?

当然,最简单的办法是完全使用软件来模拟这些外部设备的接口,并调用真实的外部设备实现输入和输出。但此种行为的效率极为低下。

有没有效率更高的方法呢?

请看下回分解。

0 人点赞