Skip to content

Building and installing GRUB

At the time of writing (August 2024) EFI and legacy changes are on different branches in the same repository and neither builds on top of the other in terms of commit history. Either clone the repository in full and switch between branches to build both versions or use shallow clones as shown below.

If your system isn't setup for development, you might want to use trenchboot-sdk Docker container. It can be run like this to perform a build:

docker run --rm -it -v "$PWD:$PWD" -w "$PWD" \
           -e HOME="$PWD/home" \
           --user "$(id -u):$(id -g)" \
           ghcr.io/trenchboot/trenchboot-sdk:master /bin/bash

Setting $HOME is necessary because GRUB will try to use ccache which fails if there is no $HOME.

EFI version

Build

# check out the sources
git clone --branch grub-sl-2.12-v9 --depth 1 \
          https://github.com/TrenchBoot/grub.git
cd grub

# make the checkout buildable
./bootstrap

# configure
mkdir build
cd build
../configure --with-platform=efi --target=x86_64

# build
make -j$(nproc)

Setup

# also from inside build/ directory
echo 'configfile ${cmdpath}/grub.cfg' > embedded.cfg
./grub-mkimage -O x86_64-efi -o grubx64.efi -p / -c embedded.cfg -d grub-core \
               all_video boot btrfs cat chain configfile echo efifwsetup \
               efinet ext2 fat font gfxmenu gfxterm gzio halt hfsplus iso9660 \
               jpeg loadenv loopback lvm mdraid09 mdraid1x minicmd normal \
               part_apple part_msdos part_gpt password_pbkdf2 png reboot \
               regexp search search_fs_uuid search_fs_file search_label serial \
               sleep syslinuxcfg test tftp video xfs backtrace http linux usb \
               usbserial_common usbserial_pl2303 usbserial_ftdi \
               usbserial_usbdebug keylayouts at_keyboard multiboot2

The first command creates an embedded config which sources grub.cfg in the directory in which GRUB image is located.

The second command produces the UEFI GRUB image named grubx64.efi. The image along with a suitable grub.cfg needs to be installed on a EFI System Partition (ESP) and pointed at so firmware can find it (via Setup UI or a tool like efibootmgr). It can also be started manually from a UEFI shell for a test.

Legacy version

Build

# check out the sources
git clone --branch tb-2.12-57-v1 --depth 1 https://github.com/TrenchBoot/grub.git
cd grub

# make the checkout buildable
./bootstrap

# configure
mkdir build
cd build
../configure --prefix=$PWD/local-install --target=i386

# build
make -j$(nproc)

Setup

