系列简介:TinyLinux 是由 LabHub 发起的"大道至简"Linux 学习项目。我们通过对内核进行"剔骨"级的物理精简,旨在构建一个 100% 透明、可重现的极简实验室。
公众号:LabHub | 项目仓库:https://gitee.com/lynyujiang/tiny-linux.git
scripts/run_qemu.sh | |
qemu-system-x86_64 模拟完整的 PC 硬件环境。在嵌入式 Linux 开发中,调试手段有限:
QEMU 提供了完美的解决方案:
┌─────────────────────────────────────────────────────────┐
│ 1. BIOS/UEFI (SeaBIOS) - 0.05s │
│ - 硬件初始化 │
│ - 引导加载器 │
├─────────────────────────────────────────────────────────┤
│ 2. 内核解压 - 0.05s │
│ - bzImage 解压到内存 │
│ - 设置页表 │
├─────────────────────────────────────────────────────────┤
│ 3. 内核早期初始化 - 0.35s │
│ - early_printk 输出 │
│ - CPU/内存检测 │
│ - 中断控制器初始化 │
├─────────────────────────────────────────────────────────┤
│ 4. 内核核心初始化 - 0.65s │
│ - 调度器初始化 │
│ - 设备驱动探测 │
│ - 挂载根文件系统 │
├─────────────────────────────────────────────────────────┤
│ 5. 用户空间 init - 0.40s │
│ - 执行 /sbin/init │
│ - 挂载 /proc /sys /dev │
│ - 启动 shell │
├─────────────────────────────────────────────────────────┤
│ 6. Shell 提示符 - 0.05s │
│ - 显示 TinyLinux# │
└─────────────────────────────────────────────────────────┘
总计:约 1.4 秒
QEMU 虚拟机 主机终端
│ │
│ ttyS0 (UART 16550A) │
│ 波特率:115200 │
│ 数据位:8 │
│ 停止位:1 │
│ 校验位:无 │
│ │
└─────── 串行通信 ───────────┘
串口调试的优势:
#!/bin/bash
###############################################################################
# TinyLinux OS - QEMU Execution Script
###############################################################################
export LC_ALL=C LANGUAGE=C LANG=C
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-load environment
if [ ! "${TINYLINUX_ENV_LOADED}" ]; then
source "${SCRIPT_DIR}/../env.sh"
fi
# Find Artifacts
KERNEL_PATH="${TINYLINUX_TARGET_DIR}/bzImage"
INITRD_PATH="${TINYLINUX_TARGET_DIR}/rootfs.cpio.xz"
# QEMU 基础参数
QEMU_ARGS="-m 512 -smp 1" # 512MB 内存,单核 CPU
QEMU_ARGS="$QEMU_ARGS -kernel ${KERNEL_PATH}" # 直接内核启动
QEMU_ARGS="$QEMU_ARGS -initrd ${INITRD_PATH}" # 加载 initrd
QEMU_ARGS="$QEMU_ARGS -nographic -no-reboot" # 无图形界面,崩溃不重启
# 内核启动参数
APPEND="console=ttyS0 earlyprintk=serial,ttyS0,115200 root=/dev/ram0 rdinit=/sbin/init loglevel=7 debug panic=1"
echo "Command: qemu-system-x86_64 $QEMU_ARGS -append \"$APPEND\""
echo "TIP: Press 'Ctrl+A then X' to exit QEMU."
qemu-system-x86_64 $QEMU_ARGS -append "$APPEND"
console=ttyS0 | |
earlyprintk=serial,ttyS0,115200 | |
root=/dev/ram0 | |
rdinit=/sbin/init | |
loglevel=7 | |
debug | |
panic=1 |
# 1. 基础调试(当前配置)
qemu-system-x86_64 -m 512 -smp 1 \
-kernel bzImage -initrd rootfs.cpio.xz \
-nographic -no-reboot
# 2. 启用 GDB 调试
qemu-system-x86_64 ... -s -S
# -s: 在 1234 端口监听 GDB
# -S: 启动时暂停,等待 GDB 连接
# 3. 添加虚拟硬盘
qemu-system-x86_64 ... -hda disk.img
# 4. 启用网络(用户模式)
qemu-system-x86_64 ... -netdev user,id=net0 -device e1000,netdev=net0
# 5. 多核调试
qemu-system-x86_64 ... -smp 4
# 6. 增加内存
qemu-system-x86_64 ... -m 1024
CONFIG_SERIAL_8250 | ||
CONFIG_SERIAL_8250_CONSOLE | ||
CONFIG_EARLY_PRINTK | ||
CONFIG_BLK_DEV_INITRD | ||
CONFIG_RD_XZ |
console=ttyS0 | ||
rdinit= 参数 | ||
-nographic 参数 | ||
/etc/init.d/rcS |
cd /home/devhub/xlabs/tiny-linux
source env.sh
./scripts/run_qemu.sh
# 启动后,所有日志会输出到终端
# 使用 tee 保存日志
./scripts/run_qemu.sh 2>&1 | tee boot.log
# 启动日志中的关键时间点
[ 0.000000] Linux version 6.12.51-tinylinux # 内核启动
[ 0.410866] Unpacking initramfs... # 解压 initrd
[ 0.674819] Run /sbin/init as init process # init 开始
[ 1.440743] TinyLinux# # Shell 就绪
# 终端 1: 启动 QEMU(带 GDB)
qemu-system-x86_64 -m 512 -kernel bzImage -initrd rootfs.cpio.xz \
-nographic -s -S
# 终端 2: 连接 GDB
gdb vmlinux
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) continue
# 创建自定义启动脚本
cat > scripts/run_qemu_debug.sh << 'EOF'
#!/bin/bash
source env.sh
qemu-system-x86_64 \
-m 1024 \
-smp 2 \
-kernel output/target/bzImage \
-initrd output/target/rootfs.cpio.xz \
-nographic \
-no-reboot \
-append "console=ttyS0 loglevel=7 debug" \
-monitor stdio
EOF
chmod +x scripts/run_qemu_debug.sh
启动过程中重点关注:
1. BIOS 阶段(约 0.05s)
SeaBIOS (version 1.16.3...)
Booting from ROM...
2. 内核版本信息
Linux version 6.12.51-tinylinux
Command line: console=ttyS0...
3. 内存映射
BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
Memory: 498316K/523768K available
4. 设备探测
serial8250: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200)
rtc_cmos rtc_cmos: registered as rtc0
5. initramfs 加载
Unpacking initramfs...
Freeing initrd memory: 996K
6. init 进程启动
Run /sbin/init as init process
7. Shell 就绪
TinyLinux#
Ctrl+A X | Ctrl+A C 切换到 QEMU 控制台,再按 x | |
earlyprintk 使用 115200 | ||
./scripts/make_all.sh | ||
sudo usermod -aG kvm $USER |
./scripts/run_qemu.sh
SeaBIOS (version 1.16.3-debian-1.16.3-2)
Booting from ROM...
[ 0.000000] Linux version 6.12.51 (gcc ... 14.2.0) #1 Sun Mar 8 12:51:17 CST 2026
[ 0.000000] Command line: console=ttyS0 earlyprintk=serial,ttyS0,115200 root=/dev/ram0 rdinit=/sbin/init loglevel=7 debug panic=1
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000001ffdffff] usable
[ 0.085365] clocksource: tsc-early: mask: 0xffffffffffffffff max_cycles: 0x2df1207f605, max_idle_ns: 440795276719 ns
[ 0.333567] Memory: 498316K/523768K available (6144K kernel code, 1191K rwdata, 904K rodata, 792K init, 2072K bss, 22988K reserved)
[ 0.410866] Unpacking initramfs...
[ 0.570831] Freeing initrd memory: 996K
[ 0.672333] Freeing unused kernel image (initmem) memory: 792K
[ 0.674819] Run /sbin/init as init process
[ 1.440743] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2df1207f605, max_idle_ns: 440795276719 ns
Please press Enter to activate this console.
TinyLinux#
# 1. 查看内核版本
uname -a
# 输出:Linux TinyLinux 6.12.51 #1 Sun Mar 8 12:51:17 CST 2026 x86_64 GNU/Linux
# 2. 查看内存使用
free -h
# 输出:约 487MB 可用
# 3. 查看进程
ps
# 输出:init + shell 进程
# 4. 查看挂载点
mount
# 输出:proc, sysfs, devtmpfs
# 5. 查看设备
ls -l /dev/
# 输出:ttyS0, null, zero 等
9e35606c4 | |
git checkout 9e35606c4 | |
source env.sh && ./scripts/run_qemu.sh | |
TinyLinux# |
⚠️ 注意:Git 提交信息请执行
git log --oneline -5获取最新提交。
通过本章,我们掌握了 QEMU 虚拟化调试的核心技能:
在 [TinyLinux-005] 中,我们将探索内核模块的编译和加载,让系统支持更多硬件设备。敬请期待!
如果你觉得这个项目对理解 Linux 底层有帮助,请不要吝啬你的支持:
本文由 LabHub 团队原创,转载请注明出处。
项目地址:https://gitee.com/lynyujiang/tiny-linux.git