ARM 服务器(鲲鹏 920)让内核日志显示在 VGA:从 console=tty0 实验到 simplefb 点亮
九月 09, 2026 [Linux 与系统] #console #serial #ipmi #kvm #kunpeng #ascend #310p #arm64一、背景:VGA 上永远只有"EFI stub 三行"
鲲鹏 920 推理服务器(TaiShan 200 / iBMC 固件 3.03.00.69,昇腾 310P 推理卡)在 IPMI KVM 上观察:
EFI stub: Booting Linux Kernel...
EFI stub: Using DTB from configuration table
EFI stub: Exiting boot services...
(此后黑屏,再也没有内容)
原因链(详见《2026-09-08-ext4-rootfs-readonly-recovery.md》第四节与第九节):
- 这板子的启动链是 UEFI → shim → grub → 内核;EFI stub 阶段通过 UEFI GOP 自绘 → VGA 有字;
- 内核接管后,控制台由 ACPI SPCR(firmware Console Redirection 表)决定 →
console [ttyS0] enabled,日志全走串口; /proc/cmdline里没有console=→ 内核注册了串口,tty0 根本不是 printk 目标。
于是:想验证能不能让内核日志同步显示到 VGA/IPMI 画面 → 下面的实验。实验本身成功了(tty0 注册),但当时画面仍黑,第一版结论判为"平台限制、无解"——本文是续篇:这个结论是错的,VGA 最终被点亮了(见第四节起)。
二、实验:console=tty0 的注册(第一次,仅证明"日志投递"成功)
2.1 配置
# 备份 + 修改 /etc/default/grub
sudo cp /etc/default/grub /etc/default/grub.bak-tty0
sudo sed -i 's/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX="console=ttyS0,115200 console=tty0"/' /etc/default/grub
sudo update-grub
为什么写两个 console=:第一个是主日志通道(串口);第二个(tty0)追加为辅助通道,同一份 printk 同时打给两者;最后一个 console= 决定 /dev/console。
2.2 重启后 dmesg 实测(第一次实验,内核 5.15.0-107)
[ 0.000211] Console: colour dummy device 80x25
[ 0.000546] printk: console [tty0] enabled ← ✅ 注册成功(改前没有这行)
[ 0.351424] fbcon: Taking over console ← ⚠️ 声称接管
[ 0.401209] pci 0000:06:00.0: BAR 0: assigned to efifb ← ⚠️ 此行的解读后来被修正(见 4.3)
[ 0.774270] printk: console [ttyS0] enabled ← ✅ 串口照常
但画面仍然失败:/dev/fb0 不存在、/sys/class/graphics/ 只有 fbcon、vtcon0 是 (S) dummy device、显卡是 Huawei Hi171x [iBMC ... w/VGA support](PCI 06:00.0,BAR0 = 32MB @ e4000000,BAR1 = 2MB @ e7200000)。
三、当时的结论(2026-09-09 上午)——已被下午的排查推翻
当时判定为平台限制,链条是:
- efifb "试图接管"("BAR 0: assigned to efifb")但没有 GOP screen_info 提供真实帧缓冲描述 → 未注册 fb0;
- DRM 侧也是空的(华为未提供该芯片开源驱动);
- fbcon 挂的是 dummy device → 内核日志投给 tty0 后无处可画。
纠错说明(为什么错,防止重复踩坑):
- ① "无 GOP screen_info" 是误读——screen_info 一直有效,物证见第四节
BOOTFB区段; - ② 把 "BAR 0: assigned to efifb" 当成 "efifb 驱动在工作" 是误读——该行出现在 PCI 资源归属日志里,而本配置下 efifb 驱动(
FB_EFI=y内置)根本没有可绑定的平台设备(见 4.3),谈不上"拿到 BAR 后放弃"; - ③ 漏查了 sysfb 已把 GOP 帧缓冲注册成
simple-framebuffer平台设备这一步——缺的不是"硬件驱动不存在",而是"驱动模块存在但没加载、且不能自动绑定"。 - 教训:查显示问题不能只看 fb0/efifb/drm 这几个名字,还要查
/sys/bus/platform/devices/有没有等驱动的显示设备、/proc/iomem里帧缓冲区段是谁预留的。
四、继续排查:sysfb 早已把路铺好,缺的只是驱动
4.1 新证据一:/proc/iomem 里的 BOOTFB
$ cat /proc/iomem | grep -B2 -A2 BOOTFB
e4000000-e5ffffff : PCI Bus 0000:06
e4000000-e5ffffff : 0000:06:00.0
e4000000-e412bfff : BOOTFB ← 起点恰是 Hi171x BAR0 基址
e412bfff - e4000000 + 1 = 0x12c000 = 1,228,800 B = 640×480×32——正好是一个 GOP 帧缓冲。也就是说:固件把 GOP 画面画在 Hi171x 显存窗口(BAR0 = e4000000)的起始处,这块内存在内核侧被预留为 BOOTFB,而 iBMC 的物理 VGA/HDMI 与 IPMI KVM 采集的就是这个显存窗口(UEFI 有字、内核黑屏的边界 = 谁在往这块内存写)。
4.2 新证据二:simple-framebuffer.0 平台设备在等驱动
$ ls /sys/bus/platform/devices/ | grep framebuffer
simple-framebuffer.0 ← 已注册,但 driver 目录不存在 = 没有驱动绑定
$ grep -E "^CONFIG_(SYSFB|SYSFB_SIMPLEFB|FB_EFI|FB_SIMPLE|DRM_SIMPLEDRM)" /boot/config-$(uname -r)
CONFIG_SYSFB=y
CONFIG_SYSFB_SIMPLEFB=y
CONFIG_FB_EFI=y # efifb 驱动内置
CONFIG_FB_SIMPLE=m # fbdev simplefb 驱动是模块
CONFIG_DRM_SIMPLEDRM=m # DRM simpledrm 驱动是模块
解读:内核启动早期(sysfb)根据 screen_info(来自 EFI stub 登记的 GOP 信息) 生成了一个平台设备 simple-framebuffer.0(这台是 ACPI 机器、无 device tree,所以该设备只能来自 sysfb)。屏幕信息不是没有,是转换成了 simple-framebuffer 形态在等 fb 驱动。
4.3 修正:efifb 为什么"没干活"——它压根没有设备
CONFIG_SYSFB_SIMPLEFB=y 的含义:sysfb 把 GOP 帧缓冲注册成 simple-framebuffer 平台设备(供 simplefb/simpledrm 绑定),而不再注册 efifb 平台设备。efifb 驱动(FB_EFI=y 内置)需要名为 efifb 的设备才会 probe——它永远等不到。所以:
- 之前看到的
pci 0000:06:00.0: BAR 0: assigned to efifb与BOOTFB都是早期资源预留/归属日志,不是 efifb 驱动工作的痕迹; - 真正缺的一环是:加载并绑定一个能认
simple-framebuffer设备的 fb 驱动。
4.4 关键差异:107 与 186 内核的模块库存
# 当前运行 5.15.0-107(内核包被 apt hold,且没有 linux-modules-extra-107)
$ ls /usr/lib/modules/5.15.0-107-generic/kernel/drivers/gpu/drm/tiny/ # 不存在
$ find /usr/lib/modules/5.15.0-107-generic/kernel -name "*simple*"
.../kernel/drivers/video/fbdev/simplefb.ko # 只有 simplefb
# 5.15.0-186(linux-modules-extra 已装)
$ ls /usr/lib/modules/5.15.0-186-generic/kernel/drivers/gpu/drm/tiny/
simpledrm.ko
- simplefb(fbdev) 与 simpledrm(DRM) 的平台驱动名都叫
simple-framebuffer(与 sysfb 设备同名,simpledrm 源码注释直接写着/* connect to sysfb */)→ 走 platform bus 的名字回退匹配即可绑定,不需要 DT 节点、也不需要 driver_override(这一点初稿判断错了,见第五节弯路记录); - 两者的
MODULE_DEVICE_TABLE都只有of:N...simple-framebuffer(of_match_table),没有platform:simple-framebuffer别名 → udev 冷插时按设备 modalias(platform:simple-framebuffer)找不到任何模块,不会自动加载——真正缺的一环只是"把模块加载进来":模块一加载,driver_register 的 attach 循环立刻按名字把设备绑上; - simpledrm 只在 186 内核存在(107 缺 linux-modules-extra)。
这决定了修复路线(见第五、七节)。
五、点亮:modprobe simplefb 即自动绑定,零重启现场修复
107 内核上没有 simpledrm,先用 simplefb 验证(不需要重启):
sudo modprobe simplefb # 模块加载 → driver_register → attach 循环 → 名字匹配 → probe,一步到位
dmesg 实测输出:
[ 4055.198726] simple-framebuffer simple-framebuffer.0: framebuffer at 0xe4000000, 0x12c000 bytes
[ 4055.198735] simple-framebuffer simple-framebuffer.0: format=a8r8g8b8, mode=640x480x32, linelength=2560
[ 4055.198932] Console: switching to colour frame buffer device 80x30
[ 4055.203598] simple-framebuffer simple-framebuffer.0: fb0: simplefb registered!
验证结果:
$ ls /sys/class/graphics/ # fbcon → fb0 + fbcon
$ cat /sys/class/vtconsole/vtcon0/name # (S) dummy device(VT0 仍哑)
$ cat /sys/class/vtconsole/vtcon1/name # (M) frame buffer device ← fbcon 绑定真设备
VGA/HDMI 与 web IPMI 上出现文本终端(TTY 登录界面),"EFI stub 三行后黑屏"结束。fb0 参数:640×480×32,stride 2560(= 640×4),即 UEFI GOP 模式本身(BMC 会做缩放)。probe 的宽高/格式来自 sysfb 附在平台设备上的 platform_data(simplefb_parse_pd,由 screen_info 解析而来)——又一次证明无 DT 也能拿到显示参数。
5.1 弯路记录:driver_override 与 "simplefb" 目录(初稿的错,已修正)
初版排查时误以为 simplefb 是 DT-only、必须 driver_override 强绑,实际是多此一举,还原过程:
- 先
modprobe simplefb—— 这一刻绑定就已发生(dmesg 单条 probe 记录); - 随后写入
driver_override=simplefb—— 绑定已完成后写入,无任何作用;且该残留值其实有害:override 会让未来只有名为simplefb的驱动能绑这个设备,而真实驱动名是simple-framebuffer→ 解绑后将无法重绑(已清空); - 手动 bind 报
drivers/simplefb/bind: Directory nonexistent—— 因为驱动目录真实名字是drivers/simple-framebuffer(驱动名≠模块名),不是simplefb; - 决定性实验:清掉 override → 解绑 → 不带 override 手动 bind → probe 成功、fb0 回来(见第十一节命令)。绑定机制 = platform bus 名字回退匹配。
注:此修复已通过 107 initramfs 持久化并重启验证(见 7.3)——VGA 从 initramfs 阶段起有画面。
六、机制补课:fbcon / framebuffer / /dev/fb0 的关系
刚踩完坑,顺手把这三层关系理清(排查显示问题必须懂的结构):
printk → console[tty0] → VT 子系统 → vtconN 绑定 → fbcon → fb_info → 显存 → 扫描输出
- 显示驱动(simplefb / simpledrm / efifb):拥有显存、提供画点/填充/位块搬运原语。调用
register_framebuffer()注册一个fb_info后,fbdev 核心(fbmem.c)才生成/dev/fb0。 /dev/fb0:用户态访问同一个fb_info的窗口(open/mmap/ioctl 直接读写像素,如fbset、截图)。内核控制台文字不走它。- fbcon(framebuffer console):VT 子系统的"显示后端"。VT 把字符交给 fbcon,fbcon 把字符点阵画进
fb_info的显存。/sys/class/vtconsole/vtcon1/name从(S) dummy device变(M) frame buffer device= fbcon 绑定成功。 - DRM 时代等价物:simpledrm 是 DRM 驱动,靠
DRM_FBDEV_EMULATION=y的模拟层同样生成 /dev/fb0 供 fbcon 挂(另外提供 /dev/dri/card0 给现代 GUI)。186 内核走的就是这条路。
所以回头看第一节说的"三个开关",第三格要修正:不是"硬件没有显示驱动",而是"驱动存在(FB_EFI=y/FB_SIMPLE=m/DRM_SIMPLEDRM=m),但模块没加载、且内置的 efifb 因 SYSFB_SIMPLEFB=y 永远等不到设备"。
6.1 platform bus 匹配规则:为什么 simplefb 能自动绑上 sysfb 设备
platform bus 匹配 设备↔驱动 按序尝试 4 条规则(drivers/base/platform.c platform_match):
of_driver_match_device:设备带 DT 节点且 compatible 命中驱动的of_match_table(DT 匹配)acpi_driver_match_device:ACPI 匹配- 驱动
id_table命中设备名 - 兜底:
strcmp(pdev->name, drv->name)——设备名 == 驱动名直接绑定
simplefb/simpledrm 走的就是规则 4:它们的 platform_driver.driver.name 都叫 simple-framebuffer(与 sysfb 设备同名;simpledrm 源码注释直白写着 /* connect to sysfb */)。不需要 DT 节点、不需要 driver_override——当初以为"DT-only 必须强绑"是误判(5.1 弯路记录)。
查看 DT 配置的方法:
- 是否 DT 启动:
ls /proc/device-tree(存在 = DT 启动;本机是 ACPI 机,只有 /sys/firmware/acpi) - 某设备是否有 DT 节点:
ls -la /sys/bus/platform/devices/<设备>/of_node(本机 simple-framebuffer.0 无 of_node) - DT 机上浏览结构:
ls /proc/device-tree/(目录=节点、文件=属性),如cat /proc/device-tree/chosen/stdout-path、ls /proc/device-tree/ | grep -i fb - 设备 modalias:
cat .../modalias——udev 靠它查模块(本机为platform:simple-framebuffer)
6.2 simplefb vs simpledrm:fbdev 老将 vs DRM 继任者
| simplefb | simpledrm | |
|---|---|---|
| 出身 | 2013 年 fbdev 时代(ARM DT simple-framebuffer) | 5.14 加入的 DRM 化重写(源码注释 connect to sysfb) |
| API | 老 fbdev:register_framebuffer → /dev/fb0 | 现代 DRM:/dev/dri/card0(KMS/atomic/damage) |
| fbcon 怎么用 | 直接提供 fb0 | DRM_FBDEV_EMULATION=y 模拟层生成 fb0 |
| 附带能力 | 仅画 | 格式转换、damage 刷新、标准 modeset 接口(GUI 可用) |
| 本机 | 107/186 都有 | 仅 186(在 linux-modules-extra) |
是官方路线上的迭代取代(fbdev→DRM 迁移,6.x 后老 fbdev 驱动陆续 obsolete),但同内核共存、绑定机制完全相同(都靠驱动名=设备名)。选型:只要控制台日志→两者等价;要 GUI 后路(/dev/dri)→simpledrm。
6.3 "modprobe 就创建了 /dev/fb0"?——一条间接链路
modprobe simplefb 并不直接创建设备,链路是:
modprobe simplefb → driver_register → platform bus 对已有无驱动设备跑 attach 循环
→ 规则 4 名字匹配 → probe() → 读 sysfb 附带的 platform_data(640×480×32 等参数)
→ register_framebuffer() → fbdev 核心注册 fb_info → devtmpfs 自动生成 /dev/fb0(c 29:0)
所以真正起作用的只有"加载模块"一步;绑定、fb0、fbcon 接管都是内核自动完成的。
七、为什么早期内核日志看不到?——fb 驱动的加载时机盲区
7.1 问题本质
fb 驱动若是模块(=m),要等根文件系统挂载、udev 运行(约开机 1 秒后)才加载;更早的内核日志(EFI stub 之后到 initramfs/udev 之前)已经只进了串口和 dmesg ring buffer,fbcon 接管时不会"回放"启动日志(最多重画当前 VT 屏存的最后一屏)。所以即使修好了,VGA 也只能看到"驱动加载之后"的输出。
# 验证"最后接入点":dmesg 中 fb0 注册的时间戳(4055s = 运行中手动加载;重启后则是 initramfs/udev 阶段)
7.2 让 fb 驱动提前:initramfs / built-in
| 方案 | 生效时机 | 代价 |
|---|---|---|
| udev 规则(根系统) | ~1s 后(udev 阶段) | 简单,但早期日志仍缺 |
initramfs 提前加载(/etc/initramfs-tools/modules) | initramfs 阶段起(约 1s,比 udev 早,根挂载前 fb0 就绪) | 需重建 initrd;模块一加载即自动绑定(见下) |
| 驱动编译为 built-in (=y) | 开机 ~0.4s(驱动先注册,sysfb 设备一出现即绑) | 本发行版 FB_SIMPLE/DRM_SIMPLEDRM 都是 =m,需自编/换内核 |
关键机制(初稿在此处判错过,修正):simplefb 与 simpledrm 加载后都会立刻按名字自动绑定(驱动名 = simple-framebuffer = 设备名),所以塞进 initramfs/模块列表都有效,不需要任何 udev 规则或 override。自动加载(autoload)盲区只在"没有任何加载动作"时存在:两个模块都只导出 of:N... 别名、没有 platform:simple-framebuffer 别名,udev 按设备 modalias 找不到可加载的模块——但只要 initramfs /etc/initramfs-tools/modules 或根系统 modules-load.d 显式 modprobe,绑定即刻发生。
7.3 本机已做的配置(186 内核,待重启验证)
107 没有 simpledrm,所以 initramfs 方案绑定 186(选择 simpledrm 而非 simplefb 的理由:simpledrm 额外提供 /dev/dri/card0,为将来跑 GUI 留路;纯日志目标两者等价):
# /etc/initramfs-tools/modules 追加(先备份)
sudo cp -n /etc/initramfs-tools/modules /etc/initramfs-tools/modules.bak-20260909
echo simpledrm | sudo tee -a /etc/initramfs-tools/modules
sudo update-initramfs -u -k 5.15.0-186-generic
# 验证模块与依赖确实进了 initrd(simpledrm 依赖 drm/drm_kms_helper/fb_sys_fops/syscopyarea/sysfillrect/sysimgblt/cec/rc-core 共 9 个 ko)
lsinitramfs /boot/initrd.img-5.15.0-186-generic | grep -E "simpledrm|drm_kms_helper|fb_sys_fops|sysimgblt"
107 已按同法处理并重启验证通过(2026-09-09):
/etc/initramfs-tools/modules改为simplefb(107/186 模块集都有它;186 的 initrd 此前已按 simpledrm 生成,两内核各自生效、互不影响)。重启后实测时间轴(这台机器启动很慢,内核设备初始化 ~11s 才 Run /init):[ 0.78s] Freeing initrd memory [10.82s] Run /init as init process ← initramfs 开始 [17.70s] simple-framebuffer.0: fb0: simplefb registered! ← initramfs 阶段绑定 [19.14s] EXT4-fs (sda2): mounted ← 根挂载(之后才轮到真实 udev) [19.31s] systemd[1]: systemd 249 ... runningfb0 在根挂载前就绪 → VGA 显示覆盖 initramfs 阶段起的全部内容。若日后 186 想从 simpledrm 换回/换用 simplefb:编辑 modules 文件(先加载者先绑设备)并
update-initramfs -u -k 5.15.0-186-generic。
重启验证用单次引导(NPU 驱动挑内核的疑虑未消除前不固化默认内核,见第九节):
sudo systemctl stop libvirtd # 上次重启因 libvirt 保存 VM 的 inhibitor 卡 20 分钟
sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 5.15.0-186-generic" # 仅下一次启动生效
sudo systemctl reboot
# 期望:dmesg 早期出现 simple-framebuffer fb0 / simpledrm 注册,VGA 从 initramfs 阶段起有字
为何不直接换默认内核:107 被 hold 是因为查到华为 NPU 驱动(昇腾 310P)在高版本内核可能有问题(待确认)。186 与 107 同属 5.15 大版本、仅 SRU 点版本差异,风险理论很低,但仍用 grub-reboot 单次验证,出问题重启即回 107(GRUB 默认仍指向 107)。
八、graphical.target 之谜:为什么是 TUI 而不是 GUI?
排查中发现 systemctl get-default 是 graphical.target,但 VGA/HDMI 上始终是 TTY——查证结果:
$ systemctl get-default
graphical.target
$ ls /etc/systemd/system/display-manager.service # 不存在
$ dpkg -l | grep -E "gdm3|lightdm|sddm|gnome-shell" # 什么都没装
结论:
- graphical.target 只是 systemd 开关,唯一实质动作是拉起
display-manager.service;机器上根本没装任何显示管理器(连服务软链都不存在),所以 graphical.target 与 multi-user.target 效果完全一样——没有 DM 就没有进程画 GUI,屏幕只能是 fbcon 文本终端。多半是装 plymouth 或某组件时被顺手设的,无害但无意义。 - GUI 也依赖 fb/DRM:fb/DRM 是地基、GUI 是房子。没有 fb0/DRM 时显示服务器(Xorg/Wayland)根本无法启动(没有 scanout 目标)。所以"先让 fb 工作"是 GUI 的前提,与 target 无关——这也是为什么过去 graphical.target 挂着、VGA 却一直黑屏。
- HDMI 与 web IPMI 看到同一份画面是正常的:这台机器物理 VGA/HDMI 和 IPMI KVM 视频都来自 iBMC 对同一显存窗口(Hi171x BAR0 = e4000000)的采集。
- 若将来要跑真 GUI:simplefb 是纯 fbdev(无 /dev/dri),只能 Xorg+fbdev 老模式;现代 GNOME/Wayland 需要 DRM 设备——186 + simpledrm 才有
/dev/dri/card0(simpledrm 同时提供 /dev/fb0)。
九、对照:串口为什么能看全启动日志?(earlycon / console 机制)
VGA 看不全早期日志,串口却能——这正好引出一段经常混淆的机制(排查时对照本机 SPCR 输出很有用)。
9.1 console=ttyS0 与 earlycon 是两回事
console=ttyS0,115200:走正常 console 框架(printk → console 子系统 → serial8250 console → UART)。console 注册和 tty 驱动初始化路径不同:console 在 start_kernel 早期就能注册并开始输出,而/dev/ttyS0是之后 serial 驱动 probe 才诞生的设备节点——console 输出不依赖 /dev/ttyS0 存在。earlycon=...:真正的"驱动框架还没初始化"之前的输出。内核直接按参数给的类型 + 地址操作寄存器,不经过任何设备模型。例如earlycon=uart8250,io,0x3f8,115200:内核知道这是 8250/16550 兼容 UART,用固定寄存器布局(THR=+0、IER=+1、LCR=+3、LSR=+5…),轮询 LSR 的 THRE 位后直接写 THR。
9.2 硬件地址从哪来?
| 平台 | earlycon/console 如何知道 UART 在哪 |
|---|---|
| 传统 x86 | 固定 legacy 地址:ttyS0=COM1@0x3f8、ttyS1=COM2@0x2f8、ttyS2=COM3@0x3e8、ttyS3=COM4@0x2e8(注意:ACPI 时代 ttyS0 编号由枚举顺序决定,不再保证等于 COM1) |
| ARM/ARM64(DT) | device tree:stdout-path = "serial0:115200n8" 或 earlycon 无参时读 DT |
| ACPI 机器 | ACPI SPCR 表:固件声明"控制台 UART 的类型/地址/波特率"。本机 dmesg:ACPI: SPCR: console: uart,mmio,0x3f00002f8,115200 → 于是 console [ttyS0] enabled |
| EFI stub 阶段 | 根本不是内核在输出——是 UEFI Simple Text Output(ConOut),走 GOP 画面/串口/SOL 由固件配置决定。本机"EFI stub 三行"= 固件通过 GOP 画到 VGA |
9.3 为什么"不是所有串口都能 earlycon"?
PCI 串口(需要先枚举 PCI、找 BAR)无法用于最早期输出;传统固定 I/O 端口(0x3f8 类)和 ARM SoC 固定 MMIO UART 最容易做 earlycon。ARM64 上还有 EFI 引导时会话:SPCR 常与"固件串口重定向"配套,即使内核参数里没写 console=,SPCR 也能让日志落到串口(这正是本机最初"无 console= 时日志全走串口"的原因)。
9.4 与本机现象对起来
串口(面板 / SOL / telnet):EFI 阶段有 → earlycon/SPCR → console [ttyS0] → 全程可见
VGA(HDMI / IPMI KVM):EFI stub 三行(固件 GOP)→ 内核阶段:tty0 注册了但 fbcon 挂 dummy
→ fb 驱动加载后:fbcon 接管,从加载时刻起可见(早期日志缺失)
一句话:串口通道在"内核刚醒来"就有 SPCR/earlycon 兜底,VGA 通道要等 fb 驱动出现才有画面来源——两个通道的"最早可见时刻"不同,不是同一个机制。
9.5 追问:为什么 KVM 看到的比 SOL 少那么多?(固件调试口 vs ConOut,printk 回放)
对比同一台机器 SOL 与 web IPMI KVM 的实际输出,差异分三段,全部是机制使然:
① 固件阶段(SasBase=...、Initialize PCIe RAS、[Bds]Booting ubuntu、XHCI HC reset、IPMI ExitBootService Event、BIOS boot completed)——SOL 有、KVM 无:
- SOL 拿到的是 BIOS 的串口调试日志(serial debug console)——华为 BIOS 几乎所有阶段文本都只写这个口,从不经过显示设备;
- KVM/VGA 只能看到 **UEFI ConOut(GOP 图形文本)**真正画出来的内容(本机即"EFI stub 三行")。
SmiGraphicsOutputQueryMode这类 VGA 驱动查模式的日志也是串口调试输出,不上屏。 - 固件阶段"调试日志 ≠ 显示输出",两套通道内容源不同。
② 内核早期(Booting Linux on physical CPU 0x... 到 ACPI RSDP 等几百行)——SOL 全量、KVM 全无:
- 此时 printk 控制台尚未就绪:
console [tty0]0.0005s 注册但无 fb 驱动可画(dummy,不产生像素);console [ttyS0]0.774s 才注册; - printk 输出先进环形缓冲(dmesg),第一个 console 注册时整体回放 → 0.774s ttyS0 一注册就把从第一行起的全部日志吐到串口 → SOL 完整;
- VGA 侧没有驱动就没有画面来源,等 fb0(本机 initramfs ~17.7s)出现时不会重放 ring buffer → 早期日志只存在于 SOL/dmesg。
③ fb0 之后(initramfs 起)——"屏幕" vs "终端流":
- KVM 只显示当前一屏(本机 640×480 → fbcon 80×30 字符 ≈ 30 行),新输出顶掉旧行;SOL 是终端流,客户端保留全部历史可回滚;
- userspace 阶段 journald 收日志,console 上只剩内核消息 + getty → KVM 长时间静止的登录界面,观感差距更大。
结论:SOL = 全量日志流(固件调试口 + printk 回放 + 终端滚动),KVM = 实时屏幕(ConOut + fbcon 当前屏,无历史无回放)。从头看日志用 SOL/dmesg;KVM 只看"此刻画面"——与 fb 修复无关,是通道设计差异。
十、现状与待办
- console=tty0 注册(实验,无副作用,配置保留)
- 确认 screen_info/GOP 有效(BOOTFB + simple-framebuffer.0 证据)
- 107 现场点亮 VGA(modprobe simplefb 即自动绑定)
- 澄清绑定机制:驱动名=设备名(simple-framebuffer),DT/override 都不需要(5.1 弯路记录)
- 186 initrd 打入 simpledrm(update-initramfs + lsinitramfs 验证依赖齐全)
- 107 initramfs 持久化 + 重启验证(simplefb 入 107 initrd;重启后 fb0 于 initramfs 阶段绑定,[17.7s] < 根挂载 [19.1s],见 7.3)
- 重启进 186 验证 initramfs 方案(grub-reboot 单次引导,见 7.3)
- 确认华为 NPU 驱动在 186 上的兼容性(107 hold 的原始顾虑)
- (可选)确认 640×480 GOP 模式能否调大 / 是否需要
回退方法(与旧文一致):sudo cp /etc/default/grub.bak-tty0 /etc/default/grub && sudo update-grub 可整体还原命令行;console=ttyS0,115200 console=tty0 保留本身无副作用(tty0 挂不上 fb 时只是哑设备)。
十一、排查命令清单(复用)
cat /proc/cmdline # 看有没有 console=
cat /proc/iomem | grep -B3 -A3 BOOTFB # GOP 帧缓冲区段(尺寸可反推分辨率:0x12c000=640×480×32)
ls /sys/bus/platform/devices/ | grep -i framebuffer # sysfb 是否已注册 simple-framebuffer 设备(有没有驱动在等)
ls /sys/bus/platform/devices/simple-framebuffer.0/driver 2>&1 # 空 = 没绑定
grep -E "^CONFIG_(SYSFB|SYSFB_SIMPLEFB|FB_EFI|FB_SIMPLE|DRM_SIMPLEDRM)" /boot/config-$(uname -r)
find /usr/lib/modules/$(uname -r)/kernel -name "*.ko*" | grep -iE "simple|efifb" # 模块库存
sudo modprobe simplefb # 加载即自动绑定(驱动名=simple-framebuffer)
# 手动解绑/重绑(注意驱动目录名是 simple-framebuffer,不是 simplefb):
# echo simple-framebuffer.0 > /sys/bus/platform/drivers/simple-framebuffer/unbind
# echo simple-framebuffer.0 > /sys/bus/platform/drivers/simple-framebuffer/bind
sudo dmesg | grep -E "simple-framebuffer|Console: switching|fb[0-9]:"
ls /sys/class/graphics/ && cat /sys/class/vtconsole/vtcon*/name
sudo fbset -i # fb0 分辨率/位深(无 fbset 可读 virtual_size/bits_per_pixel)
# initramfs 方案(simplefb/simpledrm 均可,加载即绑定;无需 udev 规则/override)
echo simpledrm | sudo tee -a /etc/initramfs-tools/modules
sudo update-initramfs -u -k 5.15.0-186-generic
lsinitramfs /boot/initrd.img-5.15.0-186-generic | grep -E "simpledrm|drm_kms_helper|fb_sys_fops"
# 单次引导测试内核
sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 5.15.0-186-generic"
# 串口机制对照
sudo dmesg | grep -E "SPCR|earlycon|console \[tty" # SPCR/earlycon/console 注册链