web-dev-qa-db-ja.com

Linuxカーネルがinitrdを正しく検出しない

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

My QEMU screen

私は何を間違ったのですか、それを修正するために何ができますか?

11
Coder404

カーネルは、どのdeviceがルートファイルシステムを保持しているかを知らないと言っています。ループマウントは必要ありません。 (続行する前にアンマウントしてください)。

次のようなコマンドを試してください

qemu -kernel bzImage -hda disk.img -append root=/dev/sda

-hda disk.imgパラメーターは、disk.imgに基づいてディスクデバイスをシミュレートするようqemuに指示します。

-append root=/dev/sdaスイッチは、qemuがそのルートデバイスについてカーネルに知らせるために使用されます。これは、カーネルコマンドラインにroot=/dev/sdaを追加することで行われます。 cat /proc/cmdlineを実行すると、これを自分のカーネルのカーネルコマンドラインと比較できます(これは安全です)。 rootパラメータも表示されます。

8
t-8ch

何が起こっているのかというと、Linuxを「廃止された」方法で起動しようとしているということです。これは、initrdがramdiskでカーネルによってアンパックされた圧縮cpioアーカイブとは対照的にramdiskであり、古い方法でエンドデバイスに切り替える方法です。

そのモードでは、カーネルはdisk.imgをルートファイルシステムとしてramdiskとしてマウントし、そこで/linuxrcを実行します。おそらくあなたのケースでは、そのようなファイルはありません。 /linuxrc(実際のルートファイルシステムのブロックデバイスを起動するために必要なすべてのことを行うことになっています)が終了すると、カーネルは実際のルートファイルシステムをマウントします。

上記のメッセージは、RAMディスクを正常にマウントしていることを示しています(1,0:1はramのため、/dev/ram0)。ただし、実際のルートファイルシステム/ dev/sda1(8,1:8はsd、1はa1です)。おそらく、カーネルコマンドライン(-append)を指定しなかったため、その/dev/sda1は、カーネルのコンパイル時に渡される、またはrdevを使用してCONFIG_CMDLINEから取得されます。

Disk.imgが、たとえば/sbin/init...を使用した小さなLinuxディストリビューションのルートファイルシステムを含むことを意図している場合は、おそらく代わりに次のように記述します。

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 ramdiskの代わりにinit ramfsを使用できます。

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は静的にリンクされたバージョンです)そしてそのカーネルでシェルと他のbusyboxユーティリティを取得します)。

このモードでは、カーネルが/initまたは/linuxrcではなく/sbin/initを実行することに注意してください。

7

CONFIG_BLK_DEV_INITRD=y

このカーネル構成オプションも必要です。 Linuxカーネルでのinitrdサポートを有効にします。

Luckly Buildrootは、BR2_TARGET_ROOTFS_CPIO=yが指定されたときにデフォルトで設定します。

次に、qemu -initrdオプションを使用してCPIOをQEMUに渡します。私の完全な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