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
wicfileReplace 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.)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-mkimagetool as flash singleboot binaryObtain 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
.wicfile for i.MX93 QSB boardi.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 -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]