📜 ⬆️ ⬇️

Linux Kernel EFI Boot Stub or "Self Loader"

UEFI Tux Logo

Introduction


After reading a recent article Booting Linux without a bootloader , I realized two things: many people are interested in the “novelty”, dating back as far as 2011; the author did not describe the most basic, without which, in fact, nothing will work in some cases. There was also another article, but either it is already outdated, or there, again, a lot of superfluous and unsaid at the same time.

Specifically, the main point was missed - the kernel build option CONFIG_EFI_STUB . Since in the latest versions of U (lu / ku / edu / * etc *) buntu, this option is already on by default, the author has no suspicions.
As far as I know, at the moment it is included in the distributions of the above versions and above: Arch Linux, Fedora 17, OpenSUSE 12.2 and Ubuntu 12.10. I also mentioned in the comments that Debian with the 2.6 kernel can, but this is nothing more than a backport from the latest versions. On these distributions rebuild does not need anything at all! But on the other, CONFIG_EFI_STUB is most likely either completely absent, since the option is available only from kernel version 3.3.0 or higher, or is disabled by default. Accordingly, everything described below is valid for the kernel compiled with the CONFIG_EFI_STUB option.

So, what is the Linux Kernel EFI Boot Stub?


general information

And nothing like ... "exe-file"! Yes, yes, PE / COFF . Well, or rather, just zakos under it with a few modifications to please the UEFI loader. You can verify this by reading the first 2 bytes of the kernel:
$ od /boot/vmlinuz-linux --address-radix=x --read-bytes=2 -t x1c 0000000 4d 5a MZ 0000002 

Familiar, is not it? At least for those who at least once “for interest” opened an MS-DOS or Windows executable file in a notebook, hex editor or something more abruptly. These are the initials of Mark Zbikowski , who, in fact, developed this file format in MS-DOS. The signature of this stub still hangs as a rudiment in modern Windows executable files, devouring as many as 64 bytes for each file!
')
The DOS header falls on a legacy code, which is executed when the kernel is booted as a boot sector, and swears in the MS-DOS style when running PE files: “Direct floppy boot is not supported. Use a boot loader program instead. Remove disk and press any key to reboot ... ". Therefore, the information from this header here is garbage, except, in fact, the 'MZ' signature and the offset address of the next header.

Go ahead.
The PE / COFF specification tells us that at offset 0x3c there is a 32-bit offset of the second header with the signature "PE \ 0 \ 0":
 $ od /boot/vmlinuz-linux --address-radix=x --read-bytes=4 --skip-bytes=0x3c -t x4 00003c 000000b8 000040 

so, the offset is 0xb8, which is true for the current stable-core x86_64 architecture, on x86 it will be 0xa8. We read:
 $ od /boot/vmlinuz-linux --address-radix=x --read-bytes=4 --skip-bytes=0xb8 -t x1c 0000b8 50 45 00 00 PE \0 \0 0000bc 

And here is the signature of the second header! As you might guess, this is an abbreviation for the Portable Executable phrase, from which the payload begins in executable files.

Even the Windows bootloader spat on half the fields of this header, and UEFI doesn't need them at all, so some of them are statically spelled out, while the important ones are filled during the kernel build. Many "unnecessary" fields, all timestamps, control sums, etc. simply remain zeros. The dimensions, offsets, entry point, etc. are filled in mainly. Therefore, it is possible with a stretch to call this PE file completely valid. However, the classic LordPE or PETools utilities are quite content with their signatures and tell everything they know about the file:

PE optional header


image The main difference from "real" executable files in Windows is the Subsystem flag of the optional header, which is set in IMAGE_SUBSYSTEM_EFI_APPLICATION, and not in IMAGE_SUBSYSTEM_WINDOWS_GUI for graphical or IMAGE_SUBSYSTEM_WINDOWS_CUI for symbolic devices that are used for symbolic displays that are applied to all the same in-house snapshots.

Structure

In general, everything is just like in a regular PE file. Currently, the stable version 3.11.4 of the Arch Linux kernel is from the repositories, it contains 3 sections: '.setup', '.reloc' and '.text'.


In fact, I was a little cunning, at the beginning I called the kernel an exe-file. In fact, this is a simple EFI application for yourself, which uses the format of PE32 +.

Primary requirements


