rss feed articles activities all_comments

indeedgeek.de

Florian Eitel

MBR vs EFI

Wer einen neueren Computer sein Eigen nennen darf wird im BIOS über verschiedenste Einstellungen zu UEFI stoßen. Um euch meinen Ärger zu ersparen, dachte ich mir, ich versuche etwas Licht in das Dunkel zu bringen was UEFI ist und wie man es nutzt.

Anschalten des Computers

Das Erste was dabei ausgeführt wird, ist das BIOS. Das initialisiert die Hardware und entscheidet was gebooted werden soll. Dazu kann man die Boot-Reihenfolge in der BIOS Konfiguration festlegen. Bei Medien ohne Partitionen wie CDROMS ist das recht einfach. Da wird einfach der erste Datenblock ausgeführt, welcher dann zum Beispiel ein Live-Betriebssystem startet.

Bei Medien mit Partitionen wie Festplatten ist dies etwas schwieriger. Dort wird der Master Boot Record (MBR) genutzt. Das sind die ersten 512 Bytes der Festplatte die in verschiedene Bereiche unterteilt sind. Zuerst wird Byte 0 bis 440 ausgeführt. Hier befindet sich der Bootloader, welcher dann das Betriebssystem startet. Um zu wissen welches Betriebssystem schaut sich der Bootloader meist die Partitionstable an, die sich ab Byte 446 im MBR befindet. Hier wird aufgelistet welche Partitionen es gibt, welche Typ diese haben (FAT, LVM, SWAP, …) und welche davon zum Beispiel Bootable sind.

Da aber nur vier Einträge in die Partitionstable passen, gibt es so genannten Extended Partitionen. Im MBR wird dazu ein großer Block reserviert, mit dem Typ 0×05 markiert und zu Beginn dessen eine weitere Partitionstable geschrieben welche diesen großen Block weiter unterteilt.

Da 440 Byte nicht viel ist für ein Bootloader ist, wird oftmals der Bootloader in einen Stage 1 und Stage 2 Loader aufgeteilt. Nur Stage 1 wird in den MBR geschrieben und dieser lädt wiederum Stage 2 welcher sich bei Linux unter /boot befindet. Stage 1 macht somit nichts anderes als Stage 2 zu suchen und zu starten. Stage 2 liest dann zum Beispiel bei Grub die menu.lst Konfiguration welche das Design und die möglichen Systeme angibt, welche man booten kann.

Wenn man sich dann für ein System entschieden hat, wir das Image des Betriebssystem gestartet.

Anschalten mit EFI

Jetzt booten wir noch einmal mit Hilfe von EFI.

Zuerst wird die UEFI Firmware gestartet. Diese initialisiert, wie das BIOS die Hardware. Allerdings gehen die Möglichkeiten noch darüber hinaus. Es ist möglich die Grafikkarte gleich zu nutzen und damit ein echt cooles BIOS anzuzeigen. (Maus Support, Lokalisierung, Dialogfelder, Drag & Drop, 3D Ansicht der Hardware, …).

Der eigentliche Unterschied sollte aber beim Booten auffallen. Hat man früher nur Devices im BIOS ausgewählt, die gebooted werden sollen (cdrom, usb, floppy, disk, …) so kann man jetzt das richtige Betriebssystem wählen. Aber wie funktioniert das?

GPT

Zuerst ist es wichtig zu wissen, wie die Partitionen erkannt werden. Dies geschieht nicht mehr über den MBR sondern über GPT (GUID Partition Table). Diese Tabelle ist genauso wie der MBR am Anfang der Festplatte, allerdings ist der Aufbau völlig anders. Die ersten 512 Bytes sind für das protective MBR reserviert. Das ist ein MBR der einfach ein Eintrag enthält, der über die gesamte Größe der Festplatte geht. Um zu verhindern, dass alte Programme Amok laufen wenn sie kein MBR finden. In den nächsten 512 Bytes ist der Primary GPT Header.

Dabei ist es erst einmal wichtig, dass nicht mehr wie im MBR mit Cylinder-head-sector die Position der Partitionen angegeben werden. Es wird dafür das Logical Block Addressing (LBA) verwendet. Dabei werden nur noch die Anzahl der Sektoren gezählt. Die Sektorgröße ist dabei fest auf 512 Byte vorgeschrieben. Somit entspricht der protective MBR (0 – 512 Byte) LBA0 und der Primary GPT Header (512 – 1024 Byte) LBA1.

Der Primary GPT Header enthält viel mehr Felder als eine alte Partitionstabelle. Es gibt eine Disk GUID welche viele vielleicht unter Linux als UUID kennen. So kann man jede Partition mit einer eindeutigen ID ansprechen. Zudem gibt es noch viele Verwaltungseinträge wie Backup of @Header, @fist useable LBA, last usable LBA, oder Revision und Checksum.

