4. QEMU启动内核基础

QEMU(Quick Emulator)是嵌入式Linux内核调试中最核心的虚拟化工具。本章将系统讲解QEMU启动内核的关键命令行参数,并通过一个完整的实践案例,引导你成功启动第一个内核镜像。掌握这些基础参数,是后续进行内核异常定位和调试的前提。

学习目标: 理解 -kernel、-initrd、-append、-m、-smp 等核心参数的含义与用法;能够独立编写QEMU启动脚本并成功启动一个最小Linux系统。

4.1 QEMU启动内核的核心参数全景

QEMU模拟一台完整的计算机,启动内核的过程类似于物理机加电启动。以下五个参数构成了最常用的启动组合,它们分别对应内核镜像、初始根文件系统、内核启动参数、内存大小和CPU数量。

QEMU启动内核核心参数架构图 QEMU 启动内核核心参数架构 QEMU 系统模拟器 -kernel -initrd -append -m -smp 参数说明: -kernel: 指定内核镜像文件路径(如 vmlinuz、bzImage) -initrd: 指定初始RAM磁盘镜像,用于挂载真正的根文件系统前提供最小环境 -append: 向内核传递启动参数(如 console、root、init 等)

4.2 五大核心参数详解

4.2.1 -kernel:指定内核镜像

-kernel 参数用于指定QEMU加载的内核镜像文件。该镜像通常是经过编译的压缩内核,常见格式包括 bzImage(x86架构)和 zImage(ARM架构)。QEMU会模拟BIOS/UEFI启动过程,直接将内核加载到内存中并跳转到入口点执行。

典型用法:
qemu-system-x86_64 -kernel /path/to/bzImage

如果内核镜像路径包含空格或特殊字符,请使用双引号包裹。

4.2.2 -initrd:初始RAM磁盘

-initrd(Initial RAM Disk)参数指定一个压缩的根文件系统镜像(如 initrd.img 或 initramfs)。内核在启动初期会将该镜像加载到内存中,作为临时的根文件系统。initrd中通常包含必要的设备驱动、模块和初始化脚本,用于挂载真正的根文件系统。

特性 initrd (ramdisk) initramfs (cpio)
文件系统类型 基于块设备的ramdisk 基于tmpfs的cpio归档
大小限制 固定大小,需预先分配 动态增长,按需分配
加载方式 内核解压到ramdisk块设备 内核直接解压到tmpfs
推荐使用 旧内核或特殊场景 现代Linux发行版标准方式
注意: 如果使用initramfs,内核配置中必须启用 CONFIG_BLK_DEV_INITRD 选项。QEMU对两种格式均支持,但推荐使用initramfs以获得更好的灵活性和性能。

4.2.3 -append:内核启动参数

-append 参数用于向内核传递命令行参数,这些参数与物理机上通过GRUB传递的参数作用完全相同。常见参数包括:

  • console:指定控制台设备,如 console=ttyS0 将串口作为控制台。
  • root:指定根文件系统设备,如 root=/dev/sda1 或 root=/dev/nfs。
  • init:指定第一个用户空间进程,默认为 /sbin/init。
  • quiet:减少内核启动时的日志输出。
  • debug:开启内核调试信息输出。
典型用法:
qemu-system-x86_64 -kernel bzImage -initrd initrd.img \
  -append "console=ttyS0 root=/dev/ram0 rdinit=/sbin/init"

多个参数之间用空格分隔,整个参数字符串需要用双引号包裹。

4.2.4 -m:内存大小

-m 参数用于指定QEMU虚拟机可用的物理内存大小。默认单位为MB,也可以使用 G 后缀指定GB。合理的内存分配对内核启动和后续调试至关重要。

场景 推荐内存大小 说明
最小启动测试 64M ~ 128M 仅启动内核和initramfs,无图形界面
标准嵌入式调试 256M ~ 512M 可运行Busybox或小型Linux系统
完整发行版调试 1G ~ 4G 运行Ubuntu/Debian等完整系统
内核内存调试 512M ~ 2G 开启KASAN/SLUB调试时需更多内存
实践建议: 在调试内核启动异常时,建议分配至少256MB内存,以避免因内存不足导致的OOM(Out of Memory)错误干扰问题定位。

4.2.5 -smp:对称多处理

