            +=====================================================+
            +     i.MX8M family Secure Boot guide using HABv4     +
            +=====================================================+

1. HABv4 secure boot process
-----------------------------

This document describes a step-by-step procedure on how to sign and securely
boot a bootloader image on i.MX8M family devices. It is assumed that the reader
is familiar with basic HAB concepts and with the PKI tree generation.

Details about HAB can be found in the application note AN4581[1] and in the
introduction_habv4.txt document.

1.1 Understanding the i.MX8M family flash.bin image layout
----------------------------------------------------------

Due to the new the architecture, multiple firmwares and softwares are required
to boot i.MX8M family devices. In order to store all the images in a single
binary the FIT (Flattened Image Tree) image structure is used.

The final image is generated by the imx-mkimage project, the tool combines all
the input images in a FIT structure, generating a flash.bin image with an
appropriate IVT set.

For a secure boot process users should ensure all images included in flash.bin
file are covered by a digital signature.

- The diagram below illustrate a signed flash.bin image layout:

                     +-----------------------------+
                     |                             |
                     |     *Signed HDMI/DP FW      |
                     |                             |
                     +-----------------------------+
                     |           Padding           |
             ------- +-----------------------------+ --------
                 ^   |          IVT - SPL          |   ^
          Signed |   +-----------------------------+   |
           Data  |   |        u-boot-spl.bin       |   |
                 |   |              +              |   |  SPL
                 v   |           DDR FW            |   | Image
             ------- +-----------------------------+   |
                     |      CSF - SPL + DDR FW     |   v
                     +-----------------------------+ --------
                     |           Padding           |
             ------- +-----------------------------+ --------
          Signed ^   |          FDT - FIT          |   ^
           Data  |   +-----------------------------+   |
                 v   |          IVT - FIT          |   |
             ------- +-----------------------------+   |
                     |          CSF - FIT          |   |
             ------- +-----------------------------+   |  FIT
                 ^   |       u-boot-nodtb.bin      |   | Image
                 |   +-----------------------------+   |
          Signed |   |       OP-TEE (Optional)     |   |
           Data  |   +-----------------------------+   |
                 |   |        bl31.bin (ATF)       |   |
                 |   +-----------------------------+   |
                 v   |          u-boot.dtb         |   v
             ------- +-----------------------------+ --------
  * Only supported on i.MX8M series

The boot flow on i.MX8M devices are slightly different when compared with i.MX6
and i.MX7 series, the diagram below illustrate the boot sequence overview:

- i.MX8M boot flow:

                  Secure World                     Non-Secure World
                                         |
                                         |
  +------------+      +------------+     |
  |     SPL    |      |  i.MX 8M   |     |
  |      +     | ---> |    ROM     |     |
  |   DDR FW   |      |   + HAB    |     |
  +------------+      +------------+     |
                             |           |
                             v           |
                      +------------+     |
                      |  *Signed   |     |
                      | HDMI/DP FW |     |
                      +------------+     |
                             |           |
                             v           |
  +------------+      +------------+     |
  | FIT Image: |      |     SPL    |     |
  | ATF + TEE  | ---> |      +     |     |
  |  + U-Boot  |      |   DDR FW   |     |      +-----------+
  +------------+      +------------+     |      |   Linux   |
                             |           |      +-----------+
                             v           |            ^
                      +------------+     |            |             +-------+
                      |    ARM     |     |      +-----------+       | Linux |
                      |  Trusted   | ----+--->  |   U-Boot  |  <--- |   +   |
                      |  Firmware  |     |      +-----------+       |  DTB  |
                      +------------+     |                          +-------+
                             |           |
                             v           |
                       +----------+      |
                       | **OP-TEE |      |
                       +----------+      |
  * Only supported on i.MX8M series
  ** Optional

Particularly on the i.MX8M, the HDMI firmware or DisplayPort firmware are the
first image to boot on the device. These firmwares are signed and distributed by
NXP, and are always authenticated regardless of security configuration. In case
not required by the application the HDMI or DisplayPort controllers can be
disabled by eFuses and the firmwares are not required anymore.

The next images are not signed by NXP and users should follow the signing
procedure as described in this document.

The Second Program Loader (SPL) and DDR firmware are loaded and authenticated
by the ROM code, these images are executed in the internal RAM and responsible
for initializing essential features such as DDR, UART, PMIC and clock
enablement.

Once the DDR is available, the SPL code loads all the images included in the
FIT structure to their specific execution addresses, the HAB APIs are called
to extend the root of trust, authenticating the U-Boot, ARM trusted firmware
(ATF) and OP-TEE (If included).

The root of trust can be extended again at U-Boot level to authenticate Kernel
and M4 images.

