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

From Gentoo Wiki
Jump to: navigation, search

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.[1]

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 (/etc/buildkernel.conf); 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).


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 and ls) 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 procedure - emerge 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 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 /EFI/Boot/bootx64.efi, 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, cryptsetup 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 tar archive, but using an older format, known as 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 (systemd track, OpenRC 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 (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 in our case), and mounts any logical volumes (LVs) within it, as dictated by the file /etc/fstab. This mounts the swap, root and home LVs.
  5. At this point the 'real' filing system is in place, and the initramfs (apart from /proc, /dev and /sys) is discarded, using switch_root. 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 daemon, or the OpenRC 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) which automates the process, and which should enable you to create a bootable EFI kernel with minimal fuss, which we'll install from the sakaki-tools overlay shortly.

So, let's go build ourselves a kernel!

Allowing Necessary Licenses and Downloading Kernel Sources and Firmware

Our default allowed license group (@FREE), which we set earlier, does not by default enable the 'freely distributable' requirement of the kernel sources (or that of sys-kernel/linux-firmware), so we'll need to add that to our permitted license overrides (by creating an appropriate file in the /etc/portage/package.license directory).

(chroot) livecd / #mkdir -p -v /etc/portage/package.license
(chroot) livecd / #touch /etc/portage/package.license/zzz_via_autounmask
(chroot) livecd / #echo "sys-kernel/gentoo-sources freedist" >> /etc/portage/package.license/gentoo-sources
As earlier, we create a zzz_via_autounmask file as a convenient receptacle for changes that you may, in future, request be automatically made to your package.license configuration to allow an emerge operation to complete successfully.

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

(chroot) livecd / #echo "sys-kernel/linux-firmware freedist linux-firmware no-source-code" >> /etc/portage/package.license/linux-firmware
There's a key choice to make here. The package sys-kernel/linux-firmware contains (opaque) compiled software for lots of different bits of hardware you may have in your system. These images are not executed directly by the CPU, but copied up to the devices in question by their drivers when needed. Now, you might take the view that, since these images are not 'open-source' as such, they represent a taint and possible danger to your system. If that's your position (and this will not apply to most users of this tutorial), then you should:
(chroot) livecd / #mkdir -p -v /etc/portage/package.use
(chroot) livecd / #echo "sys-kernel/ck-sources deblob" >> /etc/portage/package.use/ck-sources
  • allow ~amd64 ('testing branch') ebuilds for sys-kernel/ck-sources (since as of the time of writing, it had no versions marked stable), as follows:
(chroot) livecd / #mkdir -p -v /etc/portage/package.accept_keywords
(chroot) livecd / #echo "sys-kernel/ck-sources ~amd64" >> /etc/portage/package.accept_keywords/ck-sources
Be aware: if you choose to go the full Linux-libre route like this, your system will probably still boot, and chances are its wired interfaces will still work, but unless you are lucky (or are using a system, like e.g. one of the Purism Librem laptops, which has been specifically designed not to require additional firmware blobs) your wireless devices will most likely not function (since many of these devices have only static RAM and require firmware uploads every time they are connected).[2][3] In this tutorial, therefore, I have taken the pragmatic view of leaving the firmware in. If that makes you a little nervous, I'd suggest to try first building the system with firmware (i.e., per this tutorial's vanilla flow), get it to the point where it works successfully, and then try switching out the firmware (using the methods just mentioned). That way, you'll be able to roll back to the previous kernel if things go wrong. And if you are paranoid, you can always rebuild everything again from scratch, once you reach a stable configuration.
Per the handbook, you don't have to use sys-kernel/gentoo-sources; there are a number of other alternatives within the Portage tree, which provide different spins on the kernel (e.g., for security hardened server applications).[4] However, we'll stick with sys-kernel/gentoo-sources here as it's the most commonly used variant.

Right, let's fetch the kernel sources:

(chroot) livecd / #emerge --ask --verbose sys-kernel/gentoo-sources
... additional output suppressed ...
Would you like to merge these packages? [Yes/No] <press y, then press Enter>
... additional output suppressed ...
As just mentioned, users who are deblobbing (not the default in this tutorial) should use sys-kernel/ck-sources in place of sys-kernel/gentoo-sources in the above command.

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

(chroot) livecd / #emerge --ask --verbose sys-kernel/linux-firmware
... additional output suppressed ...
Would you like to merge these packages? [Yes/No] <press y, then press Enter>
... additional output suppressed ...

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

(chroot) livecd / #readlink -v /usr/src/linux

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

(chroot) livecd / #eselect kernel list

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

At the moment, there should only be one version available in the output from eselect kernel list. However, as time goes on, and you update your Portage tree (discussed later), new versions of the kernel sources will become available. When you wish to work with one of these newer versions, you issue:
root #eselect kernel set N
to choose it (where N is a number in the list output by eselect kernel list, such as 1, 2 etc.) prior to building. This action modifies the /usr/src/linux symbolic link.

Emerging buildkernel, and Additional Required Packages

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

  • sys-kernel/buildkernel This is the master build script, supplied from the sakaki-tools overlay (as described earlier). It pulls in a number of additional packages through its dependencies.
  • app-crypt/efitools 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 buildkernel dependencies). Issue:

(chroot) livecd / #echo -e "# ensure we can generate a bootable kernel and initramfs\nsys-kernel/genkernel-next cryptsetup gpg plymouth" >> /etc/portage/package.use/genkernel-next
(chroot) livecd / #echo -e "# for a smooth transition to Gnome\nsys-boot/plymouth gdm" >> /etc/portage/package.use/plymouth
(chroot) livecd / #echo -e "# required by plymouth (kernel mode setting library)\nx11-libs/libdrm libkms" >> /etc/portage/package.use/libkms

Here are what those flags do:

Package Use flag Description
sys-kernel/genkernel-next cryptsetup This enables support for LUKS disk encryption in the initramfs, via sys-fs/cryptsetup.
gpg This enables support for gpg in the initramfs. We will provide our own version of gpg but we set the use flag here for forward compatibility.
plymouth This enables support for the plymouth boot splash system (but does not mandate its use).
sys-boot/plymouth gdm This allows for a smooth transition from the plymouth splash to GNOME (incidentally, this flag may safely be set even by those targeting other graphical desktop environments, such as KDE).
x11-libs/libdrm libkms This enables the building of libkms, a library for applications to interact with kernel mode setting. It is required by (the default use flags of) sys-boot/plymouth.

Next, we need to ensure that at least version 0.9.3 of the sys-boot/plymouth boot splash manager is used (to avoid some severe bugs in earlier versions). As, at the time of writing, this version was still in testing (~amd64), we must add an exception, to allow Portage to use it. Issue:

(chroot) livecd / #echo -e "# ensure sufficiently modern plymouth used\n~sys-boot/plymouth-0.9.3 ~amd64" >> /etc/portage/package.accept_keywords/plymouth
This citation uses an extended ("~") prefix, the concept of which was introduced in a previous chapter. It will allow any revision of the specified version to be used, even if marked ~amd64 (testing) rather than amd64 (stable). Once more modern versions become available in the tree with amd64 (stable) keywording, this citation will become inactive (but harmless).

There is one more issue we need to work around. In its current configuration, app-crypt/efitools 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 Portage, namely per-package environments. First, we'll create a custom environment file that will override our usual MAKEOPTS settings. Issue:

(chroot) livecd / #mkdir -p -v /etc/portage/{env,package.env}
(chroot) livecd / #nano -w /etc/portage/env/serialize-make.conf

then enter the following text in that file:

FILE /etc/portage/env/serialize-make.confCreate a environment file to force single-threaded make
# cite "serialize-make.conf" for package <foo> in
# /etc/portage/package.env/<foo>, to suppress parallel make


Save, and exit nano. Then issue:

(chroot) livecd / #nano -w /etc/portage/package.env/efitools

then enter the following text in that file:

FILE /etc/portage/package.env/efitoolsInvoking a custom environment for app-crypt/efitools
app-crypt/efitools serialize-make.conf

Save, and exit nano. Now, whenever the app-crypt/efitools package is emerged, your custom MAKEOPTS will be used.

You can cite multiple environment configuration files for a single package, just separate them with a space, and you can use the same technique to e.g., modify Portage FEATURES on a per-package basis.

Next, we can emerge the packages themselves. Issue:

(chroot) livecd / #emerge --ask --verbose app-crypt/efitools
... additional output suppressed ...
Would you like to merge these packages? [Yes/No] <press y, then press Enter>
... additional output suppressed ...

Once this completes, issue:

(chroot) livecd / #emerge --ask --verbose sys-kernel/buildkernel
... additional output suppressed ...
Would you like to merge these packages? [Yes/No] <press y, then press Enter>
... additional output suppressed ...

and again, wait for the build to complete.

These builds may take some time, so (just as we did in the previous chapter), you can temporarily switch to the second screen virtual console and review progress with showem, if you like.

Checking we have a Minimal, Static gpg (Without pinentry)

The installation of buildkernel (which you have just performed), should have caused a special, static version of gpg version 1.4.16 - called staticgpg - to have been installed on your system. The original (standard, v2.x) gpg 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:

(chroot) livecd / #gpg --version && echo && staticgpg --version

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

You can also verify that the staticgpg binary is statically linked:

(chroot) livecd / #file "$(which staticgpg)"
/usr/local/bin/staticgpg: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, stripped
The GNU/Linux version shown by file may be different for your system; in any event, it is not the version of the kernel under which the binary was compiled (per uname -r); rather it is the version of the kernel headers that the C library the program uses was built against.[5]

Setting Up buildkernel's Configuration File

Finally, before we can use the buildkernel utility, we have to set up its configuration file. An initial version has already been copied to /etc/buildkernel.conf when you emerged buildkernel, earlier. However, you must at least specify the following shell variables:

  • EFIPARTUUID - the UUID of the first (EFI system) partition on your USB boot key.
  • CRYPTPARTUUID - the UUID of the LUKS partition which you created on your target machine's main drive.
  • KEYMAP - 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 us keymap will be used.
Users who have elected to target OpenRC init (and not the default systemd) earlier must also specify the INITSYSTEM variable.

You made a note of these UUIDs earlier in this tutorial (where we referred to them as the partition UUIDs of /dev/sdY1 and /dev/sdZn, respectively). If the buildkernel ebuild was able to identify them unambiguously (i.e., for EFIPARTUUID, only one EFI system partition on a USB device could be found, and for CRYPTPARTUUID, only one LUKS partition could be found), then these will already have been set for you, when you emerged buildkernel, 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.

By default, buildkernel assumes that your LUKS filesystem resides on a GPT partition (which it will do, if you installed it in space freed up from Windows, per the earlier instructions in this tutorial). However, as of version 1.0.8 of buildkernel, it is also possible to specify the LUKS path directly, by setting the CRYPTPATHMAP variable in /etc/buildkernel.conf. This may be useful for those whose LUKS filesystem is on an MBR-partitioned drive (if dual-booting with an older Windows 7, for example). Please refer to the buildkernel.conf manpage for more details.
Most users will not need to concern themselves with this option, however, and should entirely ignore the contents of this note.

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

Option 1: Editing buildkernel.conf Manually

You can always modify the configuration manually. To do so, issue:

(chroot) livecd / #nano -w /etc/buildkernel.conf

And then:

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

Save, and exit nano when done.

By /dev/sdY1 in the above we of course mean the USB boot key's first partition, and by /dev/sdZn the LUKS partition we created.
In the unlikely event you decided not to call your LVM volume group vg1 earlier in the tutorial, you'll also need to set the variables CMDLINE_REAL_ROOT and CMDLINE_REAL_RESUME (which are ultimately used to set the kernel command line variables real_root and real_resume). For example, if you called your volume group mynewvg, you need to set:

in buildkernel.conf for the system to work correctly. If you have used the recommended name (vg1), you do not need to worry about this point.

There is a bit of a subtlety with the KEYMAP variable; this is processed by genkernel's init script, not systemd or OpenRC (which the init script eventually hands off to), so the string you need may be slightly different from that reported by localectl list-keymaps (which we'll use when setting up systemd's configuration later) (OpenRC users will use values from /usr/share/keymaps/i386/<layout>/...). Have a look in the file /usr/share/genkernel/defaults/initrd.d/ to see the available keypap strings for use with this variable. For example, on the Panasonic CF-AX3 laptop, we need to use jp106 for the systemd console keymap, but jp for the init script (and hence KEYMAP="jp" here). Alternatively, just use the buildkernel --easy-setup approach described below, and you can then simply choose your desired keymap from a menu!

Option 2: Editing buildkernel.conf Using buildkernel --easy-setup

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 buildkernel program provides a menu-driven helper to conform /etc/buildkernel.conf.

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 buildkernel --easy-setup; when you run buildkernel --easy-setup, 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:

(chroot) livecd / #buildkernel --easy-setup
... significant amounts of output suppressed in what follows ...
* buildkernel: Warning: This system wasn't booted under UEFI, cannot check boot entries
* Current configuration (from /etc/buildkernel.conf):
  EFI system partition UUID:  2498f874-ad8f-484e-8aba-81ac1c9665b6
  LUKS root partition UUID:   8111286a-d24e-4ba2-b6af-d0650fab4130
  GPG keyfile partition UUID: DEFAULT (=EFI system partition UUID)
  GPG keyfile (for LUKS):     luks-key.gpg                        
  EFI boot directory:         /EFI/Boot                           
  EFI boot file:              bootx64.efi                         
  Plymouth theme:             NONE (textual boot)                 
  Boot-time keymap:           us                         
  Init system:                systemd                             
* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 1 then Enter
* Please choose which EFI system partition to use (or GO BACK):
Num Partition UUID                       Path       USB Win Use
--- ------------------------------------ ---------- --- --- ---
 1) 2498f874-ad8f-484e-8aba-81ac1c9665b6 /dev/sdb1   Y  ??? [*]
 2) f236e16c-ca97-4c36-b0d5-4196fa1e9930 /dev/sda2   N  ??? [ ]
Your choice: selected item is OK so press 3 then Enter
* Current configuration (from /etc/buildkernel.conf - MODIFIED):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 2 then Enter
* Please choose which LUKS partition contains the root LVM logical volume:
Num Partition UUID                       Path       USB Use
--- ------------------------------------ ---------- --- ---
 1) 8111286a-d24e-4ba2-b6af-d0650fab4130 /dev/sda7   N  [*]
Your choice: selected item is OK so press 2 then Enter
* Current configuration (from /etc/buildkernel.conf):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 3 then Enter
* Current LUKS key settings:
* Using a GPG-encrypted keyfile for LUKS:
*  KEYFILEPARTUUID unset: assuming GPG keyfile on EFI system partition
* Please choose your desired LUKS key setting (or GO BACK):
1) Use GPG-encrypted keyfile on EFI system partition
2) Use GPG-encrypted keyfile on specific USB partition...
3) Use fallback passphrase (no keyfile)
Your choice: selected item is OK so press 4 then Enter
* Current configuration (from /etc/buildkernel.conf):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 4 then Enter
* Current EFI boot file setting:
* EFI boot file path: /EFI/Boot/bootx64.efi
*  (under EFI system partition mountpoint)
* Please choose your desired EFI boot file setting (or GO BACK):
1) Use /EFI/Boot/bootx64.efi (recommended for initial USB install)
2) Use /EFI/Microsoft/Boot/bootmgfw.efi (fallback for certain systems)
3) Use /EFI/Boot/gentoo.efi (recommended for post-install use)
Your choice: selected item is OK so press 4 then Enter
* Current configuration (from /etc/buildkernel.conf):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 5 then Enter
* Current boot splash settings:
* Using textual boot (no Plymouth)
* Please choose your desired boot splash setting (or GO BACK):
1) Use textual boot (no Plymouth)
2) Use Plymouth graphical boot splash ('fade-in')
Your choice: selected item is OK so press 3 then Enter
* Current configuration (from /etc/buildkernel.conf):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 6 then Enter
* Please choose your desired boot-time keymap (or GO BACK):
* Boot-time keymap is currently 'us'
1) azerty     9) cz      17) gr       25) mk        33) sg       41) us
2) be        10) de      18) hu       26) nl        34) sk-y     42) wangbe
3) bg        11) dk      19) il       27) no        35) sk-z     43) sf
4) br-a      12) dvorak  20) is       28) pl        36) slovene  44) GO BACK
5) br-l      13) es      21) it       29) pt        37) trf
6) by        14) et      22) jp       30) ro        38) trq
7) cf        15) fi      23) la       31) ru        39) ua
8) croat     16) fr      24) lt       32) se        40) uk
Your choice: press 22 then Enter
NB - select the appropriate keymap for your system!
* Keymap selected to be 'jp'
* Current configuration (from /etc/buildkernel.conf - MODIFIED):
  EFI system partition UUID:  2498f874-ad8f-484e-8aba-81ac1c9665b6
  LUKS root partition UUID:   8111286a-d24e-4ba2-b6af-d0650fab4130
  GPG keyfile partition UUID: DEFAULT (=EFI system partition UUID)
  GPG keyfile (for LUKS):     luks-key.gpg                        
  EFI boot directory:         /EFI/Boot                           
  EFI boot file:              bootx64.efi                         
  Plymouth theme:             NONE (textual boot)                 
  Boot-time keymap:           jp                                  
  Init system:                systemd                             
* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 7 then Enter
* Current init system settings:
* Targeting systemd init
* Please choose your desired init system setting (or GO BACK):
1) systemd (select if unsure)  3) GO BACK
2) OpenRC
Your choice: selected item is OK so press 3 then Enter 
NB - users wanting to use OpenRC should press 2 then Enter here
* Current configuration (from /etc/buildkernel.conf):

... as before ...

* Please choose an option:
1) Set EFI system partition  6) Set boot-time keymap
2) Set LUKS root partition   7) Set init system
3) Set LUKS key options      8) Exit without saving
4) Set EFI boot file path    9) Save and exit
5) Set boot splash options
Your choice: press 9 then Enter
* Configuration saved to /etc/buildkernel.conf.
* Be sure to run buildkernel, to rebuild the kernel with the new
* settings, before rebooting.
... significant amounts of output suppressed in the above ...

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

FILE /etc/buildkernel.confExample settings for buildkernel after --easy-setup run (your values will differ)
# Configuration file for /usr/local/sbin/buildkernel
# Make sure the below are set correctly for your system!

# following is the partuuid of your EFI system partition
# (e.g., the first partition on your USB boot key)
# replace with an appropriate value (find with lsblk and blkid) for your system
# EFIPARTUUID="2498f874-ad8f-484e-8aba-81ac1c9665b6"

# following is the partuuid of your LUKS partition (if on a GPT drive)
# (usually, this will be a partition of a fixed drive in your machine)
# replace with an appropriate value (find with lsblk and blkid) for your system
# CRYPTPARTUUID="8111286a-d24e-4ba2-b6af-d0650fab4130"

# if your LUKS filesystem is NOT on a GPT partition (for example, if it is
# on an MBR partition, or if you have luksFormat-ed a top-level drive, rather
# than a partition within it), then you must uncomment and set the following
# variable (use "ls -l /dev/disk/by-uuid" to locate the correct path)
# NB - most users will NOT need to do this (it is a special case), and
# should accordingly leave the variable commented out;
# note also that if you set CRYPTPATHMAP directly in this manner, the
# contents of CRYPTPARTUUID will be ignored

# if your LUKS keyfile is not on your EFI system partition (for example,
# because you use a USB key to hold the keyfile, but have created an EFI
# system partition on the machine's main drive), then uncomment the below
# and replace the UUID with the appropriate value (find with lsblk and blkid)
# for your system; if you do not, then KEYFILEPARTUUID=EFIPARTUUID is assumed

# if you wish to rely only on the fallback passphrase (assuming you have set
# one up) and no keyfile, uncomment the line below; otherwise
# the value "luks-key.gpg" will be assumed (if you do set LUKSKEYFILE to the
# empty string, KEYFILEPARTUUID is ignored)

