User:Sakaki/Sakaki's EFI Install Guide/Configuring and Building the Kernel

In this section, we'll be (loosely) following Chapter 7 of the Gentoo handbook, and building a Linux kernel for use with our new system. Accordingly, it's worth reading that handbook chapter in parallel with this guide. In addition, the Gentoo kernel overview wiki page, and Greg Kroah-Hartman's Linux Kernel in a Nutshell are both highly recommended.

The process we'll be following in this section is:
 * 1) Allowing necessary licenses, then downloading kernel sources and firmware (if desired);
 * 2) Emerging  (from ) and some additional required packages;
 * 3) Checking we have a custom version of  that will work without ;
 * 4) Setting up 's configuration file ; and
 * 5) Building the kernel for the first time, using.

However, don't worry, the process is perfectly manageable! No manual kernel configuration is necessary for the above, since the provided tool will handle all the complexity for you (exactly what this script does is also explained for the curious, but of course you can skip this material if you like).

Introduction
So what is the Linux kernel anyway? In essence, it's a privileged, pre-emptive, multitasking resource manager. As such, it's the core element of the operating system, because all 'normal' software (including operating system programs like and )  must go via the kernel to access system hardware (such as disks, screen and keyboard), to request or release system resources (such as memory), or to communicate with other 'userland' software (as the kernel maintains user processes in distinct virtual memory 'silos').

The kernel is not built using the normal procedure -  will fetch the necessary source files for us, but configuration, compilation and installation is separate. Configuration here refers to the process of setting (or in come cases, commenting out) key-value pairs in a special file. This file sets vital kernel parameters (such as the kernel command line, in the case of a UEFI-bootable system), and instructs the build system which kernel components (including drivers) to omit, which to build as loadable modules ('.ko' files), and which to build in to the kernel itself.

Before continuing, it's worth saying a little bit about the EFI boot process here. When your PC boots up (in EFI mode), the UEFI BIOS loads from ROM and runs. Once it has performed initial hardware configuration, this BIOS then looks for any runnable EFI software, proceeding through a list of possible locations (which must be EFI system partitions, if they are storage devices) as specified by you via the BIOS setup screens (or the EFI boot list variable). If it finds such an executable (on 64-bit x86 machines, normally, the filename is not (usually!) path sensitive), it will load this and run it.

Traditionally, this program would be a bootloader, whose job it would be to load and run the operating system proper. However, modern Linux kernels can be configured to appear as runnable EFI programs, obviating the need for any separate bootloader, and this is the approach we're going to take.

However, there is one wrinkle to overcome. When our EFI kernel is started, it needs to invoke various userland software (such as, and various LVM programs) to activate and access the encrypted volumes we created earlier: but those programs are themselves stored... within the very encrypted volumes we wish to unlock!

This is worked around by using an initial RAM filing system, or initramfs, which is a simple archive (like a Wikipedia:Tar_(file_format) archive, but using an older format, known as Wikipedia:Cpio) of a minimal Linux root filesystem. This initramfs contains only those userland programs (and the libraries and other files on which they depend) which are needed to boot the system (including a special init program, which we'll get to shortly). Although the use of an initramfs is reasonably commonplace with Linux systems (to start up LVM for example), we elect to include the archive within the kernel file itself, so it will be protected by the secure boot signature (once we add it).

So, the actual boot process we'll be aiming to utilize is as follows:
 * 1) The UEFI BIOS starts up, and initializes the hardware. It looks for, and finds, an executable .efi program (our stub-loadable kernel) on the USB key, so it loads this and passes off control to it. (If secure boot is on, it will also check that the kernel image contains a valid cryptographic signature, but we'll get to that in a later section ( track,  track).)
 * 2) The kernel starts up and initializes. It unpacks its bundled initramfs into memory, and activates it, which provides a root directory containing a skeleton set of system files (a bit like the contents of our stage 3 archive, but much sparser).
 * 3) The kernel then looks for a special 'init' program in the initramfs and starts it (as the first userspace process).
 * 4) This initscript, which is actually provided by a Gentoo utility called  (more of which shortly), prompts the user to enter a password, unlocks the .gpg keyfile (also on the USB key), and uses the resulting binary plaintext to unlock the LUKS partition. It next activates the LVM volume group on that partition ( in our case), and mounts any logical volumes (LVs) within it, as dictated by the file . This mounts the swap, root and home LVs.
 * 5) At this point the 'real' filing system is in place, and the initramfs (apart from,  and ) is discarded, using . The init script ends by invoking the 'proper' init system on this newly mounted root - which, depending on your earlier decision, will be either the  daemon, or the  init process. In either case, this 'real' init handles the boot from that point onwards.

