keelOS: hypervisor的控制台,能不能更加有用?
装好一台 hypervisor 之后,接在主机上的那台显示器通常只剩一个用处:告诉你网页管理地址是多少。之后它就一直亮着同一个画面,直到哪天出了事,你走到机房,发现屏幕上要么什么都没有,要么停在一个早已过时的画面上。
keelOS 的答案是:把控制台交给最底层、永远不重启的 hyp 来管。宿主系统(root)只往 hyp 给它的“假屏幕”和“假串口”上写,hyp 负责把内容送到真设备上。这样宿主怎么重启、怎么崩,屏幕都有人画;顺带,同一块屏幕还能用快捷键切去看每一台虚拟机。
起因:一块“没人管”的屏幕
keelOS 的宿主分两层:下面是常驻内存、几乎不更新的 hyp,上面是可以随时重启换新版的 FreeBSD(root)。root 重启(我们叫 reload)时,虚拟机只暂停二十多秒,不关机。
问题出在屏幕上。一次开机加一次 reload,屏幕的主人要换六次:固件 → hyp → 启动加载器 → 旧内核 → hyp → 新内核。任何一次交接没做好,屏幕就没人画。2026 年 10 月 1 日,我在自己的一台 Lenovo P340 Tiny 上用网页升级、reload 之后,屏幕就停在旧内核的最后几行,再也不动了。
直接原因很快修好了:加载新内核的程序没有把帧缓冲的信息传下去,新内核只好退回 VGA 文本模式。但根本问题还在:只要屏幕在不同时段归不同的人管,下一次交接还会出事。
别人怎么做
各家的本地控制台,归谁管就决定了它有多稳。
| 系统 | 屏幕归谁 | 串口归谁 | 本地能切换吗 |
|---|---|---|---|
| ESXi | vmkernel(DCUI 是它上面的一个程序,崩溃时画 PSOD) | vmkernel | Alt-F1 shell、Alt-F2 DCUI、Alt-F11/F12 日志 |
| Xen / XCP-ng | dom0(Xen 只在开机早期写 VGA) | Xen:dom0 的输出经 hypercall 交给 Xen 转发 | 串口上连按 3 次 Ctrl-A 在 Xen 和 dom0 之间切 |
| Proxmox / KVM | 宿主 Linux | 宿主 Linux | 无 |
| Hyper-V | root 分区(Windows) | root 分区 | 无 |
| Unraid / TrueNAS | 宿主(显示地址和一个简单菜单) | 宿主 | 无 |
ESXi 的屏幕稳,是因为它的内核就是 hypervisor,不存在“宿主重启但 hypervisor 还在”这种情况。Proxmox 这一类则是宿主一重启,屏幕和虚拟机一起重来。
最接近我们想要的是 Xen 的串口:hypervisor 持有设备,管理系统只是把字符交给它转发。但屏幕这一边,我们没找到哪家把宿主的帧缓冲交给 hypervisor 中转。keelOS 的 root 会 reload,所以屏幕也得照串口那样做。
keelOS 的做法:屏幕和串口都归 hyp
原则只有一句:屏幕和串口由 hyp 持有,root 只往 hyp 给的“假设备”上写;键盘留在 root。屏幕这一半已经做完,串口那一半还在计划里,下面分开讲。
屏幕:root 画在影子上,hyp 搬到真屏幕
hyp 从它管的内存池里划出一块和真帧缓冲一样大的内存,叫影子帧缓冲,跨 reload 保留。开机时 hyp 把固件报给系统的屏幕地址改成影子的地址,root 的内核照常在上面画字,完全不知道这是假的。
hyp 每 40 毫秒比较一次影子和已显示的内容,只把变了的部分拷到真屏幕。真屏幕从此只有 hyp 一个人写:
- root 重启期间:hyp 停止拷贝,在屏幕上画自己的画面:宿主正在重启、有几台虚拟机暂停着,加上进度和日志。新内核一起来,屏幕自动切回。
- root 崩溃或卡死:拷贝照常跑,屏幕上留着 root 最后的画面,panic 信息看得见。
- hyp 自己出致命错误:屏幕上写明 15 秒后整机复位、所有虚拟机会断电,让人来得及拍下这个屏幕。
- 宿主截图:影子就是一块内存,
keel screenshot host直接读出来存成 PNG。
快捷键:一块屏幕看所有虚拟机
宿主的屏幕既然只是一块内存,往上面画什么都可以。keelOS 的管理程序把虚拟机的画面画到宿主的帧缓冲上,hyp 照常把它搬到真屏幕;每台带显示的虚拟机占一个虚拟终端。
在接着主机的键盘上:
| 按键 | 屏幕上显示 |
|---|---|
| Ctrl-Alt-F1 | 宿主控制台 |
| Ctrl-Alt-F2、F3 … | 第 1、2 … 台虚拟机的画面,键盘和鼠标也交给它 |
| Ctrl-Alt-Shift-Fn | 把 Ctrl-Alt-Fn 这个组合键本身送进虚拟机 |
给虚拟机打字走的是网页 VNC/RDP 已有的按键注入路径。切到一台没开机的虚拟机,屏幕上会提示按回车启动它。root reload 完,屏幕自动回到之前看的那台虚拟机。一台没有网络的主机,接上显示器和键盘,就是一台可以轮流使用所有虚拟机的工作站。
串口:照 Xen 的做法(计划中)
这一部分还没有做,设计已经定了:hyp 持有机器的串口,root 的串口控制台换成一个很小的“假 uart”,输出经 hypercall 交给 hyp,输入从 hyp 的环里取。做完之后:
- 在串口上可以在 hyp 和 root 之间切换,也可以切到某台虚拟机的串口直接登录,reload 之后连接还在。
- 服务器的 IPMI SOL 在 root 重启期间也是一条连续的日志,hyp 和 root 的行不再互相打断。
今天已经能用的是 keel console 命令和网页上的串口控制台,它们用 Ctrl-A 在各台虚拟机的串口之间切换。
取舍:hyp 不做什么
hyp 要保持简单到几乎不需要更新,所以控制台里复杂的部分都留在 root:
- 键盘留在 root。hyp 不写 USB 和 PS/2 驱动,快捷键由 root 里的管理程序认出来并切换画面。代价是 root reload 的二十多秒里键盘没反应,我们觉得可以接受。
- 终端模拟留在 root。字符、颜色、滚动都是 FreeBSD 的 vt(4) 画的;hyp 只搬像素,自己的画面只用一套 8×16 的 ASCII 字体。
- 开销要小。现在用的是最简单的逐帧比较,占一个 CPU 的百分之几;计划改用 EPT 的脏页标记,只拷真正变了的页,把开销压到 1% 以下。
- 分辨率不同就缩放。虚拟机的画面比显示器小时放大铺满,只差一点时原样居中。
这也是和 ESXi 的 DCUI 最大的不同:DCUI 是一个管理菜单,而 keelOS 的控制台是一个“显示器切换器”。管理的事情交给网页和 keel 命令,控制台只负责一件事:你走到机器前,永远能看到正在发生什么。
结语
控制台是 hypervisor 里最不起眼的部分,平时没人看,但一旦有人走到机器前,往往就是出事的时候。那一刻屏幕如果是黑的或者停在旧画面上,就是最糟的体验。
keelOS 把屏幕交给永不重启的 hyp,现在已经得到的是:
- 宿主升级、重启、崩溃,屏幕始终可读,并且告诉你虚拟机的状态。
- 一套键盘和显示器,就能在所有虚拟机的画面之间切换。
- 一条命令就能拿到宿主的屏幕截图。
还没做完的:串口也归 hyp(root 重启期间一条不断的日志,在串口上切换虚拟机);root 重启的那二十多秒里也能看虚拟机的画面;核显直通给虚拟机之后的宿主截图。
开头那台 P340,现在 reload 之后屏幕已经不会再卡住了。所以,hypervisor 的控制台,能不能更有用?能。