image First of all, you need to activate the boot mode EFI-mode. The item can be called as the vendor ponders, usually located in the Boot Options tab. If you see something like Legacy Mode or CSM (Compatibility Support Mode), or just BOIS Mode, change it to something like: (U) EFI Mode, Enhanced Mode or Advanced Mode.

If the motherboard has the “Windows 8 Ready!” Logo, then most likely, the EFI Boot Mode is already activated by default.

In most cases, to boot the Linux kernel into EFI-mode, you must turn off the Secure Boot option.

Disk partitioning

Many sources indicate that GPT disk layout is required, not the MBR , but this is not the case. UEFI is quite able to MBR. Another thing, for example, Windows forcibly forces to break a disk with a new method in order to boot into EFI mode and swears at the antiquity of the Master Boot Record. And rightly so! Having marked the disc “modernly” we will not lose anything, we will only win.
First, there will be no problems with all Primary / Logical partitions there, “don't go there - go here” and other rudiments.
Secondly, even though nowadays SolidState disks are being promoted massively, in which the volumes are not very surprised yet, the size of the usual “turntables” of several terabytes is no longer surprising. But under the MBR, you can partition the partition with a maximum of about 2TB. GPT, well, it sees a lot , you can not even call the figure - relatively small disks of this size will not appear soon.
Well, plus all sorts of bonuses, such as duplicating a GPT record at the beginning and end of a disk, integrity checksums, etc., add a desire without hesitation to mark up a disk under GPT.

You can find a huge amount of articles on how to split a disk with the help of various utilities in GNU / Linux.

Separate section

Partition type

After nn-tsat years of developing standards, the engineers did decide that hardcode was not good. Now it doesn’t matter where our boot partition is located, the UEFI boot loader is very simple: it goes through all the partitions and disks and searches for one special one. Its peculiarity lies in the fact that in the case of the MBR markup, it is of the type with the code 0xEF (as you can guess from EFI). In the case of GPT markup, the GUID partition is C12A7328-F81F-11D2-BA4B-00A0C93EC93B .

There is some implicitness here. All markup utilities, such as parted, have the property of setting and displaying the “boot” flag, which is applied to the partition. So, in the case of the MBR, this possibility does exist, that is, there is a real byte, which indicates to the BIOS that the partition is “bootable”. This flag can be put on any partition whose MBR we want to feed to BIOS for loading. But when we are dealing with GPT, there really is no flag! By this flag, parted means just a GUID equal to the above. That is, in fact GPT boot flag = GPT EFI Partition!
parted
 # parted /dev/sda -l : ATA ST3750330AS (scsi)  /dev/sda: 750GB   (./.): 512B/512B  : gpt Disk Flags:         1 1049kB 135MB 134MB fat32 EFI System  2 135MB 269MB 134MB ext2 Linux filesystem 3 269MB 8859MB 8590MB linux-swap(v1) Linux swap 4 8859MB 30,3GB 21,5GB ext4 Linux filesystem 5 30,3GB 46,4GB 16,1GB ext4 Linux filesystem 6 46,4GB 67,9GB 21,5GB ext4 Linux filesystem 7 67,9GB 750GB 682GB xfs Linux filesystem 
gdisk does not suffer from this:
gdisk
 # gdisk /dev/sda -l GPT fdisk (gdisk) version 0.8.7 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Disk /dev/sda: 1465149168 sectors, 698.6 GiB Logical sector size: 512 bytes Disk identifier (GUID): 02D11900-D331-4114-A3D7-8493969EF533 Partition table holds up to 128 entries First usable sector is 34, last usable sector is 1465149134 Partitions will be aligned on 2048-sector boundaries Total free space is 2014 sectors (1007.0 KiB) Number Start (sector) End (sector) Size Code Name 1 2048 264191 128.0 MiB EF00 EFI System 2 264192 526335 128.0 MiB 8300 Linux filesystem 3 526336 17303551 8.0 GiB 8200 Linux swap 4 17303552 59246591 20.0 GiB 8300 Linux filesystem 5 59246592 90703871 15.0 GiB 8300 Linux filesystem 6 90703872 132646911 20.0 GiB 8300 Linux filesystem 7 132646912 1465149134 635.4 GiB 8300 Linux filesystem 


Conclusion: if our EFI-partition is on the MBR - set the type of the EFI Partition partition and boot flag. If GPT is either an EFI Partition type or boot flag, as they are the same.

