Last edit: 2024-04-10
I have not come across any good explanations of what UEFI is and how it works, even though you have to deal with it almost every time you install an operating system. The following guide provides a comprehensive overview of UEFI and its functioning.
UEFI is a firmware on the motherboard, it can configure hardware and boot operating systems.
Actually, hardware configuration menu and operating system bootloaders are examples of UEFI applications, which you can develop too. Futher text refers specifically to UEFI bootloaders.
UEFI predecessor.
Nowadays interchangeable terms.
UEFI requires its own GPT disk partition of type EFI, formatted with FAT32 file
system. People usually follow the old habit from the days of Legacy BIOS and
create this partition at the beginning of a disk, not sure whether it is still
mandatory for UEFI (but it would not hurt). If you are unsure about the size,
make it 512 MiB. EFI partition is where the bootloader resides among other things, a
bootloader is a file with .efi
extension.
If you have a running Linux, try to locate and observe your existing EFI
partition. Open /etc/fstab
, or execute lsblk -f
and find a partition with
FAT filesystem, then look for its mount point. Within /etc/fstab
the entry
would look similar to the following:
/dev/sda1 /boot/efi vfat defaults 0 0
The partition is mounted under /boot/efi
, let us take a look at it:
$ tree /boot/efi
/boot/efi
├── EFI
│ └── Slackware
│ ├── elilo.conf
│ ├── elilo.efi
│ ├── initrd.gz
│ ├── vmlinuz-generic
│ └── vmlinuz-huge
└── limine
├── limine.cfg
└── liminex64.efi
4 directories, 8 files
Indeed, it has: two bootloaders elilo.efi
, and liminex64.efi
; their config
files elilo.conf
, and limine.cfg
; Linux kernel vmlinuz-*
and ramdisk
initrd.gz
used by the bootloader to boot Linux.
So, you have created a UEFI partition, installed a UEFI bootloader, written a
config file and provided the kernel and ramdisk. There is one last thing left
to do: you have to tell your UEFI system within the motherboard where to find a
UEFI bootloader within a UEFI partition. One of the ways is to put a bootloader
under /EFI/BOOT/BOOTX64.EFI
, which is a path that should be checked by
default. If you put it somewhere else (but within a UEFI partition), you have
to tell your UEFI system within the motherboard where to find it. Linux has
efibootmgr
program to help us. Execute efibootmgr -v
to see the current
state of things:
BootCurrent: 0000
Timeout: 2 seconds
BootOrder: 0000,0001
Boot0000* Limine HD(1,GPT,578fd4d6-329c-3e42-b9fc-c6f5a32c7bd0,0x800,0xfa000)/File(\limine\liminex64.efi)
dp: 04 01 2a 00 01 00 00 00 00 08 00 00 00 00 00 00 00 a0 0f 00 00 00 00 00 d6 d4 8f 57 9c 32 42 3e b9 fc c6 f5 a3 2c 7b d0 02 02 / 04 04 30 00 5c 00 6c 00 69 00 6d 00 69 00 6e 00 65 00 5c 00 6c 00 69 00 6d 00 69 00 6e 00 65 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 00 00 / 7f ff 04 00
Boot0001* Slackware HD(1,GPT,578fd4d6-329c-3e42-b9fc-c6f5a32c7bd0,0x800,0xfa000)/File(\EFI\Slackware\elilo.efi)
dp: 04 01 2a 00 01 00 00 00 00 08 00 00 00 00 00 00 00 a0 0f 00 00 00 00 00 d6 d4 8f 57 9c 32 42 3e b9 fc c6 f5 a3 2c 7b d0 02 02 / 04 04 36 00 5c 00 45 00 46 00 49 00 5c 00 53 00 6c 00 61 00 63 00 6b 00 77 00 61 00 72 00 65 00 5c 00 65 00 6c 00 69 00 6c 00 6f 00 2e 00 65 00 66 00 69 00 00 00 / 7f ff 04 00
The output shows the currently existing entries, and the bootloaders they point
to. As you can see, I have two of them: ‘Limine’ which points to
\limine\liminex64.efi
, and ‘Slackware’ which points to
EFI\Slackware\elilo.efi
. Backslashes (‘\’) are used because FAT is a
Microsoft filesystem. It is also worth noting that Microsoft filesystem are,
unlike UNIX, case-insensitive, so ‘myFile’ and ‘MYFILE’ are the same name.
There is no need to create an entry to point to /EFI/BOOT/BOOTX64.EFI
, as it
is being checked by default, but it should not hurt if you do. Gentoo wiki
does a very good job explaining how to use efibootmgr
, read it. To add a boot
entry you would have to issue the following command:
efibootmgr -c -d /dev/sda -p 1 -L "EntryName" -l '\path\to\bootloader.efi' # -p to specify partition number.
That is pretty much all you need to know.
Let us configure a UEFI bootloader. I hate Grub 2, it is the worst and most complex of bootloaders. Limine is perfect: dead simple, yet highly configurable. It supports FAT file system only, as it should, the rest is the kernel’s job. It supports Linux boot protocol natively, and it can simply run other UEFI bootloaders—that is, chainloading. Figure 1 shows example configuration. It is possible to try out Limine on your existing system without breaking anything, which is what I will do in this guide further down.
You can build it from the sources, or install the binaries provided on their GitHub repository. If you are on Slackware Linux, Limine Slackbuild is also available to you.
To install Limine, copy the .efi
file to anywhere within the EFI partition;
anywhere under /boot/efi
in my case. Then add a boot entry with efibootmgr
,
follow the example from the previous paragraph. You can
now boot into Limine, just write a config file to specify what you want to
load. To boot Linux, you need two things: the kernel, and initial ramdisk.
A typical Linux Limine entry would look like that:
# Save me as 'limine.cfg' at the root of the EFI partiton.
:WhateverName
PROTOCOL=linux
KERNEL_PATH=boot:///path/to/kernel
MODULE_PATH=boot:///path/to/ramdisk
CMDLINE=root=/path/to/root/system/partition vga=normal ro
CMDLINE
specifies arguments to pass to the kernel. You can copy these from
the existing bootloader config, typically you should specify the system’s root
partition. boot:///
states Limine should look for the files on the same
partition where Limine bootloader resides, read Limine documentation to
get more details.
Suppose you have Windows installed as your second OS, and you want to be able
to choose which OS Limine should run. Unlike Linux, Limine does not support
Windows boot protocol natively, but Limine can do bootloader chainloading. It
means you can ask Limine to launch Windows'—just like any other—UEFI
bootloader, which will handle Windows' boot process. So add another entry to
make your limine.cfg
file look like that:
# Save me as 'limine.cfg' at the root of the EFI partiton.
# Forward slashes ('/') should be used to build paths.
:WhateverName
PROTOCOL=linux
KERNEL_PATH=boot:///path/to/kernel
MODULE_PATH=boot:///path/to/ramdisk
CMDLINE=root=/path/to/root/system/partition vga=normal ro
# Adjust windows bootloader path if needed.
:Windows
PROTOCOL=chainload
IMAGE_PATH=boot:///EFI/Microsoft/Boot/bootmgfw.efi
My Limine config looks like that:
TIMEOUT=5 # 5 second timeout.
TERM_FONT_SCALE=2x2 # Bigger font.
:Slackware
PROTOCOL=linux
KERNEL_PATH=boot:///EFI/Slackware/vmlinuz-generic
MODULE_PATH=boot:///EFI/Slackware/initrd.gz
CMDLINE=root=/path/to/root/system/partition vga=normal ro
:Windows
PROTOCOL=chainload
IMAGE_PATH=boot:///EFI/Microsoft/Boot/bootmgfw.efi
Read Limine documentation for more options.
Laptop UEFI implementations are often horrible.
© 2024 Ivan Kovmir — CC-BY 4.0 License