1.2 Enabling the secure boot support in U-Boot
-----------------------------------------------

The first step is to generate an U-Boot image supporting the HAB features,
similar to i.MX6 and i.MX7 series the U-Boot provides extra functions for
HAB, such as the HAB status logs retrievement through the hab_status command
and support to extend the root of trust.

The support is enabled by adding the CONFIG_IMX_HAB to the build
configuration:

- Defconfig:

  CONFIG_IMX_HAB=y

- Kconfig:

  ARM architecture -> Support i.MX HAB features

The U-Boot image must then be recompiled after these changes are made.

1.3 Preparing the fit image
----------------------------

The imx-mkimage project is used to combines all the images in a single
flash.bin binary, the following files are required:

- U-Boot:
  u-boot.bin
  u-boot-nodtb.bin
  u-boot-spl.bin
  U-Boot DTB file (e.g. imx8mp-evk.dtb)

- ATF image:
  bl31.bin

- DDR firmware:
  lpddr4_pmu_train_1d_dmem.bin
  lpddr4_pmu_train_1d_imem.bin
  lpddr4_pmu_train_2d_dmem.bin
  lpddr4_pmu_train_2d_imem.bin

- HDMI firmware (Only in i.MX8M):
  signed_hdmi_imx8m.bin

- DisplayPort firmware (Only in i.MX8M):
  signed_dp_imx8m.bin

- OP-TEE (Optional):
  tee.bin

The procedure to build ATF and download the firmwares are out of the scope
of this document, please refer to the Linux BSP Release Notes and AN12212[2]
for further details.

Note: Depending on the version of firmware being used, the lpddr4
filenames may need to be appended or changed if Make errors are encountered.
(e.g. lpddr4_*mem.bin -> lpddr4_*mem_202006.bin)

Copy all files to iMX8M directory and run the following command according to
the target device, on this example we are building a HDMI target and also
including the OP-TEE binary:

- Assembly flash.bin binary:

  $ make SOC=<SoC Name> flash_hdmi_spl_uboot

The mkimage log can be used to calculate the authenticate image command
parameters and CSF offsets:

- imx-mkimage build log:

  Loader IMAGE:
   header_image_off 	0x1a000
   dcd_off 		0x0
   image_off 		0x1a040
   csf_off 		0x44600
   spl hab block: 	0x7e0fd0 0x1a000 0x2e600

  Second Loader IMAGE:
   sld_header_off 	0x57c00
   sld_csf_off 		0x58c20
   sld hab block: 	0x401fcdc0 0x57c00 0x1020

Additional HAB information is provided by running the following command:

- Printing HAB FIT information:

  $ make SOC=<SoC Name> print_fit_hab

  TEE_LOAD_ADDR=0xfe000000 ATF_LOAD_ADDR=0x00910000 ./print_fit_hab.sh \
  0x60000 fsl-imx8mq-evk.dtb
  0x40200000 0x5AC00 0x9AAC8
  0x910000 0xF56C8 0x9139
  0xFE000000 0xFE804 0x4D268
  0x4029AAC8 0x14BA6C 0x6DCF

If problems are encountered while using mkimage, please refer to the Linux
User Guide which can be found alongside the latest Linux BSP release.

1.4 Creating the CSF description file
--------------------------------------

The CSF contains all the commands that the ROM executes during the secure
boot. These commands instruct the HAB code on which memory areas of the image
to authenticate, which keys to install, use and etc. More information
on constructing a CSF file can be found in the CST User Guide, located
within the CST package's doc directory.

Key and Certificate generation done by the CST is out of the scope of
this document. Please refer to introduction_habv4.txt for keys,
certificates, SRK table, and SRK hash generation.
The resulting file locations should be inserted into the CSF files like this:

- Insertion into both csf_spl.txt and csf_fit.txt

For Example:

  [Install SRK]
    File = "<relative_path>/crts/SRK_1_2_3_4_table.bin"
    ...

  [Install CSFK]
    File = "<relative_path>/crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"

  [Install Key]
    ...
    File = "<relative_path>/crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"

CSF examples are available under doc/imx/hab/habv4/csf_examples/ directory.

As explained in sections above the SPL is first authenticated by the ROM code
and the root of trust is extended to the FIT image, hence two CSF files are
necessary to completely sign an flash.bin image.

The build log provided by imx-mkimage can be used to define the "Authenticate
Data" parameter in CSF. The addresses supplied in the build log will be
needed again for binary insertion.

- SPL "Authenticate Data" addresses in flash.bin build log:

  spl hab block: 0x7e0fd0 0x1a000 0x2e600

- "Authenticate Data" command in csf_spl.txt file:

  For example:

  [Authenticate Data]
    ...
    Blocks = 0x7e0fd0 0x1a000 0x2e600 "flash.bin"

