Der Linux-Kernel findet die initrd nicht richtig

11

Ich hatte einen Linux-Kernel kompiliert und wollte ihn in QEMU debuggen. Ich habe eine Datei zum Booten erstellt, indem ich die Befehle ausgeführt habe

$ qemu-img create -f raw disk.img 200M
$ mkfs.ext2 -F disk.img
# mkdir /mnt/rootfs
# mount -o loop disk.img /mnt/rootfs

Dann habe ich qemu -kernel bzImage -initrd disk.imgden Bildschirm unten bekommen, auf dem steht:

Kernel panic - not syncing: VFS: unable to mount root fs on unknown block

Mein QEMU-Bildschirm

Was habe ich falsch gemacht und was kann ich tun, um das Problem zu beheben?

Coder404
quelle
Dieselbe Fehlermeldung wie diese, gibt jedoch nicht die Schritte an, die er unternommen hat, um sie zu erreichen: unix.stackexchange.com/questions/48302/…
Ciro Santilli 20 病毒 审查 六四 事件 20

Antworten:

8

Der Kernel teilt Ihnen mit, dass er nicht weiß, auf welchem Gerät sich das Root-Dateisystem befindet. Ihre Schlaufenhalterung ist nicht erforderlich. (Hängen Sie es aus, bevor Sie fortfahren).

Versuchen Sie einen Befehl wie

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

Der -hda disk.imgParameter weist qemu an, ein Festplattengerät basierend auf Ihrem zu simulieren disk.img.

Der -append root=/dev/sdaSchalter wird von qemu verwendet, um dem Kernel das Root-Gerät mitzuteilen. Dies erfolgt durch Anhängen der root=/dev/sdaan die Kernel-Befehlszeile. Sie können dies mit der Kernel-Befehlszeile Ihres eigenen Kernels vergleichen, indem Sie Folgendes tun cat /proc/cmdline(Dies ist sicher). Sie sollten dort auch einen rootParameter sehen.

t-8ch
quelle
Wie würde ich die Dateien aushängen?
Coder404
umount /mnt/rootfs
t-8ch
Wenn ich das mache, bekomme ich umount: / mnt / rootfs ist nicht gemountet (laut mtab)
Coder404
Vermutlich möchte Coder404 keine Festplatte an diesen Computer anschließen und nur die initin ausführen initrd. Hier übergeben Sie disk.imgbeide als Festplatte und eine, initrddie keinen Sinn ergibt.
Stéphane Chazelas
@StephaneChazelas danke für den Hinweis, -initrddass das nicht hätte sein sollen.
t-8ch
7

Was passiert ist, dass Sie versuchen, Linux auf "veraltete" Weise zu booten. Hier initrdhandelt es sich um eine Ramdisk im Gegensatz zu einem komprimierten CPIO-Archiv, das vom Kernel in einem Ramfs entpackt wurde, und mit der alten Methode, zum Endgerät zu wechseln.

In diesem Modus stellt der Kernel die Datei disk.img als Ramdisk als Root-Dateisystem bereit und wird /linuxrcdort ausgeführt. In Ihrem Fall gibt es höchstwahrscheinlich keine solche Datei. Wenn /linuxrc(was alles tun soll, was erforderlich ist, um das Blockgerät für das echte Root-Dateisystem aufzurufen) beendet wird, stellt der Kernel das echte Root-Dateisystem bereit.

Die obigen Meldungen zeigen, dass die RAM-Festplatte erfolgreich bereitgestellt wird (1,0: 1 ist für ram, also /dev/ram0), aber nicht das echte Root-Dateisystem / dev / sda1 (8,1: 8 ist sd, 1 ist a1). Vermutlich, da Sie keine Kernel-Befehlszeile ( -append) angegeben haben, /dev/sda1stammt diese von einer CONFIG_CMDLINE, die zur Kernel-Kompilierungszeit oder mit übergeben wurde rdev.

Wenn Ihre disk.img ein Root-Dateisystem enthalten soll, beispielsweise eine kleine Linux-Distribution mit /sbin/init..., möchten Sie sie wahrscheinlich stattdessen schreiben:

kvm -kernel kernel.img -initrd disk.img -append 'root=/dev/ram0`

Dann würde der Kernel die RAM-Disk als das echte Root-Dateisystem behandeln (obwohl Sie immer noch ein pivot_rootanderes verwenden könnten ).

Um die Kernel-Nachrichten leichter sehen zu können, würde ich die Verwendung der seriellen Ausgabe empfehlen:

kvm -kernel kernel.img -initrd disk.img -nographic -append "root=/dev/ram0 console=ttyS0"

Alternativ können Sie ein Init-Ramfs anstelle eines Init-Ramdisk verwenden:

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

(vorausgesetzt, es busyboxhandelt sich um die statisch verknüpfte Version) und Sie erhalten eine Shell und andere Busybox-Dienstprogramme in diesem Kernel.

Beachten Sie, dass der Kernel jetzt /initim Gegensatz zu /linuxrcoder /sbin/initin diesem Modus ausgeführt wird.

Stéphane Chazelas
quelle
Zeile 3 der gezeigten Ausgabe zeigt, dass der Kernel das ext2-Dateisystem der initramdisk gemountet hat. Es fehlt also wahrscheinlich kein Modul.
t-8ch
Oh ja, das hatte ich verpasst, danke @ t-8ch. Ich glaube ich weiß was los ist und habe meine Antwort aktualisiert.
Stéphane Chazelas
0

CONFIG_BLK_DEV_INITRD=y

Diese Kernel-Konfigurationsoption ist ebenfalls erforderlich. Es aktiviert die initrd-Unterstützung auf dem Linux-Kernel.

Glücklicherweise legt Buildroot es für uns standardmäßig fest, wenn BR2_TARGET_ROOTFS_CPIO=yes gegeben wird.

Anschließend übergeben Sie den CPIO mit der qemu -initrdOption an QEMU . Mein vollständiger QEMU-Befehl lautet:

./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'

Hier ist ein minimalistisches vollautomatisches Buildroot + QEMU-Beispiel: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/b3868a3b009f2ab44fa6d3db3d174930b3cf7b69#initrd

Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
quelle