我已经编译了一个 Linux 内核,我想在 QEMU 中调试它。我通过执行命令创建了一个用于启动的文件
$ qemu-img create -f raw disk.img 200M
$ mkfs.ext2 -F disk.img
# mkdir /mnt/rootfs
# mount -o loop disk.img /mnt/rootfs
然后我做了qemu -kernel bzImage -initrd disk.img
并得到下面的屏幕,上面写着:
Kernel panic - not syncing: VFS: unable to mount root fs on unknown block
我做错了什么以及我能做些什么来解决它?
答案1
发生的情况是您试图以“过时”的方式启动 Linux。这就是initrd
ramdisk,而不是由内核在 ramfs 中解压的压缩 cpio 存档,并使用旧方法切换到终端设备。
在该模式下,内核将 disk.img 作为 ramdisk 挂载为根文件系统,然后/linuxrc
在其中执行。在你的情况下,很可能没有这样的文件。当/linuxrc
(应该做任何必要的事情来为真正的根文件系统启动块设备)退出时,内核就会挂载真正的根文件系统。
上面的消息表明它成功挂载了 ram 磁盘(1,0: 1 代表ram
,所以/dev/ram0
),但没有挂载真正的根文件系统 /dev/sda1(8,1: 8 代表sd
,1 代表a1
)。大概是因为您没有指定内核命令行 ( -append
),它/dev/sda1
来自在内核编译时传递的 CONFIG_CMDLINE 或使用rdev
.
如果您的 disk.img 旨在包含一个根文件系统,例如一个小型 Linux 发行版/sbin/init
,那么您可能想改为编写它:
kvm -kernel kernel.img -initrd disk.img -append 'root=/dev/ram0`
然后,内核会将 RAM 磁盘视为真正的根文件系统(尽管您仍然可以pivot_root
使用另一个)。
为了能够更轻松地查看内核消息,我建议使用串行输出:
kvm -kernel kernel.img -initrd disk.img -nographic -append "root=/dev/ram0 console=ttyS0"
作为替代方案,您可以使用 init ramfs 而不是 init ramdisk:
mkdir -p RAMFS/{bin,dev}
cd RAMFS/bin
cp /bin/busybox .
"$PWD/busybox" --install .
cd ..
cp -a /dev/{null,tty,zero,console} dev
printf '%s\n' "#! /bin/sh -" "exec /bin/sh" > init
chmod +x init
find . | cpio -oHnewc | gzip > ../initramfs.gz
cd ..
kvm -kernel kernel.img -initrd initramfs.gz
(提供的busybox
是静态链接版本)并且您将在该内核中获得 shell 和其他 busybox 实用程序)。
请注意,内核现在以该模式/init
相反的方式/linuxrc
运行。/sbin/init
答案2
内核告诉你,它不知道哪个设备保存根文件系统。你的循环安装是不必要的。 (在继续之前卸载它)。
尝试像这样的命令
qemu -kernel bzImage -hda disk.img -append root=/dev/sda
该-hda disk.img
参数告诉 qemu 根据您的disk.img
.
-append root=/dev/sda
qemu 使用该开关来告诉内核它的根设备。这是通过将 附加root=/dev/sda
到内核命令行来完成的。您可以通过执行以下操作将其与您自己的内核的内核命令行进行比较cat /proc/cmdline
(这是安全的)。您也应该看到那里有一个root
参数。
答案3
CONFIG_BLK_DEV_INITRD=y
这个内核配置选项也是必需的。它在 Linux 内核上启用 initrd 支持。
BR2_TARGET_ROOTFS_CPIO=y
幸运的是,Buildroot 在给出时默认为我们设置了它。
然后,您可以使用该选项将 CPIO 传递给 QEMU qemu -initrd
。我的完整 QEMU 命令是:
./buildroot/output.x86_64~/host/usr/bin/qemu-system-x86_64 -m 128M -monitor telnet::45454,server,nowait -netdev user,hostfwd=tcp::45455-:45455,id=net0 -smp 1 -M pc -append ' nopat nokaslr norandmaps printk.devkmsg=on printk.time=y console=ttyS0' -device edu -device lkmc_pci_min -device virtio-net-pci,netdev=net0 -kernel ./buildroot/output.x86_64~/images/bzImage -nographic -initrd './buildroot/output.x86_64~/images/rootfs.cpio'
这是一个简约的全自动 Buildroot + QEMU 示例:https://github.com/cirosantilli/linux-kernel-module-cheat/tree/b3868a3b009f2ab44fa6d3db3d174930b3cf7b69#initrd