User:Sakaki/Sakaki's EFI Install Guide/Booting Legacy Images on EFI using kexec

Some modern PC systems &mdash; particularly tablets and ultra-compacts &mdash; support only UEFI booting, and have no 'legacy'/'CSM' boot option available in their BIOS GUIs. As such, bootable images without EFI support (for example, Gentoo minimal install images issued prior to August 2018 ) cannot be used in native form with such machines.

Fortunately, we can easily surmount this problem, without using a third-party bootloader, by appending an EFI system partition to the target image, within which is placed both an EFI stub kernel (containing a simple -based init script in its integral initramfs), and an appropriate startup script fragment (, which the init script invokes).

This done, it becomes possible to select the kernel as a boot target on a UEFI-only PC (since it is an EFI executable, placed at the 'magic' path within an EFI system partition). Booting it causes (in due course) the script fragment to be run, which then:
 * locates and mounts the 'real' (i.e., legacy image's original) boot partition's filesystem read-only;
 * loads the kernel, command line and initramfs (if any) from this filesystem; then
 * invokes them, using Wikipedia:Kexec (a kernel facility which, together with some paired userland tools, allows a system running one Linux kernel to boot another, analogous to the manner in allows one userland process to replace its current process image).

From this point, the target system runs exactly as if started via a legacy boot. Furthermore, images modified in this way are still bootable in legacy mode on compatible systems, so no functionality is lost.

The contents of the appended EFI system partition's filesystem may be packaged as a tarball for future reuse (and indeed an exemplar tarball is provided, for convenience, for the specific case of EFI booting pre-August 2018 Gentoo minimal install system images). Once such a tarball has been created, it may be easily adapted for use with other target legacy images, simply by editing the script fragment within it as required (i.e., no 'bootloader kernel' recompilation is required).

Accordingly, in this mini-guide, we will run through the following steps:
 * 1) We'll begin by ensuring your existing ('helper') Gentoo PC has the necessary packages, and kernel configuration, to allow efficient manipulation of disk image files via loop mounting. (The existence of a Gentoo-based helper is assumed for simplicity; the procedure in this guide can of course be carried out on other distros, with a little translation.)
 * 2) Next, we'll build (on the helper machine) statically-linked versions of  (which provides userland utilities to interface with the kernel's  functionality), and  (a portmanteau application that provides a baseline set of Linux applications (,  etc.) packaged as a single executable for convenience). We'll install these to a dummy root directory, to avoid polluting your helper.
 * 3) We'll then create a skeleton initramfs file tree (at a marshalling location, ) on the helper, and copy these two statically-linked applications to appropriate locations within it.
 * 4) Then, we'll add a baseline  script into this tree, the sole function of which is, when executed, to locate and mount the EFI system partition's filesystem read-only, and then invoke the  script fragment from within it.
 * 5) We'll next download a current Gentoo minimal install image, and loop-mount it read-only. We'll use this to provide a sane baseline kernel configuration for our 'bootloader' kernel in the next step &mdash; it isn't to be confused with the target image we want to adapt!
 * 6) Then, we'll install a kernel source tree (to the dummy root) via the  package, enter the resulting  directory, and then create a  based upon the above minimal-install image kernel's configuration, but with EFI stub booting,  and an integral initramfs enabled (the latter pointed at the marshalling initramfs file tree created in step 3).
 * 7) We'll next build the kernel modules and install them into the staging initramfs filesystem tree, then build the kernel itself as a bzImage (which will thereby incorporate the initramfs, including the full module set).
 * 8) Next, we'll create a marshalling EFI filesystem tree on the helper, and copy the bootloader kernel's bzImage to the 'magic' path  within it.
 * 9) We'll then install an (exemplar)   shell fragment into the EFI tree. This script, which you can customize as required, when executed will locate and mount the legacy image boot partition's filesystem, load the kernel, command line, and initramfs from it, and then boot this kernel using . We'll also create a tarball of the (at this point, completed) EFI filesystem tree, for re-use in the future.
 * 10) At your option, we'll then clean up the various staging file trees, to prevent clutter on the helper.
 * 11) We'll then be ready to update a target legacy image! In this tutorial, I'll demonstrate adapting a pre-August 2018 Gentoo minimal install image. To do so, we'll first download it, and then append an additional block (here, 100MiB) of zeroed data, for subsequent use as an EFI system partition. Next, we'll use  to add that partition to the image(of type, as it is MBR; instructions will also be given for dealing with GPT images), format it FAT32, and loop mount it. We'll then untar the step 9 tarball into this filesystem, and then dismount.
 * 12) Finally, we will write the modified image to a USB stick, and check that it can indeed be booted in UEFI mode on a target PC (with secure boot off).

