如何将磁盘映像附加到包含 linux 内核的根文件系统的 QEMU?

How to attach a disk image to QEMU containing root filesystem for linux kernel?

我可以使用 -kernel 在 QEMU 上启动 linux 内核,这非常简单明了。

但现在我正在尝试不同的东西。我模拟的是UEFI+GRUB+Kernel的组合

我已经从源代码构建了 OVMF 和 GRUB2,也能够加载内核映像,但是在创建 rootfs 磁盘映像并将其附加到 qemu 以便内核检测到它时遇到困难。

这就是我为内核准备 rootfs.img 的方式:

#Create an empty ext2 disk image of size 10M
dd if=/dev/zero of=rootfs.img bs=1M count=10
mke2fs -j rootfs.img

#Populate the disk
mkdir /mnt/rootfs
mount -o loop rootfs.img /mnt/rootfs
rsync -a busybox/_install/ /mnt/rootfs
chown -R root:root /mnt/rootfs
sync
umount /mnt/rootfs

这是我的 GRUB 配置的样子:

menuentry "Linux Kernel Boot" {
        set root=(hd0,msdos1)
        linux (hd0,msdos1)/bzImage-x86_64 root=/dev/sdb1 rootwait console=ttyS0,115200n8 console=tty0
}

这是我用来启动 qemu 的命令:

qemu-system-x86_64 -m 2G -drive  if=pflash,format=raw,readonly,file=OVMF_CODE.fd -drive if=pflash,format=raw,file=OVMF_VARS.fd -net none -serial stdio -display none -hda fat:disk -drive file=rootfs.img,index=1

我附加为 hda 的 FAT 磁盘包含我的 GRUB 和内核映像。我想要一个单独的磁盘用于 rootfs,并且不想为此目的使用此 FAT。

安装程序引导至内核,但内核无法挂载磁盘 sdb1,因此在 rootfs 中看不到 init,因此出现内核崩溃。以下是内核日志:

[    1.030290] NET: Registered protocol family 17
[    1.033540] ata1.01: configured for MWDMA2
[    1.042119] Key type dns_resolver registered
[    1.045150] scsi 0:0:0:0: Direct-Access     ATA      QEMU HARDDISK    2.5+ PQ: 0 ANSI: 5
[    1.049509] sched_clock: Marking stable (1049235510, 0)->(1378961625, -329726115)
[    1.058429] registered taskstats version 1
[    1.060917] Loading compiled-in X.509 certificates
[    1.066242] sd 0:0:0:0: [sda] 1032192 512-byte logical blocks: (528 MB/504 MiB)
[    1.070386] sd 0:0:0:0: Attached scsi generic sg0 type 0
[    1.074945] sd 0:0:0:0: [sda] Write Protect is off
[    1.079585] scsi 0:0:1:0: Direct-Access     ATA      QEMU HARDDISK    2.5+ PQ: 0 ANSI: 5
[    1.082483] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[    1.090820]   Magic number: 0:346:692
[    1.094970] sd 0:0:1:0: [sdb] 20480 512-byte logical blocks: (10.5 MB/10.0 MiB)
[    1.097740] sd 0:0:1:0: [sdb] Write Protect is off
[    1.101097] sd 0:0:1:0: Attached scsi generic sg1 type 0
[    1.108436] console [netcon0] enabled
[    1.110947] netconsole: network logging started
[    1.114830] sd 0:0:1:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[    1.122345] scsi 1:0:0:0: CD-ROM            QEMU     QEMU DVD-ROM     2.5+ PQ: 0 ANSI: 5
[    1.138010]  sda: sda1
[    1.142638] sr 1:0:0:0: [sr0] scsi3-mmc drive: 4x/4x cd/rw xa/form2 tray
[    1.145513] cdrom: Uniform CD-ROM driver Revision: 3.20
[    1.149749] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    1.164130] sd 0:0:1:0: [sdb] Attached SCSI disk
[    1.169575] sr 1:0:0:0: Attached scsi generic sg2 type 5
[    1.174262] sd 0:0:0:0: [sda] Attached SCSI disk
[    1.190198] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[    1.194508] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[    1.197606] cfg80211: failed to load regulatory.db
[    1.200837] ALSA device list:
[    1.203626]   No soundcards found.
[    1.531285] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
[    1.537979] md: Waiting for all devices to be available before autodetect
[    1.541357] md: If you don't use raid, use raid=noautodetect
[    1.548186] md: Autodetecting RAID arrays.
[    1.551815] md: autorun ...
[    1.554889] md: ... autorun DONE.
[    1.559995] VFS: Cannot open root device "sdb1" or unknown-block(8,17): error -6
[    1.563196] Please append a correct "root=" boot option; here are the available partitions:
[    1.566295] 0800          516096 sda
[    1.566326]  driver: sd
[    1.572371]   0801          516064 sda1 be1afdfa-01
[    1.572397]
[    1.577560] 0810           10240 sdb
[    1.577573]  driver: sd
[    1.582573] 0b00         1048575 sr0
[    1.582585]  driver: sr
[    1.587948] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,17)
[    1.590831] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.15.3+ #2
[    1.593384] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
[    1.596327] Call Trace:
[    1.600043]  dump_stack+0x46/0x59
[    1.602665]  panic+0xca/0x218
[    1.604991]  ? printk+0x3e/0x46
[    1.607197]  mount_block_root+0x174/0x223
[    1.609463]  ? set_debug_rodata+0xc/0xc
[    1.611851]  mount_root+0xfb/0x104
[    1.614159]  prepare_namespace+0x130/0x166
[    1.616415]  kernel_init_freeable+0x1c5/0x1d7
[    1.618676]  ? rest_init+0xb0/0xb0
[    1.621326]  kernel_init+0x5/0xf0
[    1.623768]  ret_from_fork+0x35/0x40
[    1.627035] Kernel Offset: 0x24800000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[    1.632240] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,17) 

