1.5.9 虚拟化问题

更新于 2026年10月10日 版权声明
1.5.9 虚拟化问题

对于X86系统架构的CPU而言,至少在32位领域,有太多让人头痛的条条框框,但作为一条总则,它们都包含有环转换器(Ring Transitions)和有关指令。从概念意义上说,环是一种划分系统特权级别的方法(因此“Ring”也称作特权环)。你可让操作系统运行在一个特权级别上而不会使之被用户程序更改。这样即使你的程序出了问题,它也不会导致系统崩溃,而操作系统能取得控制权,关闭出毛病的程序。这些环强行控制系统的不同部分。

Intel公司的X86系列CPU(包括80386、80486、Pentium、Pentium Pro、Pentium Ⅱ、Pentium Ⅲ以及现在的Pentium 4CPU),提供4个特权级别R0、R1、R2和R3。较大的数字表示较低的特权,我们可简单理解为运行在某一级别的程序无法改变运行在较小数字级别上的程序,但较低数字级别上的程序可干扰甚至控制运行在较高数字级别的程序。

在实际运用中,被经常用到的只有R0和R3,即最高级别和最低级别。操作系统运行在R0上,而用户程序运行在R3上。X86架构在向64位扩展时,采用的方法之一就是通过去掉中间的特权级别——R1和R2。几乎没有人注意到它们消失了,除了那些使用虚拟化技术的特定人群。

像VMware这类软件模式的虚拟化机(Virtual Machines,以下简称VM)显然必须运行在R0级别上,但如它们要想保持完全控制权,就必须使操作系统在这个级别之外。最显而易见的解决办法是强迫主机操作系统运行在一个较低级别的环中,如R1。它们的部分代码原先被设定为从R0到R3,而不是R1到R3。虽然在PV环境中,你能修改操作系统从而使它工作得很好,但如果你要找到一个圆满的解决方法,就必须使操作系统工作在R1级别中。

可如此一来又出现问题了,有些指令只有当它们从R0级里发出或发往R0级时才会工作,如果不在正确的环中,这些指令会运作得很古怪。如果你试图这么去做,会有很不好的后果。让代码在正确的环中执行确实能防止操作系统破坏VM,同时也防止运行在主机操作系统上的软件破坏操作系统自身。这就是所谓的“0/1/3”模式。

还有一种模式被称为“0/3”模式。这种模式将VM放入R0级别中运行,而将操作系统和用户程序都放入R3级别中。但从本质上而言,它还是像“0/1/3”模式一样去处理其他事情。在R3级别里,有特权的操作系统能更轻松地执行用户程序,由于不存在环的阻隔,也使它运行得更快一些,但系统稳定性不佳。

另外一个方式去使用“0/3”模式,就是让CPU保有两份运行于R0级别中的事物的页表。一份为操作系统,另一份为运行在R3级别中的老程序。这样可拥有一份完整的存储器保护集,用来把用户程序隔离到操作系统空间之外。当然,这同样需要消耗性能,只是以不同的方式罢了。(https://www.daowen.com)

概括来说,在“0/1/3”模式中,系统安全性更高一些,但从R3到R1、R3到R0或R1到R0转换时性能会受到一些影响,反过来也是。在“0/3”模式中,只存在R0与R3之间的转换,所以它潜在地比一个非主机操作系统运行得更快一些。但如你碰到一个问题,“0/3”模式比“0/1/3”模式更容易出现蓝屏。尽管未来将广泛使用“0/3”模式,主要是因为上文我们提到向在64位扩展时已去掉了R1和R2,所以你必须被迫使用“0/3”模式。对计算机而言,这被称作是进步,同样,毁灭性的崩溃被认为是“古怪”行为。

理论上,如果你可忍受一点不稳定性,或者在“0/1/3”模式中牺牲一点速度,那么应该说很完美的。可它们在某些方面确实还存在一些缺陷,主要存在以下4点。首先是那些检验指令自己所在环的指令,另外是那些处在错误的环中却没有正确保护CPU现场的指令。最后两点是截然相反的,就是那些应引发错误却没有导致错误的指令,以及那些本不该导致错误却引发许多错误的指令。所有这些都让编写VM的天才程序员们活得不轻松。

其中第一点是显而易见的。如果你给予操作系统R1级别的特权,当它检验自己运行所处的环时,它会返回1而不是0。如果此时运行于该系统的一段程序期望自己应该处在R0环时,那么它会因为得到的是R1而导致错误。这会导致蓝屏的出现,存储器清除或另一些不理想的后果。二元码转译技术可捕捉到这种错误,并把返回值伪装成0,但这意味着需要几十上百条指令来完成这一工作,显然速度受到极大影响。

保护现场是一个潜在的更糟糕的问题,有些CPU里的东西在上下文开关程序中并不是很容易被保存的。那些隐藏的段寄存器状态就是一个很好的例子。一旦它们被载入主存,其中一部分无法被保存,导致内存常驻部分和CPU中实际值间的不同而引起意外中断。当然我们可为它们设立工作区,但这样做极为复杂且需付出很高的代价使之表现得聪明一些。

那些本该引起某些问题却没有导致这些问题的指令也是摆在我们眼前的一道难题。如果你期望一条指令应在你后面的设计的中断陷阱中造成错误,但却没有,这一点也不会让人因为没有错误而高兴。与此相反的情况也极为常见,如果不在正确的环中向CR0和CR4写入,则会产生错误,导致系统崩溃。虽然这两种错误在你不注意时可被修正,但却造成很多性能损失。

虚拟化技术就是要将操作系统放在一个它本不应该在的地方,不断地运转去尝试解决所有扑来的问题。虚拟化技术存在许多问题,这些问题也不断地发生,所以性能损失也就没什么奇怪的了。

↑上一章 ↓下一章
关注公众号获取验证码
复制内容需要验证码(7.99元/天)