Getting all of this to work correctly out of the box is complex, so I've provided a simple script which automates the process, and which should enable you to create a bootable EFI kernel with minimal fuss, which we'll install from the  overlay shortly.

So, let's go build ourselves a kernel!

Allowing Necessary Licenses and Downloading Kernel Sources and Firmware
Our default allowed license group, which we set earlier, does not by default enable the 'freely distributable' requirement of the kernel sources (or that of ), so we'll need to add that to our permitted license overrides (by creating an appropriate file in the directory).

Assuming that you are not intending to deblob your kernel (please see following note; most users will not wish to deblob), also issue:

Right, let's fetch the kernel sources:

And the firmware (assuming you are following our default options, and not deblobbing):

Now we need to quickly double-check that the symbolic link in is pointing to the correct place. Issue:

and check that the output of this refers to the same kernel version as following:

(the current default will have an asterisk marking it).

Emerging, and Additional Required Packages
We now have the necessary sources downloaded but, in order to proceed, there are two additional packages we should first. These are:


 * This is the master build script, supplied from the overlay (as described earlier). It pulls in a number of additional packages through its dependencies.
 * This contains a number of tools for working with UEFI, including commands to manipulate UEFI secure variables, which we will need when setting up secure boot.

Prior to emerging these, there are a number of package-specific use flags we'll need to set (some of these are in anticipation of dependencies). Issue:

Here are what those flags do:

There is one more issue we need to work around. In its current configuration, will sometimes fail during installation, when build parallelism is enabled (as it uses some of its own tools during installation in a manner that leads to a race condition). This is easily solved, and illustrates another feature of, namely per-package environments. First, we'll create a custom environment file that will override our usual settings. Issue:

then enter the following text in that file:

Save, and exit. Then issue:

then enter the following text in that file:

Save, and exit. Now, whenever the package is emerged, your custom  will be used.

Next, we can the packages themselves. Issue:

and wait for the build to complete.