- FIT image "Authenticate Data" addresses in flash.bin build log:

  sld hab block: 0x401fcdc0 0x57c00 0x1020

- FIT image "Authenticate Data" addresses in print_fit_hab build log:

  0x40200000 0x5AC00 0x9AAC8
  0x910000 0xF56C8 0x9139
  0xFE000000 0xFE804 0x4D268
  0x4029AAC8 0x14BA6C 0x6DCF

- "Authenticate Data" command in csf_fit.txt file:

  For example:

  [Authenticate Data]
    ...
    Blocks = 0x401fcdc0 0x057c00 0x01020 "flash.bin", \
           0x40200000 0x05AC00 0x9AAC8 "flash.bin", \
           0x00910000 0x0F56C8 0x09139 "flash.bin", \
           0xFE000000 0x0FE804 0x4D268 "flash.bin", \
           0x4029AAC8 0x14BA6C 0x06DCF "flash.bin"

1.4.1 Avoiding Kernel crash in closed devices
----------------------------------------------

For devices prior to HAB v4.4.0, the HAB code locks the Job Ring and DECO
master ID registers in closed configuration. In case the user specific
application requires any changes in CAAM MID registers it's necessary to
add the "Unlock CAAM MID" command in CSF file.

The current NXP BSP implementation expects the CAAM registers to be unlocked
when configuring CAAM to operate in non-secure TrustZone world.

The Unlock command is already included by default in the signed HDMI and
DisplayPort firmwares. On i.MX8MM, i.MX8MN and i.MX8MP devices or in case the
HDMI or DisplayPort controllers are disabled in i.MX8M, users must ensure this
command is included in SPL CSF.

- Add Unlock MID command in csf_spl.txt:

  [Unlock]
      Engine = CAAM
      Features = MID

1.5 Signing the flash.bin binary
---------------------------------

The CST tool is used for singing the flash.bin image and generating the CSF
binary. Users should input the CSF description file created in the step above
and receive a CSF binary, which contains the CSF commands, SRK table,
signatures and certificates.

- Create SPL CSF binary file:

 $ ./cst -i csf_spl.txt -o csf_spl.bin

- Create FIT CSF binary file:

 $ ./cst -i csf_fit.txt -o csf_fit.bin

1.6 Assembling the CSF in flash.bin binary
-------------------------------------------

The CSF binaries generated in the step above have to be inserted into the
flash.bin image.

The CSF offsets can be obtained from the flash.bin build log:

- SPL CSF offset:

  csf_off 0x44600

- FIT CSF offset:

  sld_csf_off 0x58c20

The signed flash.bin image can be then assembled:

- Create a flash.bin copy:

  $ cp flash.bin signed_flash.bin

- Insert csf_spl.bin in signed_flash.bin at 0x44600 offset:

  $ dd if=csf_spl.bin of=signed_flash.bin seek=$((0x44600)) bs=1 conv=notrunc

- Insert csf_fit.bin in signed_flash.bin at 0x58c20 offset:

  $ dd if=csf_fit.bin of=signed_flash.bin seek=$((0x58c20)) bs=1 conv=notrunc

- Flash signed flash.bin image:

  $ sudo dd if=signed_flash.bin of=/dev/sd<x> bs=1K seek=33 && sync

Note: The Universal Update Utility (UUU) can also be used to flash the
image to the target board's eMMC. Details on UUU installation and help
can be found in the supporting UUU documentation[3].

1.7 Programming SRK Hash
-------------------------

As explained in AN4581[1] and in introduction_habv4.txt document the SRK Hash
fuse values are generated by the srktool and should be programmed in the
SoC SRK_HASH[255:0] fuses.

Be careful when programming these values, as this data is the basis for the
root of trust. An error in SRK Hash results in a part that does not boot.
More information and full details regarding fuses can be found in the
Security Reference Manual of the target board. Contact an NXP Representative
for access.

The U-Boot fuse tool can be used for programming eFuses on i.MX SoCs.

- Dump SRK Hash fuses values in host machine:

  $ hexdump -e '/4 "0x"' -e '/4 "%X""\n"' SRK_1_2_3_4_fuse.bin
  0x20593752
  0x6ACE6962
  0x26E0D06C
  0xFC600661
  0x1240E88F
  0x1209F144
  0x831C8117
  0x1190FD4D

- Program SRK_HASH[255:0] fuses on i.MX8M family devices:

  => fuse prog 6 0 0x20593752
  => fuse prog 6 1 0x6ACE6962
  => fuse prog 6 2 0x26E0D06C
  => fuse prog 6 3 0xFC600661
  => fuse prog 7 0 0x1240E88F
  => fuse prog 7 1 0x1209F144
  => fuse prog 7 2 0x831C8117
  => fuse prog 7 3 0x1190FD4D


