GRUB 2.0: Ablauf des Bootvorgangs

1. Motivation

Uns ist kürzlich ein Hardware-Server unerwartet neugestartet worden. Er kam dann nicht mehr hoch, weil der Bootloader im Eimer war. Wir hatten leider keine Ahnung, was da los gewesen ist, und mussten recht viel Zeit investieren, bis das Teil wieder lief. Hier wollen wir mal ein bisschen von unserem dabei erworbenen Wissen weitergeben und darstellen, wie das so allgemein funktioniert.

2. Grober Abriss des BIOS-Boots allgemein

Es geht in diesem Artikel nur um BIOS-Boot. Die Maschine geht an und macht $Magie. Teil dieser Magie ist, dass im BIOS eine Festplatte konfiguriert ist, von der gestartet werden soll. Das BIOS muss also schon mal mit dieser Hardware reden können (weswegen man nicht von völlig beliebiger Hardware booten kann).

Das BIOS lädt dann die ersten 512 Byte von der Festplatte in den Arbeitsspeicher und springt anschließend an diese Adresse. Welcher Code auch immer also auf der Festplatte an dieser Stelle liegt: Er wird ausgeführt. Es muss auch gar kein Bootloader sein.

Weil das alles furchtbar alt ist, startet die CPU im Real Mode. Das führt dazu, dass man auch heute noch ein DOS aus dem letzten Jahrtausend booten kann. Das heißt aber zugleich, dass wir – falls wir uns den Code des Bootloaders ansehen wollen – daran denken müssen, dass es sich hier eben um 16-Bit-Code handelt. (objdump -D -Mintel,i8086 -b binary -m i386 mbr.bin – einfach mal ausprobieren und dann unter BIOS Interrupt Call und INT 13H weiterlesen, denn das ist die Schnittstelle des dort laufenden Codes mit der Außenwelt.) Und natürlich müssen wir immer im Kopf behalten, dass Intel-CPUs Little Endian sind, was gleich noch wichtig wird.

In 512 Byte befindet sich dann also der MBR. Im MBR selbst sind ein Teil des Bootloaders, die Partitionstabelle und zwei Byte typische Signatur enthalten:

Adresse Funktion / Inhalt Größe
(Bytes)
hex dez
0x0000 0 Startprogramm (englisch: Bootloader) (Programmcode) 440
0x01B8 440 Datenträgersignatur 4
0x01BC 444 Null
(0x0000)
2
0x01BE 446 Partitionstabelle 64
0x01FE 510 55hex Bootsektor-Signatur
(wird vom BIOS für den ersten Bootloader geprüft)
2
0x01FF 511 AAhex
Gesamt: 512

Tabelle aus Wikipedia

Nicht viel Platz also. Das hat schon zu Zeiten von DOS nicht gereicht (siehe IO.SYS) und heute schon gar nicht. Wir müssen ja irgendwie das Kernel-Image in den Speicher laden, vielleicht noch dekomprimieren und dann ausführen. Dazu brauchen wir eine ganze Menge an Dingen, mindestens jedoch einen Dateisystemtreiber, denn das Kernel-Image liegt ja nicht an einem festen Punkt auf der Platte, sondern befindet sich als (fragmentierte) Datei auf einem ext4. Im Falle des kaputten Servers kürzlich: Schreck, lass nach – das liegt auf einem Linux-Software-RAID! Bevor Linux starten kann, brauchen wir also vorher noch ein kleines Mini-Betriebssystem, was all diese Treiber (Festplatte, RAID, Dateisystem) umfasst. Und dies ist in unserem Fall der GRUB.

⇒ Schritt 0: Code im MBR wird ausgeführt.

3. Die Sache mit der "Boot-Partition" bei BIOS und GPT

Diesen Sonderfall hatten wir leider. Die Maschine bootet klassisch per BIOS, aber auf der Festplatte ist dann eine GPT und kein MBR. Zum Glück waren die "Erfinder" der GPT nicht ganz dumm und haben die ersten 512 Byte auf der Platte unberührt gelassen:

So weit, so gut. 440 Byte (oder 446 Byte, das macht den Braten auch nicht fett) müssen also reichen, um irgendwie an Code zu gelangen, der den Rest ausführt. Aber wo liegt dieser Code? Wir haben hier ja noch kein Dateisystem! Da bleibt nicht viel anderes übrig, als zu sagen: "Auf der Festplatte $x an Sektor $y liegt’s. Lade das in den Speicher und springe an diese Speicheradresse."