There are all sorts of things, such as the GPT legacy boot flag, which is installed in the Protective MBR, and so on, but all of these are crutches that are used only in compatibility mode. In GPT mode, UEFI Boot should be ignored.

File system

In different sources they write differently. Someone says that FAT16 can be used, someone even recommends FAT12. But, isn't it better to follow the advice of the official specification? And she says that the system partition should be in FAT32. For removable-media (USB HDD, USB Flash) - also FAT12 / FAT16 in addition to FAT32.
About the size of the section says nothing. However, due to the initial crutch and boot implementations of the boot loaders and firmwares, the people found out experimentally that in order to avoid various “surprises”, a size of at least 520MB (546MB) is recommended . Here, as lucky, there may be no problems with the 32 MB partition.

Directory structure

After the loader has found its “labeled” partition and made sure that it supports the file system, it starts performing all actions with paths relative to the root of the partition. In addition, all files in this section should be located in the \ EFI \ directory, which, in turn, is the only one in the root of the section. By agreement, each vendor is recommended to allocate a folder with a unique name and place it in \ EFI \, for example: \ EFI \ redhat \ , \ EFI \ microsoft \ , \ EFI \ archlinux \ . In the vendor directory are directly executable efi-applications. One file per architecture is recommended. Files must have the .efi extension.

For removable devices, the \ EFI \ BOOT \ directory is intended. It also recommends no more than one file for each architecture. In addition to this, the file should be called boot {arch} .efi . For example, \ EFI \ BOOT \ bootx64.efi . Available architectures: ia32, x64, ia64, arm, aa64 .

NVRAM access

By default, if nothing is written in the UEFI non-volatile memory, \ EFI \ BOOT \ bootx64.efi will be loaded. To write the path to the necessary application in NVRAM , you can use the efibootmgr utility. Let's try to display current records:
 # efibootmgr -v 

Some distributions require the kernel option CONFIG_EFI_VARS to be enabled for this utility to work.

Getting started


image So, we have allocated FAT32 EFI System Partition (ESP) with the size of 550MiB . Or, we have a second Windows system and have already created it. True, she creates it usually about 100MB in size, but personally I have never had any problems.
The / boot already has a kernel with EFI boot STUB support.
Check
To check if the option was enabled when building the kernel, run:
 $ zgrep CONFIG_EFI_STUB /proc/config.gz 
or
 $ zgrep CONFIG_EFI_STUB /boot/config-`uname -r` 

CONFIG_EFI_STUB = y means that the option is active.

Next we have a bunch of options for the development of events:

Now you need to somehow add the boot point in NVRAM UEFI. Here again, many options:

If we are already loaded in EFI mode (efibootmgr -v does not swear) using GRUB2, rEFInd, etc., then everything is fine:
If we only found out about the EFI boot mode and want to switch to it, in order to add boot points, we need to be in this mode, and we are still in compatibility mode ... There are two main solutions:

Dualboot without bootloader


If you have 2 systems installed at the same time, and still do not want to install a third-party bootloader, you can add both to the UEFI boot points and adjust the preferred boot order. The Windows boot loader is usually located in \ EFI \ Microsoft \ BOOT \ bootmgfw.efi .

Total


If everything is done correctly, reboot, call the Boot Menu, select the item we added and look at the almost instantaneous download. In the case of SSD, FastBoot, Readahead and Arch Linux - about 3-4 seconds. The home server has been loaded for a year without any third-party downloaders using EFI Boot STUB.
Of course, the speed gain here is minimal, but, as people who know like Roderick Smith write, sometimes in the EFI Boot mode, there is a “more adequate” initialization of the equipment than in compatibility modes.

Conclusion


Due to the relative dampness of the UEFI firmwares and completely different implementations, I did not give examples of code. In each case, there may be a problem. I hope the description I have described will help to understand the general principle and apply it to my case.
I also recommend flashing the latest version of UEFI from the site of the motherboard manufacturer.

Literature


UEFI official specifications
Roderick W. Smith's Web Page is the author of many utilities related to EFI, downloaders and disk partitioning.
ArchWiki: UEFI Bootloaders - permanent and one of the best and complete wiki on the GNU / Linux one of the distributions.
Official PE / COFF specification

Source: https://habr.com/ru/post/197438/


All Articles