My name is Philipp C. Heckel and I write about nerdy things.

Creating a BIOS/GPT and UEFI/GPT Grub-bootable Linux system


Linux

Creating a BIOS/GPT and UEFI/GPT Grub-bootable Linux system


Good old Master Boot Record (MBR) unfortunately cannot address anything beyond 2TB, so partitioning large disks and making them bootable is impossible using MBR. The GUID Partition Table (GPT) solves this problem: It supports disks up to 16EB. However, installing grub does not work without a special BIOS boot partition. If you also want to support booting the same system via UEFI, another partition, the EFI System Partition (ESP), is necessary.

This should post shows you how to partition a disk with GPT and make a bootable Linux system via BIOS/Legacy and UEFI.


Content


Requirements & Assumptions

For this post, I’ll assume that you are running everything on a Debian-based system, and all commands shown must be run as root.

1. Create a minimal Linux (optional)

For this example, we’ll use a small Linux install that we can create with the following commands. This will bootstrap (debootstrap) a minimal Ubuntu 16.04 system to the chroot/ folder which we will later use to boot our system. To create a bootable system, we need a kernel and the bootloader modules and files, so let’s install linux-image-generic and grub-pc:

Alternatively, you can of course use any Linux root file system, provided that it has a kernel and grub. You could, for instance, just copy your own root file system to the chroot/ folder.

2. Creating a GPT with a BIOS boot partition and an EFI System Partition

Now that we have the Linux root file system in the chroot/ folder, we’ll create a sparse file that represents our disk. You may of course do all this with a proper HDD/SSD, i.e. with /dev/sdX, but for testing things using a raw disk file is much easier. The following snippet will create 3 partitions:

  • A 1 MB BIOS boot partition (of type ef02) that Grub will use to store its core image.
  • A 100 MB EFI System Partition (of type ef00) formatted as FAT32 in which we will store the EFI boot image
  • And a partition for our root file system (in our example formatted with ext4)

Once this is done, you can list the partitions with gdisk -l test.img:

After the partitions are created, the EFI and root partition need to be formatted:

Note that I named the root partition demoroot (the ext4 label). This will be important later in the Grub configuration.

3. Copying the root file system, installing grub into the BIOS partition

Now that the partition to be used for our root file system is formatted, let’s copy our chroot/ directory to it and then install grub to the disk with grub-install. Because the disk is GPT formatted, grub will use the BIOS partition to install its core image:

After this, you should be able to boot the system via BIOS from the root GPT partition. I always do that via KVM like this:

4. Preparing the EFI partition

After you’ve verified that you can boot via BIOS, let’s make sure that we can also boot on UEFI systems. We formatted the EFI partition earlier. All that’s remaining is to create/copy the bootx64.efi image file and a valid grub.cfg to it.

Grub can create the EFI image via the grub-mkimage command using the Grub modules in /usr/lib/grub/x86_64-efi (part of the grub-efi-amd64-bin package). In order to avoid having to load anything from the file system, we include all the modules in the image. If you are not booted via EFI, you may need to install the grub-efi-amd64-bin package.

The Grub config file in the EFI partition grub.cfg is rather simple: It uses search --label demoroot to look for the root partition and then simply includes the actual grub config file via configfile ....

Let’s mount the EFI partition again, create the image and the grub config:

After that, the EFI partition should contain the two files /EFI/BOOT/bootx64.efi and /EFI/BOOT/grub.cfg. You can verify that like this:

That’s it. You should now be able to boot this image via UEFI. I always test this with KVM and OVMF:

5. One script to do it all

If you are an impatient man/woman, then you may just want to run the following script to do all of this in one go. You’ll of course have to adjust it to your needs for production use.

The script can be called in two ways:

Here’s the script:

11 Comments

  1. Mark Lomas

    Hey Philipp,

    This is a great article, I found it super useful. Thanks :-)

    FYI, I had to apt-get the ‘udev’ package because partprobe complained about ‘udevadm’ being missing and I needed to apt-get ‘parted’ so that partprobe was installed. I also added ‘–arch=amd64’ to debootstrap because I wanted a 64bit distro, it seemed to default to ‘i386’ which I assumed mean’t 32bit.

    My next step is to investigate the ‘live_boot’ package to see if I can turn the distro into one that can install itself somewhere when booted and I’d like to find a way to squeeze the image size down from 30GB to something much smaller. Any ideas?

    Thanks once again for the article,

    Best regards
    Mark


  2. Vincent Perrier

    Is it possible to have a working system on a sparse file with only uefi, without any bios partition? Thanks a lot for your script!


  3. Philipp C. Heckel

    The BIOS partition is used by grub only for BIOS boot. If you want UEFI only all you need is the EFI partition. The EFI grub.cfg references the grub.cfg on the root partition, not the boot partition, so you should be good there. You’d have to adjust the script not to create a BIOS partition, obviously.


  4. Oscar

    mkosi (https://github.com/systemd/mkosi) does the same more or less in a automated manner, but only for UEFI systems.


  5. ewe2

    You probably need to install grml-debootstrap to simplify a lot of this, for Debian Stretch I had to change a lot and it’s a lot easier to have grml-debootstrap generate the correct locales for instance.


  6. Gil Montag

    Hi
    1. Will this technique be good also for buildroot generated rootfs and kernel?
    2. I tried the method and the uefi boot didn’t work for me. It reverted to normal boot after few error messages of not being able to uefi boot from cdrom and floppy…???
    Thanks
    Gil


  7. davelister

    thanks !
    hear https://pastebin.com/wUE25LwT#mkbiosefi is a URL for he script !


  8. Marcin

    I have tried to run this solution on Debian9 Stretch (Linux dt 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u3 (2019-06-16) x86_64 GNU/Linux) however during boot I get “attempt to read or write outside of partition” from grub. The boot was through BIOS Boot after first part of the article.

    Another thing is that I have got error after this part:
    # Unmount OS partition
    umount $MOUNTDIR/{dev,proc,sys,}

    /tmp/demoQOJKO9/sys: target is busy
    (In some cases useful info about processes that
    use the device is found by lsof(8) or fuser(1).)

    there was system process:
    lsof /tmp/demoQOJKO9/sys/
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    systemd-l 397 root 7r REG 0,16 4096 2676 /sys/devices/virtual/tty/tty0/active
    which had successfully blocked all of the unmounting attempts. I had dd test.img to usb drive and powered off the system.

    Could you point which direction to go to as I belive I have tried all of the posibilities?


  9. TalisaU230

    Hey… wonderful article. Works splendid. I have one problem btw. I rewrote the scripts to make a Void Linux install. When I boot the Void linux and log in.. take ‘ls /boot’ it only shows the EFI directory not the kernel and initramdisk. This is when I boot using EFI. Do you get the idea whats wrong? Sorry for my bad english.


  10. AlHaddare

    Hi its helpful for me as newbee but can you explain more details steps as you mention in your sentences

    Alternatively, you can of course use any Linux root file system, provided that it has a kernel and grub. You could, for instance, just copy your own root file system to the chroot/ folder.

    Cause i like to copy root file system from my ubuntu 20.04.1 live usb to my hdd partition then run your script after step 1
    Please…Thank You & Bestregard


  11. MD Titoo

    I’m new to Linux and found your page when I was searching EFI to BIOS for Linux image. We have multiple systems that has BIOS and BIOS cannot be updated to support EFI. Can an existing GPT EFI Linux disk be converted to BIOS boot? Any information will be highly apricated.
    Thanks.