Bei der Kombination BIOS + GPT war man (hier also die GRUB-Leute) ausnahmsweise mal schlau und hat gesagt: Für diesen Fall musst du eine Partition erstellen, damit der Platz garantiert reserviert ist. Beim klassischen BIOS-Boot mit MBR braucht man das nicht und der Code liegt einfach irgendwo™ auf der Platte, wo man davon ausgeht, dass sich da schon nichts anderes befinden wird. Diese Partition ist wirklich nur eine reine Reservierung – da ist kein Dateisystem drin. So sieht das aus:

root@ubuntu2004:~# fdisk -l /dev/vda
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 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: gpt
Disk identifier: 18C96779-B225-4150-A4C1-302EA7BB90EA
 
Device     Start      End  Sectors Size Type
/dev/vda1   2048     4095     2048   1M BIOS boot
/dev/vda2   4096 41940991 41936896  20G Linux filesystem

Wie gesagt: reine Reservierung. Kein Dateisystem drin, nicht gemountet, und schon gar nicht ist das /boot.

4. Wo im MBR steht der Ort, an dem es weitergeht?

Wir können mal experimentell die BIOS-Boot-Partition ein bisschen hin- und herschieben und uns dann anschauen, wie sich der MBR verändert:

Im Original (links) war die Partition wie oben gezeigt bei 2048; rechts haben wir sie dann nach Sektor 40 geschoben gehabt und GRUB neu installiert. Man sieht also, wie sich im MBR eine Zahl ändert von 0x0800 zu 0x0028. (Da ist es, das Little Endian.) Das ist praktischerweise genau identisch mit dem Partitions-Offset in Sektoren und muss nicht nochmal aus irgendeinem anderen arkanen Format umgerechnet werden.

Zum Vergleich: So sieht das auf einem (etwas entstellten) Server von uns aus:

# dd if=/dev/sda bs=512 count=1 status=none | xxd | grep '^00000050'
00000050: 0000 0000 0000 0000 0000 0080 2200 0000  ............"...
 
# fdisk -l /dev/sda
Device        Start         End     Sectors  Size Type
/dev/sda1      4096    50335743    50331648   24G Linux RAID
/dev/sda2  50335744 11721045134 11670709391  5.4T Linux filesystem
/dev/sda3        34        2047        2014 1007K BIOS boot
 
# echo $((0x22))
34

Die 0x22 zeigt hübsch auf Sektor 34.

⇒ Schritt 1: Code in Partition BIOS boot wird ausgeführt.

5. Kurzer Vergleich mit BIOS-Boot + MBR

Wie sieht das auf einem System aus, das klassisch mit BIOS + MBR bootet?

# dd if=/dev/vda bs=512 count=1 status=none | xxd | grep '^00000050'
00000050: 0000 0000 0000 0000 0000 0080 0100 0000  ................
 
