Skip to main content
The systemd-boot unified extensible firmware interface (UEFI) boot manager provides options to control the boot flow and loads the user-selected boot loader. The configuration files, kernel images, initrd images, and other EFI images must reside on the EFI partition. To run the Qualcomm Linux kernel directly as EFI images, build them with CONFIG_EFI_STUB. The systemd-boot supports two configurations:
  • Type1: The Type1 configuration uses boot loader specification (BLS) description files. You can find these files in the /loader/entries/ directory on the EFI.
  • Type2: The Type2 configuration uses unified kernel images (UKI). These images combine the kernel, initrd, and kernel command-line into a single EFI executable. Type2 offers better security because the UKI contains all the necessary information for the device to boot. Signing a UKI image secures all included entities. If UEFI secure boot is enabled, the system only loads signed images, making signing a requirement.
For more details, see systemd-boot. Note To use a secure boot enabled device, signing is required.

UKI

UKI is a combination of a UEFI boot stub program, a Qualcomm Linux kernel image, an initrd, and other resources in a single UEFI portable executable (PE) file. The UEFI boot stub looks for various resources for the kernel invocation inside the UEFI PE binary. This allows combining various resources inside a single UKI image, which may then be signed using sbsign. Qualcomm Linux uses sbsign to sign PE files, while non-PE files such as DTB are signed using OpenSSL. For more details about UKI, see unified_kernel_image. The following table shows the uki.efi content:
Components of uki.efi fileContents
Initrd = Init ramdiskinitramfs-rootfs-image-rb3gen2-core-kit.cpio.gz
Linux = Kernel ImageImage (as systemd-boot expects uncompressed kernel)
Uname = Kernel Release6.18.12
Efi-arch = Architectureaa64
Stub = System-boot efi stublinuxx64.efi.stub
OS-release = OS-release
  • ID = qcom-distro
  • Name = “Qualcomm Linux reference distribution”
  • VERSION = “2.0”
  • VERSION_ID = 2.0
  • PRETTY_NAME = “Qualcomm Linux reference distribution”

Image recipes

meta-qcom/recipes-kernel/images contains the following recipes:
  • esp-qcom-image.bb generates a VFAT image, efi.bin, which contains uki.efi and systemd-boot.
The meta-qcom/classes-recipe/image_types_qcom.bbclass class invokes the esp-qcom-image.

EFI image

The EFI image, efi.bin, is a VFAT file system image stored in the EFI partition of the flash. This VFAT file system contains the images necessary for the UEFI to load and transfer execution control to systemd-boot. To transfer execution control to the systemd-boot manager, UEFI mounts efi.bin, loads bootaa64.efi, and executes it. The systemd-boot manager parses the loader.conf, loads the kernel image, and transfers the control to it. For more information about the structure of EFI, see EFI system partition. The following is the sample structure of efi.bin from Qualcomm Linux. It contains systemd-boot bootaa64.efi and Qualcomm Linux kernel vmlinuz-<version> under the /ostree/poky-<sha256-sum>directory.
Figure: ``efi.bin`` file generated with OSTree support

Figure: efi.bin file generated with OSTree support

Signing

Secure boot is a feature in the UEFI standard, but it’s not enabled by default in Qualcomm Linux. When enabled, secure boot adds a layer of protection to the preboot process by maintaining a cryptographically signed list of binaries that are run at device bootup, if successfully authenticated. This ensures that the device’s boot firmware and Linux OS boot components, such as the boot manager, kernel, and initramfs, haven’t been tampered with. UEFI secure boot uses a digital signature to validate the authenticity and integrity of the binary code that it loads. The UEFI secure variables store all the keys. Achieving UEFI secure boot involves using the platform key (PK), key exchange key (KEK), database (DB), and forbidden signatures database (DBX). Using secure boot requires the keys PK, KEK, and DB. While multiple KEK, DB, and DBX are allowed, only one PK is allowed. Enabling UEFI secure boot requires registering the PK in the system. Qualcomm recommends provisioning PK at the last step of the secure boot enabling process. For more information about how Qualcomm has implemented the UEFI secure boot feature, see Secure boot.

Host tool signing_tool.py to sign Linux OS images generated by Qualcomm Linux builds

Enabling UEFI secure boot requires signing the EFI and DTB images. Use the signing_tool.py host signing tool to streamline this process. This command-line Python script runs on a Linux host computer (Ubuntu 20.04 or later versions). It automates the signing of EFI and DTB images in two separate operations. The host signing tool is available for download on GitHub. The host signing tool runs on a Linux machine with Python3 installed. It can sign either the EFI image or the DTB image in a single operation. To sign both the EFI and DTB images, you must invoke the tool twice with different inputs.
Figure: Linux machine with OpenSSL and sbsign