Once you've run through this process the first time, you can then just skip directly to step 11 to convert other (legacy boot) Gentoo minimal install images in future. Furthermore, even if you subsequently want to adapt a completely different legacy image for EFI boot, you will generally only need to modify the shell script fragment within the untarred filesystem &mdash; no recompilation will be required.

Now, if you are ready to build your own -based bootloader from scratch, let's go!

Prerequisites
For simplicity, this tutorial assumes you have access to a 'helper' PC that is already running Gentoo Linux, together with a second, 'target' machine (the UEFI-only one) on which you wish to boot a legacy image. As outlined above, the 'helper' PC will be used to create the 'kexec-bootloader' kernel itself, to download and modify the desired legacy image (a pre-EFI Gentoo minimal install image is used in the text, for concreteness), and to write this modified image to a USB stick, for booting on the target.

For avoidance of doubt, if you have installed a GNOME-based Gentoo system using the other instructions included in this EFI Install Guide &mdash; whether under or  &mdash; your system is suitable for use as a 'helper' (subject to the setup steps below).

Setting Up the Helper PC
We'll begin by ensuring that your 'helper' Gentoo PC has the necessary kernel configuration &mdash; and installed userland packages &mdash; to allow the direct (aka 'loop mounted') manipulation of disk image files called for in this tutorial.

Kernel
If you are using one, ensure that your boot USB key is inserted. Then, open a terminal window, become root, and issue:

Or, if you use rather than, issue:

instead of the above.

Or again, if you prefer to build your kernels manually, ensure that you have a current version of the kernel source tree in, and then issue:

followed by:

Whichever workflow you use, once the menu configuration tool appears, ensure that the following kernel options are set, to allow loop-mounting of multi-partition disk images using the device mapper on your helper PC:

Once you have made the necessary changes, save the kernel configuration and exit the tool, after which &mdash; if you are using either the  or (with appropriate options)  scripts &mdash; the kernel should automatically build and install.

However, if working manually, you'll have to perform the build yourself:

Once the kernel build has successfully completed, reboot your system, then follow the usual steps to unlock the LUKS partition and log in again (using GNOME) as your regular user.

Userspace Packages
Next, we will ensure that the necessary userspace applications are in place on the helper.

First, to ensure that we can format FAT32 partitions (necessary for EFI), open a terminal window, become root, and issue:

You should also install:
 * , which provides, a tool that creates device maps from partition tables; and
 * , which provides, a tool that informs the OS of partition table changes; and
 * , which provides an easy-to-read recursive directory listing (useful for checking staging filestructures).

To do so, issue:

Lastly, install, used (inter alia) to download files to. Issue:

Creating the Bootloader
With the helper machine prepared, we are ready to start building the kexec-based bootloader itself!

Userspace Packages
Our first task is to emerge some statically-linked executables, namely and, for use in the bootloader-kernel's integral initramfs. To avoid polluting your helper system (which may not be using static libraries ) we'll install to a temporary root,. Issue:

The resulting applications we need from this are and, both of which are statically linked (i.e., can be deployed to an initramfs without any additional shared libraries).