# dd if=/dev/vda bs=512 count=1 skip=1 status=none | xxd
00000000: 52e8 2801 7408 56be 3381 e84c 015e bff4  R.(.t.V.3..L.^..
00000010: 8166 8b2d 837d 0800 0f84 e900 807c ff00  .f.-.}.......|..
00000020: 7446 668b 1d66 8b4d 0466 31c0 b07f 3945  tFf..f.M.f1...9E
00000030: 087f 038b 4508 2945 0866 0105 6683 5504  ....E.)E.f..f.U.
00000040: 00c7 0410 0089 4402 6689 5c08 6689 4c0c  ......D.f.\.f.L.
00000050: c744 0600 7050 c744 0400 00b4 42cd 130f  .D..pP.D....B...
00000060: 82bb 00bb 0070 eb68 668b 4504 6609 c00f  .....p.hf.E.f...
00000070: 85a3 0066 8b05 6631 d266 f734 8854 0a66  ...f..f1.f.4.T.f
00000080: 31d2 66f7 7404 8854 0b89 440c 3b44 080f  1.f.t..T..D.;D..
00000090: 8d83 008b 042a 440a 3945 087f 038b 4508  .....*D.9E....E.
000000a0: 2945 0866 0105 6683 5504 008a 540d c0e2  )E.f..f.U...T...
000000b0: 068a 4c0a fec1 08d1 8a6c 0c5a 528a 740b  ..L......l.ZR.t.
000000c0: 50bb 0070 8ec3 31db b402 cd13 7250 8cc3  P..p..1.....rP..
000000d0: 8e45 0a58 c1e0 0501 450a 601e c1e0 0389  .E.X....E.`.....
000000e0: c131 ff31 f68e dbfc f3a5 1fe8 3e00 7406  .1.1........>.t.
000000f0: be3b 81e8 6300 6183 7d08 000f 851d ff83  .;..c.a.}.......
00000100: ef0c e90f ffe8 2400 7406 be3d 81e8 4900  ......$.t..=..I.
00000110: 5aea 0082 0000 be40 81e8 3d00 eb06 be45  Z......@..=....E
00000120: 81e8 3500 be4a 81e8 2f00 ebfe bb17 04f6  ..5..J../.......
00000130: 0703 c36c 6f61 6469 6e67 002e 000d 0a00  ...loading......
00000140: 4765 6f6d 0052 6561 6400 2045 7272 6f72  Geom.Read. Error
00000150: 00bb 0100 b40e cd10 468a 043c 0075 f2c3  ........F..<.u..
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0200 0000 0000 0000 6500 2008  ............e. .

Es geht also direkt nach dem MBR bei Sektor 1 weiter. Da könnte theoretisch aber auch eine Partition sein (CHS-Tupel (0, 0, 2) im MBR statt (0, 1, 1) für LBA 63); es gibt also nicht wirklich eine Garantie dafür, dass da nichts anderes ist. Mutmaßlich hängt es hiermit zusammen:

"Alte Betriebssysteme erwarten den Start einer Partition immer an den Zylindergrenzen. Daher ergibt sich auch heute noch bei verbreiteten Betriebssystemen eine Lücke von 63 Sektoren zwischen erweiterter Partitionstabelle und dem Startsektor der entsprechenden logischen Partition."

Die Entscheidung bei GPT, eine Partition extra für das bisschen Bootloader-Code zu reservieren, ist schon sehr gut. Fairerweise muss man natürlich dazusagen, dass bei GPT 128 Partitionen möglich sind und bei einem MBR nur vier. Beim MBR extra eine Partition dafür zu opfern, wäre schon hart gewesen.

Der Code, der da folgt, ist auch identisch zu unserem anderen Testsystem von oben, das bei 40 startet:

root@ubuntu2004:~# dd if=/dev/vda bs=512 count=1 skip=40 status=none | xxd
00000000: 52e8 2801 7408 56be 3381 e84c 015e bff4  R.(.t.V.3..L.^..
00000010: 8166 8b2d 837d 0800 0f84 e900 807c ff00  .f.-.}.......|..
00000020: 7446 668b 1d66 8b4d 0466 31c0 b07f 3945  tFf..f.M.f1...9E
00000030: 087f 038b 4508 2945 0866 0105 6683 5504  ....E.)E.f..f.U.
00000040: 00c7 0410 0089 4402 6689 5c08 6689 4c0c  ......D.f.\.f.L.
00000050: c744 0600 7050 c744 0400 00b4 42cd 130f  .D..pP.D....B...
00000060: 82bb 00bb 0070 eb68 668b 4504 6609 c00f  .....p.hf.E.f...
00000070: 85a3 0066 8b05 6631 d266 f734 8854 0a66  ...f..f1.f.4.T.f
00000080: 31d2 66f7 7404 8854 0b89 440c 3b44 080f  1.f.t..T..D.;D..
00000090: 8d83 008b 042a 440a 3945 087f 038b 4508  .....*D.9E....E.
000000a0: 2945 0866 0105 6683 5504 008a 540d c0e2  )E.f..f.U...T...
000000b0: 068a 4c0a fec1 08d1 8a6c 0c5a 528a 740b  ..L......l.ZR.t.
000000c0: 50bb 0070 8ec3 31db b402 cd13 7250 8cc3  P..p..1.....rP..
000000d0: 8e45 0a58 c1e0 0501 450a 601e c1e0 0389  .E.X....E.`.....
000000e0: c131 ff31 f68e dbfc f3a5 1fe8 3e00 7406  .1.1........>.t.
000000f0: be3b 81e8 6300 6183 7d08 000f 851d ff83  .;..c.a.}.......
00000100: ef0c e90f ffe8 2400 7406 be3d 81e8 4900  ......$.t..=..I.
00000110: 5aea 0082 0000 be40 81e8 3d00 eb06 be45  Z......@..=....E
00000120: 81e8 3500 be4a 81e8 2f00 ebfe bb17 04f6  ..5..J../.......
00000130: 0703 c36c 6f61 6469 6e67 002e 000d 0a00  ...loading......
00000140: 4765 6f6d 0052 6561 6400 2045 7272 6f72  Geom.Read. Error
00000150: 00bb 0100 b40e cd10 468a 043c 0075 f2c3  ........F..<.u..
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 2900 0000 0000 0000 6500 2008  ....).......e. .