Figure: Linux machine with OpenSSL and sbsign

The host tool expects unsigned EFI or DTB files, along with certificates and keys, as input. After invoking, the tool unpacks the unsigned image, signs the available items using the provided key and certificate, and then repacks the images, replacing the unsigned version with the signed one.

Prerequisites

To run this tool, install the following on the Linux host computer:
  • OpenSSL, sbsign, and mtools utilities
  • Python3
  • pip, subprocess, shlex, socket, glob, and shutil Python modules

Configure the host signing tool

You must configure the host signing tool before starting the operation. The host tool requires providing the necessary information in a config.ini configuration file. The tool reads this file and signs the image accordingly. The following code snippet shows the variables in the configuration file:

config.ini file

[common]
# Section - 1: Common Selection
# Select operation: sign_image
operation = sign_image
# Possible values for file_path are 1. remote or 2. local
file_path = local
# If file_path == remote
local_machine_private_key_path = /usr2/<user_name_for_machine>/.ssh/id_rsa

# Section - 2: operation == sign_image related common selection
# Possible values for image_type are 1. efi or 2. dtb
image_type = efi
# This option is required if operation == sign_image & image_type == efi
loader_conf_timeout = 20

# Below options are required to fetch file from remote Linux machine in the same network (that is if file_path == remote)

# This option is useful if operation == sign_image & image_type == efi
[efi_config]
efi_remote_hostname = <remotemachine_ip_or_hostname_where_efi.bin_available>
efi_remote_username = <username_on_remote_machine_where_efi.bin_available>
efi_remote_filepath = <full_path_of_efi.bin_file_on_remotemachine>

# This option is useful if operation == sign_image. Both image_type requires this option
[keys_config]
keys_remote_hostname = <remotemachine_ip_or_hostname_where_keys_available>
keys_remote_username = <username_on_remote_machine_where_keys_available>
keys_remote_filepath = <full_path_of_keys_directory_on_remotemachine>

# This option is useful if operation == sign_image & image_type == dtb
[dtb_config]
dtb_remote_hostname = <remotemachine_ip_or_hostname_where_dtb_available>
dtb_remote_username = <username_on_remote_machine_where_dtb_available>
dtb_remote_filepath = <full_path_of_dtb_on_remotemachine>
Table : Variables in config.ini file
Variable in config.iniValuesDescription
operationsign_imageUse this configuration to select signing of the image.
image_typeefi/dtbIf operation == sign_image, use this configuration to select efi or dtb to sign separately.
file_pathlocal/remote
  • local: Keys and efi.bin/dtb.bin are present in the same path as the script.
  • remote: Copy efi.bin/dtb.bin and the keys from a remote Linux machine to the current path.
local_machine_private_key_path<path of id_rsa file in localmachine>This file establishes an SSH connection with a remote machine if file_path =remote.
loader_conf_timeout<timeout in seconds>The systemd-boot wait time to let you choose to authenticate the binaries. This option is required to sign efi.bin.
efi/keys/dtb_remote_hostname<ip or hostname of the remote Linuxmachine>If file_path = remote, then the host tool selects the host name of the remote machine to copy the efi/keys/dtb file from the remote machine using SCP.
efi/keys/dtb_remote_username<username_on_remote_machine>If file_path = remote, then the host tool selects the user name of the remote machine to copy the efi/keys/dtb file from the remote machine using SCP, provided the username is created on the remote machine.
efi/keys/dtb_remote_filepath<full_path_of_file_on_remote_machine>If file_path = remote, then the host tool selects the path of a efi/key/dtb file on the remote machine to copy that file from the remote machine using SCP.
To configure the host signing tool using the config.ini file, do the following:
  1. Set the operation variable to specify which operation must be performed. The option is sign_image.
  2. If you select operation == sign_image, specify which image to sign by setting the image_typevariable. The options are either efi or dtb.
  3. Indicate the location of the unsigned EFI and DTB image, keys, and certificates using the file_pathvariable.
    • If you select local in the configuration file, copy the EFI and DTB image, keys, and certificate files manually to the local working directory:
      1. Create an unsigned_binaries directory in the same path as the script, and then copy the efi.bin and dtb.bin image into that directory.
      2. Create a keys directory in the same path as the script and then copy the db.auth, db.crt, db.key, KEK.auth, and PK.auth files into that directory.
    • If you want the script to copy the required files automatically from a remote Linux machine on the same network, select remote in the configuration file. In the configuration file, provide information for the following variables:
      • local_machine_private_key_path (mandatory)
      • [efi_config] section (if operation is sign_image and if image_type is efi)
      • [keys_config] section (if operation is sign_image)
      • [dtb_config] section (if operation is sign_image and if image_type is dtb) Note The script supports copying from another Linux machine over SCP within the same network.
  4. When image_type is set to efi in the configuration file, update the loader_conf_timeout variable.
  5. If you missed any configuration information, the script runs and prompts you for the missing details through the command line.