Mit den Werten im GPT Header wird auf ein partition entry array verwiesen. Üblicherweise befindet sich dieses in LBA2. Die Partitionen sind wieder mit GUID’s versehen. Aber auch der Typ der Partition (Swap, FAT, LVM, …) besteht aus einer UUID. Swap bekommt nun zum Beispiel die Bezeichnung 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F. Ebenso gibt es einen human readable Partitionsnamen. Oder die Möglichkeit Attribute wie readonly oder automount (windows spezifisch) abzulegen.

Es ist vorgeschrieben, dass mindestens 16384 Bytes für das partition entry array frei gehalten werden müssen. Das gibt bei einer Größe von 128 Byte pro Eintrag die Möglichkeit 128 Partitionen anzulegen. Es können aber auch größere Einträge oder mehr Platz verbraucht werden. (Sollte man aber nicht machen, wenn ich das richtig verstehe).

ABER: Laut Advanced Format arbeiten moderne Festplatten intern mit 4KB Sektoren auch wenn sie nach außen 8 × 512 Blocks emulieren. Aber mit der default Größe des GPT würde die erste Partition bei LBA34 beginnen. Der nächste 4KB Block aber bei LBA40. Somit sind ALLE Blocks misaligned. Das führt zu Performance-Einbußen. Deshalb muss beim Partitionieren darauf geachtet werden, dass der erste Sektor erst bei LBA40 beginnt. ABER: Ein ähnliches Problem ergibt sich mit SSD’s. Die können zwar byteweise geschrieben werden, aber das Löschen funktioniert nur per Block. Die Blockgröße schwankt dabei und kann zum Beispiel 256KB oder 512KB groß sein. Um den ganzen Problemen mit Partition boundary aus dem Weg zu gehen, gibt es die Regel des 1-MiB alignment. Damit sind alle Partition auf 1 Megabyte Größe angepasst. Somit startet der erste Sektor bei LBA2048 (2048 * 512 = 1MB).

Achso wer sich wundert warum es Primary GPT heißt. Es gibt noch ein secondary GPT – Üblicherweise am Ende der Disk – welcher aber identisch ist und nur zum Backup dient.

GPT ist zwingend notwendig für EFI aber EFI (zumindest unter Linux) nicht für GPT. Das Betriebssystem, BIOS und Bootloader müssen es nur unterstützen. Neuere BIOS sollten das, aktuelle Bootloader (grub-legacy nicht) auch. Und sogar Windows kommt damit klar (solange es nicht ohne EFI von GPT booten muss). Also wenn ihr neu formatiert kann ich nur GPT empfehlen. Dabei muss man sich auch um das ganze Alignment keine Gedanken machen, da es die neueren Tools alle unterstützen. Partitioniert man auf Konsole nimmt man einfach statt fdisk – das von der Bedienung identische – gptfdisk. Dabei wird auch gleich passend auf 1-MB alignment formatiert.

Loading Bootloader

Da es kein MBR mehr gibt (zumindest keinen mit sinnvollen Daten). Und im GPT nicht steht wie der Bootloader gestartet werden soll, ist ein anderer Weg notwendig. Man nimmt hierbei eine spezielle Partition (Typ C12A7328-F81F-11D2-BA4B-00A0C93EC93B im GPT oder 0xEF00 im MBR) und packt den Bootloader da rein. Windows erwartet hierbei, dass es die erste Partition auf einer Disk ist, aber ansonsten sollte es egal sein wo diese liegt. Die Partition musst FAT formatiert sein wobei 100 bis 200 MB ausreichen sollten. Unter Linux muss die Partition unter /boot/efi eingehängt werden.

Die EFI Partition ersetzt aber nicht die /boot-Partition, in der dann das Grub2 Image und die Kernel Images liegen. Diese kann/muss man trotzdem noch anlegen.

Hat man nun den Kernel konfiguriert, kompiliert und installiert und Grub2 installiert dann kann man den EFI Entry anlegen. Ich nenne den Eintrag mal “gentoo”:

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=gentoo --recheck --debug

Dies erzeugt eine Datei unter /boot/efi/gentoo/grubx86.efi welche dann vom Bios geladen wird. Zudem muss noch Grub2 wie gewohnt mit grub2-mkconfig konfiguriert werden. Das erzeugt dann die entsprechenden Dateien unter /boot/grub2/grub.cfg.

Zuletzt müssen wir unser efi binary noch im BIOS registrieren. Dazu existiert das Tool efibootmgr. Hier kann man einen EFI Eintrag anlegen.