1.8 Verifying HAB events
-------------------------

The next step is to verify that the signatures included in flash.bin image is
successfully processed without errors. HAB generates events when processing
the commands if it encounters issues.

The hab_status U-Boot command call the hab_report_event() and hab_status()
HAB API functions to verify the processor security configuration and status.
This command displays any events that were generated during the process.

Prior to closing the device users should ensure no HAB events were found, as
the example below:

- Verify HAB events:

  => hab_status

  Secure boot disabled

  HAB Configuration: 0xf0, HAB State: 0x66

1.9 Closing the device
-----------------------

After the device successfully boots a signed image without generating any HAB
events, it is safe to close the device. This is the last step in the HAB
process, and is achieved by programming the SEC_CONFIG[1] fuse bit.

Once the fuse is programmed, the chip does not load an image that has not been
signed using the correct PKI tree.

- Program SEC_CONFIG[1] fuse on i.MX8M family devices:

  => fuse prog 1 3 0x2000000

1.10 Completely secure the device
----------------------------------

Additional fuses can be programmed for completely secure the device, more
details about these fuses and their possible impact can be found at AN4581[1].

2. Secure boot in SDP mode
---------------------------

For secure boot in SDP mode, please refer to the "HABv4 closed chip support"
chapter in the UUU documentation[3].

3. Authenticating additional boot images
-----------------------------------------

The High Assurance Boot (HAB) code located in the on-chip ROM provides an
Application Programming Interface (API) making it possible to call back
into the HAB code for authenticating additional boot images.

The U-Boot is running in non-secure TrustZone world and to make use of this
feature it's necessary to use a SIP call to the ATF, this is already
implemented in hab.c code and it's transparent to the user.

The process of signing an additional image is similar as in i.MX6 and i.MX7
series devices, the steps below are using the Linux Kernel image as example.

The diagram below illustrate the Image layout:

            ------- +-----------------------------+ <-- *load_address
                ^   |                             |
                |   |                             |
                |   |                             |
                |   |                             |
                |   |            Image            |
         Signed |   |                             |
          Data  |   |                             |
                |   |                             |
                |   +-----------------------------+
                |   |    Padding to Image size    |
                |   |          in header          |
                |   +-----------------------------+ <-- *ivt
                v   |     Image Vector Table      |
            ------- +-----------------------------+ <-- *csf
                    |                             |
                    | Command Sequence File (CSF) |
                    |                             |
                    +-----------------------------+
                    |     Padding (optional)      |
                    +-----------------------------+

3.1 Padding the image
----------------------

The Image must be padded to the size specified in the Image header, this can be
achieved by using the od command.

- Read Image size:

  $ od -x -j 0x10 -N 0x4 --endian=little Image
  0000020 5000 0145
  0000024

The tool objcopy can be used for padding the image.

- Pad the Image:

  $ objcopy -I binary -O binary --pad-to 0x1455000 --gap-fill=0x00 \
	Image Image_pad.bin

3.2 Generating Image Vector Table
----------------------------------

The HAB code requires an Image Vector Table (IVT) for determining the image
length and the CSF location. Since Image does not include an IVT this has
to be manually created and appended to the end of the padded Image, the
script genIVT.pl in script_examples directory can be used as reference.

- Generate IVT:

  $ genIVT.pl

Note: The load Address may change depending on the device.

- Append the ivt.bin at the end of the padded Image:

  $ cat Image_pad.bin ivt.bin > Image_pad_ivt.bin

3.3 Signing the image
----------------------

A CSF file has to be created to sign the image. HAB does not allow to change
the SRK once the first image is authenticated, so the same SRK key used in
the initial image must be used when extending the root of trust.

CSF examples are available in ../csf_examples/additional_images/ directory.

- Create CSF binary file:

  $ ./cst --i csf_additional_images.txt --o csf_Image.bin

- Attach the CSF binary to the end of the image:

  $ cat Image_pad_ivt.bin csf_Image.bin > Image_signed.bin

3.4 Verifying HAB events
-------------------------

The U-Boot includes the hab_auth_img command which can be used for
authenticating and troubleshooting the signed image, the Image must be
loaded at the load address specified in the IVT.

- Authenticate additional image:

  => hab_auth_img <Load Address> <Image Size> <IVT Offset>

If no HAB events were found the Image is successfully signed.

References:
[1] AN4581: "i.MX Secure Boot on HABv4 Supported Devices"
[2] AN12212: "Software Solutions for Migration Guide from Aarch32 to Aarch64"
[3] https://github.com/NXPmicro/mfgtools/releases/