Initramfs Tree
Next, we'll create a 'staging' tree on the helper PC for the initramfs. This is a skeleton Filesystem Hierarchy Standard structure, which we will only populate minimally. Issue:

With the core directory layout in place, create some basic device nodes in. Issue:

Lastly, copy the statically-linked binaries we just created into the staging filestructure:

Init Script
Next, we will create a simple init script in the root directory of the staging initramfs tree. The purpose of this script is, when run, to:
 * 1) set up the special,  and  pseudo-filesystems;
 * 2) setup 's symbolic links (so calls to apps like  redirect to it);
 * 3) load any necessary kernel modules for USB support;
 * 4) startup 's 'mini-udev' (which takes over automatic population of device nodes in );
 * 5) locate the EFI system partition itself;
 * 6) mount this read-only; and finally,
 * 7) source the script  from within it.

Issue:

Then put the following text in that file:

Save, and exit.

Make it executable:

EFI-Bootable Kernel
Next, we'll create an EFI-bootable (aka "EFI stub") kernel. We'll use the standard here, installing the kernel tree to our temporary working root to avoid pollution. However, since this package has a number of build-time dependencies, we won't directly emerge it into. Instead, we'll first install any missing dependencies into your helper PC's main root, and only then emerge into the temporary working tree.

Issue:

When this completes, a kernel source tree should be present in.

Our next step is to set an appropriate configuration for our new kernel. We'll need a 'sane' baseline, which, for the sake of concreteness, we'll extract here from the most recent Gentoo minimal install image's kernel (other choices are possible; however, take particular care if using the configuration captured from a kernel created by, as that will have a built-in command line etc. that we don't want).

So, begin by downloading a current version of the image. Issue:

Your output will of course likely different as new versions are released. Now download the image itself, and (if desired) its contents list and digitally signed digest list. Issue:

followed by:

Once this completes, you can verify the image if you like; for instructions please see these notes.

Next, you can loop-map the image's partitions. In this image, there should only be two partitions; to check, issue:

In this case, we only want the first partition, so issue:

The  command scans the specified image, and creates device maps corresponding to the partitions detected within it, at. The first partition (which in this case is the one we want) is at {{Path|/dev/mapper/${LOOPNAME}} (your target partition number may differ, if you have more than one partition on your target image, in which case modify these instructions accordingly). Such device-mapper entries can be treated just like regular device paths ( etc.), so we can proceed to mount it (read-only, since we just want to extract the kernel configuration). Issue:

 Next, check the contents; issue:

Again, your output may differ slightly. However, in this case, the actual 'payload' kernel is, and its initramfs is. Command line options (for the default boot case) may be found in.

The relevant stanza in that latter file (not necessary now, where we are only really interested in the kernel config, but of relevance later on) reads:

Returning to the task at hand, now we can enter the kernel source directory, and extract the config from the minimal install image kernel, using a utility script provided with the kernel sources. Issue:

then:

With the 'starter' kernel configuration extracted, the device mapping onto the image may safely be removed:

Start the kernel configuration editor (we will do a manual kernel build here, to keep things simple):

and set the required options as follows:

Then exit the tool, saving options. With that done, build the kernel modules first:

Install the modules into the staging initramfs filestructure:

The modules will now be present in

Next, clean up a few spurious soft links in the above directory (which will fail to resolve outside of the build environment):

Now, check your staging initramfs tree is complete (which it should be, at this point). To do so, issue:

Assuming that all looks good, you can proceed to build the kernel itself (which will encapsulate a copy of the above initramfs, due to the  option set earlier). Issue:

The resulting file we need (or a link to it, anyhow) is in.

Staging EFI Filestructure
Next we will create a (staging) copy of the required filestructure for the EFI partition, and then add the kernel we have just built into it. Issue:

Note that we have copied our kernel to the 'magic path' &mdash; &mdash; that most (64-bit) EFI BIOSes look for during boot.

kexec.sourceme Script Fragment
Next, we need to put in place the fragment, which the initramfs's  script (created above) will load.

Exactly what is needed in this fragment will, of course, depend upon the target legacy image you want to boot, but, for concreteness, in this tutorial we'll put together a simple script targeting legacy Gentoo minimal install images, which, accordingly, will need to:
 * 1) mount the first partition on the EFI boot device read-only;
 * 2) extract the desired command line from the isolinux config file therein;
 * 3) load the (original, target) kernel, initramfs from the same location; then
 * 4) switch to the new kernel, using.

