Signed AHAB Image Generation for U-Boot and Kernel#

In this notebook, we’ll demonstrate a proof-of-concept on how to:

  • Generate signed AHAB U-Boot and kernel images

  • Replace the unsigned AHAB U-Boot in the wic file

  • Replace the unsigned kernel image with a signed version

  • Boot up the system with authenticated images

1. Prerequisites#

  • SPSDK is needed with examples extension. pip install spsdk[examples] (Please refer to the installation documentation.)

  • Download Embedded Linux for your i.MX board

  • This demo was tested with i.MX93 (both QSB and EVK) and Linux 6.6.52-2.2.0

1.1 Images preparation#

  • to create resulting binary containing AHAB containers, we need to prepare the binaries

  • in this section we reproduce the process which is done by the imx-mkimage tool as flash singleboot binary

  • Obtain all the necessary binaries and put them into inputs directory

1.2 U-Boot#

Read the U-Boot documentation to understand the U-Boot build process In order to enable secure boot and secure boot itself, U-Boot must be built with AHAB support. CONFIG_AHAB_BOOT=y If you want to use the nxpele over fastboot, also multiplexing of console output to fastboot must be enabled by setting CONFIG_CONSOLE_MUX=y.

As building a (signed) bootloader image for i.MX93 is already explained in examples/ahab/imx93/imx93_signed_ahab_uboot.ipynb we skip the details here.

1.3 Requirements#

  • lpddr4 firmware files

  • u-boot binary (u-boot SPL and u-boot) built with AHAB support.

  • bl31.bin binary (ARM Trusted Firmware)

  • ELE firmware binary AHAB

  • Kernel image

  • Device tree blob (.dtb) for i.MX93 QSB board

  • Bootable disk image .wic file for i.MX93 QSB board

  • i.MX93 QSB board itself

from spsdk.utils.jupyter_utils import YamlDiffWidget

# This env variable sets colored logger output to STDOUT
%env JUPYTER_SPSDK=1
%alias execute echo %l && %l
%alias_magic ! execute
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.

2 Building the AHAB Images#

We first build the bootloader image, then we build the Kernel image with DTB.

U_BOOT_FLASH_BOOT_CONFIG = "./inputs/imx93_signed_ahab_uboot_bimg.yaml"
U_BOOT_FLASH_BOOT = "./outputs/imx93-ahab-uboot-signed.bin"
%! nxpimage -v bootable-image export -c $U_BOOT_FLASH_BOOT_CONFIG -o $U_BOOT_FLASH_BOOT
nxpimage -v bootable-image export -c ./inputs/imx93_signed_ahab_uboot_bimg.yaml -o ./outputs/imx93-ahab-uboot-signed.bin 
INFO:spsdk.image.ahab.ahab_iae:Adding DDR memory areas into SPL image
INFO:spsdk.apps.nxpimage_apps.nxpimage_bimg:Created Bootable Image:
Name:      Bootable Image for mimx9352, Revision: a1
Starts:    0x0
Ends:      0x1563ff
Size:      Size: 1.3 MiB; 1,401,856 B
Alignment: 1 B
Execution Start Address: Not defined
Pattern:zeros
Memory type: MemoryType.SERIAL_DOWNLOADER

INFO:spsdk.apps.nxpimage_apps.nxpimage_bimg:Created Bootable Image memory map:

+==0x0000_0000= Bootable Image for mimx9352, Revision: a1 ==+
|                Size: 1.3 MiB; 1,401,856 B                 |
|         Memory type: MemoryType.SERIAL_DOWNLOADER         |
|                      Pattern: zeros                       |
|+==0x0000_0000= primary_image_container_set ==============+|
||               Size: 308.5 kiB; 315,904 B                ||
||          AHAB Image for mimx9352, Revision: a1          ||
||                     Pattern: zeros                      ||
||+==0x0000_0000= AHAB Containers ========================+||
|||                Size: 8.0 kiB; 8,192 B                 |||
|||                 AHAB Containers block                 |||
|||                    Pattern: zeros                     |||
|||+==0x0000_0000= AHAB Container 0 =====================+|||
||||                     Size: 544 B                     ||||
||||           AHAB Container for nxp_SWver:0            ||||
|||+==0x0000_021f========================================+|||
|||                      Gap: 480 B                       |||
|||+==0x0000_0400= AHAB Container 1 =====================+|||
||||                     Size: 704 B                     ||||
||||           AHAB Container for oem_SWver:0            ||||
|||+==0x0000_06bf========================================+|||
||+==0x0000_1fff==========================================+||
||+==0x0000_2000= Container 0 AHAB Data Image 0 ==========+||
|||               Size: 94.9 kiB; 97,136 B                |||
||| AHAB encrypted data block for ele core and ele Image  |||
|||                         Type.                         |||
||+==0x0001_9b6f==========================================+||
||                       Gap: 144 B                        ||
||+==0x0001_9c00= U-Boot SPL with DDR tunning images =====+||
|||              Size: 205.5 kiB; 210,432 B               |||
|||  AHAB data block for cortex-a55 core and executable   |||
|||                      Image Type.                      |||
||+==0x0004_d1ff==========================================+||
|+==0x0004_d1ff============================================+|
|                        Gap: 512 B                         |
|+==0x0004_d400= secondary_image_container_set ============+|
||               Size: 1.0 MiB; 1,085,440 B                ||
||          AHAB Image for mimx9352, Revision: a1          ||
||                     Pattern: zeros                      ||
||+==0x0004_d400= AHAB Containers ========================+||
|||                Size: 8.0 kiB; 8,192 B                 |||
|||                 AHAB Containers block                 |||
|||                    Pattern: zeros                     |||
|||+==0x0004_d400= AHAB Container 0 =====================+|||
||||                     Size: 832 B                     ||||
||||           AHAB Container for oem_SWver:0            ||||
|||+==0x0004_d73f========================================+|||
||+==0x0004_f3ff==========================================+||
||+==0x0004_f400= ATF - ARM Trusted Firmware =============+||
|||               Size: 43.5 kiB; 44,544 B                |||
|||  AHAB data block for cortex-a55 core and executable   |||
|||                      Image Type.                      |||
||+==0x0005_a1ff==========================================+||
||                       Gap: 512 B                        ||
||+==0x0005_a400= U-Boot Firmware ========================+||
|||             Size: 1008.0 kiB; 1,032,192 B             |||
|||  AHAB data block for cortex-a55 core and executable   |||
|||                      Image Type.                      |||
||+==0x0015_63ff==========================================+||
|+==0x0015_63ff============================================+|
+==0x0015_63ff==============================================+

Success. (Bootable Image: outputs/imx93-ahab-uboot-signed.bin created) 

Kernel and Device tree blob AHAB image is also very simple, and signing works in similar fashion.

KERNEL_CONTAINER_CONFIG = "./inputs/imx93_signed_ahab_kernel_dtb.yaml"
KERNEL_CONTAINER = "./outputs/os_cntr_signed.bin"
YamlDiffWidget("./inputs/imx93_signed_ahab_kernel_dtb.diffc").html
nxpimage ahab get-template -f mimx9352 -o workspace/ahab_template.yaml --force 
Creating workspace/ahab_template.yaml template file.

Configuration Differences

%! nxpimage -v ahab export -c $KERNEL_CONTAINER_CONFIG
nxpimage -v ahab export -c ./inputs/imx93_signed_ahab_kernel_dtb.yaml 
INFO:spsdk.apps.nxpimage_apps.nxpimage_ahab:Created AHAB Image:
Name:      AHAB Image
Starts:    0x0
Ends:      0x21f7bff
Size:      Size: 34.0 MiB; 35,617,792 B
Alignment: 512 B
Execution Start Address: Not defined
Pattern:zeros
AHAB Image for mimx9352, Revision: latest

INFO:spsdk.apps.nxpimage_apps.nxpimage_ahab:Created AHAB Image memory map:

+==0x0000_0000= AHAB Image ============+
|     Size: 34.0 MiB; 35,617,792 B     |
|  AHAB Image for mimx9352, Revision:  |
|                latest                |
|            Pattern: zeros            |
|+==0x0000_0000= AHAB Containers =====+|
||       Size: 8.0 kiB; 8,192 B       ||
||       AHAB Containers block        ||
||           Pattern: zeros           ||
||+==0x0000_0000= AHAB Container 0 ==+||
|||           Size: 832 B            |||
|||  AHAB Container for oem_SWver:0  |||
||+==0x0000_033f=====================+||
|+==0x0000_1fff=======================+|
|+==0x0000_2000= Linux Kernel Image ==+|
||    Size: 33.9 MiB; 35,564,032 B    ||
||AHAB data block for cortex-a55 core ||
||     and executable Image Type.     ||
|+==0x021e_c9ff=======================+|
|              Gap: 512 B              |
|+==0x021e_cc00= Device Tree Blob ====+|
||      Size: 44.0 kiB; 45,056 B      ||
||AHAB data block for cortex-a55 core ||
||        and data Image Type.        ||
|+==0x021f_7bff=======================+|
+==0x021f_7bff=========================+

Success. (AHAB: outputs/os_cntr_signed.bin created.)
INFO:spsdk.image.ahab.ahab_container:Generated file containing SRK hash: outputs/ahab_oem0_srk0_hash.txt
INFO:spsdk.image.ahab.ahab_container:
Fuses info:

 --== Grouped register name: SRKH ==-- 