Run host signing tool

  1. After completing the code build process and obtaining the unsigned efi.bin and dtb.bin images, run the host signing tool.
  2. Store the host signing tool files (signing_tool.py and config.ini) on a Linux machine. Ensure that both the files are in the same working directory.
  3. Set up the host signing tool according to the configuration instructions.
  4. Run the following command to launch the host tool from the command line: $python3 signing_tool.pyThe host signing tool displays your selections and operational commands on the screen. It also displays errors in the command line. After the tool completes its process, it creates a directory called signed_binaries in the same working directory. The signed efi.bin or dtb.bin image is stored in the directory. The tool deletes other user-created directories after signing.
  5. Follow this process twice, once for efi.bin and once for dtb.bin. After each signing operation, delete the signed_binaries directory before starting a new operation.

Host signing tool workflow

The following figure shows the workflow of the host signing tool:
Figure: Host signing tool workflow

Figure: Host signing tool workflow

  • The host tool requires the efi.bin and dtb.bin paths (absolute path or network path).
    • efi.bin with OSTree support contains vmlinuz-x.y.z (Qualcomm Linux kernel image) and bootaa64.efi (boot loader image).
    • dtb.bin contains qclinux_fit.img.
  • The host tool requires the path of certificate and key (absolute path or network path) to sign the images.
  • The host tool mounts efi.bin and dtb.bin on the FAT partition, which provides the following directory structure and follows its separate signing process: The directory structure of efi.bin:
    Figure: efi.bin

    Figure: efi.bin

    Figure: efi.bin The directory structure of efi.bin with OSTree support:
    Figure: efi.bin with OSTree support

    Figure: efi.bin with OSTree support

    Figure: efi.bin with OSTree support The directory structure of dtb.bin:
    Figure: dtb.bin

    Figure: dtb.bin

  • After signing the images, the host tool copies the .auth files to the /loader/keys/authkeys directory for both efi.bin and dtb.bin.
  • The host tool configures the wait time in the systemd-boot loader configuration. This wait time stops the kernel loading and allows you to review and select the systemd-boot menu options. The loader.conffile must be available in an updated efi.bin file. Note The signing process isn’t followed for the dtb.bin file.
    • The host tool configures /loader/loader.conf.
    • The syntax for loader.conf is timeout x, where x = timeout in seconds.
  • After the image is signed, the host tool unmounts the efi.bin/dtb.bin from the FAT partition. Store the signed efi.bin and dtb.bin on the host computer on the similar path as the host tool in the signed_binaries directory.
  • The following is the directory structure for signed efi.bin and dtb.bin:
    Figure: Directory structures of efi.bin and dtb.bin files

    Figure: Directory structures of efi.bin and dtb.bin files

efi.bin signing process

  • The host tool uses the sbsign utility to sign the uki.efi or vmlinuz.x.y.z and bootaa64.efi images separately.
  • sbsign requires certificate and key for the signing process. Verify the following syntax where dsk1.key is key, dsk1.crt is certificate, and the output filename is the same as the input file:
    sbsign --key <key file> --cert <cert file> <efi file> <output file name>
    
    Examples:
    sbsign –key dsk1.key –cert dsk1.crt bootaa64.efi bootaa64.efi
    
    sbsign --key dsk1.key --cert dsk1.crt uki.efi uki.efi
    
    sbsign --key dsk1.key --cert dsk1.crt vmlinuz.x.y.z vmlinuz.x.y.z
    

