Last edit: 2024-09-17
UEFI disambiguation, and practical configuration guide.
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. Limine is my favorite one: 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.
To install Limine, copy .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
CMDLINE
specifies arguments to pass to the kernel. Copy these from the
existing bootloader config, at the very least you should specify the system’s
root partition. boot():
states Limine should look for the file on the same
partition where Limine bootloader resides, read Limine documentation to
get more details.
Suppose you have M$ 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' 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.
/Some Linux
PROTOCOL: linux
KERNEL_PATH: boot():/path/to/kernel
MODULE_PATH: boot():/path/to/ramdisk
CMDLINE: root=/path/to/root/system/partition
/M$ Windows 11
PROTOCOL: efi_chainload
IMAGE_PATH: boot():/EFI/Microsoft/Boot/bootmgfw.efi
My Limine config looks like that:
TIMEOUT: 5
TERM_FONT_SCALE: 2x2
/Slackware GENERIC
PROTOCOL: linux
KERNEL_PATH: boot():/EFI/Slackware/vmlinuz-generic
MODULE_PATH: boot():/EFI/Slackware/initrd.gz
CMDLINE: root=/dev/md2 vga=normal ro
/Slackware HUGE
PROTOCOL: linux
KERNEL_PATH: boot():/EFI/Slackware/vmlinuz-huge
MODULE_PATH: boot():/EFI/Slackware/initrd.gz
CMDLINE: root=/dev/md2 vga=normal ro
/M$ Windows 11
PROTOCOL: efi_chainload
IMAGE_PATH: guid(0eaaaa4b-98bf-4e16-9f3a-500000000003):/EFI/Microsoft/Boot/bootmgfw.efi
Refer to Limine documentation for more options.
Bye.
© 2024
Ivan Kovmir —
CC BY-NC-SA 4.0 License