BoxLite 为什么要用自研 VMM 替换 libkrun
Building a VMM from scratch, #0: Why BoxLite is replacing libkrun
BoxLite 正在用自研 VMM 替换现有的 libkrun,以解决进程退出状态缺失、libkrunfw 经 dlopen 加载不稳定以及多目录卷触发 IrqsExhausted 等问题。
每个 BoxLite box 都在自己的 micro-VM 中运行,目前由 libkrun 运行该 VM。我们正用自己编写的 VMM 替换它。本系列公开构建,一次一个已合并的 PR。
1. BoxLite 是什么
BoxLite 是 AI agent 的计算基座——轻量到可嵌入你的笔记本电脑,弹性到足以支撑 agentic 云。每个 box 都是一个硬件隔离的 micro-VM,可运行任何 OCI 镜像,并在多轮对话间保持状态。

图 1. 一个引擎,两处运行:嵌入式 BoxLite 运行时为每个 box 启动一个 micro-VM,在你的机器上或云 runner 上。
运行每个 micro-VM 的部分是 VMM,即虚拟机监视器。这部分正是本系列的主题。
2. 为什么我们从 libkrun 开始
libkrun 自称是“一个动态库,让程序能轻松获得在部分隔离环境中运行进程的能力”,基于 KVM(Linux)和 HVF(Apple 芯片上的 macOS),背后是“一个简单的 C API”。这契合 BoxLite:
- 是库,不是守护进程:BoxLite 嵌入你的应用,无需 root,无需后台服务。
- 一套 API 同时支持 Linux 上的 KVM 和 macOS 上的 Hypervisor.framework。
- 自带 guest 内核(libkrunfw),以及 virtio-fs、virtio-blk 和 vsock。
libkrun 是 BoxLite 目前在 macOS 和 Linux 上运行 box 的方式。
3. 为什么我们要替换它
libkrun 明确说明了自己不是什么:其 README 将“成为通用 VMM”和“兼容所有类型的工作负载”列为非目标。BoxLite 的需求已超出这些目标:
- VM 的结果。 libkrun 自行结束进程,因此调用方拿不到退出状态,每次启动失败都返回
-EINVAL。 - 内核作为共享库。 libkrunfw 通过
dlopen加载,这在某些主机上不断出问题;#1512 列出了六个此类问题。 - 设备。 每个目录卷都有自己的设备,三个卷就会导致 box 启动失败并报
IrqsExhausted(#935)。 - 下一步。 热插拔挂载、实时调整大小、用于 AutoPause 的内存快照(#1003)以及 GPU,都需要一个我们可控的 VMM。
我们不做什么
- 不 fork 或打补丁 libkrun。在新 VMM 成为默认之前,它原样发布;之后保留一个版本作为回退,然后移除。
- 不构建通用 VMM。它每个进程只运行一个 VM,且仅支持 BoxLite 的设备;机密计算、实时迁移和 Intel Mac 不在范围内。
代价是什么
- 新 VMM 需要 macOS 15 或更高版本,以使用 Hypervisor.framework 的内核内中断控制器。macOS 12–14 在切换前继续使用 libkrun。
- 路很长:首次启动(M1),然后是真实 box(M2)、卷(M3)、加固(M4)和切换(M5)。
4. 一屏看懂 VMM 如何工作

图 2. 一台机器内部。运行时为每个 box 生成一个受限制的 boxlite-shim,其中的 VMM 运行 micro-VM。PROPOSED 标记的是本系列要替换的部分。
hypervisor(KVM 或 Hypervisor.framework)在 CPU 上运行 guest 指令。VMM 是它周围的普通进程:为 guest 提供内存、创建 vCPU、加载内核并模拟每个设备。其核心是一个循环:

图 3. 运行一个 vCPU 直到它退出,处理退出,然后再次运行它。
我们新的 KVM 后端运行的第一个 guest 只有 7 字节长:
mov dx, 0x3f8 ; COM1 serial port
mov al, 'K'
out dx, al ; KVM exits to the VMM: port 0x3f8, byte 'K'
hlt
其余都是细节,每个细节在本系列中都有对应篇章:
| 部分 | 是什么 | 篇章 |
| 内存 | Guest RAM 就是主机内存;未映射的地址就是设备 | #1 |
| 退出 | 为 KVM、Hypervisor.framework 以及后续的 WHP 提供统一的退出契约 | #2 |
| 停止 | 安全地将 vCPU 从 guest 中拉出 | #3 |
| CPU 状态 | x86 上的寄存器、CPUID 和 MSR | #4 |
| 启动 | VMM 就是引导加载程序 | #6 |
| 设备 | 先串口、RTC 和复位,然后是 virtio | #7, #10–12 |
5. 系列
截至 2026 年 10 月 11 日的状态。每个部分只有在其代码合并后才会发布,因此每项声明都链接到一个已合并的 PR。
| Arc | 部分 | 发布时间 |
| 1. 最初的指令 | #1 你的第一个 VM 只有 7 字节 · #2 先设计退出契约 · #3 停止 vCPU 才是难点 · #4 手动处理 x86 CPU 状态 · #5 我们自己构建的内核 | 代码已合并 |
| 2. 首次启动(M1) | #6 你就是引导加载程序 · #7 先处理无聊的设备 · #8 在 Apple 芯片上,由你来解码退出 · #9 一个内核,三个宿主 | 随 M1 落地 |
| 3. 第一个盒子(M2–M3) | #10 从零实现 virtio · #11 磁盘、套接字、网络 · #12 每个卷一个 virtio-fs 设备 · #13 我们的 agent 作为 PID 1 | M2–M3 |
| 4. 发布它(M4–M5) | #14 客户机输入绝不能导致宿主机 panic · #15 与 libkrun 对比测量 · #16 删除 libkrun | M4–M5 |
| 后续 | 内存快照、热插拔挂载、GPU、我们自己的网络栈 | M5 之后 |
我们的进展
- ✅ 为 KVM、Hypervisor.framework 以及后续的 Windows 设计并统一了一份 hypervisor 契约
- ✅ x86_64 上的 KVM:VM、内存、运行循环、I/O 完成、kick、启动寄存器、CPUID 和 MSR
- ✅ 为我们锁定的 Linux 6.12 内核在 x86_64 上提供可复现构建
- ⏳ M1:在 macOS arm64、Linux x86_64 和 Linux arm64 上首次启动,并在 CI 中检查
通过 RSS 订阅 以及 GitHub 上的每个 PR 跟进。
6. 来和我们一起构建它
BoxLite 是开源的,这个 VMM 的每一步也都是开源的。我们很希望得到你的帮助:
- 挑战设计。 阅读 VMM 设计文档,告诉我们哪里有问题。
- 认领 M1 工作。 #1698 列出了待办切片及其依赖项:设备、内核加载器、Hypervisor.framework 后端、arm64 KVM 和三宿主 CI。
- 提问和讨论。 提交一个 GitHub issue,或者在 Discord 上找到我们。
从 CONTRIBUTING.md 开始。你的第一个 PR 会要求你签署我们的贡献者许可协议。
来源:Hacker News · blog.boxlite.ai