Project

General

Profile

Secure Boot Tutorial

Disclaimers

This tutorial is provided as a demonstration of some of the available technologies for building a secure system using Critical Link's Agilex 5 platforms. The result of the tutorial is not a fully secure system and is not intended to satisfy any regulatory compliance such as the CRA. There is no one-size-fits-all security solution, and as discussed in #Caveats and Additional Considerations below, there are many factors you may need to consider for your product.

Please also consider that Critical Link are not security specialists. This tutorial may provide a useful starting point for your product, but you should review and be sure you understand what is presented here.

References

Architecture

This tutorial creates a trusted boot chain from power on through the Linux root filesystem. The boot flow an authentication stages to accomplish this are:

  • SDM boot ROM loads and authenticates the JIC from QSPI.
    • The JIC contains the first stage FPGA bitstream and the SPL, which is the first stage bootloader for the Arm cores.
  • The SPL loads U-Boot, the U-Boot device tree, and the Arm Trusted Firmware (ATF, also referred to as TF-A) from a FIT image on the SD card's FAT partition and authenticates them via Altera's VAB driver. Boot does not continue if this authentication fails.
    • The VAB driver checks that the image hash matches what's recorded in its certificate and then sends the certificate to the SDM for authentication.
  • U-Boot loads the main U-Boot script from the SD card's FAT partition and executes it if it passes VAB authentication.
    • Note that this step and the following U-Boot script executions all happen automatically. If you're familiar with U-Boot, you may have seen its built-in shell; in this tutorial, U-Boot shell access is disabled to prevent a user with physical access from modifying the U-Boot environment or running additional U-Boot shell commands/scripts.
    • U-Boot environment loading from persistent storage is also disabled in this tutorial; the environment is completely compiled into U-Boot and amended by known scripts, all of which are signed.
  • The main U-Boot script loads a helper script for dm-verity and (on MitySOM Standard) the PLL configuration script from the SD card's FAT partition and executes them if they pass VAB authentication.
    • The dm-verity script includes the root hash for the root filesystem. Dm-verity does not inherently handle authentication, only integrity via a hash tree, so by storing the root hash in an authenticated script, the root filesystem and its hashes cannot be tampered with without causing the script authentication to fail.
  • The main U-Boot script loads the Linux kernel and device tree from a FIT image on the SD card's FAT partition and authenticates them via Altera's VAB driver. Boot does not continue if this authentication fails.
    • The main U-Boot script passes the dm-verity root hash directly to the kernel via its command line.
  • Linux boots and loads the root filesystem, and dm-verity validates as each filesystem block is accessed that the block's hash is correct.
    • Because dm-verity checks hashes on a per block basis as needed, the system may not immediately detect corruption/tampering to the root filesystem and may still boot into userspace even with a corrupt filesystem. However, at the time such corrupt data is accessed, dm-verity will detect it and (by default) issue an I/O error to prevent the data from being read/executed. The behavior of dm-verity when it encounters corruption and/or errors can be configured via additional kernel command line options (not used in this tutorial).

Once the system is booted, you can log in with the following credentials (by default; the section below on patching Yocto describes how you can change these):

  • Username: user
  • Password: changethispassword!

Root login is disabled.

Additional Considerations

Additional Hardening

Note that this tutorial does not produce a fully hardened system. It merely ensures that the data from a fresh install does not change. Some additional areas to consider are:

  • HPS debug via JTAG. You may notice that the FPGA build produces a critical warning regarding this:
    Critical Warning (20444): This design is signed, and the HPS Debug Access Port
    (DAP) has been enabled. No integrity claim could be made with HPS DAP enabled.
    After usage, this generated bitstream should be properly disposed and
    preferably, its signing key should be cancelled to guarantee no open access for
    the silicon. The options to enable HPS DAP will have different behavior in
    future releases.
    
    • Secure configuration for HPS debug is described in Altera's security documentation.
  • Kernel module signing. An attacker with elevated privilege could load a malicious kernel module.
  • Mandatory Access Control such as SELinux. Several MAC options are discussed in the Linux Security Module documentation
  • Network firewalls.
  • Restrictions on other physical interfaces such as USB and PCIe.
  • Disabling unused kernel features and removing unneeded software to reduce attack surface area. For example, if your application doesn't rely on /dev/mem to, e.g., access FPGA cores, it could be disabled in the kernel; or if your production environment doesn't require SSH access, you may consider removing SSH from the root filesystem entirely.
  • Persistent writable filesystem access. This tutorial does not provide non-volatile storage. If your application needs this for, e.g., logging, you'll need to consider where to place such data and how to protect its integrity and privacy.
  • Etc.

