Linux Boot and Startup
Reading
Optional:
man bootup
, the manual page that describes the Linux boot process
Boot phases
We can divide the Linux boot process into the following phases:
- hardware boot for initializing the hardware components,
- operating system boot during which the Linux kernel and the systemd management services get started, and
- system startup, which gets the whole machine ready for work.
Hardware boot
The first phase of the boot process isn’t particularly related to Linux yet. It’s the hardware boot, which is the process of initializing the hardware components of the computer. This is done by the BIOS or UEFI firmware, which is a small program that is stored in a flash memory chip on the motherboard. The firmware is responsible for initializing the hardware components and loading the operating system.
BIOS stands for “Basic Input/Output System”. It’s the firmware used by older computers and was introduced when IBM designed the first PC back in 1981.
UEFI is the abbreviation of “Unified Extensible Firmware Interface”. It is used by more recent computer generations, and has many more advanced features on top of the traditional BIOS functions. For example, the BIOS firmware can only boot from a hard disk that uses the MBR, “Master Boot Record”, partitioning scheme, while the UEFI firmware can boot from hard disks using GPT. GPT is short for “GUID Partition Table”, a modern partitioning scheme that supports larger disks and more partitions than MBR. UEFI also has more control over hardware features such as power management, CPU voltage and frequency, and which CPU cores are enabled.
When you switch on power, the firmware first checks the hardware components to make sure that everything is working properly. This check is called the Power On Self Test, or POST. If the POST fails, the firmware will display an error message and stop the boot process. Otherwise, the firmware will look for a boot device, which is a device that contains the operating system.
The firmware reads the first 512 bytes of the boot device, which is called the boot sector. The boot sector contains the boot loader, which is a small program that loads the operating system into memory and starts its execution.
The Linux boot loader
The boot sector loaded by the firmware is in fact the first stage of the GRUB boot loader. GRUB stands for “GRand Unified Bootloader”. It’s the default boot loader used by most Linux distributions. GRUB is a powerful software whose purpose it is to load the Linux kernel into memory from many different types of devices, including hard disks, USB drives, CDs, DVDs, network shares and even the Internet. Thanks to its support of the multiboot specification, GRUB can also initiate the boot process of other operating systems, such as Windows and macOS.
GRUB stage 1 is just a tiny piece of software because it has to fit into the first 512-byte sector on the boot device. In a generic MBR, the space available for the actual bootstrap code is only 446 bytes. The rest of the sector is used for the partition table and the boot signature. The partition table is a data structure that describes the partitions on the boot device. The boot signature is a special value that indicates that the sector contains a boot loader. The boot signature is the last two bytes of the sector and has the value 0x55AA in hexadecimal notation. If the boot signature is missing or has an invalid value, the firmware will not recognize the sector as a boot sector and will not load it.
In UEFI systems, the partition table is stored in a different location and the boot signature is not used. This means that the boot sector can be larger than 512 bytes. In fact, the boot sector can be as large as 64 kilobytes. This allows the boot loader to be much more complex and powerful than the boot loader in a BIOS system.
Because of its size limitation, the sole purpose of GRUB boot phase 1 is to load the code for GRUB phase 2, which in turn is responsible for loading the Linux kernel into memory and starting its execution. The code for this second phase is stored on the boot partition. It’s usually the first partition on the boot device. The boot partition is also called the boot directory because it’s mounted on the /boot
directory in the Linux filesystem. The boot partition has to be formatted with a filesystem that is supported by GRUB phase 1, usually ext2 or ext4.
Its larger size allows the second GRUB phase to have a more complex and powerful code than the first phase. For example, it can read files from more sophisticated filesystems, and it can display a menu of boot options. GRUB phase 2 can also boot other operating systems, such as Windows and macOS.
The boot partition is still relatively small, usually a few hundred megabytes, because it only needs to contain the GRUB boot loader and the Linux kernel. The rest of the operating system is stored on separate partitions that become available once the Linux kernel has been loaded.
Linux kernel
When you list the contents of the /boot
directory on a host that has been in operation for a while, you will find several files with names starting with vmlinuz
. These are the Linux kernels that have been installed on the system over time. The reason why there are multiple ones is safety. When you update a Linux system, the kernel packages are handled differently than most other software packages. Kernel packages do not get replaced by their latest version. Instead, newer kernel versions are installed alongside the existing ones. Keeping these older versions around as a precaution allows you to boot from them if the latest kernel version doesn’t work properly on your system for some reason. The GRUB boot manager will display a menu of boot options, allowing you to select the kernel version that you want to boot from.
GRUB configuration
GRUB reads its configuration from /boot/grub2/grub.cfg
, but we do not change that file because it gets generated automatically during kernel updates. Instead, we use the /etc/default/grub
file to configure GRUB. This file contains the default values for the GRUB configuration. It is read by the grub2-mkconfig
command, which generates the /boot/grub2/grub.cfg
file. The grub2-mkconfig
command also reads the /etc/grub.d
directory, which contains scripts that generate the GRUB configuration. The scripts in this directory are executed in alphabetical order, and the output of each script is appended to the /boot/grub2/grub.cfg
file.
The most interesting settings in /etc/default/grub
are the GRUB_TIMEOUT
and GRUB_CMDLINE_LINUX
variables.
The GRUB_TIMEOUT
variable defines the number of seconds that GRUB will wait for user input before booting the default option. The default value is 5 seconds, which might be a bit short.
The GRUB_CMDLINE_LINUX
variable defines the command line arguments that will be passed to the Linux kernel.
Experiment: GRUB configuration
Let’s make a change that is useful for system administrators. As pretty as the graphical boot screen is, it hides everything that’s happening behind the scenes. If you’d like to see what happens during system startup, remove the options rhgb
and quiet
from the GRUB_CMDLINE_LINUX
variable. The rhgb
option stands for “Red Hat Graphical Boot” and displays a progress bar during the boot process. The quiet
option suppresses all messages from the kernel and the startup scripts. By disabling these options, you will see the actual messages that are output during the boot process. This can be useful especially for troubleshooting.
Before:
After:
Since we’re at it, let’s also increase the GRUB_TIMEOUT
to 10 seconds so that we have a bit more time to select a different boot option if necessary.
GRUB_TIMEOUT=10
After modifying the GRUB configuration, we have to update the actual configuration in /boot/grub2/grub.cfg
using the grub-mkconfig
command.
grub2-mkconfig -o /boot/grub2/grub.cfg
When you reboot your machine after this change, press the Esc
key when the GRUB menu is displayed. The first thing you should notice is that the countdown is now starting at 10 instead of 5. After the countdown has expired, you will see the actual boot messages instead of the graphical boot screen.
Experiment: Rescue mode
Kernel startup
The Linux kernel is loaded from a compressed file in the /boot
directory, along with an initial RAM disk image and symbol maps. The initial RAM disk image is a small filesystem that contains the minimum set of tools and drivers that are necessary to mount the actual root filesystem. The symbol maps are used by the kdump
service to generate a crash dump if the kernel crashes.
Once the kernel is running and has initialized the system, it starts systemd
and turns control over to it.
With that, the boot process is complete and the system is ready for use.
systemd
What the actual use of the system is depends on the services that are running on it. The most important service is systemd
, which is the first process that is started by the kernel.
What the Linux kernel is for the hardware, systemd
is for the software. It’s the first process that is started by the kernel, and it’s the last process that is stopped before the system is shut down. systemd
is responsible for starting and stopping all other processes and services on the system. It also manages the system resources, such as the network interfaces, the filesystems and the user accounts.
Since at this point in the startup process, only the root partition has been mounted, systemd now mounts all other partitions that are listed in /etc/fstab
. This also includes swap files or partitions. After all partitions have been mounted, systemd starts all services that are configured to start automatically.
We will discuss systemd in detail in a later chapter. In this context, it’s important to know that systemd is responsible for starting all other processes and services on the system. What exactly is required is defined by the file /etc/systemd/system/default.target
. This file is a symbolic link to another file in the /etc/systemd/system
directory. The default target defines the services that are started when the system boots. On a Linux server, the default target is multi-user.target
; it defines the services that are required for a multi-user system. On a Linux workstation, the default target is usually graphical.target
. Additionally to multi-user.target
, it also starts the display manager that allows users to log in to the graphical user interface.
All systemd targets are again symbolic links with an explanatory name that point to the actual target file in the /usr/lib/systemd/system
directory. These target files are named after the runlevels that were used in the SystemV init system.
Before systemd, Linux distributions used the SystemV init system, named after its root process init
. It was process number 1 on every running Linux system and took care of starting all the other necessary processes. The init
command was also used to switch between the so-called “runlevels”, which were the equivalent to systemd’s targets back then. Each runlevel stood for a specific state of readiness of the system.
In this table, you can see the most important runlevels and their equivalent systemd targets.
SystemV runlevel | systemd target | Description |
---|---|---|
0 | runlevel0.target , poweroff.target | Shut down and power off the system. |
1 | runlevel1.target , rescue.target | Single-user mode. |
2 | runlevel2.target | Multi-user mode with no network services. |
3 | runlevel3.target , multi-user.target | Multi-user mode with networking. |
4 | runlevel4.target | Not used. |
5 | runlevel5.target , graphical.target | Multi-user mode with networking and graphical user interface. |
In fact, systemd still supports the SystemV runlevels, but it’s recommended to use the systemd targets instead.