Checking we have a Minimal, Static (Without )
The installation of (which you have just performed), should have caused a special, static version of  version 1.4.16 - called  - to have been installed on your system. The original (standard, v2.x) should be present as well (since it's part of the @system set for this profile).

As both versions are important to the proper functioning of your system, we need to check they are present and correct. Issue:

and verify that, per the messages produced, you do indeed have a v2.x and v1.x installed.

You can also verify that the binary is statically linked:

Setting Up 's Configuration File
Finally, before we can use the utility, we have to set up its configuration file. An initial version has already been copied to when you emerged, earlier. However, you must at least specify the following shell variables:
 * - the UUID of the first (EFI system) partition on your USB boot key.
 * - the UUID of the LUKS partition which you created on your target machine's main drive.
 * - the keymap to be used by the console early in the boot process. This is important for the passphrase protecting your LUKS keyfile to be recognized correctly. If you leave it commented out, the keymap will be used.

You made a note of these UUIDs earlier in this tutorial (where we referred to them as the partition UUIDs of and, respectively). If the  was able to identify them unambiguously (i.e., for, only one EFI system partition on a USB device could be found, and for , only one LUKS partition could be found), then these will already have been set for you, when you emerged , above. In any event, you must check to make sure, because if these values are wrong, you may not be able to boot your new Gentoo installation successfully.

There are two ways to check (and, if necessary, fix) your setup: manually, or via 's built-in menu-driven tool:

Option 1: Editing Manually
You can always modify the configuration manually. To do so, issue:

And then:
 * uncomment (if 's was able to identify only one such matching partition on a USB device, this will already have been set for you and uncommented, but you should check) the line setting, and make sure that it refers to the partition UUID of ;
 * uncomment (again, 's may already have set and uncommented this for you, but you must check) the line setting, and make sure that it refers to the partition UUID of ;
 * if not using the US keymap, uncomment the line setting, and make sure it refers to the correct keymap (in the case of the CF-AX3, for example, we'd set ).
 * if you chose to use (rather than ) init earlier, uncomment the line setting  (and make sure it reads  ). If you are on the default  install track, you should leave the variable commented out.

Option 2: Editing Using
As it is important to get these settings correct, and easy to make a slip-up when manually editing a configuration file and copying UUIDs around, the program provides a menu-driven helper to conform.

To use it, simply issue buildkernel --easy-setup, and follow the prompts, making sure to save and exit when done. You can mix and match manual editing and using ; when you run, any conflicting changes in your file will simply be automatically commented out, and any new definitions will be written to a delineated block at the end of the file.

The below shows a typical configuration run; obviously your values (UUIDs etc) will differ, as may the menu selections you need to make:

Your configuration file should look something like the below, after running (obviously, your values will differ, depending on the choices you make, and the UUIDs etc. on your target machine):

Note how the changes made by have been added in a block at the end of the file. You can manually edit the file now if you like, but avoid making changes within the "" block, as definitions within it can be overwritten next time is run.

What the Script Does (Background Reading)
Right, so now we're ready to build the kernel, using the script to do all the heavy lifting for us.

The script carries out the following steps in order:
 * 1) Reads your  file;
 * 2) Mounts the EFI partition if not already mounted (to );
 * 3) Enters the  directory;
 * 4) Copies a  file from the currently running kernel (via ) if no config already exists in, and sanitizes/updates it with ;
 * 5) Conforms the, by setting various key parameters that are required for the kernel to boot successfully in EFI mode with  or  (we review these below), including the rather gnarly kernel command line (which contains directives targeted both at the kernel, and at the  script provided by );
 * 6) Calls your user hook function  if you have defined it in  (you'll only generally want to do this to override unwanted changes made by  in the above step; other changes should be made via the standard  route, per the step below; they will be persisted);
 * 7) If in interactive mode (set by the  option), allows you to modify the resulting configuration, if you choose, using the standard menuconfig tool (see this wiki entry for a brief set of usage instructions); (it's fine to elect not to, however, in which case the conformed  will be silently sanitized/upgraded with , as it will in non-interactive mode);
 * 8) Cleans the kernel tree (optionally, you can force this with the, and you will be asked in interactive mode);
 * 9) Builds the kernel, and its modules, with the specified configuration; in this first pass, an empty initramfs is used (since it must be incorporated in the kernel, to be protected by UEFI secure boot, but we don't have everything necessary to include in it, yet!);
 * 10) If required (via the  option) builds any external modules (such as those required for VirtualBox), using Kernel/Upgrade;
 * 11) Creates a first cut of the initramfs using genkernel (see below for more details); this will contain 's  script, compiled modules, any necessary firmware (if you haven't deblobbed), and a minimal set of binaries; it does not at this point contain a static copy of ;
 * 12) Unpacks the initramfs, to the  directory;
 * 13) Modifies the initramfs by copying  directory contents across to it, and copies the  binary we discussed earlier, renaming it as  (if  does not exist,  will  it);
 * 14) Calls your user hook function  if you have defined it in  (you don't need it to make the boot work);
 * 15) Repacks the initramfs into  (the unpacked copy is left at  too, for reference, since it's useful to be able to see what is in this archive at a glance);
 * 16) Builds the kernel a second time (to incorporate this 'real' initramfs); this is a quick process as most of the components are unchanged;
 * 17) If you have a secure boot key and certificate (we haven't, yet), signs the kernel so it will secure boot;
 * 18) Backs up the old kernel and config on the EFI system partition (on the USB key), if any are present;
 * 19) Copies the newly built kernel (which is configured so as to be an EFI executable), into  (the magic location expected by most UEFI BIOSes - you can change this path via ); and also copies the config to the same directory;
 * 20) If possible, ensures that there is an EFI boot entry for the new kernel, and that this entry is at the top of the EFI boot list (we aren't booted under EFI yet, so you will get a warning here instead);
 * 21) Performs a filesystem Wikipedia:Sync_(Unix) and then unmounts the EFI system partition (if you so specify).