The above is not an exhaustive list. Appropriate measures depend on your particular product application, environment, and risks.

Build Flow and Additional Capabilities

Much of the build flow for this tutorial is dictated by key handling and how signed components are packaged together. For this tutorial, these aspects are mainly aligned with Altera's VAB tutorial, but Altera's tooling and the Agilex 5 are flexible in terms of key management (for example supporting HSMs) and also support many additional features not demonstrated here, and there's also opportunity for customizing how software components are packaged and how everything is integrated into a build environment. See Altera's security documentation for additional information.

Usage Notes for this Tutorial

  • Some utilities will appear not to be present for the non-root user created in this tutorial because /sbin is not in its $PATH. Many of these utilities are still usable if you invoke them with their absolute path or add /sbin to $PATH.
  • The non-root user created in this tutorial does not have permission to shut down or reboot the system gracefully. This is "okay" for the tutorial because the root filesystem is read-only and meant for development; however, in your production system, especially if you have non-volatile, writable storage which may become corrupted in the event of a power loss, you may wish to resolve this.

Prerequisites

Ensure your build system meets the Yocto requirements.

Additionally, you'll need:

  • guestfish (e.g., libguestfs-tools package on Ubuntu)
  • cmake (e.g., cmake package on Ubuntu)
    • At the time of writing, this must be version 3.24 or higher. For Ubuntu, this is available via the default package on 24.04 or later.
  • Quartus Prime Pro 26.1

Finally, you'll need an Arm toolchain for compiling U-Boot:

wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz

Set up the Build Environment

Many steps below refer to files and locations relative to your top-level working directory. Navigate to this location in a terminal and assign it to a shell variable as follows for convenience:

topdir=$(readlink -f "$(pwd)")

Several steps below set similar shell variables which are then referenced by subsequent steps, so it's recommended to run through this entire build flow in a single terminal.

You'll also need to set the following environment variables, substituting your own install paths for Quartus and the Arm toolchain:

export QUARTUS_ROOTDIR=<your-quartus-install-path>/quartus
export PATH="<your-arm-toolchain-install-path>/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu/bin:$QUARTUS_ROOTDIR/bin:$QUARTUS_ROOTDIR/linux64:$QUARTUS_ROOTDIR/../qsys/bin:$PATH"
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-

Obtain Sources

Yocto

Clone the layers:

cd "$topdir" 
git clone -b scarthgap https://git.yoctoproject.org/poky
cd poky
git clone -b scarthgap https://github.com/openembedded/meta-openembedded.git
git clone -b scarthgap https://gitlab.syr.criticallink.com/critical-link/yocto/meta-mitysom.git

Patch meta-mitysom

Make all of the following meta-mitysom patches within "$topdir/poky/meta-mitysom".

Note: To facilitate quick development, these changes are made directly to Critical Link's meta-mitysom layer. In a production setting, you may wish to make these changes in your own layer instead by creating a .bbappend file for the kernel and your own custom local.conf and image recipe.

Download the following kernel patches attached here and place them into recipes-kernel/linux/files:

  • verity.cfg
  • 0001-dm-init-ensure-device-probing-has-finished-in-dm-mod.patch

Add the following to the bottom of recipes-kernel/linux/linux-cl-socfpga-lts_6.18.2.bb in order to enable the new patches:

diff --git a/recipes-kernel/linux/linux-cl-socfpga-lts_6.18.2.bb b/recipes-kernel/linux/linux-cl-socfpga-lts_6.18.2.bb
index 5414322..d4fd1d4 100644
--- a/recipes-kernel/linux/linux-cl-socfpga-lts_6.18.2.bb
+++ b/recipes-kernel/linux/linux-cl-socfpga-lts_6.18.2.bb
@@ -12,3 +12,5 @@ LINUX_VERSION_SUFFIX ?= "-lts" 
 do_kernel_configcheck[noexec] = "1" 

 require recipes-kernel/linux/linux-cl-socfpga.inc