dtb.bin signing process

  • The host tool requires the path of the dtb.bin file.
  • The host tool requires the path of key and certificate (absolute path or network path) to sign the images.
  • UEFI secure boot requires PE format files for verification. Non-PE files, such as dtb, can’t be signed using sbsign as this signing tool requires PE format files as input.
  • The host tool uses the openssl utility to sign the dtb file. Verify the following syntax, where dsk1.keyis key and dsk1.crt is certificate:
       openssl cms -sign -inkey <.key file> -signer <.crt file> -binary -in <img file> --out <output .sig file> -outform DER
    
    Example:
       openssl cms -sign -inkey dsk1.key -signer dsk1.crt -binary -in <foo.img file> --out <foo.sig file > -outform DER
    
    This command adds the signature for the DTB file in a separate file (foo.sig) and doesn’t modify the original file (foo.img). Hence, the host tool must keep both the files where the *.sig file is used during the UEFI secure boot verification.

Multi-DTB support

Qualcomm supports multiple Qualcomm development kits based on the same hardware SoC. For example, the QCS6490 development kit variants include the RB3 Gen 2 Core development kit and the RB3 Gen 2 Vision development kit. Each Qualcomm development kit variant has its own DTB in the kernel. During bootup, UEFI selects the appropriate DTB based on the specific Qualcomm development kit variant. To facilitate this, use multi-DTB flattened image tree (FIT) image as follows:

Generate a multi-DTB FIT image

Qualcomm Linux supports generating a FIT‑based multi‑DTB image for platforms where multiple DTBs are required for a single hardware SoC. This allows UEFI to select the appropriate DTB at boot time based on the detected hardware variant. For platforms that support FIT images, multiple DTBs are listed using the KERNEL_DEVICETREE variable in the machine configuration file. For example, the following snippet from meta-qcom/conf/machine/rb3gen2-core-kit.conf defines two DTBs for the RB3 Gen 2 Core development kit:
KERNEL_DEVICETREE ?= " \
                      qcom/qcs6490-rb3gen2.dtb \
                      qcom/qcs6490-rb3gen2-industrial-mezzanine.dtbo \
                      qcom/qcs6490-rb3gen2-vision-mezzanine.dtbo \
                      "
These DTBs are combined into a single FIT image during the build process.
  1. Add DTB compatible strings: Each DTB included in a FIT image must have an associated compatible string. These compatible strings are used by UEFI to select the correct DTB at boot time.
    • The compatible strings are defined in meta-qcom/conf/machine/include/fit-dtb-compatible.inc.
    • The values must be derived by referencing the DTB metadata available at: https://github.com/qualcomm-linux/qcom-dtb-metadata For the RB3 Gen 2 Core Kit example, add the following entries:
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2] = " \
    qcom,qcs5430-iot \
    qcom,qcs6490-iot \
    "
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-industrial-mezzanine] = " \
    qcom,qcs5430-iot-subtype9 \
    qcom,qcs6490-iot-subtype9 \
    "
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2+qcs6490-rb3gen2-vision-mezzanine] = " \
    qcom,qcs5430-iot-subtype2 \
    qcom,qcs6490-iot-subtype2 \
 "
  1. Enable multi-DTB packaging: To package the generated FIT image as a VFAT image (dtb.bin), set the following variable in meta-qcom/classes-recipe/image_types_qcom.bbclass:
    QCOM_DTB_DEFAULT ?= "multi-dtb"
    
    When this variable is set to multi-dtb, the build system packages the combined FIT image containing all DTBs listed in KERNEL_DEVICETREE into dtb.bin.

Development kits without FIT image support

Some platforms do not support FIT‑based DTB selection. This includes certain ride development kits, such as:
  • qcs9100-ride-sx
  • qcs8300-ride-sx
For these kits, only a single DTB can be packaged into dtb.bin. For example, the following snippet from meta-qcom/conf/machine/qcs9100-ride-sx.conf lists multiple DTBs:
KERNEL_DEVICETREE ?= " \
                     qcom/qcs9100-ride.dtb \
                     qcom/qcs9100-ride-r3.dtb \
                     qcom/sa8775p-ride.dtb \
                     qcom/sa8775p-ride-r3.dtb \
                     "
Since FIT‑based DTB selection isn’t supported for this kit, a single DTB must be chosen as the default. Set the QCOM_DTB_DEFAULT variable in the same machine configuration file as follows:
QCOM_DTB_DEFAULT ?= "qcs9100-ride-r3"
With this setting, only qcs9100-ride-r3.dtb is packaged into the VFAT image (dtb.bin) and used during boot.

DTB partition

  • The generated VFAT image named dtb.bin contains the combined DTB image. A dedicated partition named dtb is present on the Qualcomm development kits. Flash the dtb.bin on this partition.
  • UEFI parses the combined DTB present in the dtb partition and selects a matching DTB for the hardware.

Next steps