# by default, buildkernel will build the kernel in /usr/src/linux. If
# LINUXBUILDDIR is specified, buildkernel will delete the contents of
# LINUXBUILDDIR/buildkernel, copy the contents of /usr/src/linux there,
# then build the kernel in that directory. This can be useful for sparing write
# cycles if /usr/src/linux is located on a SSD and the specified directory lies
# e.g. on tmpfs.

# add any additional kernel command line parameters here (most critical ones
# will be set automatically by buildkernel; you can leave this commented out)

# by default, genkernel will be instructed to include all firmware and modules
# into the initramfs; uncomment and change the below (for example, to specify
# an empty string) if you do not want this, or if you want to manage these
# options explicitly through /etc/genkernel.conf
# (caution - may cause boot issues on some systems)
#ADDITIONALGENKERNELOPTS="--all-ramdisk-modules --firmware"

# by default, buildkernel will ensure that an EFI boot entry for any kernel
# it creates exists at the top of the EFI boot order (in EFI NVRAM);
# uncomment and change the below (to specify value 0) if you do not want to
# do this (for example, because you wish to use your own EFI bootloader)

# set your keymap - this is IMPORTANT to ensure your password for the GPG
# protected keyfile gets read correctly
# if you leave this commented out, the "us" keymap will be used

# if you want a graphical boot theme, set it here; will automatically turn
# on the 'quiet splash' kernel options
# leave commented out for a textual boot screen

# if you want to use OpenRC init, rather than the default systemd, uncommment
# the below (capitalization is unimportant)

# if you need to conform the config file for some reason, uncomment this
# hook function and fill it out to suit your requirements
# NB you should only really need to do this to override a setting forced
# by buildkernel itself; other changes you make during the make menuconfig step
# are persisted, and this is the preferred way to modify the config
# user_conform_config_file() {
#     # call set_kernel_config / unset_kernel_config functions here as needed
# }

# if you need to modify the initramfs during the buildkernel process, 
# uncomment this hook function and fill it out to suit your requirements
# user_modify_initramfs() {
#     # do stuff with ${INITRAMFSDIR} directory contents;
#     # the cpio archive is already unpacked here upon function entry
#     # and will be repacked again automatically for you afterwards
# }

# leave the below two lines commented out, unless running on a *very*
# badly-behaved UEFI BIOS, that looks only at the Microsoft boot loader path
# Automatically added by buildkernel - edits here may be overwritten
# End of automatically added section

Note how the changes made by buildkernel --easy-setup 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 "Automatically added..." block, as definitions within it can be overwritten next time buildkernel --easy-setup is run.

