Introduction
Recently I replaced my ancient laptop with a new, slightly better one. People associate changing workstations with OS reinstall, setting up everything from scratch etc.
I’d rather put my old disk in my new machine and continue as is. However, due to the age of my old laptop, I had formatted the disk with a Master Boot Record (MBR) and used Legacy Boot mode, which turned out, is not supported on new DELL laptops.
Reformatting the disk without losing the data turned out to be harder that expected and was also quite interesting to explore in even greater detail the booting process on a bare-metal level.
I decided to write this blogpost in a tutorial-like style since I found very few comprehensive guides online on how to do that as well as none explained well enough what the **** is happening. Also most tutorials were quite dated and inaccurate so I reckon this one can be used a a point of reference, both by my future self and other people stuck in this situation.
How do computers boot?
First things first, let’s do a brief overview on what happens from the moment you press the power button until a kernel is loaded and executed in memory.
I won’t go into too much details here as there’s plenty of good reads online. Instead I’ll outline the key parts.
Once the power button is pressed on a computer, an electrical circuit is closed and the boot process is initiated. Depending on the system, it will either have a BIOS or UEFI - this is the first software that is run, whose purpose is to initialize all the existing hardware and check for any possible errors. Once that’s finished, control is handed over to a program known as a bootloader. The bootloader’s main job is to find and execute the kernel of an operating system (Unix machines have an additional step - a ram disk (initrd) is loaded to memory which contains preinstalled binaries that help to mount the root file system where the kernel is located - think encrypted partitions, network partitions etc.). Once the kernel is executed, depending on its type (Windows vs Unix), it will run all initializing processes and in the most common case present you with a login screen.
What is a BIOS?
Now, I’m sure that you have an idea of what’s the BIOS. Here’s some more detail - it’s a small non-volatile chip that lives on your motherboard whose purpose is to initialize system hardware, run some checks on whether everything is fine (POST) and provide some way to execute programs on your machine (in the general case a bootloader).
Booting using BIOS/MBR
The way BIOS machines boot is very simple - once the BIOS has finished its tasks (including storage initialization) it loads the first sector (512 bytes) from the first storage device it finds and sets the Instruction pointer to execute whatever is there.
And that’s it! Obviously, kernels are bigger than 512 bytes so some trickery is needed like bootloaders and even bootloaders are pretty chunky so they also split in 2 stages (see detailed post on bootloaders).
P.S: When looking for BIOS booting you will surely come across the Master Boot Record (MBR). That is just the way people call the first sector of the disk that is being executed.
Here is a summary of the whole process:
If you’ve ever messed around with grub2-install
, what it does is simply bootstrap the MBR of whatever disk you point it at so that the next time you boot from it with MBR and can run the GRUB boot menu.
Setting up a disk with MBR
If you need to setup a system to boot using BIOS/MBR these are the few steps you need to do:
Firstly, Install the grub2
package using the respective package manager.
On Fedora that’ll be:
sudo dnf install grub2
Next, find the disk where you want to install the MBR bootstrap code.
Most of the time that would be /dev/sda
but do check it. (GParted is handy)
Once you’ve got that, just run
sudo grub2-install /dev/sda
This installs GRUB on the MBR of you disk. Lastly, you’ll need to create a GRUB config file which will be used by the bootloader to show you the boot menu, boot entries and what not.
The file the GRUB will look for is /boot/grub2/grub.cfg
.
To create one simply run
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Caveats for restoring a broken MBR from a live system
Restoring MBR GRUB from a live system is relatively simple.
Keep in mind that the more complex your system is, the harder will it be to fix issues (LUKS, LVM etc.).
Firstly, make sure your disklabel type is msdos
with
sudo fdisk -l /dev/sda | grep Disklabel
If your setup happens to utilize a full disk encryption (e.g LUKS) you MUST make sure that /boot/grub2/grub.cfg
is accessible before decrypting the kernel.
This can be done by having /boot
on a separate partition which is what Fedora (I presume Ubuntu as well) does for their default installation using LUKS.
/boot
partition type can be anything GRUB can boot from (ext* works fine, so does FAT*). If for some reason that partition is missing and you are utilizing LUKS, then you have to manually create it (boot a live system and copy it’s working files to the newly created /boot
and run grub2-mkconfig
command as shown previously). Also don’t forget setting the boot
flag on the newly created partition.
IMPORTANT NOTE: grub2-mkconfig
creates a config based on the currently running system. If you are running on a live system, you MUST chroot into your system before generating the config.
Once you have checked all of the above caveats, just run the commands shown in the setting up MBR section and you should be good to go.
Fixing MBR GRUB is easier that fixing EFI GRUB as you’ll see later.
What is UEFI?
You can think of UEFI as the new kid on the block. It’s supposed to be the better version of the legacy and dated BIOS. It’s written in C (as opposed to the assembly-written BIOS), way more customizable, faster etc. etc.
Booting using UEFI/GPT
Apart from being cooler than BIOS, UEFI booting is (from my experience) completely incompatible with what we’ve had so far. UEFI brings the entire boot process to an entirely new level:
Instead of a 512-byte MBR and some boot code, the UEFI, in contrast to the legacy BIOS option, knows what a filesystem is and even has its own filesystem, with files and drivers. This filesystem is typically between 200 and 500MB and formatted as FAT32.
Instead of a few bytes of assembly code for loading the operating system, each installed OS should have its own bootloader (e.g., grubx64.efi). This bootloader will have enough logic to either display some sort of boot menu or start loading an operating system. Basically, UEFI is its own mini-operating system.
That’s right - we need a separate system partition to store EFI bootloader files - logically called an EFI System Partition (ESP). The ESP must be a FAT formatted physical partition on your hard disk. It shouldn’t be a LVM volume or something else.
Note that the ESP is not the same as the /boot
partition you might have on your installation!
In the world of EFI, we don’t manipulate bytes on our hardrive, instead we operate at the file level. I find this as a small improvement, though I had difficulties finding the paths to various files such as grub.cfg, grubenv etc.
The gist is that if you manage to put the correct files in the correct places everything will automagically work!
So in theory, the only tools you’ll need when converting from the old BIOS/MBR style of booting to the new UEFI/GPT is gdisk
(shown later) and some other tool to set disk partition flags (parted, fdisk, gparted etc.)
Creating an EFI System Partition
We know that the ESP is a simple FAT32 formatted partition with the esp
flag set.
Here is the layout on my disk. The first partition is the /boot
partition which was created with the Fedora installation, and partition 3 was manually created by me when I converted from MBR
to GPT
disk partitioning.
Model: ATA Samsung SSD 850 (scsi)
Disk /dev/sda: 1000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 1075MB 1074MB ext4 Linux filesystem boot, esp
2 ********************************************************************************
3 881GB 881GB 554MB fat32 boot, esp
5 ********************************************************************************
I previously mentioned that all we are going to need for EFI booting is some files, so how do we get them?
Luckily, there are packages that provide the necessary files. When installing these packages, they will write the files to /boot/efi/
so make sure that your ESP is mounted before you install them:
$ mount | grep /boot/efi
> /dev/sda3 on /boot/efi type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
Then install the packages:
sudo dnf install grub2-efi grub2-efi-modules shim
Here is some more info on what is the purpose of each of the packages:
The grub2-efi
package is the EFI version of GRUB and it install the bootloader in the /boot/efi
directory:
$ rpm -qlp ./grub2-efi-x64-2.02-84.fc31.x86_64.rpm
/boot/efi/EFI/fedora/fonts
/boot/efi/EFI/fedora/grubenv
/boot/efi/EFI/fedora/grubx64.efi
/boot/grub2/grubenv
/boot/loader/entries
/etc/grub2-efi.cfg
grub2-efi-modules
contains some libraries that are installed in /usr/lib/
.
What you need to know about the shim
package is that it is a bit of a hack to enable Secure Boot on Linux systems.
You can read more about it online.
The files that it provides are:
$ rpm -qlp ~/shim-14-4.4.x86_64.rpm
/boot/efi/EFI/BOOT/BOOTX64.EFI
/boot/efi/EFI/BOOT/fbx64.efi
/boot/efi/EFI/fedora/BOOTX64.CSV
/boot/efi/EFI/fedora/mmx64.efi
/boot/efi/EFI/fedora/shim.efi
/boot/efi/EFI/fedora/shimx64-fedora.efi
/boot/efi/EFI/fedora/shimx64.efi
If you have these packages installed but you have reformatted the partition, simply reinstall
them and the files will reappear.
So what exactly do we have inside the ESP?
In the root of our ESP, there is a single directory named
EFI
which contains information about bootable systems.
Each bootable system has its own directory where the bootloader (and its config) is located.
The .efi
files are binaries that we won’t worry too much about for now. The important ones are grubx64.efi
and shimx64-efi
.
The first one is - you guessed it - the grub efi binary.
The shim binary is a intended for systems that utilize Secure boot.
Since signing GRUB with microsoft keys it not possible, the shim binary bridges the gap between the two.
One very important file is grub.cfg
file which - you got it again - is grub’s config.
What boots and the location it boots from is written in this file.
It is the difference between a booting and a non-booting machine.
The rest of the files are mostly binary so you probably won’t go tweak them, but grub.cfg
is a text file that can be easily edited.
Tweaking it usually has the form
sudo grub2-mkconfig -o /boot/efi/EFI/<operating system>/grub.cfg
Now if you have a working system and you run this command while in your system, it probably won’t break anything. However, if you are in a live system, trying to fix your own, it might be tricky to get this right.
Lessons learned
The more complex a setup, the harder it is to fix anything broken (or explain what’s broken for that matter).
Me spending days debugging this.
In the beginning I mentioned that I wanted to change laptops without reinstalling. The issue was that my disk was MBR-formatted and using a BIOS (yes it was that old!) whereas my new machine does not support booting MBR-formatted disks.
This is what my disk’s partitions look like - focusing on the Linux part on the left.
Going from the inside out I have a EXT4 partition where the actual operating system is installed.
Next follows the Logical Volume Manager (LVM) which if you’re not familiar with, is roughly like a file system the makes disk partitioning less painful by providing virtual partitions which can be dynamically resized without the usual pain of partitioning.
Following that is the Linux Unified Key Setup (or everyone know it as LUKS) layer which provides the full disk encryption part of the installation.
Everything inside the LUKS layer is encrypted to the outside world.
The order of creating is inwards - the partition format is lvm2
, then inside it resides the LVM volumes and finally the ext4 partition.
As you can see, screwing the boot is not that hard at all and restoring it is painfully hard.
I spent a few days converting my MBR/BIOS setup to GPT/UEFI one from a live system which was quite hard to get right.
This guide explains the gist of it. The grub part is old and does not work anymore, so instead follow the instructions I shared above for installing an EFI bootloader.
The caveat that is not discussed in most guides
The biggest issue I faced while understanding all the guides I read was that almost none of the emphasized that the boot
partition and the esp
partitions ARE NOT THE SAME.
If you’ve installed your linux distribution using defaults with LVM and disk encryption, the installer has created a separate boot
partition that is used to boot from.
It is not encrypted in any way because the UEFI has no idea how to boot encrypted systems (That’s GRUB’s responsibility).
Knowing that, restoring your EFI bootloader will require you to
sudo mount /dev/<whereever your boot partition lives> /boot
sudo mount /dev/<whereever your ESP partition lives> /boot/efi
And only afterwards install the grub2-efi
packages and create the grub config
sudo grub2-mkconfig -o /boot/efi/EFI/<operating system>/grub.cfg
Once you have done these steps in the right order, your EFI should recognize the FAT32 EFI Partition and let you boot from it, which will then load the efi GRUB bootloader which knows what modules it needs to decrypt the LUKS, mount the LVM volumes and locate the kernel inside.
Conclusion
Hope that you’ve enjoyed reading this blogpost and you learned something new about how computers boot and how they used to do that. Here is a brief list of some of the resources I found useful while poking with my system:
References
https://docs.pagure.org/docs-fedora/the-grub2-bootloader.html
http://www.linux-magazine.com/Online/Features/Coping-with-the-UEFI-Boot-Process