赠书 | 读懂 x86 架构 CPU 虚拟化,看这文就够了

作者 | 王柏生、谢广军

导读:本文摘自于王柏生、谢广军撰写的《深度探索Linux系统虚拟化:原理与实现》一书,介绍了CPU虚拟化的基本概念,探讨了x86架构在虚拟化时面临的障碍,以及为支持CPU虚拟化,Intel在硬件层面实现的扩展VMX。

同时,介绍了在VMX扩展支持下,虚拟CPU从Host模式到Guest模式,再回到Host模式的完整生命周期。

Gerald J. Popek和Robert P. Goldberg在1974年发表的论文“Formal Requirements for Virtualizable Third Generation Architectures”中提出了虚拟化的3个条件:

1)等价性,即VMM需要在宿主机上为虚拟机模拟出一个本质上与物理机一致的环境。虚拟机在这个环境上运行与其在物理机上运行别无二致,除了可能因为资源竞争或者VMM的干预导致在虚拟环境中表现略有差异,比如虚拟机的I/O、网络等因宿主机的限速或者多个虚拟机共享资源,导致速度可能要比独占物理机时慢一些。

2)高效性,即虚拟机指令执行的性能与其在物理机上运行相比并无明显损耗。该标准要求虚拟机中的绝大部分指令无须VMM干预而直接运行在物理CPU上,比如我们在x86架构上通过Qemu运行的ARM系统并不是虚拟化,而是模拟。

3)资源控制,即VMM可以完全控制系统资源。由VMM控制协调宿主机资源给各个虚拟机,而不能由虚拟机控制了宿主机的资源。

陷入和模拟模型

为了满足Gerald J. Popek和Robert P. Goldberg提出的虚拟化的3个条件,一个典型的解决方案是陷入和模拟(Trap and Emulate)模型。

一般来说,处理器分为两种运行模式:系统模式和用户模式。相应地,CPU的指令也分为特权指令和非特权指令。

特权指令只能在系统模式运行,如果在用户模式运行就将触发处理器异常。操作系统允许内核运行在系统模式,因为内核需要管理系统资源,需要运行特权指令,而普通的用户程序则运行在用户模式。

在陷入和模拟模型下,虚拟机的用户程序仍然运行在用户模式,但是虚拟机的内核也将运行在用户模式,这种方式称为特权级压缩(Ring Compression)。在这种方式下,虚拟机中的非特权指令直接运行在处理器上,满足了虚拟化标准中高效的要求,即大部分指令无须VMM干预直接在处理器上运行。

但是,当虚拟机执行特权指令时,因为是在用户模式下运行,将触发处理器异常,从而陷入VMM中,由VMM代理虚拟机完成系统资源的访问,即所谓的模拟(emulate)。

如此,又满足了虚拟化标准中VMM控制系统资源的要求,虚拟机将不会因为可以直接运行特权指令而修改宿主机的资源,从而破坏宿主机的环境。

x86架构虚拟化的障碍

Gerald J. Popek和Robert P. Goldberg指出,修改系统资源的,或者在不同模式下行为有不同表现的,都属于敏感指令。

在虚拟化场景下,VMM需要监测这些敏感指令。一个支持虚拟化的体系架构的敏感指令都属于特权指令,即在非特权级别执行这些敏感指令时CPU会抛出异常,进入VMM的异常处理函数,从而实现了控制VM访问敏感资源的目的。

但是,x86架构恰恰不能满足这个准则。x86架构并不是所有的敏感指令都是特权指令,有些敏感指令在非特权模式下执行时并不会抛出异常,此时VMM就无法拦截处理VM的行为了。

我们以修改FLAGS寄存器中的IF(Interrupt Flag)为例,我们首先使用指令pushf将FLAGS寄存器的内容压到栈中,然后将栈顶的IF清零,最后使用popf指令从栈中恢复FLAGS寄存器。如果虚拟机内核没有运行在ring 0,x86的CPU并不会抛出异常,而只是默默地忽略指令popf,因此虚拟机关闭IF的目的并没有生效。

有人提出半虚拟化的解决方案,即修改Guest的代码,但是这不符合虚拟化的透明准则。后来,人们提出了二进制翻译的方案,包括静态翻译和动态翻译。静态翻译就是在运行前扫描整个可执行文件,对敏感指令进行翻译,形成一个新的文件。

然而,静态翻译必须提前处理,而且对于有些指令只有在运行时才会产生的副作用,无法静态处理。于是,动态翻译应运而生,即在运行时以代码块为单元动态地修改二进制代码。动态翻译在很多VMM中得到应用,而且优化的效果非常不错。

