
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:

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'.
- Section .setup, contains mostly legacy code for initialization in case of loading in compatibility mode. When booting into UEFI mode, all switchings of processor modes, initial initializations are done by flashing.
- The .reloc section is required by the loader, so when building the kernel an empty stub is created “so that it is”.
- The most interesting section of .code, in fact, contains the EntryPoint and the main code of the rest of the kernel. After the EFI-application is found, the loader executes the load service LoadImage, thereby loading the entire image into memory. The type of residence depends on the Subsystem: EFI_APPLICATION field will be unloaded when it runs. EFI_DRIVER can be Unloadable and will be unloaded only in case of a critical error. Next, control is passed to the entry point, usually this is the efi_main () function - an analog of main () in C.
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

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!
gdisk does not suffer from this:
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:
Some distributions require the kernel option CONFIG_EFI_VARS to be enabled for this utility to work.
Getting started

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.
CheckTo 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:
- You can mount ESP \ {vendor} \ to / boot via mount --bind by first copying the contents.
ExceptionsThis item is only suitable for distributions that do not contain symbolic links in the / boot directory. For example, on openSUSE it will not be possible to mount, since it contains several links there, including the kernel itself.
- As an option, when updating the kernel, each time copy it and ram-disk to ESP \ {vendor} \
- You can put the EFI driver to read the / boot file system and boot directly only by adding the extension '.efi' to the kernel (or better hardlink).
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:
- We use efibootmgr, which can transmit kernel parameters.
- If efibootmgr kicks, you can use the UEFI Shell , which, like our kernel, is an EFI application. Through his bcfg command it is possible to edit download points.
- Maybe this option: efibootmgr swears at adding parameters, then the firmware does not support their recording (or just a curve, which is more likely). In the last article in the comments mentioned the kernel parameter efi_no_storage_paranoia , which can help. But you can use it only if you are sure that your firmware is fully implemented in accordance with the specification! The developers warn that if the vendor added crutches and gag during implementation, there is a non-illusory chance to materialize the brick in place of the motherboard.
- You can also boot via UEFI Shell. For it, a startup.nsh script is created, in which the kernel boot command with the desired command line is specified. And Shell, in turn, is added as a download point.
- There is one more problem: adding an item is possible only for one path of the kernel, while the ram-disk is not visible. Most articles recommend recompiling a kernel with a built-in initrd. I don’t know for sure if this is a kernel problem or a boot loader. But at the moment in 90% of cases everything is supported and there is no need to rebuild the kernel.
Probable cause of delusionRecommendations for embedding a ramdisk into the kernel were most likely due to a massive misreading of the path to it. In early implementations of the EFI Boot Stub, the kernel did not spit a mistake about the wrong path to the ram-disk, but silently refused to boot. Apparently, therefore, everyone began to massively introduce it into the kernel, having decided that it is not supported. Although support for the initrd parameter exists since the very appearance of the Boot Stub feature in the kernel.
IMPORTANT: The path to the ram disk is transmitted absolute through backslashes "\" , and not straight lines! For example, initrd = \ EFI \ archlinux \ initramfs-linux.img.
Exceptions for anarchistsIn fact, kernels of versions above 3.8.0-rc5 do not see the difference between the forward and reverse slash - any will work. But since the appearance of the Boot Stub feature in version 3.2.0-rc5, the path, written through straight slashes, the kernel simply did not see and silently refused to boot without errors. Swearing mistakes about this, it learned in version 3.4.0.
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:
- Download the first available live-cd with EFI boot support. And from it already use the efibootmgr command.
- Download UEFI Shell. From it, you can both boot into EFI mode, simply by specifying the kernel and ram disk, or edit boot items.
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 specificationsRoderick 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