最近在某台 Ubuntu 22.04 的工作机上装 VirtualBox 7.0,打算开一个 Win10 虚拟机做测试环境,结果连续碰到两个经典报错:一个卡在内核驱动加载,一个卡在硬件虚拟化开启。这两个报错单看任何一个都不算冷门,但凑在一起,而且都是在全新安装环境下出现的,排查起来确实有点绕。把整个分析和修复过程整理出来,给同样在这个组合上栽过跟头的朋友做个参考。
1. 环境定位:Ubuntu 22.04 + VirtualBox 7.0 的组合为什么会出问题
先说清楚我当时的宿主机环境:Ubuntu 22.04 LTS,内核版本 5.15.0-xxx-generic,CPU 是 Intel 平台,支持 VT-x。VirtualBox 用的是 Oracle 官方仓库的 7.0 系列,具体小版本是当时最新的 7.0.12。目标虚拟机是 Windows 10 22H2,分配 4 核 CPU、8GB 内存、128GB 动态虚拟磁盘。
1.1 版本选型的底层逻辑
选择 Ubuntu 22.04 作为宿主机,是因为它的 LTS 性质决定了内核和用户态组件相对稳定,VirtualBox 7.0 对 5.15 内核的支持也比较成熟。但这里有个很多人忽略的细节:Ubuntu 22.04 默认启用 Secure Boot,而 VirtualBox 的内核模块 vboxdrv、vboxnetflt、vboxnetadp 都是需要加载到内核空间的驱动,Secure Boot 开启时,内核只会加载经过签名验证的模块。这为后面的 Kernel driver 报错埋下了第一个雷。
另一个细节是 VirtualBox 7.0 对内核模块的构建方式。它依赖 Linux 内核头文件和编译工具链,安装后需要通过 dkms 或者手动调用/sbin/vboxconfig来编译模块。如果你的系统恰好升级过内核,或者安装 VirtualBox 时对应的内核头文件不完整,模块编译就会失败,表现就是启动虚拟机时报 Kernel driver 未安装。
1.2 报错的宏观分类:内核模块层与虚拟化指令层
这两类报错虽然都表现为“虚拟机无法启动”,但问题所在的层级完全不同。
Kernel driver 报错,本质是宿主机内核与 VirtualBox 之间的桥接层出了问题。VirtualBox 作为 Type-2 虚拟机监控器,必须依赖一个内核驱动来执行特权指令、管理物理内存和中断。这个驱动加载不上,虚拟机就失去了运行的基础。它属于“宿主机内核层”的问题。
VT-x 报错,本质是 CPU 硬件虚拟化能力没有被正确暴露或开启。VT-x(Intel Virtualization Technology)是 CPU 级别的一组扩展指令集,虚拟机监控器需要借助它来创建隔离的硬件上下文。如果 BIOS/UEFI 里关闭了虚拟化,或者宿主机自身就是虚拟机且没有开启嵌套虚拟化,VirtualBox 就会明确提示 VT-x 被禁用。它属于“CPU 固件层和硬件特性层”的问题。
把这两类问题分开看,排查路径就清晰很多。
2. Kernel driver 报错的根因分析与修复
2.1 现象与报错原文
启动 Win10 虚拟机时,VirtualBox 弹出一个错误框,标题是 "VirtualBox - Error In supR3HardenedMainInitRuntime",正文关键句子是:
Kernel driver not installed (rc=-1908) The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv.同时,如果你在终端里手动运行virtualbox启动图形界面,再尝试启动虚拟机,还会看到类似这样的补充日志:
WARNING: The character device /dev/vboxdrv does not exist. Please install the virtualbox-dkms package and the appropriate headers.这个 rc=-1908 错误码,几乎可以锁定为 vboxdrv 内核模块没有成功加载。
2.2 根因一:内核模块未编译或未加载
先在终端里检查模块状态:
lsmod | grep vbox如果输出为空,说明 vboxdrv 根本没有加载。接下来查看模块编译状态:
sudo /sbin/vboxconfig这时大概率会看到一行报错:
Building the main VirtualBox module ... fail!按顺序排查,最常见的原因是缺少内核头文件。Ubuntu 22.04 的内核头文件包名是linux-headers-generic,但它不是 VirtualBox 安装时自动拉取的强依赖。如果你的系统之前做过内核定制或者清理过/lib/modules/下的目录,头文件很可能不完整。
补装头文件并重新构建:
sudo apt update sudo apt install linux-headers-generic build-essential sudo /sbin/vboxconfig如果一切正常,你会看到三个模块的编译输出:vboxdrv、vboxnetflt、vboxnetadp,然后提示 "VirtualBox kernel modules are loaded"。
这里要给一个实操经验:不要用modprobe vboxdrv手动加载。因为 VirtualBox 在启动时会通过自身的初始化逻辑来加载模块,手动加载容易造成版本不一致。正确做法是跑完/sbin/vboxconfig后,再执行systemctl restart virtualbox.service(如果存在)或者直接重启宿主机。
2.3 根因二:Secure Boot 签名拦截
如果你按照上面步骤执行了/sbin/vboxconfig,但输出里出现的是这样的信息:
vboxdrv.sh: Stopping VirtualBox services. vboxdrv.sh: Starting VirtualBox services. vboxdrv.sh: Building the VirtualBox kernel modules. vboxdrv.sh: failed: Secure Boot is enabled. The kernel module 'vboxdrv' needs to be signed before it can be loaded.这说明问题不是头文件缺失,而是 Secure Boot 在拦截未签名的内核模块。现代 Ubuntu 发行版默认开启 Secure Boot,编译出来的 vboxdrv.ko 没有 Microsoft 或发行版信任的签名,内核拒绝加载。
解决方案有两种路径,我分别说。
路径 A:关闭 Secure Boot(适合个人开发机)
这个方法直截了当,但需要进 UEFI 设置。重启宿主机,在开机时按下 F2 / DEL / F10(不同主板不一样)进入固件设置,找到 Secure Boot 或 Security Boot,将其设置为 Disabled。保存退出后,再执行:
sudo /sbin/vboxconfig模块就能正常编译加载了。
注意:关闭 Secure Boot 会降低系统启动链的安全性,适合个人开发环境,生产环境不建议。
路径 B:使用 Machine Owner Key(MOK)签名(适合不想动固件设置的人)
这个方法保留 Secure Boot,但需要自己生成一个签名密钥并导入固件信任列表。步骤较多,但一次配置,之后重新编译内核模块都能用。
安装签名工具并生成密钥:
sudo apt install mokutil shim-signed openssl openssl req -new -x509 -newkey rsa:2048 -keyout vbox.priv -outform DER -out vbox.der -nodes -days 36500 -subj "/CN=VirtualBox Module Signing/"导入密钥到 MOK 列表:
sudo mokutil --import vbox.der这时系统会要求你设置一个临时密码,记住它。重启后,会进入蓝色 MokManager 界面,选择 "Enroll MOK from disk",定位到刚才的 vbox.der 文件,确认导入,输入临时密码,继续启动。重启完成后,再用这个密钥给模块签名:
sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 vbox.priv vbox.der /lib/modules/$(uname -r)/updates/dkms/vboxdrv.ko然后再执行/sbin/vboxconfig验证。这个方法对包括 NVIDIA 驱动在内的其他外部内核模块同样适用,配置一次长期受益。
2.4 修复后的验证方法
模块加载是否成功,不能只看启动虚拟机的窗口。要做三件事:
第一,检查内核模块列表:
lsmod | grep vbox正常状态应该看到 vboxdrv、vboxnetflt、vboxnetadp 三个模块,其中 vboxdrv 的 Used by 列会提示当前有几个虚拟机在使用它。
第二,检查设备节点:
ls -l /dev/vboxdrv应该存在一个字符设备文件,属主是 root,组是 vboxusers。如果这个文件不存在,说明模块没加载成功。
第三,把自己使用的系统用户加入 vboxusers 组:
sudo usermod -aG vboxusers $USER改完组后需要重新登录一次会话,否则访问 /dev/vboxdrv 时依然会被拒绝。这一步很多人容易漏,导致模块明明加载了,启动虚拟机时还是报权限错误。
3. VT-x 报错的根因分析与修复
3.1 现象与报错原文
Kernel driver 修好之后,再次启动 Win10 虚拟机,结果又弹出一个新的错误框:
VT-x is disabled in the BIOS for all CPU modes (VERR_VMX_MSR_ALL_VMX_DISABLED).在 VirtualBox 7.0 里,如果是在虚拟化环境里跑(比如在某云主机里又套了一层 VirtualBox),可能还会看到:
AMD-V is disabled in the BIOS (or by the host OS) (VERR_SVM_MSR_ALL_DISABLED).前者是 Intel 平台的典型提示,后者是 AMD 平台。我这边是 Intel CPU,所以重点是 VT-x。
3.2 根因一:BIOS/UEFI 层面关闭了硬件虚拟化
这个根因很朴素,但也很容易被忽略。很多 OEM 主机的出厂设置里,Intel Virtualization Technology 默认是 Disabled。特别是一些商务品牌机和迷你主机,厂商为了省电或稳定考虑,默认关闭这个选项,需要手动去固件设置里打开。
进 UEFI 设置的方法同上文一样,在开机时按 F2 / DEL / F10。不同品牌路径不同,一般在 "Advanced"、"Processor Configuration" 或 "Security" 菜单下,找 "Intel Virtualization Technology" 或 "VT-x",设置为 Enabled。Save & Exit 之后,在宿主机里执行下面命令,确认虚拟化已开启:
grep -E -c '(vmx|svm)' /proc/cpuinfo输出值大于 0,就代表虚拟化标志位已经暴露给操作系统了。另外,lscpu里也会显示:
Virtualization: VT-x如果输出了Virtualization标签但没有后面的类型,说明固件设置可能没生效,需要确认是否保存成功。
3.3 根因二:宿主机本身就是虚拟机,嵌套虚拟化未开启
这一步是很多人卡住的地方。如果你的“宿主机”其实是云服务器、公司虚拟机平台里的一台 VM,那么在 VM 里再装 VirtualBox 属于嵌套虚拟化(Nested Virtualization)。这种场景下,仅靠宿主机 BIOS 打开 VT-x 是不够的,还取决于外层虚拟化平台是否把硬件虚拟化指令透传给内层系统。
解决方案是登录外层虚拟化平台的管理界面,为这台 VM 打开嵌套虚拟化选项。比如在常见的管理平台上,需要设置 CPU 模式为 Host Passthrough 或勾选 Expose hardware virtualization to the guest OS;在命令行环境下,可能需要给 VM 的配置加一个 CPU 特性标志。这个操作无法在 Ubuntu 系统内部完成,必须借助外层平台的管理端。
我遇到的正是这个场景:XX云平台上的一台 VM,默认没有暴露 VT-x 给客户机。在管理界面开启嵌套虚拟化后,Ubuntu 里grep vmx /proc/cpuinfo才真正出现标志位。
提示:嵌套虚拟化场景下,即使 VT-x 成功透传,虚拟机性能也会有额外损耗,尤其是在内存访问和中断处理上。如果只是临时做实验问题不大,但不要指望跑重负载的 Windows 虚拟机。
3.4 修复实验证
VT-x 修好后,VirtualBox 里还需要注意一个细节:虚拟机的系统设置中,“硬件虚拟化”相关选项通常默认是全自动的,但如果你曾经手动调整过,需要确保 Processor 选项卡里的 "Enable VT-x/AMD-V" 是勾选状态。这个选项在 7.0 版本里位于:
设置 -> 系统 -> 处理器 -> 硬件虚拟化 -> 启用 VT-x/AMD-V(如果是 Intel 平台还可能显示 "Enable Nested VT-x/AMD-V")注意,那个 "Enable Nested VT-x/AMD-V" 选项是给虚拟机内部再跑虚拟机用的,我们这里是 Windows 10 客户机,不需要勾选。如果误开了,反而可能引起性能下降。
验证 VT-x 是否被客户机正确识别,最直接的方式是进入 Windows 10 后打开任务管理器 -> 性能 -> CPU,查看“虚拟化”一栏是否显示“已启用”。也可以在 Windows 里运行systeminfo,在 Hyper-V 相关条目下看虚拟化固件状态。
4. 一次性完整实操:从零到 Win10 跑起来
既然两类核心报错都拆完了,我索性把这台机器从装 VirtualBox 到 Win10 系统正常运行的完整流程写一遍,包含关键参数和踩坑点。
4.1 安装 VirtualBox 7.0 的推荐方式
不要在 Ubuntu 软件中心里装 6.1 老版本,也不要只apt install virtualbox装发行版仓库里的版本,关于 7.0 的功能更新我就不多说了,直接说安装方法。最稳的是用 Oracle 官方 apt 仓库。
添加仓库和安装:
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle-virtualbox-2016.gpg] https://download.virtualbox.org/virtualbox/debian jammy contrib" | sudo tee /etc/apt/sources.list.d/virtualbox.list wget -O- https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo gpg --dearmor --yes --output /usr/share/keyrings/oracle-virtualbox-2016.gpg sudo apt update sudo apt install virtualbox-7.0 dkms这里把 dkms 一起装上,是为了后续内核更新时模块能自动重建。如果你不想用官方仓库,也可以直接去官网下 .deb 包,但依赖处理不如仓库方式省心。
安装完确认版本:
VBoxManage --version4.2 创建 Win10 虚拟机时的关键参数
在图形界面里新建虚拟机,选择类型 Microsoft Windows、版本 Windows 10 (64-bit),然后分配资源。我的建议参数是:
| 参数 | 推荐值 | 备注 |
|---|---|---|
| 内存 | 至少 4096 MB | 建议 8192 MB,Win10 跑起来更顺 |
| CPU | 2 核起步 | 4 核体验更好,但别超过物理机一半 |
| 显存 | 128 MB | 低于 64 MB 会明显卡顿 |
| 磁盘 | 动态分配 64GB 以上 | 动态分配不占满物理空间 |
| 网络 | 默认 NAT | 先保证能上网,后再加桥接网卡 |
| 存储控制器 | SATA 默认即可 | 不要刻意换 NVMExpress,兼容性优先 |
创建磁盘时注意勾选“动态分配”,这样最初只占用几个 GB 物理空间,随着 Windows 内部使用逐渐增长。固定大小磁盘虽然性能稍好,但对 SSD 空间不友好。
装系统前有一件容易被忽略的小事:在虚拟机设置 -> 系统 -> 主板 里,把“启用 EFI”选项根据情况勾选。Win10 原生支持 UEFI 启动,如果虚拟机不开 EFI,用传统 BIOS 引导也能装,但分区表会是 MBR,后续想扩容磁盘会麻烦一些。我建议直接勾选 EFI,磁盘分区用 GPT。
4.3 装完系统后的增强功能与性能调优
Windows 10 装好后,第一件事不是打补丁,而是安装 VirtualBox Guest Additions。在虚拟机窗口菜单栏选择:
设备 -> 插入 Guest Additions CD 映像Windows 里会自动弹出安装向导,或者手动打开 CD 驱动器运行VBoxWindowsAdditions-amd64.exe。安装完成后重启虚拟机,分辨率可以自动适配窗口大小,也能开启共享剪贴板和拖拽文件。这一步不做,虚拟机体验会非常难受。
性能调优方面,我习惯做三件事:
第一,关闭 Windows 的透明度和动画效果。在 Windows 设置 -> 个性化 -> 颜色 里关掉“透明效果”,在性能选项里调整为“调整为最佳性能”。虚拟机的 CPU 资源本来就有限,动画效果纯粹浪费指令周期。
第二,把虚拟机的显示驱动换成 Guest Additions 提供的 VirtualBox Graphics Adapter,而不是基础的 Microsoft Basic Display Adapter。后者不支持硬件加速,窗口拖动都卡。
第三,在 VirtualBox 设置 -> 系统 -> 处理器 里,把“启用 PAE/NX”和“启用 VT-x/AMD-V”都勾上。PAE/NX 对 64 位系统是必须的,虽然默认是好。
5. 高频问题速查与避坑清单实录
把我在这个过程中遇到过的、以及周围同事常问的问题整理成一张速查表,方便直接对照。
| 报错信息 | 问题层级 | 排查顺序 |
|---|---|---|
| Kernel driver not installed (rc=-1908) | 内核模块层 | 1. `lsmod |
| /dev/vboxdrv 不存在 | 模块加载或权限 | 1. dkms modules 2.usermod -aG vboxusers3. 重新登录 |
| VT-x is disabled in the BIOS (VERR_VMX_MSR_ALL_VMX_DISABLED) | CPU 固件层 | 1. UEFI 开启 VT-x 2. 确认grep vmx /proc/cpuinfo3. 外层虚拟化平台透传 |
| AMD-V is disabled (VERR_SVM_MSR_ALL_DISABLED) | CPU 固件层 | AMD 平台同理,确认 svm 标志位 |
| Kernel driver version mismatch | 版本兼容 | sudo /sbin/vboxconfig重编;确认没有残留旧模块 |
| 虚拟机启动后黑屏 | 显存或 EFI | 显存调到 128MB;关闭 EFI 用传统 BIOS 引导试试 |
| 复制粘贴失效 | Guest Additions | 重装 Guest Additions,确认版本与 VirtualBox 一致 |
5.1 两个容易被忽略但很关键的细节
第一个细节是内核更新后的沉默故障。Ubuntu 22.04 如果开启了自动安全更新,内核可能从 5.15.0-xxx 升级到 5.15.0-yyy。这时候 dkms 理论上会自动重建 VirtualBox 模块,但如果你没有安装 dkms,或者 dkms 编译时缺少新内核的头文件,就会出现这样一种诡异现象:系统重启后,VirtualBox 启动正常,但从终端里跑虚拟机直接报 Kernel driver 未安装,而图形界面打开又看起来一切正常。
这个现象的原因是 VirtualBox 图形界面启动时自动调用了模块加载逻辑,但因为模块编译失败,加载逻辑也失败了。排查方法就是执行/sbin/vboxconfig,把缺的头文件补上。
第二个细节是内核模块签名在 Ubuntu 22.04 上的隐藏坑。如果你执行mokutil --import导入过密钥,之后再升级 VirtualBox 小版本,模块会被重新编译,之前签名的文件失效。你需要重新执行一次 sign-file 命令,或者干脆把签名的动作交给 dkms 的 post-install 钩子。我现在的做法是写了一个简单脚本放在/etc/kernel/postinst.d/里,每次内核更新后自动对新编译的 vboxdrv.ko 做签名。脚本逻辑很简单,核心就是判断当前 Secure Boot 是否启用、找到新版模块文件、调用 sign-file。
5.2 关于“为什么不用 KVM 而用 VirtualBox”一点个人看法
写到最后还是要提一句。在 Ubuntu 22.04 上用 KVM/QEMU 跑 Windows 虚拟机,性能上限比 VirtualBox 高,尤其是有大量 IO 的场景。但 VirtualBox 7.0 的优势在于配置图形化、跨平台迁移方便、以及网卡和 USB 设备的兼容性好。如果只是需要偶尔跑一个 Windows 环境做测试,VirtualBox 的学习成本和维护成本要低很多。
我个人的使用习惯是:长期跑的开发环境虚拟机用 KVM,偶尔临时开的测试虚拟机用 VirtualBox。两类工具解决的问题不完全一样,不存在谁完全取代谁的问题。
回到这次的问题本身。Kernel driver 和 VT-x 这两类报错,根本原因有一个共同点:都是宿主机底层环境没有完整地准备好。内核模块问题解决的是“VirtualBox 能不能控制硬件”,VT-x 问题解决的是“CPU 愿不愿意被控制”。把这两个前提搞定,后续的虚拟机安装其实就是一路下一步的问题。