Page 51 - 《软件学报》2020年第10期
P. 51
李鼎基 等:基于跨虚拟机零下陷通信的加速器虚拟化框架 3027
换到对应的页表.以一次客户端切换到服务端的地址空间为例,一种符合直觉的想法是在 VMFUNC 指令的前后
修改 CR3 寄存器的值达到切换页表的目的,但是细看之下就会发现无法达到目的:程序计数器是根据虚拟地址
获取当前指令的,如果 VMFUNC 前一条指令更换了页表,那么 CPU 在执行下一条指令时由于 GVA 到 GPA 映
射的变化,实际上硬件看到的已经是一份无效的页表,从而导致运行错误;反之,如果试图在 VMFUNC 后一条指
令更换页表,由于在 VMFUNC 指令执行完成后 GPA 到 HPA 的映射发生变化,实际访问到的下一条指令内容也
不再是对于 CR3 的修改,同样会引发异常.
Wormhole 通过将第①步中 CR3 映射的添加与第⑤步中硬件虚拟化技术相结合,在不下陷到虚拟机监视器
的情况下,实现了如图 5 所示的一条 VMFUNC 指令可以同时完成页表和扩展页表的切换,保证了切换前后地址
翻译机制的正确,一条指令完成多项操作也大幅降低了跨虚拟机通信的开销.同时,因为代理执行的特点,客户端
虚拟机与服务端虚拟机均运行在同一个物理 CPU 上,避免了跨核中断(inter pocessor interrupt,简称 IPI)带来的高
昂开销.
Fig.5 Switch virtual machine address space through VMFUNC
图 5 VMFUNC 指令切换虚拟机地址空间原理图
针对切换前后 CPU 指令流的过渡,Wormhole 在第③步操作中提供了一份共享跳板代码页以及一个代理执
行专用的栈,代码页包括了 VMFUNC 指令以及一些上下文的保存逻辑,将它们映射到双方虚拟机的页表中相同
的 GVA.这样,客户端进程在需要进行代理执行时可以跳转到这份代码页,在地址空间切换成功后,由于在服务端
进程在相同的地址共享这份代码页,程序计数器可以无缝地过渡到 VMFUNC 的下一条指令继续执行,也不会污
染双方进程原本的栈的内容.另外,还需要服务端进程提前向虚拟机监视器注册代理执行函数的入口,跳板代码
在控制流切换完成后会跳转到被注册的函数入口,正式开始在服务端进行加速器的访问操作.
(2) 支持在控制流切换后系统调用、中断等复杂操作的正确处理.
一些以 SkyBridge [21] 为代表的前序工作同样使用了类似的代理执行思想,但是这些工作只是针对一些基于
微内核的较简单的操作系统,面向的场景也仅仅是同一个操作系统中进程间的代理执行.在微内核的设计理念
中,内核部分的代码量很小,通常只会保留几个最基础的管理功能,大量传统宏内核中的功能(例如设备驱动程
序)被移出了内核态,作为一个专门的用户态进程提供相应的功能.因此,在微内核场景下,大多数功能不会在内
核中完成.例如,I/O 相关的功能会由用户态的驱动程序负责,而中断发生后也会转交给用户态的特定进程进行
中断处理.
然而,目前在数据中心内部,主流的依然是基于宏内核的 Linux 操作系统.出于性能上的考虑,宏内核中集成
了包括设备驱动、中断处理和资源管理在内的各类复杂功能,因此,用户态应用程序在运行时会比较频繁地与