Wie lädt Linux das 'initrd'-Image?

13

Ich habe versucht, den Startvorgang zu verstehen, aber es gibt nur eine Sache, die mir durch den Kopf geht.

Sobald der Linux-Kernel gebootet und das Root-Dateisystem (/) gemountet wurde, können Programme ausgeführt und weitere Kernel-Module eingebunden werden, um zusätzliche Funktionen bereitzustellen. Um das Root-Dateisystem bereitzustellen, müssen bestimmte Bedingungen erfüllt sein. Der Kernel benötigt die entsprechenden Treiber, um auf das Gerät zuzugreifen, auf dem sich das Root-Dateisystem befindet (insbesondere SCSI-Treiber). Der Kernel muss auch den Code enthalten, der zum Lesen des Dateisystems erforderlich ist (ext2, reiserfs, romfs usw.). Es ist auch denkbar, dass das Root-Dateisystem bereits verschlüsselt ist. In diesem Fall wird ein Kennwort benötigt, um das Dateisystem bereitzustellen.

Die initiale Ramdisk (auch initdisk oder initrd genannt) löst genau die oben beschriebenen Probleme. Der Linux-Kernel bietet die Möglichkeit, ein kleines Dateisystem auf eine RAM-Disk zu laden und dort Programme auszuführen, bevor das eigentliche Root-Dateisystem eingehängt wird. Das Laden von initrd übernimmt der Bootloader (GRUB, LILO usw.). Bootloader benötigen nur BIOS-Routinen, um Daten vom Bootmedium zu laden. Wenn der Bootloader den Kernel laden kann, kann er auch die ursprüngliche Ramdisk laden. Spezielle Treiber sind nicht erforderlich.

Wenn / boot keine andere Partition ist, aber in der / -Partition vorhanden ist, benötigt der Bootloader dann nicht die SCSI-Treiber, um auf das 'initrd'-Image und das Kernel-Image zuzugreifen? Wenn Sie direkt auf die Bilder zugreifen können, warum brauchen wir dann genau die SCSI-Treiber?

rpthms
quelle

Antworten:

20

Nun, ich werde versuchen, Ihre Frage zu beantworten. Eine ausführlichere Beschreibung des Startvorgangs finden Sie im IBM-Artikel .