VMX

虽然大家从软件层面采用了多种方案来解决x86架构在虚拟化时遇到的问题,但是这些解决方案除了引入了额外的开销外,还给VMM的实现带来了巨大的复杂性。于是,Intel尝试从硬件层面解决这个问题。

Intel并没有将那些非特权的敏感指令修改为特权指令,因为并不是所有的特权指令都需要拦截处理。举一个典型的例子,每当操作系统内核切换进程时,都会切换cr3寄存器,使其指向当前运行进程的页表。

但是,当使用影子页表进行GVA到HPA的映射时,VMM模块需要捕获Guest每一次设置cr3寄存器的操作,使其指向影子页表。而当启用了硬件层面的EPT支持后,cr3寄存器不再需要指向影子页表,其仍然指向Guest的进程的页表。

因此,VMM无须再捕捉Guest设置cr3寄存器的操作,也就是说,虽然写cr3寄存器是一个特权操作,但这个操作不需要陷入VMM。

Intel开发了VT技术以支持虚拟化,为CPU增加了Virtual-Machine Extensions,简称VMX。一旦启动了CPU的VMX支持,CPU将提供两种运行模式:VMX Root Mode和VMX non-Root Mode,每一种模式都支持ring 0 ~ ring 3。

VMM运行在VMX Root Mode,除了支持VMX外,VMX Root Mode和普通的模式并无本质区别。VM运行在VMX non-Root Mode,Guest无须再采用特权级压缩方式,Guest kernel可以直接运行在VMX non-Root Mode的ring 0中,如图1所示。

图1 VMX运行模式

处于VMX Root Mode的VMM可以通过执行CPU提供的虚拟化指令VMLaunch切换到VMX non-Root Mode,因为这个过程相当于进入Guest,所以通常也被称为VM entry。

当Guest内部执行了敏感指令,比如某些I/O操作后,将触发CPU发生陷入的动作,从VMX non-Root Mode切换回VMX Root Mode,这个过程相当于退出VM,所以也称为VM exit。

然后VMM将对Guest 的操作进行模拟。相比于将Guest的内核也运行在用户模式(ring 1 ~ ring 3)的方式,支持VMX的CPU有以下3点不同:

1)运行于Guest模式时,Guest用户空间的系统调用直接陷入Guest模式的内核空间,而不再是陷入Host模式的内核空间。

2)对于外部中断,因为需要由VMM控制系统的资源,所以处于Guest模式的CPU收到外部中断后,则触发CPU从Guest模式退出到Host模式,由Host内核处理外部中断。

处理完中断后,再重新切入Guest模式。为了提高I/O效率,Intel支持外设透传模式,在这种模式下,Guest不必产生VM exit,“设备虚拟化”一章将讨论这种特殊方式。

3)不再是所有的特权指令都会导致处于Guest模式的CPU发生VM exit,仅当运行敏感指令时才会导致CPU从Guest模式陷入Host模式,因为有的特权指令并不需要由VMM介入处理。

如同一个CPU可以分时运行多个任务一样,每个任务有自己的上下文,由调度器在调度时切换上下文,从而实现同一个CPU同时运行多个任务。在虚拟化场景下,同一个物理CPU“一人分饰多角”,分时运行着Host及Guest,在不同模式间按需切换,因此,不同模式也需要保存自己的上下文。

为此,VMX设计了一个保存上下文的数据结构:VMCS。每一个Guest都有一个VMCS实例,当物理CPU加载了不同的VMCS时,将运行不同的Guest如图2所示。

图2 多个Guest切换

VMCS中主要保存着两大类数据,一类是状态,包括Host的状态和Guest的状态,另外一类是控制Guest运行时的行为。其中:

1)Guest-state area,保存虚拟机状态的区域。当发生VM exit时,Guest的状态将保存在这个区域;当VM entry时,这些状态将被装载到CPU中。这些都是硬件层面的自动行为,无须VMM编码干预。

2)Host-state area,保存宿主机状态的区域。当发生VM entry时,CPU自动将宿主机状态保存到这个区域;当发生VM exit时,CPU自动从VMCS恢复宿主机状态到物理CPU。

3)VM-exit information fields。当虚拟机发生VM exit时,VMM需要知道导致VM exit的原因,然后才能“对症下药”,进行相应的模拟操作。为此,CPU会自动将Guest退出的原因保存在这个区域,供VMM使用。

4)VM-execution control fields。这个区域中的各种字段控制着虚拟机运行时的一些行为,比如设置Guest运行时访问cr3寄存器时是否触发VM exit;控制VM entry与VM exit时行为的VM-entry control fields和VM-exit control fields。此外还有很多不同功能的区域,我们不再一一列举,读者如有需要可以查阅Intel手册。

