author: hjjdebug
date: 2026年 05月 02日 星期六 16:50:42 CST
descrip: qemu直接启动内核+内存文件系统+双终端+文件共享+USB直通
文章目录
- [1. qemu 启动脚本文件](#1. qemu 启动脚本文件)
-
- [1.1 脚本解释](#1.1 脚本解释)
- [2 配套的制作根内存文件系统的脚本](#2 配套的制作根内存文件系统的脚本)
直接启动内核 + 内存文件系统 + 双终端 + 文件共享 + USB 直通
适合场景:Linux 内核开发,驱动调试,usb驱动调试,嵌入式系统调试
这些命令组合,本人花了不少时间来实验和体会. 是一个基础命令
1. qemu 启动脚本文件
cpp
$ cat qemu_run.sh
#!/bin/bash
qemu-system-x86_64 \
-m 2G -smp 1 \
-enable-kvm -cpu host \
-kernel arch/x86/boot/bzImage \
-initrd ~/test/rootfs/initramfs.cpio.gz \
-append "root=/dev/ram0 console=ttyS0 console=ttyS1 nokaslr" \
-serial stdio \
-serial telnet:127.0.0.1:5555,server=on,wait=off \
-fsdev local,security_model=passthrough,id=hostshare,path=/mnt/share \
-device virtio-9p-pci,fsdev=hostshare,mount_tag=host_share \
-usb \
-device usb-host,vendorid=0x067b,productid=0x2303 \
-display none
1.1 脚本解释
cpp
-m 2G # 给虚拟机分配 2GB 内存
-smp 1 # 给虚拟机分配 1个CPU核心, 调试时不会乱跳,如果不调试,可以给多个
cpp
-enable-kvm # 开启Linux KVM 硬件虚拟化,速度接近物理机
-cpu host # 让虚拟机CPU模型和物理主机完全一致,发挥cpu性能
cpp
-kernel arch/x86/boot/bzImage
直接使用编译好的 Linux 内核镜像,不需要 ISO / 磁盘镜像,适合内核开发 / 调试。
cpp
-initrd ~/test/rootfs/initramfs.cpio.gz
initramfs 是内存文件系统(压缩包),内核启动后直接把它加载到内存作为根目录,不需要硬盘。
cpp
-append "root=/dev/ram0 console=ttyS0 console=ttyS1 nokaslr"
内核启动参数
root=/dev/ram0:告诉内核根文件系统在内存盘(对应 initramfs)
/dev/ram0 是现代写法,代表主设备号1,次设备号0的内存盘.
console=ttyS0 console=ttyS1:把内核日志 / 终端输出重定向到两个串口
nokaslr:关闭内核地址随机化,方便内核调试、GDB 跟踪
cpp
-serial stdio: 把串口0 直接映射到你当前执行命令的终端,内核日志会直接打印在这里
-serial telnet:127.0.0.1:5555,server=on,wait=off
串口 1 绑定到 localhost:5555
server=on: localhost 服务器.
你可以用:telnet 127.0.0.1 5555 连接服务器,服务器时第二个串口终端设备
wait=off:QEMU 不用等待 Telnet 连接,继续执行
在启动脚本中你需要启动第二个shell
cpp
-fsdev local,security_model=passthrough,id=hostshare,path=/mnt/share \
-device virtio-9p-pci,fsdev=hostshare,mount_tag=host_share
这是主机和虚拟机共享文件夹的配置:
主机路径:/mnt/share
虚拟机挂载标签:host_share
虚拟机内挂载命令:mount -t 9p -o trans=virtio host_share /mnt
cpp
-usb # 开启虚拟机USB控制器
-device usb-host,vendorid=0x067b,productid=0x2303
ust-host, USB 直通:使用物理 USB / 串口硬件
0x067b:0x2303 主机上开放的usb转串口的VID:PID
虚拟机可以直接使用这个硬件
cpp
-display none
没有显卡、没有窗口、没有虚拟控制台tty0(键盘+显示器终端)
模拟了两路硬件串口:ttyS0、ttyS1
内核只能把日志 / 控制台绑到 存在的串口设备
适合服务器 / 调试场景
2 配套的制作根内存文件系统的脚本
注释都在脚本中了.
cpp
$ cat build_initramfs.sh
#!/bin/bash
# 配置项
BUSYBOX="/bin/busybox" # 改成你自己的静态 busybox 路径,要静态的,否则不能运行
OUTPUT="initramfs.cpio.gz"
WORKDIR="./initramfs.tmp"
# 清理
rm -rf "$WORKDIR" "$OUTPUT"
mkdir -p "$WORKDIR"
cd "$WORKDIR" || exit 1
# 1. 创建目录结构
mkdir -p bin dev etc proc sys host
# 2. 创建 etc/fstab(mount -a 调用, 9P 自动挂载)
cat > etc/fstab <<EOF
devtmpfs /dev devtmpfs defaults 0 0
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
host_share /host 9p trans=virtio,version=9p2000.L 0 0
EOF
# 3. 创建 profile, login shell 调用
cat > etc/profile <<EOF
alias ls='ls --color'
alias ll='ls -l'
alias his='history'
mknod /dev/demo_drv c 247 0
insmod /host/demo_drv.ko
EOF
# 4. 生成 init 脚本, 内核默认调用该用户态文件
cat > init <<'EOF'
#!/bin/sh
# 按 fstab 自动挂载
mount -a
# setsid,开新会话,是后面程序成为组长
# cttyhack 修复终端, 我碰到的是消除一个Can't access tty; job control turned off的警告
# sh 跑shell
# -l 会启用login shell, 从而执行profile文件
setsid /bin/cttyhack /bin/sh -l &
# -c 是执行一个子shell命令
# 把当前 shell 的 键盘输入、屏幕输出、报错输出,全部切换到 /dev/ttyS1 这个串口上
# 用新sh替换当前进程
setsid sh -c 'exec 0<>/dev/ttyS1 1>&0 2>&0; exec sh' &
wait
EOF
chmod +x init
# 5. 放入 busybox
cp "$BUSYBOX" bin/
chmod +x bin/busybox
# 建立软链接
cd bin || exit 1
for cmd in sh setsid cttyhack mount modprobe ls cat mkdir dmesg insmod rmmod; do
ln -s busybox "$cmd"
done
cd ..
# 6. 打包 cpio+gzip
find . | cpio -o -H newc | gzip -9 > ../"$OUTPUT"
# 完成
cd ..
rm -rf "$WORKDIR"
echo "✅ 生成成功:$OUTPUT"