Booting HOWTO
License notice
Copyright © 2023 Strahinya Radich. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front‑Cover Texts, and no Back‑Cover Texts. A copy of the license is included in the file LICENSE.
Foreword
One of the perhaps most frequent issues with configuring a Unix‑like OS is setting up boot configuration correctly. The perceived difficulty mostly comes from not understanding the basic concepts behind booting.
This guide will attempt to summarize the most important concepts and offer some practical shorthands for setting up booting with Galeb. All the commands assume running them as root, as with any system administration tasks. The most practical way to do that is to login as root or use the command
su -l root
Firmware type
There are two firmware types: the older, BIOS, and newer, UEFI. Which one of the two is used depends on your system. If you can run
efibootmgr -v
and it doesn't give an error message but a list of boot entries, then you have UEFI. With Linux as kernel, a mounted efivarfs, usually at /sys/firmware/efi/efivars, is also needed for the above command to work.
Partition table type
There are two partition table types: older, Master Boot Record (MBR), and newer, GUID Partition Table (GPT). UEFI systems usually use GPT, but other combinations are also possible.
Boot loader
The program which carries out the initial stage of booting an OS is called a boot loader. This can be a program like GRUB, rEFInd, SYSLINUX, LILO and so on, or, in the case of Linux with UEFI, the kernel itself (EFISTUB).
With BIOS, bootloaders are written into the (master or volume) boot records of disk partitions themselves (BIOS/MBR) or BIOS boot partitions (BIOS/GPT), and this is where the system will look for them.
With UEFI/GPT, bootloaders are normal files on an EFI System Partition (ESP). In order for the system to find them, their boot entries must be written to EFI variables. This can be done by the program efibootmgr(8), but it can also be done by the UEFI interface or an UEFI shell.
Linux boot
During the boot process, Linux executes the init program (usually /sbin/init) on the system root partition. This can be done in two ways:
By creating an initial root partition (initramfs) having a temporary init program, which if needed handles loading the necessary kernel modules (drivers) to access the root partition. This method also supports advanced partition selection, for example by their UUIDs or LABELs, and doesn't require the support for filesystem type of the root partition to be compiled into the kernel. initramfs is passed to EFISTUB through the kernel command line:
initrd=\initramfs.img
, where the “root” directory is ESP.Note that UEFI uses DOS filesystem path separator, backslash (
\
), instead of a slash (/
) used on Unix-like systems.By compiling the necessary filesystem modules and storage device drivers into the kernel and specifying the root partition on the kernel command line. This is more minimal, as it doesn't require initramfs. However, advanced partition selection by UUIDs and LABELs is not supported (but see below), and licenses for “binary blobs” (drivers/modules) usually clash with the requirements of GPL (which is the license of the kernel), preventing them from being compiled in the kernel in such a way. That's why initramfs is the most used option, and recommended in Galeb. In Galeb, there is a script mkinitramfs(8), which can be used to generate initramfs. Refer to [5].
Partition can always be specified by a device pathname, such as
root=/dev/sda2
, which can lead to boot failure if the storage device driver
(kernel module) is inaccessible or the disk configuration is changed. For
example, this can happen when plugging in a USB flash drive or physically
connecting hard drives to different cables, and rebooting, or otherwise changing
the order of hard disks.
Partition on GPT systems can also be specified by PARTUUID, which uniquely
identifies a partition: root=PARTUUID=...
. This is the recommended approach.
Recommended setup in Galeb
The following is the basic recommended partition configuration in Galeb on the traditional SCSI drives. It assumes an UEFI/GPT system.
Partition | Mountpoint | Filesystem Type | Size |
---|---|---|---|
/dev/sda1 | /boot | vfat (32-bit) | ~500MB |
/dev/sda2 | / | ext4 | Rest |
When configuring a boot entry, this means that the kernel command line will include
root=/dev/sda2
or
root=PARTUUID=[PARTUUID of /dev/sda2]
and that the ESP is in /dev/sda1, mounted later during the boot process to /boot. This is where the kernel stub should go into, and will later be accessible from the booted system at /boot/vmlinuz.
When the partition /dev/sda2 exists, its PARTUUID can be obtained with the command
lsblk -no PARTUUID /dev/sda2
NVME SSDs require the nvme
and nvme_core
kernel modules, and the partition
device pathnames usually become /dev/nvme0n1p1 and /dev/nvme0n1p2,
respectively:
Partition | Mountpoint | Filesystem Type | Size |
---|---|---|---|
/dev/nvme0n1p1 | /boot | vfat (32-bit) | ~500MB |
/dev/nvme0n1p2 | / | ext4 | Rest |
Creating a boot entry in efibootmgr
The necessary command line parameters will be briefly explained here. For more
information, see man 8 lsblk
, man 8 efibootmgr
and efibootmgr -h
.
partuuid=$(lsblk -no PARTUUID /dev/sda2) efibootmgr -c -d /dev/sda -l '\vmlinuz' -L 'Galeb EFISTUB' -p1 \ -u 'initrd=\initramfs.img root=PARTUUID='${partuuid}' rw'
Explanation
partuuid=$(lsblk -no PARTUUID /dev/sda2)
- Obtain the PARTUUID of /dev/sda2 and store it in the shell variable
partuuid
.
-c
- Create a new boot entry.
-d /dev/sda
- Disk on which the root partition is (boot disk).
-l '\vmlinuz'
- Boot loader (our EFISTUB) is in the file vmlinuz on ESP.
-L 'Galeb EFISTUB'
- Label for the boot entry.
-p1
- ESP is the partition #1 on the boot disk (/dev/sda1).
-u
- Treat the kernel command line as UCS-2.
'initrd=\initramfs.img root=PARTUUID='${partuuid}' rw'
- Kernel command line, quoted to prevent parsing by the shell. Value of the
shell variable
partuuid
is inserted where needed.
Boot image
After the boot scripts have finished, you will be presented with a choice to create a boot image. The boot image will be compressed with xz and needs to be sent to a USB flash medium, for example:
xz -dc galeb-2.2-x86_64-20230417.raw.xz > /dev/sdb
or, if you have pv:
xz -dc galeb-2.2-x86_64-20230417.raw.xz | pv > /dev/sdb
Be careful when specifying the device you send the output to, in order to not overwrite any existing partitions (your hard disk, etc)! You can find out the correct device by using
lsblk -f
or
blkid
The boot image is designed for UEFI systems and will be partitioned as GPT.
When you reboot, enter UEFI setup and choose to boot from USB flash. Fallback
shim will automatically create a boot entry for Galeb, which will set the device
specified as USBROOT
in lib/env.sh as the root device for that entry. If the
boot fails, you need to reboot back into your original system, remove the UEFI
entry (for example, by using efibootmgr(8)), change USBROOT
in
lib/env.sh, rerun the bootstrap scripts, copy the newly generated image to USB
flash and reboot.
You can safely remove the “Galeb USB” UEFI entry if you don't need it anymore, since it will be automatically generated by fallback shim whenever you choose to boot from the Galeb USB medium.
Multi-booting
If you are using Galeb with other distributions which are using GRUB, and in particular GRUB's os-prober, when you have added a custom configuration snippet in /etc/grub.d/40_custom (if Galeb is installed in /dev/sda2):
uuid=$(lsblk -no UUID /dev/sda2) cat <<! >>/etc/grub.d/40_custom menuentry "Galeb 2.2" --class os { load_video insmod gzio insmod part_gpt insmod ext2 search --no-floppy --set=root --fs-uuid $uuid linux /boot/vmlinuz root=UUID=$uuid rw rootdelay=1 rootfstype=ext4 initrd /boot/initramfs.img } !
you might want to then also add an exception to /etc/default/grub so a new menu item for Galeb's partition doesn't get added by os-prober every time there is a kernel update. First, take note of the UUID of the partition where Galeb is installed:
GALEB_PART=/dev/sda2 GALEB_UUID=$(lsblk -no UUID $GALEB_PART)
then append it to /etc/default/grub in your other distro:
cat <<! >> /etc/default/grub GRUB_OS_PROBER_SKIP_LIST=$GALEB_UUID@$GALEB_PART !
You should then regenerate GRUB's configuration file in your distro.