+
+SRC_URI += "file://verity.cfg file://0001-dm-init-ensure-device-probing-has-finished-in-dm-mod.patch" 

Remove the EXTRA_IMAGE_FEATURES assignment from conf/local.conf.sample:

diff --git a/conf/local.conf.sample b/conf/local.conf.sample
index abfdad7..fa5cf04 100644
--- a/conf/local.conf.sample
+++ b/conf/local.conf.sample
@@ -144,7 +144,6 @@ PACKAGE_CLASSES ?= "package_rpm" 
 # There are other application targets that can be used here too, see
 # meta/classes/image.bbclass and meta/classes/core-image.bbclass for more details.
 # We default to enabling the debugging tweaks.
-EXTRA_IMAGE_FEATURES ?= "debug-tweaks" 

 #
 # Additional image features

Make the following changes to recipes/images/mitysom-image-base.bb as shown below:

  • Replace debug-tweaks in IMAGE_FEATURES with read-only-rootfs. You can read about what these do in the Yocto documentation.
  • At the bottom of the file, add configuration for dm-verity, ext4 formatting, and a new non-root user.
diff --git a/recipes/images/mitysom-image-base.bb b/recipes/images/mitysom-image-base.bb
index 672ee6c..49a4e20 100644
--- a/recipes/images/mitysom-image-base.bb
+++ b/recipes/images/mitysom-image-base.bb
@@ -2,7 +2,7 @@ DESCRIPTION = "MitySOM Base Image" 

 include recipes-core/images/core-image-minimal.bb

-IMAGE_FEATURES += "debug-tweaks package-management ssh-server-openssh" 
+IMAGE_FEATURES += "read-only-rootfs package-management ssh-server-openssh" 
 PACKAGE_CLASSES = "package_rpm " 
 IMAGE_INSTALL:append = "\
        canutils\
@@ -45,3 +45,13 @@ IMAGE_INSTALL:append:mity-a5e = " si5338-cfg" 

 # libdaq and libfpga
 IMAGE_INSTALL:append:mity-a5e = " libdaq libfpga" 
+
+IMAGE_FSTYPES += "verity" 
+VERITY_SALT = "cd2c697fbd5a329902bce928fbef13fdf00c6fa7e7cb567fbc56a12c4207349f" 
+inherit image_types_verity
+
+EXTRA_IMAGECMD:ext4 += "-b 4096" 
+
+# Password: changethispassword!
+inherit extrausers
+EXTRA_USERS_PARAMS = "useradd -p '\$5\$DK47Cu6DlT6fwfD9\$KF.tAnaQFVTOiPZsDiLJCmoY3nMZJY5WySE1KNX2ByA' user;" 

Note: As noted in the patch comment, the new user's password will be changethispassword!. You should change this by replacing the string after useradd -p with one generated from your chosen password, as described in the Yocto documentation. You may also change the username (user in the patch above) if you wish.

FPGA Design

Clone one of the following reference designs depending on your platform (MitySOM Standard/Mini or MitySBC, respectively):

cd "$topdir" 

# One of the following:
git clone -b pro_26.1_stable git://support.criticallink.com/home/git/mitysom-a5e-ref.git
git clone -b pro_26.1_stable git://support.criticallink.com/home/git/mitysbc-a5-ref.git

Navigate to one of the projects for your device and assign it to a shell variable as follows for convenience:

# For example, mitysom-a5e-ref/A5ED-B44-1X4-MRI/mitysom-a5e-ref-base
cd <platform>/<variant>/<project>
fpgadir=$(readlink -f "$(pwd)")

Note: This tutorial does not support device tree overlays, which limits which reference projects may be used. It's recommended to use the -base project for your device.

Patch the U-Boot Script

Make the following changes to scripts/boot.cmd within "$fpgadir":