Installation for legacy boot from inside of a container requires access to device files and mounting of boot directory. For this reason the container needs to be started as root (inside of the container, don't prepend sudo to the command) and be a privileged one:

docker run --rm -it -v "$PWD:$PWD" -w "$PWD" \
           --user root:root --privileged \
           ghcr.io/trenchboot/trenchboot-sdk:master /bin/bash
# if done in a container
cd build
mount BOOT-PARTITION PATH-TO-BOOT

# also from inside build/ directory
make install
local-install/sbin/grub-install --target=i386-pc \
                                --boot-directory PATH-TO-BOOT \
                                DISK-DEVICE

In the second command above replace:

  • BOOT-PARTITION with the /dev/... file corresponding to the boot partition
  • PATH-TO-BOOT with the path to where the boot partition is mounted (grub/ directory will be created there)
  • DISK-DEVICE with the /dev/... file corresponding to the drive (not a partition) on which GRUB is to be installed (double check before running the command to avoid accidentally overwriting some working GRUB setup)

If you get a weird error like error: disk `hostdisk//dev/sda1' not found., it means that GRUB doesn't have write permissions for device files.

Configuration

There is a new GRUB command, which instructs GRUB to initiate a Secure Launch when booting an OS, called slaunch. This is an example of a GRUB menuentry that would be used to do a Secure Launch of the Linux kernel:

menuentry 'Linux with Secure Launch 6.8.0-rc3-master-v8' --unrestricted {
        load_video
        insmod gzio
        insmod part_gpt
        insmod xfs
        search --no-floppy --fs-uuid --set=root bba24662-776e-4396-9b1e-9ee5606d79b8
        slaunch
        slaunch_module /dce-for-a-given-platform
        linux /vmlinuz-6.8.0-rc3-master-v8 root=/dev/mapper/root ro crashkernel=auto resume=/dev/mapper/swap rd.lvm.lv=my/root rd.lvm.lv=my/swap rhgb console=ttyS0,115200n8 console=tty0 LANG=en_US.UTF-8
        initrd /initrd-6.8.0-rc3-master-v8.img
}

Note also the optional slaunch_module command which tells GRUB to load an external SINIT ACM for this configuration. In general, server platforms contain an existing SINIT ACM in the firmware and this line can be omitted. For client platforms, an external ACM is required to be supplied. The SINIT ACM for a given platform can be acquired from Intel.

Validation

There are a number of ways to validate that a successful Secure Launch was done. Using serial logging or dmesg, search for the string "TXT" after booting:

[root@my-system ~]# dmesg | grep TXT
[    0.000094] slaunch: Intel TXT setup complete
[    2.617782] slaunch: TXT AP startup vector address updated

That indicates a successful Secure Launch boot. Another way is to display the Secure Launch TPM event log. This can be done as follows after booting (note only the tail end of the log is shown here for brevity, the rest is snippped):

[root@my-system ~]# cat /sys/kernel/security/slaunch/eventlog | hexdump -C
...
[snip]
...
00000490  a3 e2 de 6b fb 1f 79 ef  c9 5e de bf ef bf 92 fb  |...k..y..^......|
000004a0  fc b2 89 ea 64 c1 d7 d2  99 fb 49 e6 12 00 00 00  |....d.....I.....|
000004b0  4d 65 61 73 75 72 65 64  20 53 4c 52 20 54 61 62  |Measured SLR Tab|
000004c0  6c 65 12 00 00 00 02 05  00 00 01 00 00 00 0b 00  |le..............|
000004d0  cd 64 bf e1 70 96 4c ce  53 2f 2f 7a 85 85 fe f0  |.d..p.L.S//z....|
000004e0  05 22 40 f6 62 18 bf 94  2a 2f 3d 14 b1 25 60 31  |."@.b...*/=..%`1|
000004f0  18 00 00 00 4d 65 61 73  75 72 65 64 20 62 6f 6f  |....Measured boo|
00000500  74 20 70 61 72 61 6d 65  74 65 72 73 11 00 00 00  |t parameters....|
00000510  02 05 00 00 01 00 00 00  0b 00 18 7d 80 8f 2c ca  |...........}..,.|
00000520  03 bf a7 54 ff 1d 16 6d  49 51 25 f6 bc ec 46 dc  |...T...mIQ%...F.|
00000530  23 a7 39 a8 db 96 28 8e  d4 1d 16 00 00 00 4d 65  |#.9...(.......Me|
00000540  61 73 75 72 65 64 20 4b  65 72 6e 65 6c 20 69 6e  |asured Kernel in|
00000550  69 74 72 64 12 00 00 00  02 05 00 00 01 00 00 00  |itrd............|
00000560  0b 00 11 02 09 6f c6 1d  78 11 87 1a 93 49 10 2f  |.....o..x....I./|
00000570  14 69 dd 45 b8 c3 03 e7  e6 80 6e 21 9b 87 47 90  |.i.E......n!..G.|
00000580  d6 27 1c 00 00 00 4d 65  61 73 75 72 65 64 20 4b  |.'....Measured K|
00000590  65 72 6e 65 6c 20 63 6f  6d 6d 61 6e 64 20 6c 69  |ernel command li|
000005a0  6e 65 12 00 00 00 02 05  00 00 01 00 00 00 0b 00  |ne..............|
000005b0  b2 29 3f 3c da 25 4a 78  61 be 76 91 3e 06 f9 5d  |.)?<.%Jxa.v.>..]|
000005c0  7d 6b 0d 75 6b 30 74 0c  26 b2 76 96 1e 60 19 a5  |}k.uk0t.&.v..`..|
000005d0  18 00 00 00 4d 65 61 73  75 72 65 64 20 55 45 46  |....Measured UEF|
000005e0  49 20 6d 65 6d 6f 72 79  20 6d 61 70 11 00 00 00  |I memory map....|
000005f0  04 05 00 00 01 00 00 00  0b 00 00 00 00 00 00 00  |................|
00000600  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00008000

The final measurements starting with the description "Measured..." are put in the log by the Secure Launch kernel code if everything went fine. During a poweroff, restart or a kexec of another kernel, the following log lines will indicate that TXT was properly disabled and SMX mode was left:

[  696.907094] slaunch: TXT clear secrets bit and unlock memory complete.
[  696.914827] slaunch: TXT SEXIT complete.

If tpm2_eventlog is installed, it can be used parse the log into a readable form:

[root@my-system ~]# tpm2_eventlog /sys/kernel/security/slaunch/eventlog
...