在创建VCPU时,KVM模块将为每个VCPU申请一个VMCS,每次CPU准备切入Guest模式时,将设置其VMCS指针指向即将切入的Guest对应的VMCS实例:

commit 6aa8b732ca01c3d7a54e93f4d701b8aabbe60fb7
[PATCH] kvm: userspace interface
linux.git/drivers/kvm/vmx.cstatic struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
{u64 phys_addr = __pa(vcpu->vmcs);int cpu;cpu = get_cpu();…if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {…per_cpu(current_vmcs, cpu) = vcpu->vmcs;asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0": "=g"(error) : "a"(&phys_addr), "m"(phys_addr): "cc");…}…
}

并不是所有的状态都由CPU自动保存与恢复,我们还需要考虑效率。以cr2寄存器为例,大多数时候,从Guest退出Host到再次进入Guest期间,Host并不会改变cr2寄存器的值,而且写cr2的开销很大,如果每次VM entry时都更新一次cr2,除了浪费CPU的算力毫无意义。因此,将这些状态交给VMM,由软件自行控制更为合理。

VCPU生命周期

对于每个虚拟处理器(VCPU),VMM使用一个线程来代表VCPU这个实体。在Guest运转过程中,每个VCPU基本都在如图3所示的状态中不断地转换。

图3 VCPU生命周期

1) 在用户空间准备好后,VCPU所在线程向内核中KVM模块发起一个ioctl请求KVM_RUN,告知内核中的KVM模块,用户空间的操作已经完成,可以切入Guest模式运行Guest了。

2) 在进入内核态后,KVM模块将调用CPU提供的虚拟化指令切入Guest模式。如果是首次运行Guest,则使用VMLaunch指令,否则使用VMResume指令。在这个切换过程中,首先,CPU的状态(也就是Host的状态)将会被保存到VMCS中存储Host状态的区域,非CPU自动保存的状态由KVM负责保存。然后,加载存储在VMCS中的Guest的状态到物理CPU,非CPU自动恢复的状态则由KVM负责恢复。

3) 物理CPU切入Guest模式,运行Guest指令。当执行Guest指令遇到敏感指令时,CPU将从Guest模式切回到Host模式的ring 0,进入Host内核的KVM模块。在这个切换过程中,首先,CPU的状态(也就是Guest的状态)将会被保存到VMCS中存储Guest状态的区域,然后,加载存储在VMCS中的Host的状态到物理CPU。同样的,非CPU自动保存的状态由KVM模块负责保存。

4) 处于内核态的KVM模块从VMCS中读取虚拟机退出原因,尝试在内核中处理。如果内核中可以处理,那么虚拟机就不必再切换到Host模式的用户态了,处理完后,直接快速切回Guest。这种退出也称为轻量级虚拟机退出。

5) 如果内核态的KVM模块不能处理虚拟机退出,那么VCPU将再进行一次上下文切换,从Host的内核态切换到Host的用户态,由VMM的用户空间部分进行处理。VMM用户空间处理完毕,再次发起切入Guest模式的指令。在整个虚拟机运行过程中,步骤1~5循环往复。

下面是KVM切入、切出Guest的代码:

commit 6aa8b732ca01c3d7a54e93f4d701b8aabbe60fb7
[PATCH] kvm: userspace interface
linux.git/drivers/kvm/vmx.cstatic int vmx_vcpu_run(struct kvm_vcpu *vcpu, …)
{u8 fail;u16 fs_sel, gs_sel, ldt_sel;int fs_gs_ldt_reload_needed;again:…/* Enter guest mode */"jne launched \n\t"ASM_VMX_VMLAUNCH "\n\t""jmp kvm_vmx_return \n\t""launched: " ASM_VMX_VMRESUME "\n\t"".globl kvm_vmx_return \n\t""kvm_vmx_return: "/* Save guest registers, load host registers, keep flags */…if (kvm_handle_exit(kvm_run, vcpu)) {…goto again;}}return 0;
}

在从Guest退出时,KVM模块首先调用函数kvm_handle_exit尝试在内核空间处理Guest退出。函数kvm_handle_exit有个约定,如果在内核空间可以成功处理虚拟机退出,或者是因为其它干扰比如外部中断导致虚拟机退出等无须切换到Host的用户空间,则返回1;

否则返回0,表示需要求助KVM的用户空间处理虚拟机退出,比如需要KVM用户空间的模拟设备处理外设请求。