diff --git a/A5ED-B44-1X4-MRI/mitysom-a5e-mini-ref-base/scripts/boot.cmd b/A5ED-B44-1X4-MRI/mitysom-a5e-mini-ref-base/scripts/boot.cmd
index d4ea849..8a41cc6 100644
--- a/A5ED-B44-1X4-MRI/mitysom-a5e-mini-ref-base/scripts/boot.cmd
+++ b/A5ED-B44-1X4-MRI/mitysom-a5e-mini-ref-base/scripts/boot.cmd
@@ -3,7 +3,7 @@ mw 0x10d120e4 0 # Assert fabric reset (HPS gp_out)
 # A missing or bad RBF leaves the fabric unconfigured, and the first driver to
 # touch it takes the kernel down. Bail out of the script instead of booting, so
 # the failure shows up here with the SDM error still on screen.
-if ext2load mmc 0:2 ${loadaddr} /lib/firmware/a5e.core.rbf && fpga load 0 ${loadaddr} ${filesize}; then
+if load mmc 0:1 ${loadaddr} a5e.core.rbf && fpga load 0 ${loadaddr} ${filesize}; then
        bridge enable
        mw 0x10d120e4 1 # Deassert fabric reset (HPS gp_out)
 else
@@ -12,9 +12,9 @@ else
        exit 1
 fi
 gpio clear 3; sleep 1; gpio set 3
-ext2load mmc 0:2 ${kernel_addr_r} /boot/Image
-ext2load mmc 0:2 ${fdt_addr_r} /boot/socfpga_agilex5_mitysom_mini_devkit.dtb
-setenv bootargs console=ttyS0,115200 root=${mmcroot} rw rootwait;
-booti ${kernel_addr_r} - ${fdt_addr_r}
+load mmc 0:1 $loadaddr verity-params.scr; if vab $loadaddr $filesize; then source $loadaddr; else panic 'Failed to authenticate verity params'; fi
+load mmc 0:1 $loadaddr kernel.itb
+setenv bootargs console=ttyS0,115200 root=/dev/dm-0 ro rootwait dm-mod.waitfor=$mmcroot dm-mod.create="\"verity-root,,,ro,0 $verity_data_sectors verity $verity_hash_type $mmcroot $mmcroot $verity_data_block_size $verity_hash_block_size $verity_data_blocks $verity_data_blocks $verity_hash_algorithm $verity_root_hash $verity_salt\"" 
+bootm $loadaddr

Note: The above diff is an example for MitySOM Mini; the removed lines and surrounding context will change slightly depending on platform. Functionally, the required changes are:

  • Change where the core RBF is loaded from. In Critical Link's standard reference designs, the core RBF is placed in the root filesystem. To simplify the build flow for this tutorial, here it's placed in the FAT partition instead.
  • Change where the kernel and device tree are loaded from. In Critical Link's standard reference designs, the kernel and device tree are placed in the root filesystem. To facilitate signing and simplify the build flow for this tutorial, here they're packaged into a FIT image in the FAT partition instead.
  • Load an additional helper U-Boot script to populate parameters for the dm-verity kernel driver.
  • Update the kernel command line to pass parameters to the dm-verity kernel driver.
  • Update the boot command to boot from the FIT image rather than separate kernel and device tree.

Additionally, for the MitySOM Standard only, the PLL configuration U-Boot script must be signed as well, which requires the following additional change to scripts/boot.cmd:

diff --git a/A5ED-B64-144-SRI/mitysom-a5e-ref-base/scripts/boot.cmd b/A5ED-B64-144-SRI/mitysom-a5e-ref-base/scripts/boot.cmd
index 23a7780..58741ae 100644
--- a/A5ED-B64-144-SRI/mitysom-a5e-ref-base/scripts/boot.cmd
+++ b/A5ED-B64-144-SRI/mitysom-a5e-ref-base/scripts/boot.cmd
@@ -4,7 +4,8 @@ mw 0x10d120e4 0 # Assert fabric reset (HPS gp_out)
 # config_pll.scr leaves the design mis-clocked. source reports only that the
 # script loaded and ran, not that the transfers landed, so config_pll.scr
 # leaves its own verdict in pll_programmed and that is what decides here.
-if fatload mmc 0:1 ${loadaddr} config_pll.scr && source ${loadaddr} && test "${pll_programmed}" = "1"; then
+load mmc 0:1 $loadaddr config_pll.scr; if vab $loadaddr $filesize; then source $loadaddr; else panic 'Failed to authenticate PLL configuration'; fi
+if test "${pll_programmed}" = "1"; then
        echo "PLL configured" 
 else
        echo "*** PLL configuration failed, not continuing the boot ***" 