OTP ID: 128, Value: 0xA69C79E7
OTP ID: 129, Value: 0x578B8D35
OTP ID: 130, Value: 0x5DF512B9
OTP ID: 131, Value: 0x5C13EE65
OTP ID: 132, Value: 0x2F06222F
OTP ID: 133, Value: 0xEA8799AB
OTP ID: 134, Value: 0x2A25A34B
OTP ID: 135, Value: 0x3AB3699A

INFO:spsdk.image.ahab.ahab_container:Generated script for writing fuses for container 0: outputs/ahab_oem0_srk0_hash_nxpele.bcf
Exporting AHAB fuses to the output directory.
outputs/ahab_oem0_srk0_hash.txt
outputs/ahab_oem0_srk0_hash_nxpele.bcf

3 Image Download#

First we will download the WIC image onto the board, which by default comes with an unsigned bootloader and Linux kernel (amongst other things like root filesystem, software, etc.)

It is possible to replace U-Boot with a signed one in the .wic file, but the issue with that is that once we do that, the system wont boot, because the signed bootloader will also expect a signed kernel image with device tree blob.

For completeness the script below would replace the old U-Boot with the new signed one:

WIC = “./dist/imx-image-full-imx93evk.wic”

To download the WIC image onto the board we can use the SPSDK utility nxpuuu. As the WIC image often has size of several gigabytes, this process can take several minutes.

First we set our iMX93 board into serial download mode, then use the following command:

WIC = "./dist/imx-image-full-imx93evk.wic"
%! nxpuuu write -f mimx9352 -b emmc_all $WIC
nxpuuu write -f mimx9352 -b emmc_all ./dist/imx-image-full-imx93evk.wic 
SDPS: boot -scanterm -f ./dist/imx-image-full-imx93evk.wic -scanlimited 0x800000


FB: flash -raw2sparse all ./dist/imx-image-full-imx93evk.wic


Success

4 Bootloader replacement#

Now that we have uploaded the .wic image onto the board, we can proceed with replacing the bootloader with the signed one, as we did not modify the .wic image.

Since we just uploaded the .wic image onto the board, we should still be in serial download mode.

Following command writes the new bootloader onto the emmc:

%! nxpuuu write -f mimx9352 -b emmc $U_BOOT_FLASH_BOOT
nxpuuu write -f mimx9352 -b emmc ./outputs/imx93-ahab-uboot-signed.bin 
SDPS: boot -f ./outputs/imx93-ahab-uboot-signed.bin


Success

5 Kernel replacement#

Now that we uploaded signed bootloader, namely U-Boot which now expects a signed kernel image named os_cntr_signed.bin in the FAT partition, which is why we need to upload it.

import os

KERNEL_SIZE = hex(os.path.getsize(KERNEL_CONTAINER))
FASTBOOT_BUFFER_ADDRESS = hex(0x98000000)
MMCDEV = 0
MMCPART = 1
# We turn on the u-boot console multiplexing into terminal so that we are able to see the output
%! nxpuuu run "FB: ucmd setenv stdout serial,fastboot"
# We set fastboot buffer to a known address we have access to, in this case 0x98000000
%! nxpuuu run "FB: ucmd setenv fastboot_buffer $FASTBOOT_BUFFER_ADDRESS"
# Download the kernel
%! nxpuuu run "FB: download -f $KERNEL_CONTAINER"
# Write the kernel to FAT partition, these parameters may vary if we use SD card etc.
%! nxpuuu run "FB: ucmd fatwrite mmc $MMCDEV:$MMCPART $FASTBOOT_BUFFER_ADDRESS Image $KERNEL_SIZE"
nxpuuu run "FB: ucmd setenv stdout serial,fastboot" 
Success
nxpuuu run "FB: ucmd setenv fastboot_buffer 0x98000000" 
Success
nxpuuu run "FB: download -f ./outputs/os_cntr_signed.bin" 
Response: Starting download of 35617792 bytes
..........................................................................
..........................................................................
..........................................................................
.................................................
downloading of 35617792 bytes finished

Success
nxpuuu run "FB: ucmd fatwrite mmc 0:1 0x98000000 Image 0x21f7c00" 
Response: 35617792 bytes written in 195 ms (174.2 MiB/s)

Success

We can now delete the old unsigned kernel, note that this step is optional, but the signed bootloader should not be loading unsigned kernel by default.

%! nxpuuu -v run "FB: ucmd fatrm mmc 0:1 Image"
nxpuuu -v run "FB: ucmd fatrm mmc 0:1 Image" 
Success

We can list the fat partition and see the various device tree blobs, other binaries, and most importantly our os_cntr_signed.bin file.