Ok, ich gehe davon aus, dass Sie zur Erklärung GRUB oder GRUB2 als Bootloader verwenden. Wenn das BIOS auf Ihre Festplatte zugreift, um den Bootloader zu laden, verwendet es zunächst seine integrierten Routinen für den Festplattenzugriff, die im berühmten 13-Stunden-Interrupt gespeichert sind. Der Bootloader (und der Kernel in der Setup-Phase) verwenden diese Routinen, wenn sie auf die Festplatte zugreifen. Beachten Sie, dass das BIOS im Real-Modus (16 Bit) des Prozessors ausgeführt wird und daher nicht mehr als 2 ^ 20 Byte RAM adressieren kann (2 ^ 20 nicht 2 ^ 16), da jede Adresse im Real-Modus aus segment_address * 16 + Offset besteht (wo sowohl die Segmentadresse als auch der Offset 16-Bit sind, siehe http://en.wikipedia.org/wiki/X86_memory_segmentation ). Daher können diese Routinen nicht auf mehr als 1 MiB RAM zugreifen, was eine strenge Einschränkung und ein wesentlicher Nachteil ist.

Das BIOS lädt den Bootloader-Code direkt aus dem MBR - den ersten 512 Byte Ihrer Festplatte - und führt ihn aus. Wenn Sie GRUB verwenden, ist dieser Code GRUB-Stufe 1. Dieser Code lädt GRUB-Stufe 1.5, die sich entweder in den ersten 32 KB des Speicherplatzes befindet, der als DOS-Kompatibilitätsregion bezeichnet wird, oder von einer festen Adresse des Dateisystems. Dazu muss das Dateisystem nicht bekannt sein, da sich Phase 1.5 im Dateisystem befindet, es sich um "unformatierten" Code handelt und direkt in den Arbeitsspeicher geladen und ausgeführt werden kann: http://www.pixelbeat.org/ docs / disk / . Beim Laden der Stufe 1.5 von der Festplatte in den RAM werden BIOS-Festplattenzugriffsroutinen verwendet.

Bildbeschreibung hier eingeben

Stage1.5 enthält die Dateisystem-Dienstprogramme, so dass Stage2 vom Dateisystem gelesen werden kann (naja, es verwendet immer noch BIOS 13h, um vom Datenträger in den Arbeitsspeicher zu lesen, aber jetzt kann es Dateisysteminformationen über Inodes usw. entschlüsseln und Rohcode aus dem lesen Platte). Ältere BIOS können möglicherweise aufgrund von Einschränkungen im Festplattenadressierungsmodus nicht auf die gesamte Festplatte zugreifen. Möglicherweise verwenden sie das Cylinder-Head-Sector-System und können nicht mehr als die ersten 8 GB Festplattenspeicher adressieren: http: //en.wikipedia. org / wiki / Zylinderkopfbereich .

Stage2 lädt den Kernel in den RAM (ebenfalls mit den BIOS-Dienstprogrammen). Wenn es sich um einen 2.6+ Kernel handelt, sind auch initramfs kompiliert, sodass Sie ihn nicht laden müssen. Wenn es sich um einen älteren Kernel handelt, lädt der Bootloader auch ein eigenständiges initrd-Image in den Speicher, so dass der Kernel es mounten und Treiber zum Mounten des realen Dateisystems von der Festplatte abrufen kann.

Das Problem ist, dass der Kernel (und die Ramdisk) mehr als 1 MiB wiegen. Um sie in den RAM zu laden, müssen Sie den Kernel zuerst auf 1 MiB laden, dann in den geschützten Modus (32 Bit) springen und den geladenen Kernel in den hohen Speicher verschieben (frei) die ersten 1 MiB für den Real-Modus), dann wieder in den Real-Modus (16 Bit) zurückkehren, die RAM-Disk von der Festplatte auf die ersten 1 MiB bringen (wenn es sich um einen separaten initrd- und älteren Kernel handelt), möglicherweise wieder in den geschützten Modus (32 Bit) wechseln, Platzieren Sie es dort, wo es hingehört, und kehren Sie möglicherweise in den Real-Modus zurück (oder nicht: /programming/4821911/does-grub-switch-to-protected-mode ), und führen Sie den Kernel-Code aus. Warnung: Ich bin nicht ganz sicher, ob dieser Teil der Beschreibung vollständig und richtig ist.

Wenn Sie den Kernel nun endlich ausführen, haben Sie ihn bereits und die RAM- Disk wurde vom Bootloader in den RAM geladen , sodass der Kernel die Festplatten-Dienstprogramme von der RAM- Disk verwenden kann, um Ihr echtes Root-Dateisystem zu mounten und das Root-Pivot darauf zu verlagern. ramfs-treiber sind im kernel vorhanden, damit er den inhalt von initramfs versteht.