Please ensure that you have specified the correct KEYMAP and INITSYSTEM settings. In particular:
  • users of PCs with non-US keyboards (such as the CF-AX3's Japanese keyboard, as here) should ensure they have chosen an appropriate keymap from the buildkernel --easy-setup menu, since without this it may be impossible to type the LUKS keyfile password successfully at boot time; and
  • users who have elected to use OpenRC init (not the default) earlier should ensure that they have INITSYSTEM set thus: INITSYSTEM="openrc" (the variable is not case sensitive). Users wanting to use systemd init (the default) should ensure that the INITSYSTEM variable is either commented out, or set thus: INITSYSTEM="systemd".
buildkernel --easy-setup does not cover all possible changes you might wish to make to the configuration file, only the main variables. Therefore if, for example, you wished for example to enable TRIM support (see below) for your hard drive, you'd need to set ADDITIONALKERNELCMDS variable in the configuration file directly - there's (currently) no menu-driven way to set that flag via buildkernel --easy-setup.
As mentioned, the actual settings for at least EFIPARTUUID, CRYPTPARTUUID and possibly KEYMAP will be different for your system - the above is an example only.
More information about the variables and functions settable in /etc/buildkernel.conf may be found in its manpage. To view this, issue:
(chroot) livecd / #man buildkernel.conf
We specify a textual boot at this stage (PLYMOUTHTHEME commented out in /etc/buildkernel.conf), as we will try a boot without a graphical splash screen initially, for safety.

What the buildkernel Script Does (Background Reading)

Right, so now we're ready to build the kernel, using the buildkernel script to do all the heavy lifting for us.

If you're interested in what this script does, read on, otherwise you can skip over to the next section and get building right away!

The buildkernel script carries out the following steps in order:

  1. Reads your genkernel.conf file;
  2. Mounts the EFI partition if not already mounted (to /boot/efi);
  3. Enters the /usr/src/linux directory;
  4. Copies a .config file from the currently running kernel (via /proc/config.gz) if no config already exists in /usr/src/linux, and sanitizes/updates it with make olddefconfig;
  5. Conforms the .config, by setting various key parameters that are required for the kernel to boot successfully in EFI mode with systemd or OpenRC (we review these below), including the rather gnarly kernel command line (which contains directives targeted both at the kernel, and at the init script provided by genkernel);
  6. Calls your user hook function user_conform_config_file if you have defined it in /etc/genkernel.conf (you'll only generally want to do this to override unwanted changes made by buildkernel in the above step; other changes should be made via the standard make menuconfig route, per the step below; they will be persisted);
  7. If in interactive mode (set by the --ask 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 .config will be silently sanitized/upgraded with make olddefconfig, as it will in non-interactive mode);
  8. Cleans the kernel tree (optionally, you can force this with the --clean, 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 --build-external-modules option) builds any external modules (such as those required for VirtualBox), using emerge @module-rebuild;
  11. Creates a first cut of the initramfs using genkernel (see below for more details); this will contain genkernel's init 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 gpg;
  12. Unpacks the initramfs, to the /boot/initramfs directory;
  13. Modifies the initramfs by copying modprobe.d directory contents across to it, and copies the staticgpg binary we discussed earlier, renaming it as gpg (if staticgpg does not exist, buildkernel will emerge it);
  14. Calls your user hook function user_modify_initramfs if you have defined it in /etc/genkernel.conf (you don't need it to make the boot work);
  15. Repacks the initramfs into /boot/initramfs.cpio (the unpacked copy is left at /boot/initramfs 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 /boot/efi/EFI/Boot/bootx64.efi (the magic location expected by most UEFI BIOSes - you can change this path via /etc/buildkernel.conf); 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);
    You can prevent buildkernel modifying the EFI boot settings in NVRAM by setting CREATEEFIBOOT=0 in /etc/buildkernel.conf, although most users will not need to do this, unless wanting to e.g., specify their own EFI bootloader.
  21. Performs a filesystem sync 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 --ask option is passed. It is also possible to specify the --stage-only option, in which case buildkernel will create a new kernel in the /boot 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 --copy-from-staging option. For more details, see the buildkernel manpage. Issue:

(chroot) livecd / #man buildkernel

Kernel Configuration Options Conformed by buildkernel

Here are the .config values conformed by buildkernel, 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 make menuconfig (in the /usr/src/linux directory), as instructed here):

Kernel Option Value Set Effect Reason
GENTOO_LINUX y Enables the various GENTOO_LINUX_... options (discussed below). These in turn are intended to ease configuration of a new kernel for use with Gentoo, by forcing certain other kernel options to appropriate values. This option should be on by default anyway, and certainly will be if you are using a .config pulled from the running minimal-install system kernel's /proc/config.gz. But for safety's sake we set it again here.
GENTOO_LINUX_UDEV y This currently causes the options DEVTMPFS, TMPFS, UNIX, MMU and SHMEM to be set (and their dependencies). Necessary to have sysfs and udev functioning correctly in early boot, and for the correct functioning of systemd.
GENTOO_LINUX_PORTAGE y This causes options required by various Portage FEATURES to be set (at the time of writing, CGROUPS, NAMESPACES, IPC_NS, NET_NS and SYSVIPC). As its kconfig help text states, "[it] is highly recommended that you leave this enabled as these FEATURES are, or will soon be, enabled by default" (the FEATURES in question are cgroup, ipc-sandbox and network-sandbox).
GENTOO_LINUX_INIT_SCRIPT y This selects BINFMT_SCRIPT, which in turn enables kernel support for init scripts starting with #!. Needed for the kernel to run the init script in the initramfs (provided by genkernel).
GENTOO_LINUX_INIT_SYSTEMD y Switches on a group of options related to systemd, specifically (at the time of writing) AUTOFS4_FS, BLK_DEV_BSG, CGROUPS, CHECKPOINT_RESTORE, CRYPTO_HMAC, CRYPTO_SHA256, CRYPTO_USER_API_HASH, DEVPTS_MULTIPLE_INSTANCES, DMIID, EPOLL, FANOTIFY, FHANDLE, INOTIFY_USER, IPV6, NET, NET_NS, PROC_FS, SECCOMP, SECCOMP_FILTER, SIGNALFD, SYSFS, TIMERFD, TMPFS_POSIX_ACL, TMPFS_XATTR, ANON_INODES, BLOCK, EVENTFD, FSNOTIFY, INET and NLATTR. These are key settings for the systemd init system, which the initramfs init script eventually hands off to in the default case. Note that we leave this option set even when OpenRC booting is desired, for future flexibility.
SECCOMP y Enables the secure computation of untrusted bytecode. These are additional kernel configuration settings recommended by the Gentoo Wiki article on systemd, but not enabled by the GENTOO_LINUX_INIT_SYSTEMD option, above, in at least some earlier variants.[6]
DMIID y Exports DMI identification via sysfs to userspace.
TMPFS_POSIX_ACL y Enables POSIX access control lists for tmpfs.
UEVENT_HELPER_PATH "" This specifies a path to a uevent helper program to be forked by the kernel after every uevent. It is now recommended to leave this blank, to prevent excessive system load.[7]
AUDIT y Enables the kernel auditing infrastructure (required by AUDITSYSCALL, below).
AUDITSYSCALL y Enables the low-overhead kernel system-call auditing infrastructure. Now a systemd requirement.[8] It is generally useful so we enable even when OpenRC init is specified.
CMDLINE_BOOL y Activates the built-in kernel command line (specified by the CMDLINE option, see below. When stub-loading under UEFI, the kernel's command line must be hardcoded (since we're not firing it off from a EFI shell).[9] Getting this right is quite difficult, but buildkernel will set the appropriate command line options automatically for us.
CMDLINE See discussion following This is the command line string for the kernel.
INITRAMFS_SOURCE /boot/initramfs.cpio This string specifies the path to the initramfs to incorporate within the kernel. Because our main system partitions reside within LVM hosted over LUKS, we need to use an initramfs hosted initscript, to prompt for the LUKS keyfile passphrase, and then unlock and mount all the necessary logical volumes, before handing off control to the 'real' systemd or OpenRC init on the newly established root directory. Furthermore, because this is a UEFI system (and we intend to use secure boot later), the initramfs' cpio archive must be embedded in the kernel itself, not provided as a separate file on the boot partition, and it must be uncompressed (this isn't really an issue, since the enclosing kernel image is itself compressed).
INITRAMFS_COMPRESSION_xxx (where xxx is GZIP, BZIP2, LZMA, XZ or LZO) unset These options specify various compression types that can be applied to the initramfs within the kernel. We turn them all off.
INITRAMFS_COMPRESSION_NONE y This specifies that the initramfs cpio image should be used uncompressed.
CRYPTO_SERPENT y Enables use of the Serpent cipher algorithm via the kernel's cryptographic API. We have made use of the Serpent encryption and SHA-512 hash algorithms (and in previous versions of this guide, the Whirlpool hash algorithm) earlier when creating the LUKS partition (on which the LVM logical volumes hosting our /, /home and swap are located). We therefore activate these options so that dm-crypt (invoked via its cryptsetup interface by the initial, initramfs init script) can work with the LUKS partition successfully.
CRYPTO_WP512 y Enables use of the Whirlpool digest algorithm via the kernel's cryptographic API.
CRYPTO_SHA512 y Enables use of the SHA-512 digest algorithm via the kernel's cryptographic API.
BLK_DEV_DM y Enables device mapper support (so we can e.g., use /dev/mapper/...).
DM_CRYPT y Enables cryptographic targets within the device mapper (dm-crypt).
VFAT_FS y Enables VFAT filesystem support. We need to be able to access files on the EFI system partition during the early boot process (and this partition is FAT formatted).
PARTITION_ADVANCED y Enables (the display of options regarding) the use of partition types that are not native to Linux. We need to turn on GUID partition table (GPT) support for UEFI booting.
EFI_PARTITION y Enables support of EFI GPT partitioned disks.
EFI y Enables the kernel to use the EFI runtime services, such as EFI variable services. These three settings enable access to EFI variables via /sys/firmware/efi/efivars (this special efivarfs filesystem is automatically mounted under systemd and OpenRC). This is useful to modify the boot order, set the keys required for secure boot, and so on.
EFIVAR_FS y Enables the EFI variable filesystem.
EFI_VARS y Provides EFI variable support via sysfs.
EFI_STUB y Enables EFI stub-loader support. This enables the kernel to boot directly as an EFI executable, without requiring a separate bootloader.[10]
RTC_CLASS y Generic real-time-clock class support. A functional RTC is important for booting successfully. These settings should be present in any sane 'inherited' kernel .config, but we set them here to be doubly sure.
RTC_HCTOSYS y Sets the system time from the RTC, on startup and resume.
RTC_SYSTOHC y Sets the RTC time periodically based upon the NTP time exported from userspace (where available).
RTC_HCTOSYS_DEVICE rtc0 Specifies the identity of the RTC device used to set the system time.
RTC_INTF_SYSFS y Allow access to RTCs via sysfs interface.
RTC_INTF_PROC y Allow access to RTCs via proc interface.
RTC_INTF_DEV y Allow access to RTCs via dev interface.
RTC_DRV_CMOS y Provides support for PC-style RTCs.
SUSPEND y Enables support for suspending to RAM (a.k.a. 'sleep', 'ACPI S3' etc.) These options are not required for a bootable EFI system. However, many users will want them so they are enabled here. If you don't, you can override this by uncommenting the user_conform_config_file function in /etc/buildkernel.conf, and adding unset_kernel_config "SUSPEND" and/or unset_kernel_config "HIBERNATION", as you wish.
HIBERNATION y Enables support for suspending to disk (a.k.a. 'hibernation').
SYSFS_DEPRECATED unset This feature enables deprecated sysfs features required by some older userspace tools. We turn it off. This is unset, as recommended by the Gentoo Wiki article on systemd.[6] (We also unset when targeting OpenRC init.)
unset if plymouth in use This feature provides the 'penguins' display during early boot. It will be forced off by buildkernel if the graphical plymouth boot splash is in use (i.e., ${PLYMOUTHTHEME} is non-empty), to avoid conflicts / flashing.
If you are looking in the .config file, the option names above will all be prefixed with CONFIG_; so e.g., CONFIG_GENTOO_LINUX and not GENTOO_LINUX, etc.
The buildkernel script assumes you are starting from a 'sane' configuration (e.g., one taken from the Gentoo minimal-install system's /proc/config.gz, as we do in this tutorial). The conforming operation does not check for all necessary common options, such as support for the ext4 filesystem. Therefore, you cannot issue e.g., make allnoconfig followed by buildkernel, and expect the resulting kernel to boot - it will not.

Kernel Built-In Command Line Conformed by buildkernel

At this initial stage, the built-in kernel command line (CMDLINE) will be conformed as follows (your specific values will be different, depending on what is set in EFIPARTUUID, CRYPTPARTUUID, KEYMAP and INITSYSTEM):

root=/dev/ram0 crypt_root=/dev/disk/by-partuuid/8111286a-d24e-4ba2-b6af-d0650fab4130 dolvm real_root=/dev/mapper/vg1-root rootfstype=ext4 real_init=/usr/lib/systemd/systemd root_keydev=/dev/disk/by-partuuid/2498f874-ad8f-484e-8aba-81ac1c9665b6 root_key=luks-key.gpg real_resume=/dev/mapper/vg1-swap keymap=jp

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[11]); however, others are really targeted at the init script. The Linux kernel passes the init script (or program) any parameters it has not already processed as arguments,[12] and the init script can also read the full command line in any event, via /proc/cmdline.

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

Parameter Value in Example Value in buildkernel Consumed By Description
root /dev/ram0 ${CMDLINE_ROOT} kernel, init This specifies the location of the root filesystem to the kernel. It is set to point to the device path for the initramfs, since that's what the root will be, until the LUKS partition is unlocked, the LVM volumes activated, and switch_root is called.
crypt_root /dev/disk/by-partuuid/8111286a-d24e-4ba2-b6af-d0650fab4130 ${CRYPTPATHMAP} (which, unless explicitly overridden, will be /dev/disk/by-partuuid/${CRYPTPARTUUID}) init This tells the init script (provided by genkernel) which partition it should be attempting to unlock with cryptsetup. It is set to the partition UUID of the LUKS partition we created earlier.
dolvm N/A N/A init This instructs the init script (provided by genkernel) to attempt to initialize LVM volume groups at an appropriate point in the boot.
real_root /dev/mapper/vg1-root ${CMDLINE_REAL_ROOT} init This specifies the device path of the device holding the actual root directory (in our case, an LVM logical volume). The init script will switch to this once it is available, invoking systemd as it does so. Here, it is set to the device path of the root logical volume, from the vg1 volume group.
rootfstype ext4 ${CMDLINE_ROOTFSTYPE} kernel, init Specifies the filing system used for the (real) root partition; by default ext4 is used.
real_init /usr/lib/systemd/systemd ${CMDLINE_REAL_INIT} init The path of the 'real' init program to invoke, within the real root, once this is mounted. (By default it points to the systemd executable. Users who have set INITSYSTEM="openrc" in /etc/buildkernel.conf will have /sbin/init here instead.)
root_keydev /dev/disk/by-partuuid/2498f874-ad8f-484e-8aba-81ac1c9665b6 /dev/disk/by-partuuid/${KEYFILEPARTUUID} init This specifies the device path of the device on which the keyfile is located. Note that KEYFILEPARTUUID defaults to be the same as EFIPARTUUID, unless you override it explicitly in /etc/buildkernel.conf.
root_key luks-key.gpg ${LUKSKEYFILE} init This specifies the filename of the LUKS keyfile, held in the top-level directory of the root_keydev. If it has a .gpg extension (as here), the init script will treat it as being a gpg encrypted file, and prompt for a passphrase to unlock it (either textually at the console, or using the plymouth splash screen manager, if that has been specified).
real_resume /dev/mapper/vg1-swap ${CMDLINE_REAL_RESUME} init This specifies the device path (of a swap volume) to use for resuming (from a hibernation). We use the main LVM-based swap logical volume here. If no resume data has been written to the swap file, a normal boot will take place.
keymap jp ${KEYMAP} init Specifies which keymap to use in early boot. This is important because it will be used when you enter your passphrase, to unlock the gpg LUKS keyfile. Note that the appropriate name here is the one used by genkernel's init script, not that used by systemd/OpenRC etc. (which won't have been started up yet at the point this variable is referenced). See this earlier note for clarification of this point.
quiet unset set if ${PLYMOUTHTHEME} non-empty kernel, init Tells the kernel to suppress most log messages, and also affects some settings within genkernel's init script. It is currently unset, but will be set automatically when we specify a plymouth theme, later in the tutorial.
splash unset set if ${PLYMOUTHTHEME} non-empty init Instructs genkernel's init script to use the plymouth boot splash system. It is currently unset, but will be set automatically when we specify a plymouth theme, later in the tutorial.
udev.log-priority unset set to 3 if ${PLYMOUTHTHEME} non-empty, and using systemd boot init Prevents systemd from printing a textual version number during graphical boot.[13] It is currently unset, but will be set automatically when we specify a plymouth theme, later in the tutorial (if you have chosen systemd as your init system, earlier).