The default behaviour of buildkernel is to run in an non-interactive mode, unless the option is passed. It is also possible to specify the option, in which case  will create a new kernel in the  staging area, but will not attempt to copy it to the USB key. This is useful in unattended contexts, when you may have the boot key removed, for security. You can then subsequently copy over the new kernel with the option. For more details, see the manpage. Issue:

<span id="kernel_opts_set_by_buildkernel">Kernel Configuration Options Conformed by
Here <span id="buildkernel_config_changes">are the values conformed by, what effect they have, and why they are set as they are (should you wish to find further information about any option, you can do this from within  (in the  directory), as instructed here):

<span id="kernel_cmd_line_set_by_buildkernel">Kernel Built-In Command Line Conformed by
At this initial stage, the built-in kernel command line will be conformed as follows (your specific values will be different, depending on what is set in,  ,  and ):

Note that the term 'kernel command line' can be a little misleading - some of these parameters are indeed consumed by the kernel (a reasonably complete list of which is provided by kernel.org ); however, others are really targeted at the script. The Linux kernel passes the script (or program) any parameters it has not already processed as arguments, and the  script can also read the full command line in any event, via.

The various parameters in the above are explained in the table below:

If you wish to override any of these, simply set the appropriate variable in (of course, per the earlier instructions, you must at least set  and, and possibly , to get a bootable kernel). You can also specify additional kernel command line options, in the variable. For example, one common additional option you may wish to set would be to <span id="enable_trim">enable passing TRIM commands down to the underlying LUKS partition (if using a solid state drive, to prevent performance degradation as the device fills up). To accomplish this, you would set in  (this is then passed on by 's  script to ). You can specify multiple additional options via this variable, if you need to; simply separate them with a space.

<span id="genkernel_opts_used_by_buildkernel"> Options Used by, When Creating initramfs
The script calls the Gentoo utility Genkernel (from package ) to create the initramfs. It does this because provides some very useful features, for instance:
 * a significantly evolved script, which deals with e.g., the set up of a root directory using LVM over LUKS, prior to handoff to the 'real' init system ( or ) on the unlocked root;
 * automatic inclusion in the initramfs archive of not only (the minimal set) of necessary binaries, but also the libraries upon which they depend (if dynamically linked);
 * dealing with the installation of firmware and kernel modules to the initramfs; and
 * managing the use of the boot splash manager, if specified.

is also capable of building the kernel itself, but since it does not provide the UEFI and secure-boot hooks yet, we do not use it for this, preferring our script instead.

When invokes, it does so using the following command:

These options override anything specified in, and have the following description and rationale for use:

That concludes our brief tour through some of the internals of. Now we can get on and use it!

<span id="build_using_buildkernel">Building the New Kernel (Using )
So, without further ado, let's <span id="first_buildkernel">build the kernel.

Make sure your boot USB key is plugged into the target machine, then issue:

This will take some time to complete during the first pass, since all kernel components must be built from scratch. Subsequent runs of should complete much more quickly, provided you answer  when prompted if you want to  (there's generally no need to, unless you experience some strange build problems, or are building a new version for the first time). Furthermore, the next time you run, it will use the configuration now saved in the file, rather than the currently running kernel's configuration (read from ).

<span id="next_steps">Next Steps
Assuming that completed successfully, congratulations, you have just built a UEFI-bootable kernel! Just a few more minor configuration steps to perform, and we'll be ready to try it out. Click here to go to the next chapter, "Final Preparations and Reboot into EFI".