Boris Burkov
quelle
Kann der Bootlader den Kernel nicht einfach in Chunks laden, anstatt in den geschützten Modus zu springen? Und was ist die Notwendigkeit zu befreien, dass 1 MB .. (Sorry .. konnte das nicht verstehen ..)
rpthms
Für die Freigabe der ersten 1 MB ist Folgendes erforderlich: Der Bootloader kann nur im Real-Modus auf Ihre Festplatte zugreifen, da er mit BIOS-Dienstprogrammen im Real-Modus darauf zugreift (sie verarbeiten 16-Bit-Argumente und verwenden 16-Bit-Operationen). Im Real-Modus wird nur 1 MB RAM angezeigt. Sie müssen jedoch Kernel + Initramfs in den RAM laden, und sie belegen ~ 5 MiB Speicherplatz im RAM. Diese BIOS-Dienstprogramme können nur 5 MiB nicht in die ersten 1 MiB drücken. Der Bootloader muss sie also von der Festplatte auf die ersten 1 MB kopieren, dann in den geschützten Modus wechseln und sie vom ersten 1 MB RAM auf einen höheren RAM verschieben. Ist es jetzt klarer? :)
Boris Burkov
1
Das ganze Stage 1 / 1.5 / 2-Zeug ist Grub-Legacy.
Psusi
1
@CMCDragonkai Ja, der stage2-Bootloader befindet sich im Dateisystem (nämlich in der /bootPartition). Der Kernel ist zu diesem Zeitpunkt nicht geladen - es ist Grubs Stage1.5, der über seine minimalistischen Dateisystemtreiber auf Stage2 im /bootDateisystem (z. B. in /boot/grubDatei) zugreift . Der Kernel kann auch von der /bootPartition lesen , dies geschieht jedoch später, nachdem der grub2-Code ausgeführt und der Kernel geladen wurde und nachdem der Kernel initramfs gelesen hat. Sprichst du voninit.sh von den initramfs? Es befindet sich in der /bootPartition Ihrer Festplatte, dann legt Stage2 von Grub es in den RAM und der Kernel liest es aus dem RAM.
Boris Burkov
1
Initrd musste eine separate Datei sein. Das neuere initramfs kann mit dem Kernel verknüpft werden, muss es aber nicht sein - es kann auch vom Bootloader als separate Datei geladen werden. Da die initramfs-Datei als Folge von cpio-Archiven definiert ist, lassen einige Bootloader (z. B. iPXE) sogar mehrere zu initramfs-Dateien, die nacheinander in den Speicher geladen werden. Einige Linux-Distributionen verwenden aus Gründen der Abwärtskompatibilität Dateinamen im initrd-Stil, obwohl die derzeit verwendete Technologie initramfs ist.
TelcoM
1

Ich glaube, es läuft darauf hinaus, welche Funktionen bestimmte Bootloader unterstützen. Z.B. Es muss kein bestimmtes Dateisystem Ihrer kombinierten Partition (Boot + Root) kennen. In diesem Fall erstellen Sie einfach eine separate Boot-Partition, sofern diese mit Ihrem Bootloader kompatibel ist. Alle anderen komplizierten Schritte zum Mounten Ihrer Root-Partition verbleiben im Kernel und im initrd-Image, das von der Boot-Partition gebootet wurde. Der Bootloader kann auf die SCSI-Geräte (und auch auf andere Geräte, je nachdem, welcher Bootloader verwendet wird) zugreifen, indem er entweder eigene Treiber verwendet oder BIOS-Routinen verwendet. Außerdem kann es einige Dateisysteme usw. lesen.

Betrachten Sie zB. UEFI-Boot-Methode, bei der die UEFI-Firmware bereits weiß, wie sie auf die EFI-Partition zugreift, diese liest und den Linux-Kernel von dort lädt, ohne dass ein dazwischenliegender Bootloader erforderlich ist. In diesem Fall ist das Linux-Image von der Root-Partition getrennt und die UEFI-Firmware muss nicht alle exotischen Dateisysteme kennen, um darauf zugreifen zu können. Ich halte die Trennung von "Boot" -Images von der "Root" -Partition für sinnvoll. Wenn nicht für irgendetwas anderes, ist dies beim Einrichten der Root-Dateisystemverschlüsselung erforderlich.

Miroslav Koškár
quelle
0

Wenn ein Bootloader nicht initrd lädt, lohnt es sich, einen anderen Bootloader zu testen. Ich habe gerade lief in einer Situation wie dieser , wenn LILO leise ein richtig angegeben initrd von mittlerer Größe ignoriert (<4 MB; Einzel ext4 rootfs auf einem SATA SSD; GPT) und GRUB 2.00 gelungen.

Der Bootvorgang endete schnell mit einem typischen

RAMDISK: Couldn't find valid RAM disk image starting at 0.
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,3)
Michael Shigorin
quelle