I have always used old/refurbished hardware which almost always used old BIOS firmware. As such, I never had to deal with the intricacies of UEFI. In fact, even in the few recent times when the hardware I was using came with UEFI firmware, I simply switched its legacy mode on, and never looked back. Having now built myself a state-of-the-art machine, I wanted to put an end to this bad habit, and embrace the “new” technology that was UEFI for me. In this article, I try to summarize what I have learned, and highlight the differences between BIOS and UEFI.
BIOS (Basic Input/Output System) is quite the old system, and dates back to the days of the IBM Personal Computer. It has several limitations which include: a limited maximum disk volume, limited number of partitions, and limited protection against certain security threats1.
UEFI (Unified Extensible Firmware Interface) was initially developed by Intel, before it was handed in 2005 to the Unified EFI Forum, which is an alliance between several big-name technology companies which all share the goal of improving the booting process. The specification has since then been maintained by the Unified EFI Forum.
UEFI was a complete overhaul from BIOS. It made the booting process much more robust, eliminated multiple possible points of failure, and brought multiple enhancements to it, including the ability to use cryptography in order to ensure its security2
The firmware (whether BIOS or UEFI) is set to work very closely with the disks connected to the system. These disks are usually organized into partitions, which contain the different operating systems that will actually be booted. For this reason, the firmware is closely coupled to the partitioning schemes (or partitioning tables) used on the disks connected to the system. Thus, before getting into the details of BIOS and UEFI, we need to learn about the possible ways a disk can be partitioned.
Partitioning tables: MBR vs. GPT
As the name might lead to believe, a disk’s partitioning table is a data structure stored on the disk, which contains information about the partitions existing within it. This table is used by the firmware of a computer, as well as by operating systems and disk utilities, in order to correctly handle the disk and its partitions. Information in these tables includes the number of partitions present, their start and end addresses, as well as possible partition labels and identifiers.
The two most popular partitioning tables are: the admittedly antiquated MBR, and the new and improved GPT.
MBR stands for Master Boot Record. This partitioning scheme is closely tied to the BIOS, and as such, also traces its history back to the IBM Personal Computer3. The MBR saves all meta-data about the disk in a single data structure stored at the start of the disk. The name MBR is used exchangeable to refer to both this data structure and to the partitioning scheme as a whole.
Figure 3 shows the layout of a disk partitioned following the MBR layout. The MBR is highlighted, and as can be seen, occupies the first 512 Bytes of the disk. Historically, this length corresponded to the size of one disk sector, which is the minimum storage unit on a hard drive.
The “location” column in Figure 3 uses Logical Block Addresses as a unit. Logical Block Addressing (LBA)4 is an addressing scheme used to refer to physical data blocks on a disk. It boasts simple linear addressing when compared to its predecessors, such as the CHS scheme (Cylinder-Head-Sector) which was common in the early days of spinning-disk hard drives. CHS addressing was the scheme originally used in MBR, before support for LBA was later added, with one Logical Block being equal to one sector of 512 Bytes. This would mean that all 512 Bytes of the MBR fit within LBA 0. This first block is also referred to as the boot sector.
As illustrated in Figure 3, the MBR is divided into the following regions:
- The Bootstrap Code Area (446 Bytes): This area stores actual code which will be loaded from the disk by the system’s firmware and then executed during the boot process. We will look more into how that works in the BIOS/MBR Section.
- The Partition Table (4 x 16 Bytes): MBR supports a maximum of four primary partitions on disk. Information about these four partitions is stored in the partition table, with 16 Bytes allocated for each partition entry. Each entry contains the location, size, type as well as other information pertaining to its corresponding partition. Within The partition table, the start and end of partitions are both represented using 32 bits. For a disk with a sector size of 512 Bytes, this puts an inherent upper limit on the total disk size of:
2^32 * 512 Bytes = 2 TiB.
- The Boot Signature (2 Bytes): Contains the signature value
0x55AAwhich marks the end of the MBR.
MBR has many limitations. Mainly, the low number of possible partitions on disk, and the inherent upper limit on the disk size. However, later improvements have allowed to circumvent these limitations. For example, support for a single extended partition was later introduced to MBR. An extended partition being itself capable of holding as many logical partitions as needed. Additionally, a workaround exists to double the maximum allowable disk size up to
4 TiB. This workaround requires the second half of the disk to be used as a single
2 TiB partition, and the operating system to use 64-bit addressing internally5. Both these requirements are not extreme: the partition occupying the second half of the disk can be an extended partition (and thus hold multiple logical partitions) and most desktop operating systems nowadays use 64-bit addressing. Finally, newer hard drives use a larger 4096 Bytes sector size, thus allowing for an increase of the maximum disk size to a total of
2^32 * 4096 Bytes = 16 TiB5. These workarounds remain however just that: Fixes that were thought of after the fact, in order to attempt to prolong the life of a partitioning scheme which dated back to the 80s and which was initially designed to support disks with a maximum size of 10MB3.
A new partitioning scheme was needed, and it came in the form of GPT.
GPT stands for GUID Partitioning Table. It was developed by Intel in the late 1990s, and ended up becoming part of the UEFI specification (More on that in the UEFI/GPT Section). GUID stands for Global Unique IDentifier, and refers to the unique strings that are used in this scheme in order to uniquely refer to the different partitions included in a disk. Figure 4 shows how layout of a disk looks like under the GPT scheme.
As illustrated in Figure 4, the GPT scheme consists of the following:
- The Protective MBR (LBA 0): This area is used to prevent disk utilities from mistaking the GPT disk for a MBR one. This sector is a fully pledged MBR on its own. However, it contains a single partition entry of type GPT (
0xEE) which encompasses the whole disk (or
2 TiB, whichever is smaller). Legacy disk utilities which cannot read GPT tables and expect a MBR table, will read this protective MBR and realize the whole disk is used up by a partition of ‘unknown type’, thus avoiding an erroneous data overwrite. On the other hand, disk utilities that are only aware of GPT, can check this protective MBR and stop any further disk manipulation if the MBR does not contains the single entry of type GPT. Finally, this area can also be used to store an actual MBR table in the case of a hybrid MBR setup (more on that in the Less common configurations Section).
- The Primary GPT (LBAs 1 - 33) it consists of:
- The GPT Header (LBA 1): which contains the number of partition entries in the table, the size of each entry, in addition to a signature, and a checksum of its content. Additionally, the header also contains the address of a secondary GPT header, in which its content is backed up.
- The Partition Table (LBA 2 - 33): which contains the actual partition entries. Each entry contains the type of the corresponding partition, its start and finish, name, flags, and unique GUID.
- The Secondary GPT (last 33 LBAs on disk): This is a backup of the Primary GPT, and can be used for backup in the case the primary GPT is corrupted.
Each partition entry in the partition table is 128 Bytes long. The UEFI specification, which uses GPT as the De facto partitioning scheme, specifies a minimum partition table size of 16,384 Bytes. This would allow for a minimum of 128 partitions on a single disk. Additionally, GPT uses 64-bit addressing. When using disks with a 512 Bytes sector size, This allows for a theoretical maximum disk size of
2^64 * 512 Bytes = 2 ZiB.
BIOS vs. UEFI in a nutshell
As mentioned in the previous section, the firmware of a computer operates very closely to the partitioning tables of the connected disks. As such, not all combinations of firmware (BIOS/UEFI) and disk partitioning tables (MBR/GPT) are created equal. In fact, in the vast majority of cases, you will be confronted with either one of two possible setups: Either a system with BIOS firmware booting off a disk with a MBR partitioning scheme, or a UEFI system booting off a GPT disk. The first setup is more common on old computers, whereas the second one is more likely in computers from at least the last decade. In the following, we will look into these two combinations. The other two combinations although possible, are less common, and as such will only be discussed shortly at the end of this section.
Figure 5 shows the successive steps which make up the process of booting a BIOS system from a MBR disk:
- Step 1: The first step occurs when the system is first powered on. The BIOS, which lives on the system’s non-volatile memory, is loaded into memory and executed. This program is very primitive, and its only goal is to loop through the different bootable devices connected to the system. The order in which these devices are traversed is usually configurable in the BIOS (e.g. first attempt to boot connected USBs, then hard drives, then CD readers). A bootable disk is simply one which contains a MBR. The BIOS checks for this by looking up the last two bytes in the first sector of each device (See Figure 3). If the signature value
0x55AAis found at this location, the BIOS knows that it just found a bootable disk, and proceeds to load the MBR from the disk into memory.
- Step 2: As we have mentioned in the MBR Section, the first area of the MBR is the bootstrap code. During this step, this code is loaded into memory, executed, and handed control of the boot process. The bootstrap code area is only 446 Bytes long, and as such cannot store all the necessary drivers which might be needed in order to boot the operating systems present on the disk. For this reason, this area is usually used to store only the first stage of the boot loader. The goal of this first stage is to load the next stage of the boot loader which is usually stored in further sectors on the disk. At the end of this step, the bootstrap code passes control to this next stage.
- Step 3: The next stage of the boot loader usually has enough space to store all the drivers necessary to recognize further partitions present on disk. These can contain kernel files, initram archives, or other boot-loaders which can be chain-loaded. Following its configuration, the boot-loader will optionally prompt the user to choose the operating system to boot, and will promptly load the kernel file corresponding to the user’s choice.
- Step 4: In this step the kernel is read from disk, unpacked and loaded into memory. Additionally, initram archives which contain all modules needed in order to mount the root file-system are loaded (e.g. in the case the root file-system is stored on a RAID array, or on an encrypted partition).
- Step 5: The final step of the boot process is to mount the root file-system, and launch the initial process of the target OS.
The BIOS/MBR boot process, is flaky at best. It relies on multiple moving pieces, and has the following possible points of failure:
- Because the BIOS is too primitive to be aware of partitions, the Bootstrap code is written directly to the disk sectors. Most disks know not to mess with the first sector of a disk if they recognize it as MBR-partitioned. However, as it turns out, that can be a big ask in certain scenarios.
- There is no backup of the MBR. Unless you make a manual backup, data stored on your disk might be completely lost if the partition table is ever damaged. If you actually opt for making a manual backup of the MBR (e.g. using a tool like Linux’s
dd) you will have to update that backup whenever you create/delete/edit partitions on the disk.
- Because the Bootstrap code area is so small, most boot-loaders only use it to store their first stage, and save their later stages farther on the disk. However, even with this workaround the first stage is limited in the disk space it can address, and boot-loaders resort to storing their later stages in the first few sectors of the disk, immediately following the MBR. In order to accommodate this, most disk utilities and operating systems jump over the first
1MiBof the disk and never make use of it, thus leaving it empty for the boot-loader’s purposes. This is also a bit flimsy, as all it takes is a slight misconfiguration (e.g. during an OS installation) and this region might end up being mistakenly overwritten.
As we will see in the next section, the UEFI/GPT scheme resolves these issues, and makes for a much sturdier boot process.
The UEFI boot process is built upon the following three elements6:
- The EFI System Partition (ESP): We have learned in the previous section that the BIOS loads code for subsequent boot steps, directly from disk sectors without any awareness of the partitions therein. In contrast to that, the UEFI specification defines a particular partition which the firmware will be able to detect when present on a disk. This is called the EFI System Partition. The UEFI specification requires such a partition to be present for a successful boot. Moreover, this partition needs to be formatted with a
FAT32file-system, and to have a specific reserved value for its GUID. Finally, the size of this partition is usually at least 100MB. Whenever an operating system or a boot-loader is installed on a disk, it is supposed to store its EFI binary files in this partition.
- The EFI binary files: These are binary files which need to follow certain aspects defined in the UEFI specification in order to be executable by UEFI firmware. Whenever a UEFI-aware OS or boot-loader is installed on a GPT disk, it will create an EFI binary for itself and store it in the EFI System partition. During boot, the UEFI can choose to execute any of these binaries, thus booting the corresponding OS/Boot-loader. The order in which execution of the different EFI binaries will be attempted is defined using the EFI Boot manager.
- The EFI Boot manager: Not to be confused with the boot loader, which takes over control of the boot process in a later step. The boot manager is a utility which manages configuration variables used by the UEFI. Among other things, these variables determine which devices/paritions/binaries should by attempt for booting, and in which order. These different bootable objects, are stored as boot entries within the UEFI’S NVRAM (Non-Volatile RAM). Each boot entry is a simple pointer to an EFI binary, and contains information about the disk’s ESP in which the EFI binary resides, and about the location of this binary within the ESP. These entries are not to be confused with the partition entries discussed in previous sections, which are stored in partition tables on a disk. Finally, the boot entries, are in fact not limited to EFI binaries. Because UEFI is backward compatible, these entries can also point to MBR-partitioned disks, which can also be booted from UEFI, following the BIOS booting process.
With the knowledge of these three main component of UEFI, we can start to construct a good mental image of what the boot process looks like. Figure 6 illustrates the different steps of this process.
As can be seen in Figure 6 the UEFI boot process on a GPT-partitioned disk unfolds as follows:
- Step 1: At power on, the UEFI firmware takes control over the boot process. The firmware reads the boot entries as stored in its NVRAM by the boot manager, and sequentially attempts to load the EFI binary each boot entry points to. Alternatively, a MBR disk can also be pointed to, but we are not considering that scenario here. Once a binary pointed to by a boot entry is found, the firmware executes it, and passes control to it.
- Step 2: At this point, the EFI binary chosen by the firmware takes control over the boot process. This binary would be loaded from the ESP, where it would have been stored by either an OS or a boot-loader during its installation. The binary contains all drivers and modules needed to load any further partition in which the kernels of OSes to be booted might reside.
- Steps 3 & 4: These last two steps are identical to the last two in the BIOS/MBR process. At this point, the Kernel and initram archives are loaded into memory. Following that, the root file-system is mounted, and the initial process of the target operating system is started.
Compared to the BIOS/MBR process, the UEFI/GPT process is much more robust, and is composed of fewer steps. Additionally, the guarantee that the firmware will always recognize the EFI System partition, alleviates a lot of the hurdles which BIOS has to deal with. The ESP allows for a better cohabitation between the different OSes sharing the disk: Instead of boot-loaders successively overwriting the Bootstrap code area at each installation, under UEFI, they can save their EFI binaries under the same partition, under different locations. Furthermore, this partition can be made as large as needed. Finally, although not covered here, the UEFI firmware is also more sophisticated than its predecessors, and allows for more features, chief among them perhaps is Secure Boot2.
Less common configurations
As mentioned in the introduction to this section, BIOS/MBR and UEFI/GPT are probably the setups, one is most likely to encounter. However, the other two combinations of firmware/partitioning scheme are still possible, and deserve at least a few short words.
BIOS on a GPT disk (Hybrid MBR)7: This is a workaround to boot GPT disks on BIOS systems. In this configuration, the protective MBR present on the GPT disk is used in order to store entries for up to three partitions present on disk. The fourth entry is still reserved as a GPT partition with type
0xEE. This entry is needed in order to protect the second sector on disk (LBA 1, see Figure 4) which still contains the GPT structure. In fact, in most cases, this entry needs to be the first one in the MBR partitions table, otherwise, a number of disk utilities and OSes might run into issues during boot8.
UEFI on a MBR disk (UEFI Compatibility Support Mode): The UEFI specification includes support for the Compatibility Support Mode. This mode allows booting a MBR disk following the BIOS boot process. This is meant to enable booting older OSes, and older disks which use the MBR partitioning scheme. Most UEFI firmware contains configuration options to enable CSM booting (either exclusively or alongside UEFI booting).
Legacy boot on UEFI works pretty seamlessly (and I can attest to that personally). However, many UEFI features are left to the waste side when UEFI booting is not used (e.g. secure boot).
On the other hand, what I have learned from multiple articles online, is that the Hybrid MBR workaround seems to be just that: a workaround, with the details hidden underneath often showing their ugly head in practice. The main issue seems to be that different OSes, boot-loaders, and disk utilities seem to treat the hybrid MBR in different, and often unpredictable and conflicting ways8. With that being said, sometimes there is no alternative to having to resort to this scheme, and There are at least two realistic use-cases for hybrid MBR I can think of. The first one is when a disk larger than
2 TiB is needed on a BIOS system, and using additional disks is not possible (e.g. on an old laptop). The other is when trying to create a multi-boot USB device, intended to be used on both BIOS and UEFI systems. In such cases, a hybrid MBR might just be the only way out. However, in any other case, hybrid MBR should be avoided as much as possible.
Before concluding, I thought I would improve upon all the theory in my talk so far with a touch of practical knowledge. In particular, since GNU Grub is the most popular boot loader for Linux, I thought it would be interesting to highlight the difference in its installation on UEFI vs. BIOS systems.
grub-install command in used for installation on systems using either types of firmware, only the arguments given to the command make a difference:
- BIOS/MBR: In this case, installing grub is pretty straight forward:
# grub-install --target=i386-pc /dev/sdX
--target=i386-pcargument is what tells grub that the system uses BIOS firmware. The
/dev/sdaXis the disk to which grub will be installed. Notice that
sdaXrefers to the whole disk, and not any single partition on it. Additionally, you will need to replace
Xwith the target disk of your case. With this command, grub will overwrite the Bootstrap code area on the target disk’s MBR with its own boot code.
As we have mentioned in the BIOS/MBR Section, the Bootstrap code area is too small to contain the totality of grub’s boot code. To circumvent this, grub saves only its Stage 1 in the Bootstrap code area. Additional code, is stored by grub further in the disk, in the empty space between the MBR and the first partition. This code is referred to as Stage 1.5. The final stage of grub, Stage 2 is saved in the boot directory under
/boot/grub/, either under the root tree or in a separate boot partition.
- UEFI/GPT: This case requires a couple more arguments to be given to grub:
# grub-install --target=x86_64-efi --efi-directory=/path/to/esp --bootloader-id=GRUB
x86_64-efivalue given to the
--targetparameter informs grub that the system uses UEFI firmware. The
--efi-directoryparameter, should contain the path to the mount location of the EFI system partition. This is so that grub can store its EFI binaries there. Finally, when installing grub on a UEFI system, the additional
efibootmgrpackage will be required. This package is a utility which enables interacting with the firmware’s boot manager in order to edit its configuration variables and set its boot entries. This in fact, is exactly what the
bootloader-idparameter is for. The argument given to this parameter will be used by
efibootmgras the ID for the UEFI’s boot entry corresponding to this grub installation.
There is no end to the information available online when it comes to the topic of booting, and it has been a daunting task to try to summarize it all in this one article. I have tried to keep this write-up as lean as possible, and only keep information which I deemed necessary in order to gain a good birds-eye view of this topic. As such, there was a lot of information I had to leave out, and many details that didn’t make it to the final edit.
If after reading this far you still feel the need for more, and are still interested in delving more into the nitty-gritty of the boot process, I can recommend the following resources:
- Rod Smith is linux expert who, among many things, developed the GPT fdisk suite of disk utilities. This family of programs is arguably the De facto Linux disk utility for GPT-partitioned disks. He is also the developer behind rEFInd a relatively popular boot manager for UEFI systems. His Website is a great resource for all things boot, disks, and Linux related, and has been a great resource for me while doing research for this article.
- This one article on Adam Williamson’s blog has been very helpful to me when I started preparing for this write-up. Adam Williamson is a Red Hat developer.
- Matthew Garrett is a firmware developer who worked on UEFI and secure boot. His blog also seems to be a great resource when it comes to those two subjects. I haven’t read through enough of his articles yet, but I expect to do so in the upcoming weeks and months as I want to learn more about secure boot on UEFI.
Finally, if your thirst for knowledge is still not quenched even after going through all these resources, you can always dive into the UEFI Specification. As of writing of this article, the latest version totals 2540 pages, so maybe take a day off or two… Just in case.