6. Was tut der Code, der in der BIOS-Boot-Partition steht?

Das ist die Stage 1.5 bzw. core.img:

Gucken wir mal nach:

root@ubuntu2004:~# dd if=/dev/vda bs=1 count=26089 skip=$((40 * 512)) of=core.img.test
26089+0 records in
26089+0 records out
26089 bytes (26 kB, 25 KiB) copied, 0.048789 s, 535 kB/s
root@ubuntu2004:~# md5sum /boot/grub/i386-pc/core.img core.img.test
63f1ec80b97abcb86322462b1974e819  /boot/grub/i386-pc/core.img
e5bab1f58fdd9fc58a69b66bcc278b2a  core.img.test

(Die tatsächliche Größe des core.img kann variieren, weil da Module für diesen und jenen Treiber drin sein können. grub-mkimage baut auf jedem System eine eigene core.img zusammen.)

Hm, falsch? Naja, fast:

Im Diff sieht man, dass es großteils übereinstimmt – bis auf sechs Bytes. Es hat sich dann später gezeigt, dass dieser Unterschied völlig egal ist. Wie gesagt, die core.img wird auf jedem System neu gebaut. Und zwar nicht nur einmalig, sondern bei jedem Aufruf von grub-install. Spannenderweise wird dabei aber nur ein Zwischenergebnis im Dateisystem abgelegt und das finale Resultat nur direkt in der BIOS boot-Partition.

In der core.img muss nun der Ort stehen, an dem es weitergehen soll. Irgendwo hier drin muss hinterlegt sein, auf welcher Partition des Systems sich das /boot-Verzeichnis und die "eigentlichen" GRUB-Configs befinden.

An dieser Stelle kommt man mit bloßem Ausprobieren nicht mehr weiter. Wir müssen uns jetzt zumindest am GRUB-Quellcode orientieren, auch wenn wir ihn sicherlich nicht in Gänze verstehen werden können – das Ding ist komplexer, als einem lieb sein kann, und selbstverständlich auch gespickt mit #ifdefs und anderen hübschen Dingen.

Hier liegt der Großteil des Quellcodes:

(Das reicht natürlich längst nicht aus, um GRUB zu kompilieren, wie man dem PKGBUILD von Arch Linux entnehmen kann. Wir haben einen Kompilierungsversuch übrigens nach ca. zehn Minuten abgebrochen. Das rödelt ewig und war uns zu viel für einen "simplen" Bootloader.)

Wir werfen nur ganz schnell einen Blick an diese Stellen:

Wie man sehen kann, ist nämlich ein Teil der core.img standardmäßig komprimiert. Womit? Mit LZMA. Und wer dekomprimiert das? Tja, den Code dafür muss man natürlich auch in die core.img stecken. Ganz grob sieht die Datei dann so aus:

  • Irgendeine Form von Header, der nicht weiter interessiert
  • Dekompressions-Code
  • Der eigentliche Inhalt, LZMA-komprimiert

Um das zu dekomprimieren, muss man den Offset in der Datei kennen, wo Nummer 3 anfängt. Ein geübtes Auge kann das tatsächlich durch das reine Draufgucken ermitteln:

Nein, keine Magic-Number, aber so ungefähr bei Offset 0xd10 hört die Häufung an ähnlichen Bytes auf. Vorher gibt es öfter mal FF FF oder viele Null-Bytes hintereinander. Von starker Kompression würde man aber erwarten, dass derlei "Verschwendung" nicht auftritt und die Informationsdichte viel höher ist. Etwa ab dem genannten Punkt geht das los und die Daten sehen eher "zufällig" aus.

