我目前正在通过实现块设备驱动程序开始内核编程。我能够进行“简单”的实现,并且我想进一步了解块子系统提供的功能。
为此,我想使用 qemu 模拟我自己的操作系统,以避免每次在内核设备代码中犯错时导致我的开发操作系统崩溃。
主机系统配置
在我的工作站上,我使用的是运行内核 4.9.0 的 Debian 9。
$ uname -a
Linux PC325 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) x86_64 GNU/Linux
镜像盘制作
为了创建虚拟机,我创建了一个 500M 的原始映像dd if=/dev/zero of=vm-image.raw bs=1M count=512
然后使用以下命令将其格式化为 ext4mkfs.ext4 vm-image.raw
@meuh 评论后更新:
然后我按如下方式填充磁盘映像:
mount vm-image.raw /mnt
mkdir /mnt/dev /mnt/lib /mnt/proc /mnt/root /mnt/run /mnt/sbin /mnt/sys
cp -r /etc /mnt/
cp -r /lib/systemd /mnt/lib
ln -s /lib/systemd/systemd /mnt/sbin/init
我现在尝试启动模拟操作系统,但在配置它时遇到一些问题。
运行命令
$ qemu-system-x86_64 -k fr -kernel /boot/vmlinuz-$(uname -r) -initrd /boot/initrd.img-$(uname -r) -hda vm/vm-image.raw -append "initrd=/boot/initrd.img-$(uname -r) root=/dev/sda rw console=ttyS0" -nographic
引导跟踪
[...] Kernel boot sequence [...]
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ... done.
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... [ 2.015241] tsc: Refined TSC clocksource calibration: 3392.292 MHz
[ 2.016768] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x30e5dd94d34, max_idle_ns: 440795304975 ns
[ 2.895630] random: fast init done
Begin: Waiting for suspend/resume device ... Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
[ 11.111765] random: crng init done
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
done.
Gave up waiting for suspend/resume device
done.
Begin: Will now check root file system ... fsck from util-linux 2.29.2
[/sbin/fsck.ext4 (1) -- /dev/sda] fsck.ext4 -a -C0 /dev/sda
/dev/sda: clean, 3607/32768 files, 12617/131072 blocks
done.
[ 35.528453] EXT4-fs (sda): mounted filesystem with ordered data mode. Opts: (null)
done.
Begin: Running /scripts/local-bottom ... done.
Begin: Running /scripts/init-bottom ... done.
run-init: /sbin/init: No such file or directory
[ 35.569247] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
[ 35.569247]
[ 35.570469] CPU: 0 PID: 1 Comm: run-init Not tainted 4.9.0-6-amd64 #1 Debian 4.9.82-1+deb9u3
[ 35.571599] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[ 35.572695] 0000000000000000 ffffffff9792e074 ffff974c05e14d00 ffffa66e8003feb8
[ 35.573741] ffffffff9777cfbd ffff974c00000010 ffffa66e8003fec8 ffffa66e8003fe60
[ 35.574780] a4112d94e56af84a ffff974c05e14d80 0000000000000100 ffff974c05e84490
[ 35.575793] Call Trace:
[ 35.576132] [<ffffffff9792e074>] ? dump_stack+0x5c/0x78
[ 35.576815] [<ffffffff9777cfbd>] ? panic+0xe4/0x23f
[ 35.577453] [<ffffffff9767c2de>] ? do_exit+0xade/0xae0
[ 35.578136] [<ffffffff978058b4>] ? vfs_write+0x144/0x190
[ 35.578830] [<ffffffff9767c313>] ? SyS_exit+0x13/0x20
[ 35.579510] [<ffffffff97603b7f>] ? do_syscall_64+0x8f/0xf0
[ 35.580223] [<ffffffff97c113b8>] ? entry_SYSCALL_64_after_swapgs+0x42/0xb0
[ 35.581209] Kernel Offset: 0x16600000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[ 35.582584] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
[ 35.582584]
问题
1 - 尝试读取软盘设备
启动时,内核似乎尝试从不存在或不可读的软盘设备读取数据。内核在 30 次尝试后放弃,因此这不是一个关键问题,但它使启动顺序减慢了 30 秒。
我尝试使用-no-fd-bootchk
选项运行 qemu 但它没有改变任何东西
更新:-fda floppy.img
作为1ko 的原始归零映像, 精确floppy.img
抑制与软盘相关的错误消息,并在启动时节省长达 20 秒的时间。然而,正如您在引导跟踪中看到的那样,/scripts/local-block
仍然会运行多次,并且需要最多 10 秒才能进入下一步。
2 - 无法初始化系统
@meuh 评论后更新:
内核似乎无法找到有效的初始化脚本。但是/sbin/init
存在于磁盘映像上并且是到 的符号链接/lib/systemd/systemd
。
我遇到了内核恐慌,但我不知道是什么原因造成的。
问题
我对 qemu 很陌生,我认为我的模拟系统工作已经不远了,但我无法更进一步。
我尝试使用参数,但找不到一种能够完全启动并显示 bash 提示符而不是 initramdisk 提示符的解决方案。
@meuh 评论后更新:
我应该将什么复制到磁盘映像才能初始化系统?
答案1
我还没有这样做,因为通常人们会从 iso 或现有的 qemu 映像安装 qemu,所以可能有一种比以下更简单的方法。您缺少的几乎相当于您需要的文件系统chroot。
要尝试的一件事是
sudo debootstrap --arch=amd64 unstable ~/debian-tree/
它会下降并解压大约 300Mbytes 的文件,您可以将其作为 systemd 容器“启动”并进行测试
sudo systemd-nspawn -D ~/debian-tree/ -b
看man machinectl
。您可以通过将 qemu 映像设为块设备来挂载它:
sudo apt-get install qemu-utils
sudo modprobe nbd
ls /dev/nbd* # gives /dev/nbd0 /dev/nbd1 ...
sudo qemu-nbd -c /dev/nbd0 /my/vm-image
sudo mount /dev/nbd0 /mnt/... # nbd0p1 if you have partitioned
sudo rsync -HSaxX ~/debian-tree/ /mnt/...
并将这棵树复制到其中。运行 qemu 时,您通常需要提供更大的 VM 大小以避免崩溃:
qemu-system-x86_64 -m 512M ... -machine pc,accel=kvm -cpu host -enable-kvm
使用-boot d
可能会避免访问软盘。