-smp 参数用于指定QEMU模拟的CPU核心数量。对于单核调试,使用 -smp 1 可以简化问题;对于多核并发问题,可以设置 -smp 4 或更多。

典型用法:
# 单核模式(推荐用于调试)
qemu-system-x86_64 -kernel bzImage -smp 1

# 四核模式(测试多核调度)
qemu-system-x86_64 -kernel bzImage -smp 4

# 指定拓扑结构
qemu-system-x86_64 -kernel bzImage -smp 4,sockets=1,cores=4,threads=1

4.3 启动第一个内核镜像:完整实践

下面通过一个完整的实践案例,展示如何使用QEMU启动一个最小Linux内核。我们将使用Busybox构建的最小根文件系统作为initramfs。

4.3.1 准备内核镜像和initramfs

假设你已经编译好了一个x86_64架构的内核镜像 bzImage,并准备好了initramfs文件 initramfs.cpio.gz。如果还没有,可以使用以下命令快速生成一个最小initramfs:

# 创建一个最小initramfs(使用Busybox)
mkdir -p initramfs/{bin,sbin,etc,proc,sys,dev}
cp /path/to/busybox initramfs/bin/
# 创建必要的设备节点
sudo mknod initramfs/dev/console c 5 1
sudo mknod initramfs/dev/null c 1 3
# 创建init脚本
cat > initramfs/init << 'EOF'
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Hello from QEMU Linux!"
exec /bin/sh
EOF
chmod +x initramfs/init
# 打包为cpio.gz
cd initramfs
find . | cpio -H newc -o | gzip > ../initramfs.cpio.gz
cd ..

4.3.2 编写QEMU启动命令

将以下命令保存为 boot.sh 脚本:

#!/bin/bash
# QEMU启动第一个内核镜像
qemu-system-x86_64 \
  -kernel ./bzImage \
  -initrd ./initramfs.cpio.gz \
  -append "console=ttyS0 rdinit=/init" \
  -m 256M \
  -smp 1 \
  -nographic
参数说明:
  • -nographic:不使用图形窗口,所有输出重定向到当前终端,便于调试。
  • console=ttyS0:将串口作为控制台,与 -nographic 配合使用。
  • rdinit=/init:指定initramfs中的init程序路径。

4.3.3 执行启动并观察输出

运行启动脚本:

chmod +x boot.sh
./boot.sh

你将看到内核启动日志从终端输出,最终进入Busybox的shell提示符。如果一切正常,输出应包含类似以下内容:

...
[    0.000000] Linux version 6.1.0 ...
[    0.123456] console [ttyS0] enabled
...
Hello from QEMU Linux!
/ # _
QEMU启动内核完整流程 QEMU 启动内核完整流程 1. QEMU 解析命令行 2. 加载内核到内存 3. 加载 initramfs 4. 内核解压并初始化 5. 挂载 initramfs 6. 执行 /init 程序 关键输出标识: - "Linux version ..." : 内核开始解压并初始化 - "console [ttyS0] enabled" : 控制台初始化成功 - "/ #" : 进入shell,系统启动完成

4.4 常见问题与排查

现象 可能原因 解决方案
QEMU提示 "Could not open kernel image" 内核镜像路径错误或文件不存在 检查 -kernel 参数路径是否正确,使用绝对路径
内核启动后卡住,无任何输出 console参数未正确设置 添加 console=ttyS0 并配合 -nographic
提示 "Kernel panic - not syncing: VFS: Unable to mount root fs" initramfs未正确加载或根文件系统损坏 检查 -initrd 路径,确认cpio.gz文件完整
内存不足导致启动失败 -m 分配的内存过小 增加内存分配,建议至少256M
多核启动异常 ACPI或SMP配置问题 先使用 -smp 1 排除多核问题
重要提示: 在调试内核启动异常时,建议始终使用 -nographic 模式,并将内核日志级别设置为 loglevel=8(通过 -append 传递),以获取最完整的启动日志。日志是定位启动异常的第一手资料。

4.5 本章小结

本章详细讲解了QEMU启动内核的五个核心参数:-kernel 指定内核镜像、-initrd 提供初始根文件系统、-append 传递内核启动参数、-m 控制内存大小、-smp 设置CPU数量。通过完整的实践案例,你已经成功启动了第一个内核镜像。这些基础操作是后续进行内核异常定位和QEMU调试的基石,请务必熟练掌握。