虚拟机是怎么实现的?

原文转自:http://www.manio.org/cn/virtual-machine-implementation/

997年,斯坦福的Mendel Rosenblum带着Edouard Bugnion, Scott Devine在SOSP上发了篇论文,叫做Disco: running commodity operating systems on scalable multiprocessors (http://research.cs.wisc.edu/areas/os/Qual/papers/disco.pdf)。发了之后,我想他们应该是觉得这个主意太好了,就开了家公司,名叫VMWare。

这篇论文起名叫Disco(迪士高)是因为虚拟机本身不是一个新的东西,大概在上世纪70年代就有了。作者们为了表示敬意,或者是显示这是一个复古的东西,就把这个项目取名为disco。这篇论文介绍了虚拟机关键技术,用来回答这个问题再合适不过了。(多年之后,OSDI上的另一篇论文(Memory Resource Management in VMware ESX Server)介绍了一些VMWare的改进。近年来论文越来越多。)

当初他们为什么要做虚拟机?简单说就是,新硬件层出不穷,但是OS赶不上。当初,他们想在Stanford的ccNUMA机器上跑IRIX(一个操作系统)。可是IRIX跑不起来。他们觉得修改OS或者写一个新的OS太难了(因为一个操作系统从出生到成熟要很长的时间,无数BUG要FIX,无数的新功能要增加。。。那样人家博士要怎么毕业。。)。所以,他们决定用虚拟机。

对于他们的项目,虚拟机大致有下面这些好处:

  1. 只要对商业OS做简单地修改,就能让他们在多个VM(Virtual Machine)间共享内存。
  2. Flexible。除了论文里的IRIX,实际上其他的OS也能跑。
  3. 扩展性好。系统可以以虚拟机为单位扩展。
  4. fault-containment。每一个VM都是一个几乎独立的个体,一个坏了,不影响另一个。
  5. 新老软件可共存。比如,新的软件只能在Linux-3.15跑。你可以用两个VM,一个是Linux2.6,一个是Linux-3.15。

这篇文章回答下面这几个实现虚拟技术的关键问题:

  1. VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?
  2. 有那么多个操作系统一起运行,内存是怎么管理的?
  3. 多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?

注意:如无特别说明,这篇文章里所说的处理器是指MIPS,而不是x86。

VMM(Virtual Machine Monitor, 或者叫hypervisor)是怎么管住Guest OS的?或者说,皇上(VMM)是怎么防止大臣(OS)夺权的?

要理解VMM是怎么工作的,我们得先了解没有VMM的时候,系统是怎么工作的。在没有VMM的时候,计算机系统中的”应用”可分为用户进程(比如VIM)和操作系统。他们分别运行在不同的模式中(mode)。我们用一个类比来解释系统中的模式(mode)。模式这个机制是用来限制一段指令所在的环境的权限的,它是需要处理器的支持的。MIPS结构当时有三个模式:用户模式(user mode),长官模式(supervisor mode,原谅我的翻译…)和内核模式(kernel mode)。这三种模式分别对应于人类社会里的民宅、官衙和金銮殿。显而易见,在金銮殿里的人拥有的权限最高,民宅里的最低。我们可以说,在没有VMM时,用户进程住在民宅里,县衙空着,OS住在金銮殿里(如图)。用户可以直接做一些不用什么特权的事情(unprivileged instructions),比如计算1+1。做这些事情不经过OS。但是,有些要特权才能做的事情,一定要经过OS。比如保存正在编辑的文档到硬盘(IO operations)。访问硬盘是特权操作是因为硬盘是共享的资源,要有人管着,不能让人乱来。试想,要是人人都能读写档案馆的档案,那不就乱套了。


VIM(用户进程)不能直接写磁盘上的文件。VIM必须请求在金銮殿里的操作系统来做。怎么请求呢?通过系统调用(system call)。系统调用的过程是这样的:比如要调用的是write(fd, buf, len, off),首先把fd, buf, len, off放到stack里,然后再把一个write()函数对应的号码(system call number)放到stack里,最后调用一个特殊的指令使CPU进入内核模式(图中的圈1)。在x86结构中,这个指令是int(中断)。在MIPS结构中,这个指令是trap。这个指令会引导CPU执行一段代码(trap handler),依照stack里的system call number 找到对应的函数(在这里是write()的实现),然后调用这个函数(函数的参数在刚才的stack里)。在这里函数里,操作系统调用文件所在的文件系统里的write()实现,文件系统使用磁盘的驱动来最终实现。所以文件的操作完成后,操作系统调用与trap功能相反的一个指令,回到VIM程序的指令里(图中的圈2)。

关于trap(陷阱)指令:把这个指令叫trap(陷阱)是非常形象又准确的。当trap指令执行里,就像是掉入了有更多特权的人(比如皇上)设置的陷阱里一样,任人摆布。


操作系统维护自己的特权的过程大概就是这样。但是这个特权等级到底是怎么实现的呢?我们可以想像CPU里有一个特权状态(privileged state bit)。状态为开(On)的时候,CPU的特权等级高,你可以做任何事,包括转到低特权状态。关(Off)的时候,你所能做的事情就所限了。那怎么从off状态转到on状态呢?你必须到执行CPU的特殊指令,这个指令会把你带到一个特定的地方执行操作系统的指令,检查你是不是有进入高特权状态的权限。这就像是在机场,你可以很容易地从登机口到售票大厅,可是你要从售票大厅到登机口,你就得过安检。另外,为什么操作系统就能有高特权呢?Hmm…因为操作系统一开始就把那占了,之后运行的应用程序就只能听它使唤了。

现在,终于要说VMM(virtual machine monitor, 或者叫hypervisor)是怎么实现的了。如下图:

现在VMM进了金銮殿,有了最高的特权。操作系统被放到了官衙里(但是它自己并不知道)。用户进程还是在民宅里住着。要是现在用户进程VIM调用write(),会发生什么?在这种情况下,用户进程会trap到VMM(拥有kernel mode)里去。但是,VMM并不知道如何处理write()。所以,VMM接下来会调用操作系统的里对应的trap handler,这个handler会执行文件系统的write()。 在执行过程中,文件系统的非特权指令可以直接在真的CPU上执行。要是文件系统运行特权指令,CPU会从操作系统(supervisor mode)trap到VMM(kernel mode)里去,由VMM仿真(emulate)操作系统要运行特权指令。之所以要由VMM来仿真,有几个理由。第一,VMM不相信操作系统。例如,在VMM上可能同时运行着几个操作系统,如果让其中一个操作系统执行直接内存访问的指令,它可能修改内存中另一个操作系统的代码或数据。第二,操作系统只了解虚拟的环境,并不知道实际的环境。例如,操作系统想要写/dev/sda3的第10个sector。但是,实际上/dev/sda3可能对应的是VMM里一个叫/fake_dev/sda3.data的文件。这个时候,我们就需要VMM来把操作系统的指令转化为实际环境中的操作了。

仿真完特权指令之后,CPU会回到操作系统。当write()这个系统调用执行完之后,操作系统会调用一个特权指令(在MIPS里是rett指令),试图回到user mode。这个时候CPU又会trap到VMM,由VMM来完成最终的模式转换。

为什么VMM能够知道操作系统的trap handler在哪?系统中先有VMM。当你在VMM上安装操作系统的时候,操作系统会尝试调用特权指令安装trap handler。因为有最高特权的VMM实际上是监视着这一切的,所以它可以记录下trap handler的位置就行了。

总的说来,VMM占据了CPU的最高特权,使得在更低特权等级的操作系统无法进行有害操作,并且在实际环境中完成操作系统的需求。

有那么多个操作系统一起运行,内存是怎么管理的?

在没有VMM的时候,系统中有两种内存地址:虚拟地址(virtual address)和物理地址(physical address)。从虚拟地址到物理地址的转换有两种方式。方式一:在TLB(translate lookside buffer,硬件实现)查找。方式二:在页表(page table)中查找,找到之后把结果放到TLB中去。系统会先尝试方式一,要是找不到(TLB miss),就用方式二。


在有了VMM之后,系统中有三种内存地址:虚拟地址(virtual address),物理地址(physical address)和机器地址(machine address)。机器地址才是真正与内存条上的地址一一对应的。物理地址只是操作系统认为的物理地址。

当操作系统试着要使用特权指令来完成一个虚拟地址到物理地址的转换时(TLB miss),VMM就介入了(VMM监视着所有对特权寄存器的操作)。VMM会先使用操作系统内的代码来先完成虚拟地址到物理地址的转化(因为VMM并不知道这个映射关系)。然后,操作系统认为自己已经完成了转化,尝试去更新TLB(特权操作)。这个时候,VMM会介入,用一个叫个pmap的映射表找到物理地址对应的机器地址,用机器地址替换掉物理地址,然后把TLB更新为虚拟地址到机器地址的映射。之后,所有对这个虚拟地址的访问都会被转换为对相应机器地址的访问。(注意,MIPS用的是software-reloaded TLB,x86用的是hardware-reloaded TLB)

多个VM之间是怎么分享资源的?或者说,1GB内存怎么当2GB用?

我们知道,每一个虚拟机都要占用大量的内存空间。在内存有限的情况下,怎么在一台机器运行更多的虚拟机?幸运的是,不用的虚拟机之间在内存中数据可能会完全一致(比如,系统文件在内存中的缓存)。如要我们可以只在内存中保留一份数据,我们就行节省很多空间。Disco使用虚拟IO设备和虚拟网络设备来节省内存空间。

虚拟IO设备:当两个虚拟机从同一个磁盘上读同一个文件时,VMM会intercept DMA,然后就会发现这两个VM在使用同样的数据。这份数据只需要在机器内存里保存一份,然后修改pmap,使得两个VM的物理地址指向同一个机器地址就可以了。当任何一个VM更新这份数据,VMM会给它一份新的拷贝,原来的那份不做更改(copy on write机制)。 

虚拟网络设备:当使用NFS从VM1向VM2复制文件时,文件并没有被真正地复制。虚拟网络设备会更新VM2上的pmap,使之指向在内存中的文件,使得VM2上的操作系统认为自己已经有了这个文件。

后来,VMWare还有用hash来找相同的内存页然后再共享的技术。

时间: 2024-08-27 20:44:45

虚拟机是怎么实现的?的相关文章

XShell 连接虚拟机中的服务器 失败 、连接中断(Connection closed by foreign host.)

在使用XShell连接虚拟机中的服务器时,报以下错误并断开连接,之前连接还是挺稳定的,忽然就这样了 Last login: Thu Aug 10 21:28:38 2017 from 192.168.1.102 [[email protected] ~]# Socket error Event: 32 Error: 10053. Connection closing...Socket close. Connection closed by foreign host. Disconnected f

初识运维3--在虚拟机中安装Linux发行版系统(CentOS)的方法

在讲Linux系统发行版本的安装过程之前,先大略说明一下虚拟化. 虚拟化:将底层硬件资源抽象为用户更容易读懂和使用的逻辑抽象层的技术. 最早由IBM提出,现使用率较高的虚拟化软件平台有三类:VMware workstation.VirtualBOX.HyperV.在这里使用VMware workstation作为例子讲解说明安装过程. 虚拟化网络: 桥接模式:让物理机和虚拟机利用物理网络接口完成通信.虚拟机可以访问互联网. 仅主机模式:让虚拟机和物理机利用被虚拟出来的VMnet1网络接口完成通信

Windows10 使用Virtual Box一启动虚拟机就蓝屏(错误代码SYSTEM_SERVICE_EXCEPTION)解决方案

原文:Windows10 使用Virtual Box一启动虚拟机就蓝屏(错误代码SYSTEM_SERVICE_EXCEPTION)解决方案 一打开虚拟机电脑就立马蓝屏重启,新建虚拟机也没用,然后就开始百度,百度上全说什么驱动不对,然后我就卸载升级各种驱动,然后各种重装VirtualBox,还是不行,搞了一两个小时,都快放弃了.决定上个google,终于看到一篇文章说是因为Hyper-V与Virtual Box冲突了,只需要在控制面板关闭就行.然后抱着试一试的心态. 首先我们先打开控制面板.按Wi

VMware链接Linux虚拟机

最近刚刚开始学习Linux,觉得每次从桌面切换到虚拟机还需要按"alt+ctrl".甚是麻烦,于是就想用ssh连接虚拟机这样就可以不用频繁切换,省去了很多麻烦.不过本人实在智障,这么简单的事情还困住了好半天....所以记录一下,方便日后参考: 首先,需要一个虚拟机(我的是centos6.9,VMware平台),需要进入"网络适配器"选项调整虚拟机的网络连接模式到 桥接模式 .之后虚拟机的相关设置就完成了...(的确很智障...) 其次,就是在实机上配置"网

通过VMWare安装Linux(Ubuntu) 虚拟机在Window10系统和问题解决方案

为了减少被喷的可能,小编自我介绍一下.小编不是技术大牛,只是暂时还算比较热衷IT程序媛.小编写的可能不是很深奥,但是保证是如实书写,主要是目的是为了积累和记录学习的过程. 安装VMWare 如下链接是安装VMWare参考链接,虽然我当时参考的链接忘记存储了,这个地址也是用的还有一些VMWare功能介绍,值得点赞! http://blog.csdn.net/lamp_yang_3533/article/details/53136474 Window10,Intel CPU遇到了问题.我们需要手动在

《深入理解Java虚拟机》笔记04 -- 并发锁

Java虚拟机在操作系统层面会先尽一切可能在虚拟机层面上解决竞争关系,尽可能避免真实的竞争发生.同时,在竞争不激烈的场合,也会试图消除不必要的竞争.实现这些手段的方法包括:偏向锁.轻量级锁.自旋锁.锁消除.锁膨胀等 1. 偏向锁 偏向锁是JDK1.6提出的一种锁优化方式.其核心思想是:如果程序没有竞争,则取消之前已经取得锁的线程同步操作.也就是说,若某一锁被线程获取后,便进入偏向模式,当线程再次请求这个锁时,无需再进行相关的同步操作,从而节省了操作时间.如果在此之间有其他线程进行了锁请求,则锁退

Mac系统下虚拟机VMware Fusion下Win10如何通过Navcat连接Mysql 5.7

最近一直在折腾Mac系统,原先对Mac使用也不是很熟悉,所以安装过程中出现了很多问题.为了以后查阅方便,当然也为了使得和我一样的小白少踩一些坑, 所以就记录一下这些问题. 首先说一下VMware Fusion这个虚拟机软件吧.我下载的官方最新的版本8.5.7.然后开始安装,安装比较容易.最麻烦的就是如何安装WIn10系统呢?一开始我采取按部就班的方法,通过Mac自带的浏览器Safari去下载Win10 ISO的文件.结果速度太让人崩溃了,非常慢.后来我尝试把ISO通过百度网盘离线下载的方式先下载

译:SOS_SCHEDULER_YIELD类型等待在虚拟机环境中的增多

原文出处:Increased SOS_SCHEDULER_YIELD waits on virtual machines 注: 原文的用词是Increased,想译作增强(增长),或者加强,这么译起来是褒义词,而原文要表达的Increased并没有褒义的含义,最起码是一个中性的含义,想来想起用一个“滋长”偏编译的含义还是比较合适的,感觉还是有点过于贬义了,还是用最通俗的增多吧.个人英语水平有限,另外就是对于文中提到的“rdtsc周期”也不是非常清楚,翻译的也不是很清楚,权当是自娱自乐.总是原文的

VMware虚拟机交换机介绍

创建虚拟机时自带网卡需要桥接网络,这时使用虚拟交换机虚拟交换机:标准交换机.分布式虚拟交换机 虚拟交换机提供的功能:网络桥接.在线迁移 标准交换机:单个主机的虚拟交换机配置,在ESXI主机上创建,在另一台ESXI主机是不可见的分布式虚拟交换机:在vCenter server上创建,在所有ESXI主机都是可见的,便于网络集中管理和规划,虚拟交换机端口类型:VMkernel.虚拟机端口组VMkernel:用于存储.vMotion.管理,需要配置IP地址虚拟机端口组:针对虚拟机,用于上行传输业务的端口

虚拟机VMware的安装以及操作系统的安装1

打开虚拟机!我们对虚拟机进行设置,这里我们选择自定义(高级) 虚拟机硬件兼容性---默认的就可以,因为低版本的不兼容新硬件的和新系统 安装来源我们选择"稍后安装操作系统" 现在我们来选择需要安装的操作系统和版本(我以windows为例 版本:需要安装什么版本的就选择什么版本的) . 设置虚拟机的名称和安装路径(安装路径尽量不要放在C盘) 处理器的配置(默认就可以) 设置虚拟机的内存(一般按推荐就可以 记得不要超出你电脑的内存!会很卡的) 设置网络类型(根据自己的需要选择 后期也可以更改