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 buildkernel (from sakaki-tools) and some additional required packages;
 * 3) Checking we have a custom version of gpg that will work without pinentry;
 * 4) Setting up buildkernel's configuration file ; and
 * 5) Building the kernel for the first time, using buildkernel.

However, don't worry, the process is perfectly manageable! No manual kernel configuration is necessary for the above, since the provided buildkernel 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 cat</tt> and ls</tt>) 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 emerge</tt> procedure - emerge</tt> 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 .config</tt> 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 gpg</tt>, cryptsetup</tt> 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 <span id="initramfs_intro">worked around by using an initial RAM filing system, or initramfs, which is a simple archive (like a tar</tt> archive, but using an older format, known as cpio</tt>) 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 (systemd</tt> track, OpenRC</tt> 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 genkernel</tt> (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 (vg1</tt> 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 switch_root</tt>. 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 systemd</tt> daemon, or the OpenRC</tt> 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 (buildkernel</tt>) which automates the process, and which should enable you to create a bootable EFI kernel with minimal fuss, which we'll install from the <tt>sakaki-tools</tt> overlay shortly.

So, let's go build ourselves a kernel!

<span id="downloading_kernel_source">Allowing Necessary Licenses and Downloading Kernel Sources and Firmware
Our default allowed license group (<tt>@FREE</tt>), 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:

<span id="install_firmware">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).

<span id="emerging_buildkernel">Emerging <tt>buildkernel</tt>, and Additional Required Packages
We now have the necessary sources downloaded but, in order to proceed, there are two additional packages we should <tt>emerge</tt> first. These are:


 * This is the master build script, supplied from the <tt>sakaki-tools</tt> 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. Currently supplied from the <tt>sakaki-tools</tt> overlay, because of a required patch (see earlier discussion).

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 <tt>buildkernel</tt> dependencies). Issue:

Here are what those flags do:

Next, we can <tt>emerge</tt> the packages themselves. <span id="install_buildkernel">Issue:

and wait for the build to complete.

<span id="ensure_static_gpg">Checking we have a Minimal, Static <tt>gpg</tt> (Without <tt>pinentry</tt>)
The <span id="staticgpg_intro">installation of <tt>buildkernel</tt> (which you have just performed), should have caused a special, static version of <tt>gpg</tt> version 1.4.16 - called <tt>staticgpg</tt> - to have been installed on your system. The original (standard, v2.x) <tt>gpg</tt> 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 <tt>staticgpg</tt> binary is statically linked:

<span id="setup_buildkernel_conf">Setting Up <tt>buildkernel</tt>'s Configuration File
Finally, before we can use the <tt>buildkernel</tt> utility, we have to set up its configuration file. An initial version has already been copied to when you emerged <tt>buildkernel</tt>, earlier. However, you must at least <span id="important_conf_vars">specify the following shell variables:
 * <tt>EFIPARTUUID</tt> - the UUID of the first (EFI system) partition on your USB boot key.
 * <tt>CRYPTPARTUUID</tt> - the UUID of the LUKS partition which you created on your target machine's main drive.
 * <tt>KEYMAP</tt> - 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 <tt>us</tt> 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 <tt>buildkernel</tt> <tt>ebuild</tt> was able to identify them unambiguously (i.e., for <tt>EFIPARTUUID</tt>, only one EFI system partition on a USB device could be found, and for <tt>CRYPTPARTUUID</tt>, only one LUKS partition could be found), then these will already have been set for you, when you emerged <tt>buildkernel</tt>, 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 do check (and, if necessary, fix) your setup: manually, or via <tt>buildkernel</tt>'s built-in menu-driven tool:

<span id="manual_buildkernel_conf">Option 1: Editing <tt>buildkernel.conf</tt> Manually
You can always modify the configuration manually. To do so, issue:

And then:
 * uncomment (if <tt>buildkernel</tt>'s <tt>ebuild</tt> 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 <tt>EFIPARTUUID</tt>, and make sure that it refers to the partition UUID of ;
 * uncomment (again, <tt>buildkernel</tt>'s <tt>ebuild</tt> may already have set and uncommented this for you, but you must check) the line setting <tt>CRYPTPARTUUID</tt>, and make sure that it refers to the partition UUID of ;
 * if not using the US keymap, uncomment the line setting <tt>KEYMAP</tt>, and make sure it refers to the correct keymap (in the case of the CF-AX3, for example, we'd set <tt>KEYMAP="jp"</tt>).
 * if you chose to use <tt>OpenRC</tt> (rather than <tt>systemd</tt>) init earlier, uncomment the line setting <tt>INITSYSTEM</tt> (and make sure it reads ). If you are on the default (<tt>systemd</tt>) install track, you should leave the variable commented out.

<span id="assisted_buildkernel_conf">Option 2: Editing <tt>buildkernel.conf</tt> Using <tt>buildkernel --easy-setup</tt>
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 <tt>buildkernel</tt> 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 <tt>buildkernel --easy-setup</tt>; when you run <tt>buildkernel --easy-setup</tt>, 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 <tt>buildkernel --easy-setup</tt> (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 <tt>buildkernel --easy-setup</tt> 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 "<tt>Automatically added...</tt>" block, as definitions within it can be overwritten next time <tt>buildkernel --easy-setup</tt> is run.

<span id="what_buildkernel_does">What the <tt>buildkernel</tt> Script Does (Background Reading)
Right, so now we're ready to build the kernel, using the <tt>buildkernel</tt> script to do all the heavy lifting for us.

The <tt>buildkernel</tt> script carries out the following steps in order:
 * 1) Reads your <tt>genkernel.conf</tt> file;
 * 2) Mounts the EFI partition if not already mounted (to );
 * 3) Enters the  directory;
 * 4) Copies a <tt>.config</tt> file from the currently running kernel (via ) if no config already exists in, and sanitizes/updates it with <tt>make olddefconfig</tt>;
 * 5) Conforms the <tt>.config</tt>, by setting various key parameters that are required for the kernel to boot successfully in EFI mode with <tt>systemd</tt> or <tt>OpenRC</tt> (we review these below), including the rather gnarly kernel command line (which contains directives targeted both at the kernel, and at the <tt>init</tt> script provided by <tt>genkernel</tt>);
 * 6) Calls your user hook function <tt>user_conform_config_file</tt> if you have defined it in  (you'll only generally want to do this to override unwanted changes made by <tt>buildkernel</tt> in the above step; other changes should be made via the standard <tt>make menuconfig</tt> route, per the step below; they will be persisted);
 * 7) If in interactive mode (set by the <tt>--ask</tt> option), allows you to <span id="make_menuconfig_step">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 <tt>.config</tt> will be silently sanitized/upgraded with <tt>make olddefconfig</tt>, as it will in non-interactive mode);
 * 8) Cleans the kernel tree (optionally, you can force this with the <tt>--clean</tt>, 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 <tt>--build-external-modules</tt> option) builds any external modules (such as those required for VirtualBox), using <tt>emerge @module-rebuild</tt>;
 * 11) Creates a first cut of the initramfs using <tt>genkernel</tt> (see below for more details); this will contain <tt>genkernel</tt>'s <tt>init</tt> 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 <tt>gpg</tt>;
 * 12) Unpacks the initramfs, to the  directory;
 * 13) <span id="copy_static_gpg">Modifies the initramfs by copying <tt>modprobe.d</tt> directory contents across to it, and copies the <tt>staticgpg</tt> binary we discussed earlier, renaming it as <tt>gpg</tt> (if <tt>staticgpg</tt> does not exist, <tt>buildkernel</tt> will <tt>emerge</tt> it);
 * 14) Calls your user hook function <tt>user_modify_initramfs</tt> 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) <span id="initramfs_into_kernel">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 <tt>sync</tt> 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 <tt>--ask</tt> option is passed. It is also possible to specify the <tt>--stage-only</tt> option, in which case <tt>buildkernel</tt> 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 <tt>--copy-from-staging</tt> option. For more details, see the <tt>buildkernel</tt> manpage. Issue:

<span id="kernel_opts_set_by_buildkernel">Kernel Configuration Options Conformed by <tt>buildkernel</tt>
Here <span id="buildkernel_config_changes">are the <tt>.config</tt> values conformed by <tt>buildkernel</tt>, 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 <tt>make menuconfig</tt> (in the directory), as instructed here):

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

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 <tt>init</tt> script. The Linux kernel passes the <tt>init</tt> script (or program) any parameters it has not already processed as arguments, and the <tt>init</tt> 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 <tt>EFIPARTUUID</tt> and <tt>CRYPTPARTUUID</tt>, and possibly <tt>KEYMAP</tt>, to get a bootable kernel). You can also specify additional kernel command line options, in the variable <tt>ADDITIONALKERNELCMDS</tt>. 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 <tt>ADDITIONALKERNELCMDS="root_trim=yes"</tt> in (this is then passed on by <tt>genkernel</tt>'s <tt>init</tt> script to <tt>cryptsetup</tt>). 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"><tt>genkernel</tt> Options Used by <tt>buildkernel</tt>, When Creating initramfs
The <tt>buildkernel</tt> script calls the Gentoo utility <tt>genkernel</tt> (from package ) to create the initramfs. It does this because <tt>genkernel</tt> provides some very useful features, for instance:
 * a significantly evolved <tt>init</tt> 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 (<tt>systemd</tt> or <tt>OpenRC</tt>) 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 <tt>plymouth</tt> boot splash manager, if specified.

<tt>genkernel</tt> 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 <tt>buildkernel</tt> script instead.

When <tt>buildkernel</tt> invokes <tt>genkernel</tt>, 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 <tt>buildkernel</tt>. Now we can get on and use it!

<span id="build_using_buildkernel">Building the New Kernel (Using <tt>buildkernel</tt>)
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 <tt>buildkernel</tt> should complete much more quickly, provided you answer when prompted if you want to <tt>make clean</tt> (there's generally no need to <tt>make clean</tt>, unless you experience some strange build problems, or are building a new version for the first time). Furthermore, the next time you run <tt>buildkernel</tt>, 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".