efibootmgr --create --gpt --disk=/dev/sda --part 1 --write-signature --label "gentoo" --loader "\\EFI\\gentoo\\grubx64.efi"

Zudem kann man die Bootreihenfolge oder den Timeout des BIOS einstellen:

# efibootmgr
BootCurrent: 0000
Timeout: 1 seconds
BootOrder: 0000,0008,0003,0004,0007
Boot0000* gentoo
Boot0003* Hard Drive
Boot0004* CD/DVD Drive

So und jetzt das Beste: Um Grub2 mit EFI zu installieren muss das Kernel Modul efivars geladen sein. Dieses lässt sich aber nur laden wenn man mit EFI Boot gebooted hat. Ein wundervolles Henne-Ei-Problem. Und das Beste: Es gibt kein schnellen Workaround.

Was ich gemacht habe: USB-Stick mit FAT formatieren und grub2 darauf installieren. Kernel mit EFI_VARS bauen. Im Bios von USB-Stick booten, dort (da grub2 nichts zum Booten findet) über die Grub2 rescue console den Kernel booten.

Seit dem habe ich ein efi bootfähigen USB Stick rumliegen ^^.

Arch beschreibt auch ein Weg wie man ein EFI-ISO erstellen kann. Habe ich aber nicht getestet.

Booting ohne Bootloader

Es gibt auch die Möglichkeit ganz auf einen Bootloader zu verzichten. Linux agiert dabei selbst als EFI Binary und man kann sich den Bootloader sparen.

Das Problem: Hat man mehrere Kernel oder Kernel mit unterschiedlichen Parametern, so muss man für jeden immer das EFI Binary pflegen. Zudem muss man jedes mal ins BIOS wenn man ein anderen Kernel booten will.

Dafür gibt es auch schon Lösungen wie gummiboot, was ein Bootloader für EFI Binary ist.

Ich habe diese Möglichkeit nicht ausprobiert. Daher kann ich nur berichten, dass es die Option gibt. Arch beschreibt das ganz gut.

Kernel für EFI

Kurz ein paar Optionen für den Linux Kernel die man für EFI/GPT benötigt:

Secure Boot

Da dies wohl das bekannteste “Feature” von UEFI ist, will ich ganz kurz darauf eingehen.

Dabei soll das Booten nur für signierte EFI Binaries erlaubt sein, damit keiner Veränderungen am Kernel vornehmen kann. In der EFI Firmware werden dazu Zertifikate hinterlegt, mit denen dann das EFI Binary signiert sein muss um es starten zu können. In einem Modi ist es auch möglich neue Zertifikate der Kette hinzuzufügen. Dann wechselt man auf einen zweiten Modi in der Firmware und ab dann ist es verboten nicht signiertes zu booten. Ein dritter Modi deaktiviert Secure Boot komplett.

Die Idee finde ich prinzipiell gar nicht so schlecht. Bei Full-Disk-Encryption stellt sich immer das Problem, dass jemand den unverschlüsselten Kernel präparieren und so ein Keylogger einbauen kann. Wenn nur signierte EFI Binaries gestartet werden können, dann kann auch kein Kernel untergeschoben werden.

Die Kritik, die gegen Windows 8 entstanden ist, hängt mit der Microsoft Policy zusammen. Demnach ist es so, dass ein Windows 8 Rechner Secure Boot aktiviert haben muss. Da Windows so eine Vormachtstellung hat, werden wohl nur in den Rechnern die Windows Zertifikate installiert sein. Somit kann man per default nichts starten was nicht von Microsoft signiert ist.

Natürlich könnte man Secure Boot abschalten, aber dann muss man erstmal im EFI rum konfigurieren.

Möchte man Secure Boot mit Linux nutzen wird es vermutlich notwendig sein, eine Zertifikatskette zu erstellen und sein Root Zertifikat im EFI hinzuzufügen. Das dürfte sicher viele Neulinge überfordern. Zudem es nicht sicher ist, dass alle EFI Hersteller diesen Modi überhaupt unterstützen.

Außerdem gestattet Windows in der ARM-Version es nicht Secure Boot zu deaktivieren. Somit bleibt dort nicht mal mehr die Hoffnung, dass die EFI Hersteller einem die Freiheit gewähren, sondern man wird zwingend beschnitten.

Linux Distributionen umgehen dies, indem sie ihre Bootloader von Microsoft zertifizieren lassen. Das ist momentan wohl gegen eine Gebühr von 100 USD möglich. Oder aber man verwendet einen signierten EFI Bootloader. Aber mit selbst kompilieren ist es dann erst einmal vorbei.

Comments:

(howto comment?)