有人可以指导在 qemu 中附加磁盘的正确方法来解决这个问题,或者我是否需要更改 GRUB 配置中的某些内容?

编辑

这次我按照@stark 的建议创建了分区table 的磁盘镜像

$ dd if=/dev/zero of=rootfs.img bs=1M count=10

#Using fdisk, created a partition of type Linux (83). This is how it looks now
$ fdisk -l rootfs.img
Disk rootfs.img: 10 MiB, 10485760 bytes, 20480 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc08ab9b0

Device      Boot Start   End Sectors Size Id Type
rootfs.img1       2048 20479   18432   9M 83 Linux

$ sudo losetup -o 1048576 --sizelimit 10485248 /dev/loop23 rootfs.img
$ sudo mkfs.ext2 /dev/loop23
$ sudo mount /dev/loop23 /mnt/rootfs
$ sudo cp -vrf busybox/_install/* /mnt/rootfs/
$ sudo umount /mnt/rootfs
$ sudo losetup -d /dev/loop23

现在我再次使用与上面相同的命令启动内核,但这次内核只是挂起:

[    1.593046] EXT4-fs (sdb1): couldn't mount as ext3 due to feature incompatibilities
[    1.599792] EXT4-fs (sdb1): mounting ext2 file system using the ext4 subsystem
[    1.614366] EXT4-fs (sdb1): mounted filesystem without journal. Opts: (null)
[    1.618589] VFS: Mounted root (ext2 filesystem) readonly on device 8:17.
[    1.626643] devtmpfs: mounted
[    1.665158] Freeing unused kernel memory: 1216K
[    1.667934] Write protecting the kernel read-only data: 18432k
[    1.670772] tsc: Refined TSC clocksource calibration: 2207.976 MHz
[    1.673349] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x1fd3a19a709, max_idle_ns: 440795259673 ns
[    1.681441] Freeing unused kernel memory: 2004K
[    1.693107] Freeing unused kernel memory: 1080K
[    1.836603] modprobe (1041) used greatest stack depth: 14072 bytes left
[    1.877586] rcS (1037) used greatest stack depth: 13984 bytes left
[    2.683414] clocksource: Switched to clocksource ts
[  333.025228] kworker/dying (178) used greatest stack depth: 13944 bytes left

除此之外没有输出。我在 rootfs.img 中创建了 etc/init.d/rcS,其中包含以下内容:

#!/bin/sh
mount -t sysfs none /sys
mount -t configfs none /config
mount -t devtmpfs none /dev

echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "+++++++++++++++++++++++++++++++ HELLOO ++++++++++++++++++++++++++++++"
echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"

EDIT2

我从 GRUB 配置中删除了 console=tty0,内核引导至 shell。但是我不确定为什么会导致在这个虚拟环境中挂起?

我在想,因为 tty0 代表当前显示,并且因为 -display none 是为 qemu 设置的,所以这种混淆会产生一些冲突,因此这个问题...

但是请有人就此问题给出正确和具体的结论,以便此线程将来对某人有用。

您在整个卷(文件)上创建了文件系统,而不是在分区上。如果你想把它放在一个分区上,那么你必须在文件中写一个分区 table 并在分区中创建文件系统。
编辑。不确定 grub 是否可以在没有 GPT 或 MBR 的情况下启动。

要使用此图像分区,请创建一个 1MB 的大文件,将 GPT 分区 table 写入第一个兆字节,使用 dd 将图像复制到其余部分。

dd obs=1M seek=1 rootfs.img newroot.img