%! nxpuuu -v run "FB: ucmd fatls mmc 0:1"
nxpuuu -v run "FB: ucmd fatls mmc 0:1" 
Response:  35617792   Image
    69501   imx93-11x11-evk-aud-hat.dtb
    66805   imx93-11x11-evk-boe-wxga-lvds-panel.dtb
    65761   imx93-11x11-evk-flexio-i2c.dtb
    66065   imx93-11x11-evk-flexspi-m2.dtb
    66855   imx93-11x11-evk-i2c-spi-slave.dtb
    65118   imx93-11x11-evk-i3c.dtb
     2725   imx93-11x11-evk-inmate.dtb
    51206   imx93-11x11-evk-iw612-otbr.dtb
    65418   imx93-11x11-evk-ld.dtb
    65576   imx93-11x11-evk-lpuart.dtb
    66039   imx93-11x11-evk-mqs.dtb
    68870   imx93-11x11-evk-mt9m114.dtb
    70541   imx93-11x11-evk-pmic-pf0900-aud-hat.dtb
    67845   imx93-11x11-evk-pmic-pf0900-boe-wxga-lvds-panel.dtb
    66801   imx93-11x11-evk-pmic-pf0900-flexio-i2c.dtb
    67105   imx93-11x11-evk-pmic-pf0900-flexspi-m2.dtb
    67895   imx93-11x11-evk-pmic-pf0900-i2c-spi-slave.dtb
    66158   imx93-11x11-evk-pmic-pf0900-i3c.dtb
    66458   imx93-11x11-evk-pmic-pf0900-ld.dtb
    66616   imx93-11x11-evk-pmic-pf0900-lpuart.dtb
    67079   imx93-11x11-evk-pmic-pf0900-mqs.dtb
    69910   imx93-11x11-evk-pmic-pf0900-mt9m114.dtb
    66915   imx93-11x11-evk-pmic-pf0900-rm67199.dtb
    66669   imx93-11x11-evk-pmic-pf0900-root.dtb
    67204   imx93-11x11-evk-pmic-pf0900-rpmsg-lpv.dtb
    67228   imx93-11x11-evk-pmic-pf0900-rpmsg.dtb
    66414   imx93-11x11-evk-pmic-pf0900.dtb
    65875   imx93-11x11-evk-rm67199.dtb
    65629   imx93-11x11-evk-root.dtb
    66164   imx93-11x11-evk-rpmsg-lpv.dtb
    66188   imx93-11x11-evk-rpmsg.dtb
    65374   imx93-11x11-evk.dtb
    49548   imx93-14x14-evk-aud-hat.dtb
    46985   imx93-14x14-evk-dsi-serdes.dtb
    46290   imx93-14x14-evk-flexspi-m2.dtb
    45470   imx93-14x14-evk-i3c.dtb
    46050   imx93-14x14-evk-lvds-it6263.dtb
    46474   imx93-14x14-evk-mqs.dtb
    46294   imx93-14x14-evk-rm67199.dtb
    48085   imx93-14x14-evk-sja1105.dtb
    46367   imx93-14x14-evk-tja1103.dtb
    45772   imx93-14x14-evk.dtb
    47890   imx93-9x9-qsb-aud-hat.dtb
    45350   imx93-9x9-qsb-can1.dtb
    45511   imx93-9x9-qsb-flexspi-m2.dtb
    44511   imx93-9x9-qsb-i3c.dtb
    45025   imx93-9x9-qsb-ld.dtb
    45271   imx93-9x9-qsb-lpspi-slave.dtb
    45384   imx93-9x9-qsb-lpspi.dtb
    47807   imx93-9x9-qsb-mt9m114.dtb
    45467   imx93-9x9-qsb-ontat-wvga-panel.dtb
    45364   imx93-9x9-qsb-rpmsg-lpv.dtb
    45388   imx93-9x9-qsb-rpmsg.dtb
    45555   imx93-9x9-qsb-tianma-wvga-panel.dtb
    44981   imx93-9x9-qsb.dtb
            mcore-demos/
   593744   tee.bin
  1185792   u-boot-atf-container.img
 35355200   uImage
    77661   imx93-11x11-evk-falcon.dtb
 35617792   os_cntr_signed.bin

61 file(s), 1 dir(s)


Success

6 Boot of authenticated container#

Now that everything is done, we can change the boot mode to EMMC and see that the authenticated container is booting.

To check if the authenticated container is being booted, we deleted the original unsigned kernel Image.

And during the boot we should see the following message in the console:

Running BSP bootcmd ...
switch to partitions #0, OK
mmc0(part 0) is current device
Failed to load 'boot.scr'
35807506 bytes read in 132 ms (258.7 MiB/s)
Booting from mmc ...
Authenticate OS container at 0x98000000
mu receive msg wait 1s
mu receive msg wait 2s
## Flattened Device Tree blob at 83000000
   Booting using the fdt blob at 0x83000000
Working FDT set to 83000000
   Using Device Tree in place at 0000000083000000, end 000000008300dfbc
Working FDT set to 83000000

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x412fd050]