Wir können’s zum Glück genauer bestimmen. In der oben verlinkten mkimage.c ist zu sehen, dass der Dekompressions-Code geschrieben wird – und zwar wird das unverändert aus einer Datei kopiert, die auf dem System rumliegt. Und direkt im Anschluss ohne Padding oder Alignment kommt der komprimierte Teil. Sprich: Wir schauen uns diese Datei mal an, suchen ihren Anfang in der core.img, addieren ihre Länge drauf und haben dann den Startpunkt der komprimierten Daten.

And here we go:

# l /usr/lib/grub/i386-pc/*decomp*
-rw-r--r-- 1 root root 2,832 Aug 24 08:45 /usr/lib/grub/i386-pc/lzma_decompress.img
 
# xxd /usr/lib/grub/i386-pc/lzma_decompress.img | head -n 3
00000000: ea1c 8200 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 5407 0000 ffff ff00 fa31 c08e  ....T........1..
00000020: d88e d08e c066 bdf0 1f00 0066 89ec fb88  .....f.....f....

Uh, diese erste Zeile sieht aber äußerst bekannt aus. Sie ist nicht ganz identisch mit dem, was wir schon gesehen haben, aber nahe genug dran. (Viel Spaß damit herauszufinden, was genau da noch beim Installieren reingepatcht wird. Leicht im Quellcode zu finden ist, dass noch Fehlerkorrektur-Codes abgelegt werden. Durch Ausprobieren sieht man noch, dass auch die Länge des komprimierten Teils hinterlegt wird. Viel Erfolg mit dem Rest!).

Im obigen Screenshot ist das bei Offset 0x200. Von dort aus 2832 Bytes (0xb10) weiter landet man bei... lustig, ganz genau 0xd10. Wer hätte das nur ahnen können?

Also nochmal, der komprimierte Teil startet bei:

  • 0x200, um den "Header" zu überspringen,
  • + 0xb10, Größe der lzma_decompress.img, um den Dekompressions-Code zu überspringen,
  • = 0xd10.

Probieren wir’s mal:

# dd if=core.img of=compressed bs=1 skip=$((0xd10)) status=none
 
# xzcat --lzma1 --format=raw <compressed >core_decomp
xzcat: (stdin): Unexpected end of input

Hm, na gut. Mal schauen, wie weit er kam:

# xxd core_decomp | head
00000000: 898e 4100 0000 89be 4500 0000 8986 6401  ..A.....E.....d.
00000010: 0000 b9f8 6d00 00bf 0090 0000 f3a4 be25  ....m..........%
00000020: 9000 00ff e6bf f8fd 0000 b964 7501 0029  ...........du..)
00000030: f931 c0fc f3aa 8915 00fe 0000 e86a 3800  .1...........j8.
00000040: 0000 0000 0000 0000 00a1 4590 0000 ffd0  ..........E.....
00000050: cd18 31c0 bf72 0489 05ea f0ff 00f0 5589  ..1..r........U.
00000060: e556 5753 89cb 89c1 89d0 83e0 0fc1 ea04  .VWS............
00000070: c1e2 1001 c2a1 4590 0000 ffd0 6653 6652  ......E.....fSfR
00000080: 5189 e336 ff5f 06fc 83c4 0a89 c166 a141  Q..6._.......f.A
00000090: 9066 ffd0 0fb7 c15b 5f5e 5dc3 9cfa 9d55  .f.....[_^]....U
 
# xxd core_decomp | tail
0000de30: 0900 0000 0400 0000 1000 0000 0900 0000  ................
0000de40: 0300 0000 0000 0000 0000 0000 dc0c 0000  ................
0000de50: 3301 0000 0000 0000 0000 0000 0100 0000  3...............
0000de60: 0000 0000 1100 0000 0300 0000 0000 0000  ................
0000de70: 0000 0000 1810 0000 5c00 0000 0000 0000  ........\.......
0000de80: 0000 0000 0100 0000 0000 0000 0300 0000  ................
0000de90: 3c00 0000 286d 6475 7569 642f 3764 3037  <...(mduuid/7d07
0000dea0: 3032 3530 6561 3465 3435 3466 3134 6632  0250ea4e454f14f2
0000deb0: 6632 3034 3135 3966 6434 3462 292f 626f  f204159fd44b)/bo
0000dec0: 6f74 2f67 7275 6200 00                   ot/grub..

Das sieht erstaunlich gut aus. Und, frohlocket, was steht denn da ganz am Ende?

(mduuid/7d070250ea4e454f14f2f204159fd44b)/boot/grub

Das ist ein GRUB-Identifier für eine bestimmte Partition im System, in diesem Fall ein Linux-Software-RAID:

# blkid
/dev/sdc1: UUID="7d070250-ea4e-454f-14f2-f204159fd44b" ...

Auf einfacheren Systemen wird man eher so etwas sehen:

(,gpt2)/boot/grub

In diesem Verzeichnis befinden sich dann die üblichen GRUB-Configs, die angeben, welches Betriebssystem als nächstes gebootet werden soll.

⇒ Schritt 2: In der komprimierten core.img steht, wo sich die GRUB-Configs befinden.

Ich möchte noch ein bisschen in die Suppe spucken: Etwas wie (,gpt2) ist natürlich eine abstrakte Repräsentation, die nur GRUB wirklich versteht. Das ist jetzt keine Sektornummer mehr, die man auch problemlos als Mensch nachvollziehen kann. Exakt welche Festplatte und welche Partition er da wählt, weiß man nicht so genau. Hat der GRUB Bugs oder verhält er sich unerwartet, ist man aufgeschmissen. Beispiel: Was ist wohl "Festplatte Nummer 1"? Werden die garantiert in der Reihenfolge nummeriert, wie sie im BIOS stehen? Solcherlei Fragen stellen sich dann. Da hülfe nur, noch tiefer einzusteigen, und den restlichen GRUB-Code genauer zu lesen.

7.2 Zusammenfassung

7.1. Rekonstruktion des konfigurierten Boot-Pfads

Gehen wir nochmal alles in Kurzform an einem anderen System durch.

Aus dem GRUB-Code im MBR den Sektor entnehmen, an dem die core.img beginnt:

# dd if=/dev/vda bs=512 count=1 status=none | xxd | grep ^00000050
00000050: 0000 0000 0000 0000 0000 0080 0100 0000  ................

Hier ist es Sektor 0x0001.

Teils komprimierte core.img auslesen:

# dd if=/dev/vda bs=1 count=$(stat -c %s /boot/grub/i386-pc/core.img) skip=$((0x0001 * 512)) of=core_compressed

Sanity-Check, ob da wirklich ein Dekompresser mit drin ist, und anschauen, wo er startet (wird sehr wahrscheinlich 0x200 sein):

# xxd /usr/lib/grub/i386-pc/lzma_decompress.img | head -n 3
00000000: ea1c 8200 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 5407 0000 ffff ff00 fa31 c08e  ....T........1..
00000020: d88e d08e c066 bdf0 1f00 0066 89ec fb88  .....f.....f....
 
# dd if=core_compressed bs=1 skip=$((0x200)) | xxd | head -n 3
00000000: ea1c 8200 0000 0000 5258 0000 20ad 0000  ........RX.. ...
00000010: 9e66 0000 5407 0000 ffff ff00 fa31 c08e  .f..T........1..
00000020: d88e d08e c066 bdf0 1f00 0066 89ec fb88  .....f.....f....

Auslesen des komprimierten Teils:

# dd if=core_compressed bs=1 skip=$((0x200 + $(stat -c %s /usr/lib/grub/i386-pc/lzma_decompress.img) )) of=only_compressed

Dekompression:

# xzcat --lzma1 --format=raw <only_compressed >decompressed

Anschauen der konfigurierten /boot-Partition:

# xxd decompressed | tail -n 5
0000ace0: 0300 0000 0000 0000 0000 0000 1810 0000  ................
0000acf0: 5c00 0000 0000 0000 0000 0000 0100 0000  \...............
0000ad00: 0000 0000 0300 0000 1c00 0000 282c 6d73  ............(,ms
0000ad10: 646f 7331 292f 626f 6f74 2f67 7275 6200  dos1)/boot/grub.
0000ad20: 00   

Siehe da, in diesem Beispiel hatten wir ein System genommen, das ganz klassisch mit BIOS + MBR bootet, und da trifft auch alles wie erhofft zu.

7.2. Bei Installation von GRUB auf BIOS + GPT beachten

Es muss eine GPT-Partition vom Typ BIOS boot geben. Rein als Reservierung. grub-install wird da die core.img ablegen und frech den Dienst verweigern, wenn es eine solche Partition nicht gibt.

Im IT-Tagebuch schreibt ein Kollege aus unserem IT-Team in loser Folge über Themen, Probleme und Lösungen, die ihm im Arbeitsalltag begegnen.


Mehr über die Creative-Commons-Lizenz erfahren