QEMU启动日志保存与内核串口输出捕获方案

8 次阅读

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启动后,默认会将虚拟机显示内容输出到当前终端。例如:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0"

其中:

  • -kernel指定Linux内核镜像;

  • -append向内核传递启动参数;

  • console=ttyS0表示将内核控制台绑定到第一个串口。

如果终端直接关闭,日志也会随之丢失。因此实际开发过程中通常需要进行输出重定向。

使用标准输出保存QEMU日志

最简单的方法是利用Shell重定向:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0" 
    > qemu.log 2>&1

执行后:

  • 标准输出保存到qemu.log;

  • 错误输出也写入同一个文件。

查看日志:

Bash
cat qemu.log

或者实时查看:

Bash
tail -f qemu.log

这种方式适用于普通启动日志记录,但对于内核串口调试场景还不够完善。

使用QEMU串口重定向捕获内核输出

Linux内核通过串口输出日志时,推荐使用QEMU的串口参数。

例如:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0" 
    -serial file:qemu_serial.log

参数说明:

-serial file:qemu_serial.log

表示将虚拟串口数据直接写入文件。

启动后,可以查看:

Bash
less qemu_serial.log

这种方式相比普通重定向更加可靠,因为它捕获的是虚拟串口设备的数据流。

使用stdio模式实时查看串口日志

开发内核时,经常需要边运行边观察输出:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0" 
    -serial stdio

此时:

  • QEMU占用当前终端;

  • 内核串口信息实时显示;

  • 可以快速观察启动流程。

适用于:

  • 内核启动调试;

  • 驱动开发;

  • Panic错误分析。

如果需要同时保存,可以结合tee:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0" 
    -serial stdio | tee qemu.log

这样终端显示和文件保存同时进行。

使用mon:stdio同时管理QEMU控制台

QEMU提供了更加灵活的字符设备管理方式:

Bash
qemu-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自身运行信息,例如设备初始化、异常信息等。

可以使用:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -d guest_errors 
    -D qemu_debug.log

参数说明:

-d guest_errors

记录客户机错误。

-D qemu_debug.log

指定日志文件。

QEMU支持多种调试类别:

查看支持列表:

Bash
qemu-system-x86_64 -d help

常见选项:

参数作用
guest_errors捕获客户机错误
int记录中断信息
cpu_resetCPU复位日志
in_asm输出执行指令
exec指令执行跟踪

例如:

Bash
qemu-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串口:

启动:

Bash
qemu-system-x86_64 
    -chardev file,id=char0,path=serial.log 
    -device virtio-serial 
    -device virtconsole,chardev=char0

适用于:

  • 虚拟机通信;

  • Guest和Host数据交换;

  • 自动化测试环境。

相比传统UART,virtio串口具有更高性能和更灵活的设备管理能力。

使用GDB结合串口日志调试内核

当日志无法定位问题时,可以结合GDB远程调试。

启动QEMU:

Bash
qemu-system-x86_64 
    -kernel bzImage 
    -append "console=ttyS0" 
    -S 
    -s

参数:

-S

启动后暂停CPU。

-s

开启GDB端口1234。

连接:

Bash
gdb vmlinux

进入:

gdb
target 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启动后没有内核日志

检查内核启动参数:

Bash
cat /proc/cmdline

确认包含:

console=ttyS0

同时确认内核配置:

CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y

日志文件为空

可能原因:

  1. 内核没有输出到串口;

  2. 串口设备配置错误;

  3. 使用了错误的tty设备。

尝试:

console=ttyS0,115200

指定波特率。


QEMU终端无法退出

使用:

Ctrl+A
X

退出QEMU。

或者启动时加入:

Bash
-no-reboot

方便观察崩溃现场。


日志内容乱码

检查串口速率:

console=ttyS0,115200

并确保QEMU配置一致。

QEMU日志捕获最佳实践

在实际内核开发中,推荐组合:

Bash
qemu-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参数,可以建立稳定、高效的虚拟硬件调试环境。