If you wish to override any of these, simply set the appropriate variable in /etc/genkernel.conf (of course, per the earlier instructions, you must at least set EFIPARTUUID and CRYPTPARTUUID, and possibly KEYMAP, to get a bootable kernel). You can also specify additional kernel command line options, in the variable ADDITIONALKERNELCMDS. For example, one common additional option you may wish to set would be to 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 ADDITIONALKERNELCMDS="root_trim=yes" in /etc/genkernel.conf (this is then passed on by genkernel's init script to cryptsetup). You can specify multiple additional options via this variable, if you need to; simply separate them with a space.

If you do turn TRIM-passthrough on like this, make sure you are comfortable with the possible information leakage it entails (specifically, that it can reveal some disk-usage patterns, allowing filesystem fingerprinting).[14]

genkernel Options Used by buildkernel, When Creating initramfs

The buildkernel script calls the Gentoo utility genkernel (from package sys-kernel/genkernel-next) to create the initramfs. It does this because genkernel provides some very useful features, for instance:

  • a significantly evolved init 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 (systemd or OpenRC) 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 plymouth boot splash manager, if specified.

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

When buildkernel invokes genkernel, it does so using the following command:

genkernel --install --no-mountboot --luks --lvm  --no-gpg --udev \
    --kernel-config="${TARGETCONFIG}" --busybox \
    --no-compress-initramfs --all-ramdisk-modules --firmware \
    ${PLYMOUTH_OPTS} initramfs

These options override anything specified in /etc/genkernel.conf, and have the following description and rationale for use:

genkernel Option / Action Description Reason Used
--install Install the initramfs into the /boot directory after completion. In our configuration, /boot is simply a normal directory, which we use as a convenient marshalling ground (for e.g., the generated initramfs), rather than the mountpoint of the boot partition (which it would be in an MBR-based system). Because it is just a regular directory, though, we have to use the --no-mountboot option to prevent genkernel from trying to mount it.
--no-mountboot Do not attempt to mount /boot automatically.
--luks Includes LUKS support from static binaries if they exist on the system. We have a LUKS encrypted partition that genkernel's init script must unlock, so this option is required.
--lvm Adds LVM support from static binaries, and compiles static LVM binaries if these do not exist. We have configured root, home and swap on LVM logical volumes (hosted on the LUKS partition), and we need the init script to mount these prior to a switch_root, so this option is needed.
--no-gpg Excludes gpg from the initramfs. This option looks a bit surprising at first glance, as we have used gpg to encrypt our LUKS keyfile. We use it because it prevents genkernel from copying the v2.x gpg binary, and its many library dependencies, into the initramfs, since (as explained above) the v2.x gpg will not work properly there, given its dependency on a correctly configured pinentry service. This option does not prevent genkernel's init script from attempting to use gpg, however, and buildkernel copies our static version of v1.x gpg into the initramfs once genkernel has built it.
--udev Adds udev support to static binaries if they exist in the system. This is necessary for correct device management (and therefore, the boot process).
--kernel-config="${TARGETCONFIG}" Specifies the location of the .config file used for the kernel build. This currently simply points to /usr/src/linux/.config. Although we don't require genkernel to do any kernel compilation for us, we nevertheless set it here for safety.
--busybox Includes a busybox binary in the initramfs. This provides a number of standard Linux tools in a single executable file. Using this ensures that genkernel's init script has access to the necessary external programs it needs in order to run (such as echo, cat etc.). Once buildkernel has run, you can look in /boot/initramfs/bin for example - many of the programs therein will simply be links to the busybox executable.
--no-compress-initramfs Specifies that the generated initramfs should not be compressed. When using UEFI, we must use an uncompressed initramfs, hence this option. It is mirrored by the INITRAMFS_COMPRESSION_NONE kernel parameter, discussed earlier.
--all-ramdisk-modules Copies all kernel modules to the initramfs. This is done for safety, because if a necessary module is missing at boot, your system may not start up properly. In fact, even without this option, genkernel will pull what it regards as 'necessary' kernel modules into the initramfs, which will account for a good proportion of them ^-^. Once you have a properly booting system, nothing prevents you from manually disabling unnecessary modules in the make menuconfig step of buildkernel, and, if you like, turning all others into built-ins, so this option does not imply that you are stuck with a 'bloated' kernel image forever. (Should you wish to override buildkernel's setting of this option, modify the ADDITIONALGENKERNELOPTS variable in /etc/buildkernel.conf (most users will not need to do this).)
--firmware Copies the firmware (from the default directory of /lib/firmware into the initramfs. Many devices will not start up properly without firmware, and so we copy these files over so they are available during early boot. If you have chosen to deblob your kernel, this option is a no-op. (Should you wish to override buildkernel's setting of this option, modify the ADDITIONALGENKERNELOPTS variable in /etc/buildkernel.conf (most users will not need to do this).)
${PLYMOUTH_OPTS} Used to specify the --plymouth and --plymouth-theme=${PLYMOUTHTHEME}, iff PLYMOUTHTHEME has been defined to a non-blank value (in /etc/buildkernel.conf). These options respectively copy support for plymouth, and the specified plymouth boot theme, into the initramfs. Subsequently, if the splash kernel command line parameter is set (see above), plymouth will be activated at boot (by genkernel's init script). The plymouth system can be used to provide a graphical boot screen, replacing the usual textual console. This will automatically be turned on by buildkernel if you uncomment the PLYMOUTHTHEME variable in /etc/genkernel.conf. We will turn this on later; however, at the current point in the tutorial, it should be left commented out.
initramfs Instructs genkernel to build only the initramfs. buildkernel does its own kernel compilation, so the only the initramfs construction ability of genkernel is needed.

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

Building the New Kernel (Using buildkernel)

So, without further ado, let's build the kernel.

The kernel build system is separate from the main Gentoo emerge process, so the showem utility cannot be used here.

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

(chroot) livecd / #buildkernel --ask --verbose
... significant amounts of output suppressed in what follows ...
* There is no config file; use current (linux-<...>-gentoo) config (y/n)? press y
* Updating old config using make olddefconfig
* Secure-bootable EFI kernel build script
* Will build linux-<...>-gentoo; running kernel is linux-<...>-gentoo
* Do you want to proceed (y/n)? press y
* The EFI boot partition is not mounted.
* (If using a USB key to boot from, please ensure it is inserted)
* Would you like to mount it now (y/n)? press y
* Proceeding - entering /usr/src/linux...
* Setting Gentoo flags for systemd...
* Setting additional recommended settings for systemd...
* Setting kernel command line = <...>
* Setting up initramfs location and type...
* Ensuring Serpent, Whirlpool and SHA-512 are included...
* Ensuring VFAT file system support included...
* Ensuring device mapper and crypt target support are included...
* Ensuring kernel makes config available under /proc...
* Setting options needed for EFI / stub loading...
* Enabling real-time-clock support...
* Enabling suspend and hibernation support...
* Ensuring deprecated sysfs support turned off...
* Would you like to modify the configuration using the editor (y/n)? press n
* OK, autoconforming configuration using make olddefconfig instead...
* Now build a kernel with this new configuration (y/n)? press y
* Do a 'make clean' prior to build (y/n)? press y; this is good hygiene on a first build, can enter n on subsequent runs
* Cleaning up...
* Building linux-<...>-gentoo (pass 1 - dummy initramfs)...
* Installing modules...
* Installing firmware...
* Creating any necessary external modules (e.g., VirtualBox)...
* Creating initramfs (uncompressed)...
* Unpacking initramfs cpio archive to /boot/initramfs...
* Copying static gpg program into initramfs...
* Copying contents of /etc/modprobe.d directory into initramfs...
* Deleting old initramfs cpio archive, and repacking...
* Building linux-<...>-gentoo (pass 2, to include real initramfs)...
* Installing boot files to /boot; for reference only...
* buildkernel: Warning: No key / certificate present in /root/.buildkernel/db.key
* buildkernel: Warning: This kernel will only boot in unsecured EFI mode!
* Backing up old bootfile in case of failure...
* Backing up old config in case of failure...
* Copying EFI-bootable kernel linux-<...>-gentoo to EFI directory...
* Copying .config file to EFI directory (for reference only)...
* buildkernel: Warning: Your system is not currently booted under EFI
* buildkernel: Warning: As such, unable to set EFI stub kernel in boot list
* buildkernel: Warning: Manually select device using BIOS, to boot this kernel
* buildkernel: Warning: If unsuccessful, try using /EFI/Microsoft/Boot/bootmgfw.efi instead
* Syncing filesystem...
* Completed: would you like to unmount the EFI boot USB key now (y/n)? press y
* Unmounted, it is now safe to remove the EFI boot USB key
* All done!
... significant amounts of output suppressed in the above ...

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

As the warnings at the end of the run indicate, because you are currently not booted using EFI, buildkernel cannot access the EFI boot list persistent variable. However, on most machines, you can use the BIOS GUI to specify that it should run an EFI executable from a USB key (and we'll do this shortly). Once the machine is booted in EFI, subsequent runs of buildkernel will ensure that an entry for any newly built kernel is present on the EFI boot list, and at the top of the boot order.
The default Gentoo kernel configuration from the minimal-install system, on which this first build is based, has a lot of kernel modules specified for build. This is to ensure that the resulting system will work on a wide range of hardware. There's no need to take any action yet, but as discussed later on, feel free to pare back the number of unnecessary modules created - this will reduce your build time, and decrease your attack surface for exploits. You can easily switch modules off using the standard make menuconfig editor - simply press y when buildkernel prompts you
* Would you like to modify the configuration using the editor (y/n)?
A brief introduction to using the make menuconfig system can be found here and here. However, there is no need to perform any kernel configuration editing at this point in the tutorial.
If you do choose to use the graphical kernel configuration editor when running over ssh, be aware that you may get some pretty strange characters showing up on the display, if the locale on your helper machine (which sshd will try to import) is not present on the target (in the host, not the chroot, since the former is the context the sshd is running).[15] You can always get around this by opening another chroot directly on the target machine (i.e. using the target's keyboard), and issuing your buildkernel command from there. The issue should not be present once the system is fully configured.
On a minor hygiene point, note that buildkernel performs the kernel build as root. To be fair, this is the same approach taken by the default manual configuration in the Gentoo handbook, so I have left it this way for simplicity.
The files produced by the build differ a little from the layout you may be used to from an MBR-based boot system. For example, only the stub-loadable bootable kernel image and its configuration file are copied to the system partition on the USB boot key. A file is produced, but it is left in the /boot directory (which, as has already been mentioned, in our case is just a regular directory, used as a marshalling yard, with no significance during the UEFI boot process itself). To be precise:
  • the kernel used for boot is placed in /boot/efi/EFI/Boot/bootx64.efi (this path is configurable), and a copy is kept at /boot/vmlinuz-<version>-gentoo; the kernel is an x86 boot executable bzImage - it behaves like an EFI executable (as it has been built with EFI stub loader support), but it is still a regular kernel that we could load with a normal bootloader outside of EFI, if we chose);[16][9]
  • the configuration file for that kernel is at /boot/efi/EFI/Boot/config (for reference only, it isn't needed to boot), and a copy is at /boot/config-<version>-gentoo; when booted a live version is available at /proc/config.gz;
  • the system map is at /boot/<version>-gentoo (and /usr/src/linux/; also, when booted, a live version is available at /proc/kallsyms;
  • for UEFI (secure) booting, the initramfs is encapsulated inside the kernel, but:
    • a copy of the initial (pre-modification) initramfs is kept at /boot/initramfs-genkernel-x86_64-<version>-gentoo;
    • a copy of the final, post-modification initramfs is kept at /boot/initramfs.cpio, and
    • an unpacked copy of the latter is maintained at /boot/initramfs, for ease of reference.
Note that the /boot/efi path is a mountpoint for the EFI system partition on the boot USB key, and this should generally be kept unmounted when not building (buildkernel, as above, will automatically mount it for you, and offer to unmount at the end of the build). You can of course manually mount the EFI system partition if desired.
If a previous kernel and config are present in the /boot/efi/EFI/Boot directory when buildkernel is run, they will be renamed with an .old suffix (so, to /boot/efi/EFI/Boot/boox64.efi.old and /boot/efi/EFI/Boot/config.old, respectively). We haven't booted off this new kernel yet, but once we have, this allows us to revert back to the previous version, in case changes made have caused a boot problem. The EFI partition is simply fat32 and so can be accessed from most machines, including Windows boxes. Simply rename or remove the problematic kernel and config, rename the /boot/efi/EFI/Boot/boox64.efi.old to /boot/efi/EFI/Boot/boox64.efi (and rename the config too, if you wish), and reboot. Of course, this is simply a hint for use in the future - you don't need to do anything like that at this point in the tutorial!
In the default kernel command line produced by buildkernel, TRIM has not been activated for the LUKS partition (this is a feature which can prevent performance degradation when using solid-state drives). If you wish to enable it, see these instructions above.
When you upgrade your portage tree (discussed later), if you find that a new version of sys-kernel/gentoo-sources has become available, then you can very easily use buildkernel to upgrade your kernel (the instructions below will work off your running kernel's configuration as a basis to start with). Simply issue:
root #eselect kernel list

to view the available kernel versions, followed by:

root #eselect kernel set N

to choose the new one (remember to substitute the appropriate number for N here, generally it will be the number for the last item in the list just displayed), followed by:

root #buildkernel --verbose

which will run the process in non-interactive mode. See the buildkernel manpage for more details. Alternatively, you could use the genup script, which will handle updating all packages and your kernel automatically (we will introduce this utility later in the tutorial (systemd track, OpenRC track)).

However, there is no action you need to take at this point.

To run buildkernel in non-interactive mode, simply omit the --ask option. For example, to achieve the same effect as the interactive command above, you could instead have issued:
(chroot) livecd / #buildkernel --verbose --clean --unmount-at-end

See the buildkernel manpage for more details.

Even if you have previously chosen to target OpenRC (rather than the default systemd) as your init system earlier, you will still see buildkernel output regarding setting systemd kernel options etc. This is by design, since these settings do not prevent an OpenRC boot, but do provide future flexibility.

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".


< Previous Home Next >