Patch U-Boot

First, clone U-Boot via the FPGA Makefile:

cd "$fpgadir" 
make software/bootloader/u-boot-socfpga

Next, make the following U-Boot patches within "$fpgadir/software/bootloader/u-boot-socfpga".

Update arch/arm/dts/socfpga_agilex5_mity_a5e-u-boot.dtsi to allow the build system to create a FIT image with the Linux kernel and device tree:

diff --git a/arch/arm/dts/socfpga_agilex5_mity_a5e-u-boot.dtsi b/arch/arm/dts/socfpga_agilex5_mity_a5e-u-boot.dtsi
index 6ee9f84a053..6d9eef599c7 100644
--- a/arch/arm/dts/socfpga_agilex5_mity_a5e-u-boot.dtsi
+++ b/arch/arm/dts/socfpga_agilex5_mity_a5e-u-boot.dtsi
@@ -21,10 +21,6 @@
        };
 };

-&binman {
-       /delete-node/ kernel;
-};
-
 &mmc {
        /* SD card default speed (DS) and UHS-I SDR12 mode timing configuration */
        cdns,phy-dqs-timing-delay-sd-ds = <0x00780000>;

Update either configs/socfpga_mitysom_a5e_defconfig or configs/socfpga_mitysbc_a5e_defconfig, depending on your platform (MitySOM Standard/Mini or MitySBC, respectively):

diff --git a/configs/socfpga_mitysom_a5e_defconfig b/configs/socfpga_mitysom_a5e_defconfig
index a848cc2c5fc..a9f2d24080d 100644
--- a/configs/socfpga_mitysom_a5e_defconfig
+++ b/configs/socfpga_mitysom_a5e_defconfig
@@ -15,6 +15,7 @@ CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
 CONFIG_SPL_BSS_START_ADDR=0x9ff00000
 CONFIG_SPL_BSS_MAX_SIZE=0x100000
 CONFIG_SYS_LOAD_ADDR=0x82000000
+CONFIG_SOCFPGA_SECURE_VAB_AUTH=y
 CONFIG_TARGET_SOCFPGA_MITYSOM_A5E=y
 CONFIG_IDENT_STRING="socfpga_agilex5" 
 CONFIG_SPL_FS_FAT=y
@@ -27,8 +28,8 @@ CONFIG_SPL_FIT_SIGNATURE=y
 CONFIG_SPL_LOAD_FIT=y
 CONFIG_SPL_LOAD_FIT_ADDRESS=0x82000000
 CONFIG_QSPI_BOOT=y
-CONFIG_BOOTDELAY=5
-CONFIG_BOOTCOMMAND="load mmc 0:1 ${scriptaddr} ${scriptfile} && source ${scriptaddr}" 
+CONFIG_BOOTDELAY=-2
+CONFIG_BOOTCOMMAND="load mmc 0:1 ${scriptaddr} ${scriptfile}; if vab $scriptaddr $filesize; then source ${scriptaddr}; else panic 'Failed to authenticate boot script'; fi" 
 CONFIG_CYCLIC_MAX_CPU_TIME_US=1000
 CONFIG_MISC_INIT_R=y
 CONFIG_BLOBLIST=y
@@ -75,8 +76,6 @@ CONFIG_CMD_TIMER=y
 # CONFIG_ISO_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 CONFIG_OF_LIST="" 
-CONFIG_ENV_IS_IN_FAT=y
-CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" 
 CONFIG_BOOTFILE="Image" 
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_WARN=y

Note: The above diff is an example for MitySOM Standard/Mini; the surrounding context will change slightly for MitySBC. Functionally, the required changes are:

  • Enable Altera's VAB driver to allow authenticating signed images.
  • Update the boot delay to disallow manual shell access in U-Boot.
  • Update the boot command to authenticate the main U-Boot script.
  • Disallow modifying the U-Boot environment via a file in the FAT partition.

Certificate Tool

cd "$topdir" 
git clone https://github.com/altera-fpga/libfcs.git

Build the Image

Yocto

Run the following commands to build the root filesystem.

Note: The build itself (the bitbake command) may take up to several hours depending on your build system, and it will heavily load the system such that it may be difficult to use for other tasks at the same time.

cd "$topdir/poky" 
. oe-init-build-env
cp ../meta-mitysom/conf/bblayers.conf.sample conf/bblayers.conf
cp ../meta-mitysom/conf/local.conf.sample conf/local.conf
bitbake mitysom-image-base

Keys

Generate development keys with the following commands based on Altera's VAB tutorial. You may wish to consult Altera's security documentation for more information or if you have different key handling requirements or infrastructure.

cd "$fpgadir" 
mkdir keys
cd keys
mkdir privatekeys
mkdir publickeys
mkdir qky

quartus_sign --family=agilex5 --operation=make_private_pem --curve=secp384r1 --no_passphrase privatekeys/private_root0.pem
quartus_sign --family=agilex5 --operation=make_public_pem privatekeys/private_root0.pem publickeys/public_root0.pem
quartus_sign --family=agilex5 --operation=make_root publickeys/public_root0.pem qky/root0.qky

quartus_sign --family=agilex5 --operation=make_private_pem --curve=secp384r1 --no_passphrase privatekeys/private_fpga0.pem
quartus_sign --family=agilex5 --operation=make_public_pem privatekeys/private_fpga0.pem publickeys/public_fpga0.pem
quartus_sign --family=agilex5 --operation=append_key --previous_pem=privatekeys/private_root0.pem --previous_qky=qky/root0.qky --permission=14 --cancel=1 --input_pem=publickeys/public_fpga0.pem qky/fpga0_cancel1.qky

quartus_sign --family=agilex5 --operation=make_private_pem --curve=secp384r1 --no_passphrase privatekeys/private_software0.pem
quartus_sign --family=agilex5 --operation=make_public_pem privatekeys/private_software0.pem publickeys/public_software0.pem
quartus_sign --family=agilex5 --operation=append_key --previous_pem=privatekeys/private_root0.pem --previous_qky=qky/root0.qky --permission=0x80 --cancel=3 --input_pem=publickeys/public_software0.pem qky/software0_cancel3.qky

Certificate Tool

Run the following commands to build Altera's certificate tool:

cd "$topdir/libfcs" 
ARCH= CROSS_COMPILE= cmake -S . -B build -DBUILD_FCS_PREPARE=ON
cmake --build build

FPGA Design

Run the following commands to enable authentication in the FPGA design and then compile the design into an SOF:

cd "$fpgadir" 
echo "set_global_assignment -name QKY_FILE keys/qky/fpga0_cancel1.qky" >> a5e.qsf
make quartus_compile

U-Boot Prerequisites

The U-Boot build system is used to package signed software components into FIT images. Run the following commands to build and sign the ATF, to sign the Linux kernel and device tree built by Yocto, and to place the signed components into the U-Boot build area.

Note: The name of the device tree binary assigned to the dtb shell variable depends on the platform you're building for:

  • MitySOM Standard: socfpga_agilex5_mitysom_devkit.dtb
  • MitySOM Mini: socfpga_agilex5_mitysom_mini_devkit.dtb
  • MitySBC: socfpga_agilex5_mitysbc_devkit.dtb

As an example, the steps below use the MitySOM Mini device tree.

cd "$fpgadir" 
make atf

mkdir certs
cd certs
ln -sr "$topdir/libfcs/build/tools/fcs_prepare/fcs_prepare" .

./fcs_prepare --hps_cert "$topdir/poky/build/tmp/deploy/images/mity-a5e/Image" 
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_Image.ccert
./fcs_prepare --finish ./signed_cert_Image.ccert --imagefile "$topdir/poky/build/tmp/deploy/images/mity-a5e/Image" 
mv hps_image_signed.vab ../software/bootloader/u-boot-socfpga/signed-Image
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

# Set for your platform as described above
dtb=socfpga_agilex5_mitysom_mini_devkit.dtb

./fcs_prepare --hps_cert "$topdir/poky/build/tmp/deploy/images/mity-a5e/$dtb" 
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_linux.dtb.ccert
./fcs_prepare --finish ./signed_cert_linux.dtb.ccert --imagefile "$topdir/poky/build/tmp/deploy/images/mity-a5e/$dtb" 
mv hps_image_signed.vab ../software/bootloader/u-boot-socfpga/signed-linux.dtb
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

./fcs_prepare --hps_cert ../software/bootloader/arm-trusted-firmware/build/agilex5/release/bl31.bin
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_bl31.bin.ccert
./fcs_prepare --finish ./signed_cert_bl31.bin.ccert --imagefile ../software/bootloader/arm-trusted-firmware/build/agilex5/release/bl31.bin
mv hps_image_signed.vab ../software/bootloader/u-boot-socfpga/signed-bl31.bin
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

U-Boot

Run the following commands to build U-Boot. This will build the SPL and U-Boot but will ultimately report errors and fail; this is because the full build relies on having already compiled and signed the U-Boot binaries, and Altera's signing process isn't part of the automated build system.

cd "$fpgadir" 
make bootloader

Run the following commands to sign the U-Boot binaries and finally package them into FIT images with the ATF and kernel components. This time, this build should not report any errors.

cd "$fpgadir/certs" 

./fcs_prepare --hps_cert ../software/bootloader/u-boot-socfpga/u-boot.dtb
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_u-boot_pad.dtb.ccert
./fcs_prepare --finish ./signed_cert_u-boot_pad.dtb.ccert --imagefile ../software/bootloader/u-boot-socfpga/u-boot.dtb
mv hps_image_signed.vab ../software/bootloader/u-boot-socfpga/signed-u-boot.dtb
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

./fcs_prepare --hps_cert ../software/bootloader/u-boot-socfpga/u-boot-nodtb.bin
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_u-boot-nodtb.bin.ccert
./fcs_prepare --finish ./signed_cert_u-boot-nodtb.bin.ccert --imagefile ../software/bootloader/u-boot-socfpga/u-boot-nodtb.bin
mv hps_image_signed.vab ../software/bootloader/u-boot-socfpga/signed-u-boot-nodtb.bin
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

cd ..
make bootloader

JIC and RBF

Run the following commands to create and sign the final FPGA programming files. This performs the following:

  • Converts the SOF into first and second stage (hps and core, respectively) RBFs and merges the SPL with the first stage. Note that the SPL itself is unsigned at this stage because the RBF containing it will be signed instead.
  • Signs both RBFs.
  • Converts the first stage RBF into a JIC file for programming into flash.
  • Produces a signed helper RBF which is used to program the JIC into flash. This helper bitstream is normally handled invisibly when flashing the JIC, but when authentication is enabled, the helper must also be signed.

Note: The device string assigned to the device shell variable depends on the platform and variant you're building for. The command given below automatically detects this from the QSF file.

cd "$fpgadir" 
device=$(awk '/\<DEVICE\>/ {print $4}' a5e.qsf)
quartus_pfg -c -o hps_path=software/bootloader/u-boot-socfpga/spl/u-boot-spl-dtb.hex -o hps=on -o sign_later=on output_files/a5e.sof output_files/a5e_unsigned.rbf
quartus_sign --family=agilex5 --operation=sign --qky=keys/qky/fpga0_cancel1.qky --pem=keys/privatekeys/private_fpga0.pem output_files/a5e_unsigned.hps.rbf output_files/a5e.hps.rbf
quartus_sign --family=agilex5 --operation=sign --qky=keys/qky/fpga0_cancel1.qky --pem=keys/privatekeys/private_fpga0.pem output_files/a5e_unsigned.core.rbf output_files/a5e.core.rbf
quartus_pfg -c -o device=MT25QU256 -o mode=ASX4 -o flash_loader=$device output_files/a5e.hps.rbf output_files/a5e.hps.jic
quartus_pfg --helper_image -o helper_device=$device -o subtype=QSPI -o signing=ON -o qky_file=keys/qky/fpga0_cancel1.qky -o pem_file=keys/privatekeys/private_fpga0.pem output_files/signed_qspi_helper.rbf

U-Boot Scripts

Run the following commands to compile and sign the main U-Boot script and the helper dm-verity U-Boot script. Note that the source for the dm-verity U-Boot script is post-processed from information from the Yocto build, where the dm-verity image itself was created.

cd "$fpgadir" 

make UBOOT_SCRIPT_BIN=scripts/boot_unsigned.scr scripts/boot_unsigned.scr
gawk 'match($0, "(.+)=(.+)", groups) {print "setenv " tolower(groups[1]) " " groups[2]}' "$topdir/poky/build/tmp/deploy/images/mity-a5e/mitysom-image-base-mity-a5e.rootfs.ext4.verity-params" | tr -d '\r' > scripts/verity-params.cmd
make UBOOT_SCRIPT_SRC=scripts/verity-params.cmd UBOOT_SCRIPT_BIN=scripts/verity-params_unsigned.scr scripts/verity-params_unsigned.scr

cd certs

./fcs_prepare --hps_cert ../scripts/boot_unsigned.scr
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_boot.scr.ccert
./fcs_prepare --finish ./signed_cert_boot.scr.ccert --imagefile ../scripts/boot_unsigned.scr
mv hps_image_signed.vab ../scripts/boot.scr
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

./fcs_prepare --hps_cert ../scripts/verity-params_unsigned.scr
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_verity-params.scr.ccert
./fcs_prepare --finish ./signed_cert_verity-params.scr.ccert --imagefile ../scripts/verity-params_unsigned.scr
mv hps_image_signed.vab ../scripts/verity-params.scr
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

Additionally, for the MitySOM Standard only, run the following commands to build and sign the PLL configuration U-Boot script as well.

cd "$fpgadir" 

make PLL_SCRIPT_BIN=scripts/config_pll_unsigned.scr scripts/config_pll_unsigned.scr

cd certs

./fcs_prepare --hps_cert ../scripts/config_pll_unsigned.scr
quartus_sign --family=agilex5 --operation=SIGN --qky=../keys/qky/software0_cancel3.qky --pem=../keys/privatekeys/private_software0.pem ./unsigned_cert-spec15.ccert ./signed_cert_config_pll.scr.ccert
./fcs_prepare --finish ./signed_cert_config_pll.scr.ccert --imagefile ../scripts/config_pll_unsigned.scr
mv hps_image_signed.vab ../scripts/config_pll.scr
rm -f unsigned_cert.ccert unsigned_cert-spec15.ccert

SD Card Image

Run one of the following commands to build the final SD card image, depending on your platform (MitySOM Mini/MitySBC or MitySOM Standard, respectively).

Note: Before running these commands, replace scripts/make_sd.sh in "$fpgadir" with the copy of make_sd.sh attached here.

cd "$fpgadir" 

# MitySOM Mini or MitySBC
scripts/make_sd.sh -o sd.img -d Agilex5 -f software/bootloader/u-boot-socfpga/u-boot.itb -f scripts/boot.scr -f scripts/verity-params.scr -f output_files/a5e.core.rbf -f software/bootloader/u-boot-socfpga/kernel.itb -v "$topdir/poky/build/tmp/deploy/images/mity-a5e/mitysom-image-base-mity-a5e.rootfs.ext4.verity" 

# MitySOM Standard
scripts/make_sd.sh -o sd.img -d Agilex5 -f software/bootloader/u-boot-socfpga/u-boot.itb -f scripts/boot.scr -f scripts/config_pll.scr -f scripts/verity-params.scr -f output_files/a5e.core.rbf -f software/bootloader/u-boot-socfpga/kernel.itb -v "$topdir/poky/build/tmp/deploy/images/mity-a5e/mitysom-image-base-mity-a5e.rootfs.ext4.verity" 

Flash and Boot the Image

Flash the SD card using your preferred method, e.g. Balena Etcher, dd, etc. For example, to use dd, where /dev/sdX is a placeholder for your SD card's actual device path, run the following command (which may require sudo depending on your user permissions):

dd of=/dev/sdX if=sd.img conv=fsync

Install the flashed SD card and power on the device. Depending on what, if any, JIC was previously flashed, the device may start booting. You can ignore this and continue on with the instructions below.

For development and testing, program the key to the device non-destructively with the following command. The device will forget the key upon poweroff.

In order to permanently program the key to the device, add the --non_volatile_key flag.

cd "$fpgadir" 
quartus_pgm -m jtag -o "piv;keys/qky/root0.qky@2" 

Then, flash the JIC with the following commands:

cd "$fpgadir" 
quartus_pgm -m jtag -o "p;output_files/signed_qspi_helper.rbf" 
quartus_pgm -m jtag -o "pv;output_files/a5e.hps.jic" 

Press the config button to reset the device and load the newly flashed JIC and boot the device.