Issue:

Then put the following text in that file:

Save, and exit.

With the script in place, our staging EFI filestructure is complete.

Check yours looks as follows:

If all looks good, tar the tree up for future use:

(Don't forget the period at the end!) The resulting file is.

Cleaning Up
With all that done, the staging directories can be deleted, if you like (the following step is optional):

Adapting a Target Legacy Image
Now that we have created a target EFI -bootloader tarball, we can use it to 'EFI'-ify an existing legacy bootable image. To do this, we'll download the image, add a new EFI system partition) to it, create a FAT32 filesystem thereon, and then mount it, untar the file we just created there, edit the  file if necessary, and then  and dismount. The legacy image should then be bootable for both UEFI and legacy systems, and can subsequently be tested.

For concreteness, I'll illustrate how to modify a September 2018 Gentoo minimal install image &mdash; you can easily adapt these instructions for a different target.

Download the image, and, if desired, the matching contents and digitally-signed digest listing for it:

Once this completes, you can verify the image if you like; for instructions please see these notes.

Next, append some extra space to the image for use as an EFI system partition. How much you need will depend upon your system, but 100MiB should suffice (we'll actually add 101MiB, to allow some free space at the end for GPT use, should this be required). Issue:

Now add a new EFI system partition to the image using.

If your image is MBR (which most will be, including our example in this case), then use:

Or, if your image is GPT (unusual, since most of these will already be provisioned with EFI bootloaders), then use instead:

Check the structure of the image (for our example, it should now have two partitions (we just added the second), but your target may differ), using ; issue:

Assuming that looks good, map the partitions:

Next, create a FAT32 filesystem in the newly created partition, ensuring its label is set to, as that is the name which the init script looks we created earlier looks for:

With that done, we can make a temporary mountpoint, and mount the newly created EFI system partition (mapped from within the image file) there:

Unpack the EFI tarball into the root directory of the filesystem you just mounted:

Then, if required, you can edit the file to suit.

For this particular target, however, we're already done (no editing required), so you just need to, dismount the filesystem, then unbind the device mapper from the image file. Issue:

And with that, modification of the legacy image to support EFI booting is complete!

Writing and Booting the Modified Image
Now the image has been created, you can try writing it to a USB stick, and then booting a (UEFI) PC with it.

To do so, insert an unused USB stick into your machine, and note its device path (you can use the tool, run before and after insertion, to help you; alternatively, look at  ). Then, write the image:

Replace in the above with actual path to your USB stick (e.g.,  etc. Be sure to use the top-level device, and not a partition within it (so e.g.,  and not ;  and not  etc.).

Once this completes, remove the new USB key and place it into your target PC (which should be powered off at the time). Then, apply power to your target machine, and use the (system-specific) hotkey to enter the BIOS (or bring up the one-time boot selection). You should then (provided that you ensure secure boot is off) be able to select the USB stick as an EFI boot target, save, and reboot.

If all is well, the target system should then load and run the EFI-stub kernel from on the USB stick. This will unpack the embedded kernel and its initramfs, and start it, which will, after initialization, run the initramfs init script. This will attempt to locate the filesystem and mount it read-only, then source the  script fragment from within it. This, in turn will mount (in the case of the Gentoo minimal install image) the first partition of the image read-only, load its kernel, initramfs and command line, and then pass control over to that new kernel via. The system should then start up, just the same as if it were booted from a legacy, non-EFI BIOS.

That concludes this mini-guide! To rejoin the main tutorial, please click here or here.