如果内核空间成功处理了虚拟机的退出,则函数kvm_handle_exit返回1,在上述代码中即直接跳转到标签again处,然后程序流程会再次切入Guest。

如果函数kvm_handle_exit返回0,则函数vmx_vcpu_run结束执行,CPU从内核空间返回到用户空间,以kvmtool为例,其相关代码片段如下:

commit 8d20223edc81c6b199842b36fcd5b0aa1b8d3456
Dump KVM_EXIT_IO details
kvmtool.git/kvm.cint main(int argc, char *argv[])
{…for (;;) {kvm__run(kvm);switch (kvm->kvm_run->exit_reason) {case KVM_EXIT_IO:…}…
}

根据代码可见,kvmtool发起进入Guest的代码处于一个for的无限循环中。当从KVM内核空间返回用户空间后,kvmtool在用户空间处理Guest的请求,比如调用模拟设备处理I/O请求。

在处理完Guest的请求后,重新进入下一轮for循环,kvmtool再次请求KVM模块切入Guest。

福利

留言点赞数量最多的前两名

CSDN 携手【机械工业出版社】送出

《深度探索Linux系统虚拟化:原理与实现》一本

截至12月25日18:00点

作者简介:

王柏生

资深技术专家,先后就职于中科院软件所、红旗Linux和百度,现任百度主任架构师。在操作系统、虚拟化技术、分布式系统、云计算、自动驾驶等相关领域耕耘多年,有着丰富的实践经验。

著有畅销书《深度探索Linux操作系统》(2013年出版)。

谢广军

计算机专业博士,毕业于南开大学计算机系。

资深技术专家,有多年的IT行业工作经验。现担任百度智能云副总经理,负责云计算相关产品的研发。多年来一直从事操作系统、虚拟化技术、分布式系统、大数据、云计算等相关领域的研发工作,实践经验丰富。

声明:本文经出版社授权发布,更多关于虚拟化技术的内容推荐阅读《深度探索Linux系统虚拟化:原理与实现》。

更多阅读推荐

  • 程序员应如何理解高并发中的协程

  • 为了追求更快,CPU、内存、I/O都做了哪些努力?

  • 我是Redis,MySQL大哥被我害惨了!

  • 被盗超800万美元,DeFi协议Nexus Mutual创始人遭黑客攻击损失惨重!

  • AI化身监工,上班还能摸鱼吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nacos 持久化 mysql(windows/linux环境)

文章目录1. 下载nacos-server2. 修改配置3. 创建数据库4. 初始化数据库脚本5. 启动nacos1. 下载nacos-server nacos-server-1.4.3.zip https://github.91chi.fun//https://github.com//alibaba/nacos/releases/download/1.4.3/nacos-server-1.4.3.zip解压 略 2. 修改配置 c…

HSF服务注册失败,项目启动后,EDAS列表无法发现注册的服务

背景: 本地使用edas轻量配置中心进行开发联调。 异常现象: 1.redis和edas已经启动正常,本地http://localhost:8080可以打开,但是配置列表和服务列表为空。 2.项目可以正常启动,但是postman调用时,发生hs…

解密阿里云高效病原体基因检测工具

1.背景介绍 病原体基因检测,为各种严重感染的诊断提供了基础。病原体检测流程分成五个步骤:(1)采集病人的样本,比方说静脉血,痰液,肺泡灌洗液,或者脑脊髓液等。(2&#…

企业使用云计算低效益怎么办?区块链或成良药

作者 | Ged Alexander翻译 | 火火酱,责编 | 晋兆雨出品 | CSDN云计算头图 | 付费下载于视觉中国在云资源浪费现象激增的大环境中,企业如何才能寻得一线生机?借助云计算服务,企业和开发人员能够通过互联网远程组织资源并运行工作负载。全球范围…

基于X-Engine引擎的实时历史数据库解决方案揭秘

实时历史库需求背景 在当今的数字化时代,随着业务的迅速发展,每天产生的数据量会是一个惊人的数量,数据库存储的成本将会越来越大,通常的做法是对历史数据做归档,即将长期不使用的数据迁移至以文件形式存储的廉价存储…

seata 整合 nacos(windows/linux环境)

文章目录一、下载安装nacos-server二、 seata-server下载配置2.1. 下载seata-server-1.4.2.zip2.2. 修改配置2.3. 创建命名空间2.4. 配置registry.conf2.5. 创建数据库2.6. 初始化sql脚本2.7. 配置config.txt2.8. 创建nacos-config.sh2.9. 初始化脚本数据到nacos2.10. 数据验证…

加密相关(对称加密、非对称加密、信息摘要、数字签名、CA数字证书)

1.对称加密: 说明:加密的密钥和解密的密钥相同;效率快;适合加密大信息量 常见算法:DES、3DES、AES、RC-5 块加密: 流加密:数据量大时效率高 2.非对称加密: 说明:加密的…

ClickHouse内核分析-MergeTree的存储结构和查询加速

注:以下分析基于开源 v19.15.2.2-stable 版本进行 引言 ClickHouse是最近比较火的一款开源列式存储分析型数据库,它最核心的特点就是极致存储压缩率和查询性能,本人最近正在学习ClickHouse这款产品中。从我个人的视角来看存储是决定一款数据…

“智汇光大 E启未来” 中国光大集团ESBU协同核心系统1.0正式发布

12月22日,“中国光大集团ESBU协同核心系统1.0”正式发布,标志着光大集团战略和光大数字化发展取得又一重大进展。光大集团党委书记、董事长李晓鹏现场发布“E-SBU协同核心系统”及“光大云生活”超级APP。集团党委副书记、副董事长、总经理吴利军在发布会…

云原生之路:容器技术落地最佳实践

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 阿里妹导读:随着容器技术的快速发展和广泛应用,毫无疑问云原生技术是未来发展的必然趋势。作为国内最…

SpringBoot微服务项目构建war包 部署排除指定jar

文章目录一、构建war包部署SpringBoot项目二、构建war包2.1. 适用范围2.2. 构建war包三、部署排除指定jar3.1. 下载排除插件3.2. 搜索部署排除指定jar3.3. 排除部署指定jar3.4. 验证3.5. 核心理念一、构建war包部署SpringBoot项目 如何把springboot项目构架war包部署到tomcat上…

软件设计师 - 算法思想

文章目录递归和迭代软考常见算法思想分治法回溯法贪心法动态规划法递归和迭代 递归:函数不断的调用自己,存在终止条件,分为递推和回归两部分; 迭代:不断用变量的旧值递推新值的过程,当前保存的结果作为下一…

毕业两年升主管,自沉稳而后顾人 对话阿里云MVP陈琦

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 简介: 1993年出生,毕业2年,团队主管,这是我对陈琦产生好奇的原因。但随着他优…

极道创始人吴江:企业级数据系统,初创一样可以做出好产品

随着云、大数据炒作热度褪去,对数据的存储计算技术正在回归理性。在存储这条传统toB市场的赛道上,创业远比toC市场复杂艰难许多。近日,一家以分布式文件存储创业,集合了存储计算与数据分析的初创公司——极道,表示从20…

2020年阿里云年中大促【福利】【选品】全攻略

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 2020年阿里云年中大促活动于6月1日正式上线啦!活动时间为:2020年6月1日至2020年6月30日主会场链接&am…

使用Istio进行多集群部署管理(2):单控制平面Gateway连接拓扑

单控制平面拓扑下,多个 Kubernetes 集群共同使用在其中一个集群上运行的单个 Istio 控制平面。控制平面的 Pilot 管理本地和远程集群上的服务,并为所有集群配置 Envoy Sidecar 代理。 集群感知的服务路由 Istio 1.1 中引入了集群感知的服务路由能力&am…

智能制造的灾备问题如何解决?

提起压力、温度校准行业会让大部分非专业人士感到陌生。但实际上,在我们的日常生活中,很多设备都是需要经过压力检测、温度检测、过程信号检测合格之后才正式投放市场使用的, 北京康斯特仪表科技股份有限公司(以下简称康斯特&…

疫情下开源数据库逆势增长,新基建下国产数据库迎机遇

2020年5月DB-Engines 数据库流行度排行大家都看了吗? 虽然 Top 10 与上月没有任何变化,但仔细观察本月的排行榜,Oracle 较上月几乎持平,仅微涨 0.02 分;相较而言,MySQL 增长明显,达到 14.29 分…

寻找长沙“科技之星”,CSDN星城大巡礼

2020年,长沙市委主要领导发出“软件产业再出发”的号召,并颁布了软件三年行动计划。今年5月,CSDN作为专业的IT社区,与长沙高新区签约,将全国总部落户长沙,这一战略决策,让CSDN与长沙的联结进一步…

分布式任务调度平台一站式讲解

文章目录一、传统的定时任务1. 传统的定时任务存在那些缺点2. 分布式任务调度3. 定时任务集群幂等性问题二、传统定时任务的实现方案2.1. 多线程2.2. TimeTask2.3. 线程池2.4. SpringBoot注解形式2.5. 基于Quartz三、常⻅分布式定时任务3.1. Quartz3.2. TBSchedule3.3. Elastic…