QEMU作为开源虚拟化工具,广泛应用于操作系统开发、Linux内核调试、嵌入式系统开发以及虚拟硬件测试场景。在调试Linux内核启动过程时,启动日志和串口输出是定位问题的重要依据。合理保存QEMU启动日志,并捕获内核串口输出,可以帮助开发者分析内核启动失败、驱动加载异常、文件系统挂载错误等问题。
很多开发者在使用QEMU运行自定义内核时,会遇到日志无法保存、终端输出混乱、串口信息丢失等情况。掌握QEMU日志捕获机制,能够建立稳定的调试环境,提高内核开发效率。
QEMU启动日志的重要性
Linux内核启动阶段会输出大量调试信息,包括:
-
Bootloader传递的启动参数;
-
内核初始化过程;
-
CPU和内存检测信息;
-
中断控制器初始化;
-
设备驱动加载状态;
-
根文件系统挂载结果;
-
用户空间启动过程。
这些信息通常通过串口输出,例如:
[ 0.000000] Linux version 6.x.x [ 0.000000] Kernel command line: console=ttyS0 [ 0.500000] Serial: 8250/16550 driver initialized
如果没有保存这些日志,一旦系统启动失败,只能重复启动并观察终端输出,不利于问题分析。
通过将QEMU日志重定向到文件,可以实现:
-
多次启动结果对比;
-
自动化测试日志收集;
-
CI环境中的错误分析;
-
内核崩溃后的问题追踪。
QEMU默认日志输出方式
QEMU启动后,默认会将虚拟机显示内容输出到当前终端。例如:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0"
其中:
-
-kernel指定Linux内核镜像; -
-append向内核传递启动参数; -
console=ttyS0表示将内核控制台绑定到第一个串口。
如果终端直接关闭,日志也会随之丢失。因此实际开发过程中通常需要进行输出重定向。
使用标准输出保存QEMU日志
最简单的方法是利用Shell重定向:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" > qemu.log 2>&1
执行后:
-
标准输出保存到
qemu.log; -
错误输出也写入同一个文件。
查看日志:
Bashcat qemu.log
或者实时查看:
Bashtail -f qemu.log
这种方式适用于普通启动日志记录,但对于内核串口调试场景还不够完善。
使用QEMU串口重定向捕获内核输出
Linux内核通过串口输出日志时,推荐使用QEMU的串口参数。
例如:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -serial file:qemu_serial.log
参数说明:
-serial file:qemu_serial.log
表示将虚拟串口数据直接写入文件。
启动后,可以查看:
Bashless qemu_serial.log
这种方式相比普通重定向更加可靠,因为它捕获的是虚拟串口设备的数据流。
使用stdio模式实时查看串口日志
开发内核时,经常需要边运行边观察输出:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -serial stdio
此时:
-
QEMU占用当前终端;
-
内核串口信息实时显示;
-
可以快速观察启动流程。
适用于:
-
内核启动调试;
-
驱动开发;
-
Panic错误分析。
如果需要同时保存,可以结合tee:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -serial stdio | tee qemu.log
这样终端显示和文件保存同时进行。
使用mon:stdio同时管理QEMU控制台
QEMU提供了更加灵活的字符设备管理方式:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -serial mon:stdio
其中:
-
串口输出显示在终端;
-
QEMU Monitor也共享当前终端。
按下:
Ctrl+A C
可以进入QEMU Monitor模式。
Monitor中可以执行:
info registers info cpus savevm snapshot1
方便进行底层调试。
保存完整QEMU运行日志
除了串口输出,有时候还需要记录QEMU自身运行信息,例如设备初始化、异常信息等。
可以使用:
Bashqemu-system-x86_64 -kernel bzImage -d guest_errors -D qemu_debug.log
参数说明:
-d guest_errors
记录客户机错误。
-D qemu_debug.log
指定日志文件。
QEMU支持多种调试类别:
查看支持列表:
Bashqemu-system-x86_64 -d help
常见选项:
| 参数 | 作用 |
|---|---|
| guest_errors | 捕获客户机错误 |
| int | 记录中断信息 |
| cpu_reset | CPU复位日志 |
| in_asm | 输出执行指令 |
| exec | 指令执行跟踪 |
例如:
Bashqemu-system-x86_64 -d cpu_reset,int -D debug.log
可以用于分析系统启动异常。
Linux内核串口参数配置
QEMU能够捕获串口输出的前提是内核正确配置console。
常见启动参数:
console=ttyS0
表示使用第一个串口。
完整示例:
root=/dev/sda console=ttyS0 earlyprintk=serial,ttyS0,115200
其中:
console
指定正式内核日志输出设备。
earlyprintk
开启早期内核打印。
例如:
earlyprintk=serial,ttyS0,115200
可以捕获内核非常早期阶段的信息。
如果启动过程中出现:
Kernel panic
或者:
Unable to mount root fs
早期日志对于定位原因非常关键。
使用virtio串口进行高级调试
除了传统ttyS0,QEMU还支持virtio串口:
启动:
Bashqemu-system-x86_64 -chardev file,id=char0,path=serial.log -device virtio-serial -device virtconsole,chardev=char0
适用于:
-
虚拟机通信;
-
Guest和Host数据交换;
-
自动化测试环境。
相比传统UART,virtio串口具有更高性能和更灵活的设备管理能力。
使用GDB结合串口日志调试内核
当日志无法定位问题时,可以结合GDB远程调试。
启动QEMU:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -S -s
参数:
-S
启动后暂停CPU。
-s
开启GDB端口1234。
连接:
Bashgdb vmlinux
进入:
gdbtarget remote :1234
此时可以:
-
设置断点;
-
查看寄存器;
-
单步执行;
-
分析内核初始化流程。
串口日志和GDB结合,可以快速定位复杂启动问题。
自动化保存QEMU测试日志
在持续集成环境中,可以编写脚本自动保存日志:
Bash#!/bin/bash LOG=qemu_$(date +%Y%m%d_%H%M%S).log qemu-system-x86_64 -kernel bzImage -append "console=ttyS0" -serial file:$LOG -nographic echo "Log saved: $LOG"
运行后,每次测试都会生成独立日志文件。
这种方式适合:
-
Linux内核CI测试;
-
操作系统实验环境;
-
自动化启动验证。
常见问题与解决方法
QEMU启动后没有内核日志
检查内核启动参数:
Bashcat /proc/cmdline
确认包含:
console=ttyS0
同时确认内核配置:
CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y
日志文件为空
可能原因:
-
内核没有输出到串口;
-
串口设备配置错误;
-
使用了错误的tty设备。
尝试:
console=ttyS0,115200
指定波特率。
QEMU终端无法退出
使用:
Ctrl+A X
退出QEMU。
或者启动时加入:
Bash-no-reboot
方便观察崩溃现场。
日志内容乱码
检查串口速率:
console=ttyS0,115200
并确保QEMU配置一致。
QEMU日志捕获最佳实践
在实际内核开发中,推荐组合:
Bashqemu-system-x86_64 -kernel bzImage -append "console=ttyS0 earlyprintk=serial,ttyS0" -serial file=serial.log -d guest_errors -D qemu_debug.log -no-reboot
该方案可以同时获得:
-
内核串口输出;
-
QEMU错误日志;
-
崩溃现场保留;
-
自动化分析基础。
对于开发Linux内核、Bootloader或嵌入式系统而言,完善的日志保存方案能够显著减少调试时间。通过合理利用QEMU提供的-serial、-D、-d以及内核console参数,可以建立稳定、高效的虚拟硬件调试环境。