Appearance
虚拟机
2026 大纲 一(六)虚拟机。
让操作系统以为自己在管硬件,其实它管的也是假的
本章一路讲下来,操作系统始终是那个站在最上面做主的角色:它在内核态, 用户程序在用户态,特权指令只有它能执行。这一节把这个格局再翻一层—— 如果我们想在一台机器上同时跑好几个完整的操作系统呢?
它们每一个都认为自己独占硬件、每一个都要在内核态执行特权指令。 显然不能都让它们如愿,否则彼此立刻打架。所以必须再加一层: VMM(虚拟机监控程序,也叫 Hypervisor),由它真正掌握硬件, 而把每个 Guest OS 降到用户态去跑。
"真正处于内核态的是 VMM,Guest OS 被降到用户态"——这一句是整节的根, 后面所有技术难点都由它派生。
难点在哪?Guest OS 被降级之后,它照样会执行关中断、写页表基址这类指令。 理想情况下这些指令在用户态会触发异常、陷入 VMM,VMM 就能替它"假装"做了—— 这套办法叫陷入-模拟。可现实机器上偏偏有一类指令, 在用户态执行既不陷入也不报错,只是安静地返回一个错误答案。 VMM 收不到任何通知,Guest OS 拿着错答案继续跑。
这一节的四种 CPU 虚拟化方案、内存的三层地址、I/O 的三条路, 全都是围绕"怎么让该陷入的都陷入、以及陷入太频繁怎么办"展开的。
一、敏感指令:整篇的枢纽
Guest OS 跑在用户态。它执行一条敏感指令时,若这条指令同时是特权指令,硬件就产生异常并陷入 VMM;VMM 拿到控制权,在自己维护的那份虚拟机器状态上模拟出效果,再让 Guest 继续——三条性质同时满足,因为绝大多数指令是非敏感的,直接在硬件上跑。
麻烦全在"敏感但不特权"这一类上:它读或改了关键状态,却在用户态执行时既不陷入也不报错,只是安静地返回一个"当前是用户态"的结果,或者干脆什么也不做。于是 VMM 完全没有介入的机会(没有异常就没有通知),Guest OS 据一个错误答案做判断却毫不知情,等价性被打破。这正是 x86 在很长一段时间里无法用单纯的"陷入-模拟"虚拟化的原因。
三条性质各自违反了会怎样(想弄清"什么叫做成功地虚拟化"这个判据的来历时展开)
| 性质 | 含义 | 违反了会怎样 |
|---|---|---|
| 等价性(保真) | 在 VMM 上运行的程序,行为应与在真实机器上运行基本相同 | Guest OS 会跑出与真机不同的结果,等于换了一台机器 |
| 资源控制(安全) | VMM 完全掌控全部物理资源,Guest 不能绕过它直接碰硬件 | 隔离失效,一台虚拟机能影响别人 |
| 效率 | 绝大多数指令由硬件直接执行、无须 VMM 介入 | 若每条指令都要软件模拟,性能塌方 |
二、CPU 虚拟化:四种方案是一条演进线
| 方案 | 做法 | 它在解决什么 | 代价 |
|---|---|---|---|
| 陷入-模拟 | Guest 执行特权指令时产生异常,VMM 捕获并模拟执行 | 敏感指令都是特权指令时的标准解法 | 每次陷入都有开销;对"敏感但不特权"完全失效(根本不会陷入) |
| 二进制翻译 | VMM 在执行前扫描 Guest 的指令流,把敏感指令替换成能陷入 VMM 或直接调用 VMM 的等价代码 | 专门补那个漏——既然它不会自己陷入,就在执行前把它换掉 | 翻译耗时;要维护翻译缓存;实现复杂 |
| 半虚拟化 | 修改 Guest OS 源码,把敏感操作替换成对 VMM 的显式调用(Hypercall) | 换个方向补漏——不去猜代码里有什么,直接让 Guest 主动报告 | 必须能改 Guest 源码,闭源系统用不了;Guest 与 VMM 耦合 |
| 硬件辅助(VT-x / AMD-V) | CPU 增加根模式/非根模式两套完整特权级:Guest OS 在非根模式下仍运行在它自己的"内核态",敏感指令按硬件配置自动触发 VM Exit | 从根上消灭问题——"敏感但不特权"这一类不复存在 | 依赖 CPU 支持;每次 VM Exit/Entry 仍有固定开销 |
① 陷入-模拟是理想情形下的标准答案 → ② 现实机器有"敏感但不特权"指令,它失效 → ③ 软件上两条补救路:二进制翻译(Guest 不知情)与半虚拟化(Guest 知情且配合)→ ④ 硬件直接把"所有敏感指令都能陷入"这个前提造出来,前两条补救路的必要性大幅下降。一句话:前两种是"在软件层面把不陷入的变成陷入",第三种是"让 Guest 主动来陷入",第四种是"让硬件保证一定陷入"。
三、内存虚拟化:多出来的一层地址转换
| 层次 | 地址 | 谁维护这张映射表 |
|---|---|---|
| Guest 应用视角 | GVA(Guest 虚拟地址) | Guest OS 的页表 |
| Guest OS 视角 | GPA(Guest 物理地址)——Guest 以为这是真实物理内存,其实不是 | Guest OS 认为自己说了算 |
| 真实硬件 | HPA(宿主机物理地址) | VMM |
Guest OS 会去写页表基址寄存器、指向它自己那张 GVA→GPA 的页表;可硬件真正需要的是一张 GVA→HPA 的表。影子页表把两张表合成一张交给 MMU,开销集中在"页表修改时"(改一次同步一次,访存无损),且每个 Guest 进程都要维护一张,内存占用高;EPT/NPT 让 MMU 支持两级遍历,开销分摊到"每次 TLB 未命中时"(改页表零成本,转换变慢),并配套引入带虚拟机标识的 TLB 表项减少切换刷新。判据是负载特征——页表改动频繁(如进程频繁创建销毁)的选 EPT,现代系统普遍使用 EPT。
四、I/O 虚拟化:三条路
| 方案 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 全模拟(设备模拟) | VMM 用软件完整模拟一个常见物理设备(如某型号网卡)。Guest 用现成驱动,对虚拟化毫不知情 | Guest 完全不用改,兼容性最好 | 每次 I/O 端口访问都要陷入 VMM 并软件模拟,性能最差 |
| 半虚拟化 I/O(virtio) | Guest 里装一个知道自己在虚拟机中的专用驱动,通过共享内存中的环形队列批量把请求交给 VMM | 一次陷入处理一批请求,性能大幅优于全模拟 | 需要在 Guest 里安装专用驱动 |
| 设备直通(IOMMU + SR-IOV) | 把物理设备(或它虚拟出的一个功能)直接分配给某个 Guest,由 IOMMU 把设备发出的 DMA 地址从 GPA 翻译成 HPA 并做隔离 | 接近原生性能,VMM 几乎不介入数据路径 | 设备被独占(SR-IOV 可缓解);依赖硬件支持;虚拟机迁移变困难 |
五、两类 VMM
第一类(Type 1):VMM 直接跑在硬件上,自身就扮演"操作系统"的角色,直接管理 CPU、内存与设备。
第二类(Type 2):VMM 只是宿主 OS 上的一个普通应用程序,要访问硬件必须通过宿主 OS 的系统调用。
| 比较 | Type 1 | Type 2 | 判据 |
|---|---|---|---|
| VMM 下面还有没有 OS | 没有 | 有(宿主 OS) | 这一行是根 |
| 一次 I/O 要穿几层 | Guest → VMM → 硬件 | Guest → VMM → 宿主 OS → 硬件 | 多一层就多一次态切换与数据拷贝 |
| 谁掌控物理资源 | VMM 自己 | 宿主 OS(VMM 只能申请) | Type 2 的调度受宿主 OS 摆布,实时性差 |
| 安装与管理 | 复杂(要独占整机) | 简单(装个软件即可) | 由前三行决定性能与易用性的取舍 |
六、虚拟机与进程的对比
| 比较 | 虚拟机 | 进程 |
|---|---|---|
| 隔离边界画在哪 | OS 级隔离——每台虚拟机里跑一个完整的 OS | 进程级隔离——各进程共用一个内核 |
| 运行内容 | 完整的操作系统 + 其上的所有应用 | 单个程序 |
| 资源消耗 / 启动速度 | 大 / 慢(要走一遍完整引导) | 小 / 快 |
| 故障影响 | 一台虚拟机崩溃不影响其他 | 一个进程崩溃不影响其他,但内核崩溃则全崩 |
考点速记
- 真正处于内核态的是 VMM,Guest OS 被降到用户态——VMM 的特权级严格高于 Guest OS。若两者同级,Guest 一执行特权指令就直接生效,VMM 拦不住,整套机制瓦解。
- 成功虚拟化要同时满足三条性质:等价性(行为与真机基本相同)、资源控制(VMM 完全掌控物理资源)、效率(绝大多数指令由硬件直接执行)。
- 特权一定敏感,敏感不一定特权;当且仅当全部敏感指令都是特权指令时,"陷入-模拟"才自动成立。
- "敏感但不特权"是全部麻烦的源头:用户态执行它既不陷入也不报错 ⇒ VMM 收不到通知、Guest 拿到错答案。二进制翻译(背着 Guest 改指令流)与半虚拟化(让 Guest 主动 Hypercall)是两条补救路,判据是 Guest 知不知情、源码要不要改;硬件辅助(VT-x/AMD-V)则从根上取消了这一类。
- 内存多一层 GVA→GPA→HPA,而 MMU 只认一张页表。影子页表在软件里合成一张 GVA→HPA 表,开销压在"改页表时";EPT/NPT 由硬件走两级,开销分摊到"TLB 未命中时"。
- I/O 三条路按陷入频率排序:全模拟 → virtio 半虚拟化 → 设备直通/SR-IOV。直通必须有 IOMMU——否则设备 DMA 拿到未翻译的 GPA,一台虚拟机能改写另一台的内存。
- Type 1 / Type 2 的唯一判据是 VMM 访问硬件要不要经过另一个操作系统。KVM 装上后 Linux 内核自身就是 Hypervisor,更接近 Type 1。
- 虚拟机可以跨 ISA:软件全仿真(如 QEMU)能在一种指令集的主机上模拟另一种指令集,代价是每条指令都要翻译、性能很低。所以"虚拟机的 ISA 必须和宿主机相同"是错的。
- 虚拟机是 OS 级隔离,进程是进程级隔离:前者跑完整操作系统、资源消耗大启动慢,一台崩溃不影响其他;后者轻量启动快,但内核崩溃则全崩。
这一节在真题里被考过的形式:
大纲把虚拟机单列成一条是近年的事,至今只出过一道选择题, 且考的是第一条速记——VMM 和 Guest OS 谁的特权级高。
- 判断虚拟化技术的四条说法,选错误的(2025-24)。错项是 "VMM 与操作系统特权级相同"。VMM 必须比 Guest OS 高(硬件辅助下 Guest 在非根模式,VMM 在根模式,俗称 Ring -1),否则截获不了特权指令。⚠️ 另一个值得注意的选项是 "可以用一台主机模拟多种 ISA",它是对的——软件全仿真能跨指令集,别因为"虚拟机不就是切一台机器出来吗"而误判。
复习优先级:按选择题准备,重点只有第一条和第三、四条。 "VMM 特权级高于 Guest OS""特权一定敏感、敏感不一定特权""陷入-模拟成立的充要条件" 这三句是全部得分点。影子页表与 EPT 的取舍、I/O 三条路、Type 1/Type 2 至今没考过, 理解各自的判据即可,不必记具体产品名。
易错:认为 VMM 与 Guest OS 特权级相同。VMM 必须更高,否则拦不住 Guest 的特权指令。
易错:认为虚拟机不能跨 ISA。软件全仿真可以,只是慢。
易错:把"特权指令"和"敏感指令"当成一回事。特权一定敏感,敏感不一定特权,而后者正是全部技术难点的来源。
易错:混淆二进制翻译与半虚拟化。判据是 Guest 知不知情:翻译是背着它改指令流(闭源系统也能跑),半虚拟化要改它的源码。
易错:认为设备直通不需要额外硬件支持。必须有 IOMMU为设备的 DMA 地址做翻译与隔离。
易错:认为影子页表和 EPT 只是新旧之别。两者是把开销压在不同位置——改页表时 vs TLB 未命中时。
相关知识
操作系统引导|CPU运行模式(内核态与用户态)|系统调用|进程基本概念