如果在公有云上买了一台虚拟机,如何知道虚拟机运行在什么hypervisor上呢?如果买的是一台裸机如何确认公有云不是拿一台虚拟机滥竽充数裸机呢?一般公有云厂商为了安全不暴露底层,留给用户有限的api做一些非常简单的操作,为了一些功能还给镜像里预装了很多组件,完全不对称,用户在公有云厂商面前裸奔,公有云厂商在用户面前带着层层的面具。
Intel早早就推出了vt-x,进入guest模式,guest就运行在物理cpu上了,但在guest模式部分指令是要exit到host模式,然后emulation再进入guest模式继续执行,但exit开销很大,所有cpu厂商hypervior厂商os厂商努力的目标就是减少exit的次数,所以三者互相暴露功能和提供接口,cpu厂商就提供了一堆新的寄存器和说明手册说这些寄存器能干什么每个位代表什么,什么时候操作什么寄存器,依赖于那些寄存器,hypervisor厂商为guest准备了一堆新的数据结构,额外加了很多功能,os厂商为了利用hypervior厂商开发的功能又开发了很多driver,这一套机制在linux领域叫做paravirtualization,在windows领域叫做enlightment,虚拟机最难以理解的就是这点,三者互相提供了什么样的功能和接口,给对方每一个操作触发了对方进行了什么操作,谁主动谁被动,初始化都是什么样的,都准备了什么,然后整体串起来流程是什么样的。目前paravirtualization技术又多又杂,linux方面有virtio, kvmclock,apicv,windows方向有virtio和hyperclock等libvirt中<hyperv/>那一坨,windows enlightment就更有意思了,linux开源了,hypervisor厂商直接修改linux代码和hypervisor交互,windows就比较麻烦了,不开源没代码,好在Microsoft有自己的Hyper-V,windows和Hyper-V做过对接,Hyper-V一定有接口,linux和其它os也得运行在Hyper-V上,Hyper-V就得给linux和其它os提交接口文档,那其它hypervisor开发和Hyper-V一样的接口那么就和windows对接上了。所以判断自己买到底是虚拟机还裸机就看机器里有没有paravirtulization device,cpuid看是否支持vmx特性,执行VMXON指令看是否成功,执行hypercall指令看能不能成功,能不能获取hypervisor的类型就得看hypervisor有没有实现对应的read msr了,或者dmidecode看acpi有没有提供hypervisor相关的信息。
那为什么要隐藏hypervisor呢?虚拟机为原来的计算机生态带来了剧变,原来卖软件基于cpu id授权,现在cpu共享玩不转了,原来我的低端硬件用于PC机,高端硬件用于服务器领域,现在云上一台虚拟机把低端硬件passthrough了,理论上可以做到分时利用,影响销量,为了限制这样的使用场景,厂商开发的闭源driver和软件选择了检测是否运行在hypervior中,如果是对功能做限制或者干脆罢工。碰到nvidia的getforce 1080ti pasthrough到虚拟机中driver一直不能正常运行,显示error 43,上网查了很多有人说是kvm和qemu不能emulation显卡上的电源,有人说得自己制作rom,让qemu passthrough给显卡加载自己的制作的rom,有人说nvidia的driver做了限制,把libvirt的xml文件中把hypervisor vendor id和kvm hidden state on了,试了都不行,但pasthrough到linux中,用开源driver和nvidia linux driver都没问题,大概率就是windows driver的问题了,如果windows pci driver没问题那就是nvidia driver的问题,个人的想法就是反汇编,看driver有没有执行可疑的指令,再看driver有没有调用windows内核接口获取bios/acpi等这些信息,如果有来个patch,可惜空想一场,不会干。另一种思路就是修改hypervisor给guest返回定制信息。
虚拟化就怕细想,一细想就发现逻辑走不通了,一看代码一大堆,一查手册就好多页,这依赖于那,那依赖于那,然后感觉快要穷尽x86和os的历史长河了。前几天想到这个问题就写一写,希望后面能写点更深入更细节的主题,暂时想到的就是APICv,vt-d,virtio和hotplug,希望能坚持一下。