From f0b436bffa423dda9956420fc462fabda4ed8aa8 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Tue, 6 Oct 2026 12:40:17 -0500 Subject: [PATCH 1/5] first pass for zephyr uboot --- .../1-boot-chain.md | 48 +++++----- .../2-set-up-tools.md | 49 ++++++++--- .../3-build-zephyr.md | 88 ++++++++++--------- .../4-sign-zephyr.md | 33 +++---- .../5-build-uboot.md | 53 ++++++----- .../6-boot-the-target.md | 62 +++++++------ .../7-test-the-checks.md | 34 +++---- .../8-production.md | 39 ++++---- .../_index.md | 12 +-- 9 files changed, 241 insertions(+), 177 deletions(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md index 4f504e4497..fb0fcb23ef 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md @@ -9,36 +9,38 @@ layout: learningpathall ## Zephyr is the last stage, not the first -On a microcontroller (MCU), Zephyr runs first, so secure boot means adding a bootloader such as MCUboot. A Cortex-A processor starts in a ROM (read-only memory) inside the SoC (system on chip), and several firmware stages run before your code. Zephyr is the last stage, so the stage before it, usually U-Boot, can check it before starting it. +On a microcontroller (MCU), Zephyr runs first, so secure boot means adding a bootloader such as MCUboot. A Cortex-A processor starts in a read-only memory (ROM) inside the system on chip (SoC), and several firmware stages run before your code. Zephyr is the last stage, so the stage before it, usually U-Boot, can check it before starting it. -You package Zephyr in a Flattened Image Tree (FIT) with a signature that U-Boot verifies before starting the image. +You'll package Zephyr in a Flattened Image Tree (FIT) with a signature that U-Boot verifies before starting the image. -You can build and boot a verified Zephyr image in QEMU without hardware, or on a TI AM62L evaluation module (EVM). Both targets use the same signing and verification workflow, with separate instructions where setup differs. +You'll build and boot a verified Zephyr image either in QEMU without hardware, or on a TI AM62L evaluation module (EVM). You can use the same signing and verification workflow for both targets. The Learning Path includes separate instructions where setup differs. ## The boot chain on a Cortex-A board On an Armv8-A board using U-Boot, boot proceeds from the SoC's boot ROM through early firmware to U-Boot. U-Boot then loads and starts the payload: Zephyr in your setup. -The early firmware is usually the SPL (Secondary Program Loader), a small U-Boot that loads the full one, plus TF-A (Trusted Firmware-A) and OP-TEE (Open Portable Trusted Execution Environment), which run in the Secure world. Many SoCs add the vendor's own security firmware, which checks the later stages. You build the SPL with U-Boot; the rest comes prebuilt in the vendor's SDK. +The early firmware is usually the Secondary Program Loader (SPL), a small U-Boot that loads the full one. In addition, Trusted Firmware-A (TF-A) and Open Portable Trusted Execution Environment (OP-TEE) run in the Secure world. Many SoCs add the vendor's own security firmware, which checks the later stages. + +You'll build the SPL with U-Boot. The rest comes prebuilt in the vendor's SDK. ![Cortex-A boot chain from boot ROM through early firmware and U-Boot to a signed Zephyr FIT image. U-Boot verifies Zephyr; trust in the earlier stages depends on the platform's secure-boot configuration.#center](images/boot-chain-generic.svg "U-Boot verifies Zephyr in the Cortex-A boot chain") ## Choose your target -Pick one target now. QEMU is the default and needs nothing but your host; the AM62L EVM shows the same work on real silicon. Every page is written for both, and marks the few steps that differ. +Choose between QEMU and AM62L EVM. QEMU is the default target for which you need nothing but your host. The AM62L EVM shows the same work on real silicon. | Requirement or feature | QEMU | AM62L EVM | |---|---|---| -| Hardware | None | The board, a micro-SD card and reader, a micro-USB cable, a USB-C PD supply | +| Hardware | None | The board, a micro-SD card and reader, a micro-USB cable, and a USB-C PD supply | | Download | U-Boot source, 32 MB | TI Processor SDK, 4.5 GB, unpacks to 11 GB | | Stages before U-Boot | None: QEMU starts `u-boot.bin` directly | Boot ROM, `tiboot3.bin`, `tispl.bin` | | Zephyr board | `qemu_cortex_a53` | `am62l_evm/am62l3/a53` | -| Boot media | FAT partition in a 64 MiB disk image, `virtio 0:1` | FAT partition on a micro-SD card, `mmc 1:1` | -| Console | The terminal you start QEMU in | USB serial at 115200 baud | +| Boot media | File Allocation Table (FAT) partition in a 64 MiB disk image, `virtio 0:1` | FAT partition on a micro-SD card, `mmc 1:1` | +| Console | The terminal that you start QEMU in | USB serial at 115200 baud | ### The boot chain in QEMU -QEMU's `virt` machine has no boot ROM and no vendor firmware. It loads the file you pass to `-bios` and starts the Cortex-A53 on it, so the chain is two links long: +QEMU's `virt` machine has no boot ROM and no vendor firmware. It loads the file that you pass to `-bios` and starts the Cortex-A53 on it, so the chain is two links long: ```output QEMU -bios u-boot.bin -> U-Boot -> Zephyr inside a FIT image @@ -48,7 +50,7 @@ QEMU runs U-Boot's FIT verifier, but nothing authenticates U-Boot itself. ### The boot chain on the AM62L EVM -On the AM62L, the early stages are two files. `tiboot3.bin` holds TF-A's first stage and TIFS (TI Foundational Security), TI's security firmware; `tispl.bin` holds the rest of TF-A, OP-TEE and the SPL. You build them together with `u-boot.img` in a later step when you build U-Boot. The EVM ships in TI's High Security, Field Securable (HS-FS) development state. +On the AM62L, the early stages are two files. `tiboot3.bin` holds TF-A's first stage and TI Foundational Security (TIFS), TI's security firmware. `tispl.bin` holds the rest of TF-A, OP-TEE, and the SPL. You'll build them together with `u-boot.img` when you build U-Boot. The EVM ships in TI's High Security, Field Securable (HS-FS) development state. ![AM62L boot chain from boot ROM through `tiboot3.bin`, `tispl.bin`, and `u-boot.img` to the Zephyr FIT image. In HS-FS development mode, the early stages accept any signing key; U-Boot verifies Zephyr against your key before starting it.#center](images/boot-chain.svg "The same chain on the AM62L, with TI's file names") @@ -56,28 +58,34 @@ On the AM62L, the early stages are two files. `tiboot3.bin` holds TF-A's first s A FIT is U-Boot's container format for boot images. It's a device tree blob (DTB) whose nodes hold images instead of hardware descriptions. -The signed FIT you build contains: +The signed FIT that you'll build contains: -- The image itself, which is Zephyr's `zephyr.bin` here -- A hash of that image, so U-Boot can tell if a byte changed +- The image itself, which is Zephyr's `zephyr.bin` +- A hash of that image, so that U-Boot can tell if a byte changed - A configuration that names the image to use (`kernel = "kernel-1"`) and carries a signature -`mkimage`, a U-Boot host tool, builds the FIT from a text source file (a `.its` file) and signs it with your private key. On the target, U-Boot's `bootm` command parses the FIT, verifies the signature and the hash, and copies the image to its load address. +`mkimage`, a U-Boot host tool, builds the FIT from a text source `.its` file and signs it with your private key. On the target, U-Boot's `bootm` command parses the FIT, verifies the signature and the hash, and copies the image to its load address. -You sign the FIT configuration with `sha256,rsa2048`, which combines SHA-256 hashing with a 2048-bit RSA key. +You'll sign the FIT configuration with `sha256,rsa2048`, which combines SHA-256 hashing with a 2048-bit RSA key. -The public key lives inside U-Boot's own device tree, the control device tree, under a `/signature` node. That key node carries `required = "conf"`: every configuration in every FIT must carry a valid signature by this key, or U-Boot refuses to load it. Without `required`, a FIT with no signature at all still boots. +The public key lives inside U-Boot's own device tree, the control device tree, under a `/signature` node. That key node carries `required = "conf"`. Every configuration in every FIT must carry a valid signature by this key, or U-Boot refuses to load it. Without `required`, a FIT with no signature still boots. ![Signed FIT image beside U-Boot's control device tree, which holds the required public key. The signature covers the FIT configuration and payload hash; the hash covers the Zephyr image bytes.#center](images/fit-signature.svg "What the signature and the hash each cover in a FIT image") -The signature does not cover the image bytes: it covers the configuration node plus the hash node, and the hash covers the bytes. +The signature doesn't cover the image bytes. It covers the configuration node plus the hash node, and the hash covers the bytes. ## Verify Zephyr before starting it -You configure U-Boot to verify the Zephyr FIT before starting Zephyr with `go`, U-Boot's command for jumping to an address. +Configure U-Boot to verify the Zephyr FIT before starting Zephyr with `go`, U-Boot's command for jumping to an address. + +If you choose QEMU as your target, there's no key to fuse and nothing checks U-Boot at all. -In QEMU there is no key to fuse and nothing checks U-Boot at all. You leave the AM62L EVM in its development state without fusing your key into the chip. In that state, the ROM and vendor firmware accept boot files signed with any key. U-Boot's check of Zephyr is enforced either way. You'll review what a production device needs in the final section of this Learning Path. +If you choose AM62L EVM as your target, leave it in its development state without fusing your key into the chip. In that state, the ROM and vendor firmware accept boot files signed with any key. U-Boot's check of Zephyr is enforced either way. + +You'll review what a production device needs in [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). ## What you've learned and what's next -Zephyr is the last stage of a Cortex-A boot chain, so U-Boot can verify it, and `required = "conf"` makes U-Boot refuse any FIT it can't verify. Next, you set up the host tools for your target. +You've learned that Zephyr is the last stage of a Cortex-A boot chain, so U-Boot can verify it. You also learned that `required = "conf"` makes U-Boot refuse any FIT it can't verify. + +Next, you'll set up the host tools for your target. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md index 22aadc75cb..7eb439916e 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md @@ -9,15 +9,25 @@ layout: learningpathall ## What you need -You need Zephyr host tools, U-Boot source, and a cross compiler for your chosen target. For QEMU, you download U-Boot source and install the emulator and compiler from Ubuntu packages. For the AM62L EVM, the TI Processor SDK supplies U-Boot source, the cross compiler, and prebuilt early firmware. +You need Zephyr host tools, U-Boot source, and a cross compiler for your chosen target. For QEMU, download U-Boot source and install the emulator and compiler from Ubuntu packages. For the AM62L evaluation module (EVM), the TI Processor SDK supplies U-Boot source, the cross compiler, and prebuilt early firmware. ## Install the Zephyr host tools -Open Visual Studio Code and select **Workbench for Zephyr** in the Activity Bar. In its panel, select **Install Host Tools** to install the dependencies used to build Zephyr: Python, CMake, Ninja, Git, Device Tree Compiler, and West. +To install host tools on Visual Studio Code: -When installation finishes, select **Verify Host Tools**. Resolve any missing-tool errors before continuing. +1. Open Visual Studio Code and select **Workbench for Zephyr** in the Activity Bar. +2. In its panel, select **Install Host Tools** to install the dependencies used to build Zephyr: -You'll import the AArch64 toolchain and create the West workspace in the next lesson, before building Zephyr. +- Python +- CMake +- Ninja +- Git +- Device Tree Compiler +- West + +3. When installation finishes, select **Verify Host Tools**. Resolve any missing-tool errors before continuing. + +You'll import the AArch64 toolchain and create the West workspace later, before building Zephyr. ## Install the host packages @@ -27,15 +37,18 @@ Install the additional packages used to build U-Boot, sign images, and prepare t sudo apt install -y build-essential bison flex swig python3-dev python3-setuptools libssl-dev libgnutls28-dev uuid-dev device-tree-compiler openssl mtools dosfstools xz-utils curl picocom ``` -If you chose QEMU, install the emulator and U-Boot cross compiler with this command. For the AM62L EVM, skip it; you'll get the cross compiler from the TI SDK: +If you chose QEMU as your target, install the emulator and U-Boot cross compiler with this command: ```bash sudo apt install -y qemu-system-arm gcc-aarch64-linux-gnu ``` +For the AM62L EVM, skip installing the emulator. You'll get the cross compiler from the TI SDK ## Create the working directory and environment file -Keep your source, tools, and build outputs under `$HOME/zephyr-secure-boot`. An environment file stores the paths and target settings you'll reuse throughout the workflow. Select your target's tab, create and load its environment file, and create the signing-key and FIT directories: +Keep your source, tools, and build outputs under `$HOME/zephyr-secure-boot`. An environment file stores the paths and target settings that you'll reuse throughout the workflow. + +Follow the instructions for your target to create and load its environment file, and create the signing-key and Flattened Image Tree (FIT) directories: {{< tabpane code=true >}} {{< tab header="QEMU" language="bash" >}} @@ -95,14 +108,16 @@ mkdir -p $KEYS $FIT {{< /tab >}} {{< /tabpane >}} -The variables are available only in the shell where you load the environment file. Load it again whenever you open a new terminal; later lessons include a reminder. If you adapt the workflow to another board, the later section, [Review what is verified and what production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/), explains how to choose its target values and paths. +The variables are available only in the shell where you load the environment file. If you open a new terminal, you'll have to load the environment file again. If you adapt the workflow to another board, you'll learn how to choose its target values and paths in [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). {{% notice Note %}} -Example output shows paths under `/home/user/`, the home directory of the account that produced it. Your paths reflect your own username. On a standard Ubuntu cloud instance, for example, they appear under `/home/ubuntu/`. The commands use `$HOME` and `$WORK`, so they adapt to your account automatically, and only the printed paths differ. +Example output shows paths under `/home/user/`, the home directory of the account that produced it. The paths in your output will reflect your own username. On a standard Ubuntu cloud instance, for example, they appear under `/home/ubuntu/`. The commands use `$HOME` and `$WORK`, so they adapt to your account automatically. Only the printed paths in the output might differ. {{% /notice %}} ## Get the U-Boot source and the cross compiler +Follow the instructions for your target to download U-Boot and the cross compiler. + {{< tabpane-normal >}} {{< tab header="QEMU" >}} Download U-Boot 2025.07 and unpack it into your working directory. The archive is about 32 MB: @@ -119,7 +134,9 @@ The expected output is: /home/user/zephyr-secure-boot/u-boot-2025.07 ``` -You'll add the public key and boot command through build configuration, without patching U-Boot source. Check that the cross compiler runs: +You'll add the public key and boot command through build configuration, without patching U-Boot source. + +Check that the cross compiler runs: ```bash ${CROSS}gcc --version @@ -145,10 +162,12 @@ QEMU emulator version 8.2.2 (Debian 1:8.2.2+ds-0ubuntu1.18) ... ``` -You'll create a 64 MiB disk image when you prepare the boot media; you don't need to download one for QEMU. +You'll create a 64 MiB disk image when you prepare the boot media. You don't need to download one for QEMU. {{< /tab >}} {{< tab header="AM62L EVM" >}} -The TI Processor SDK Linux for AM62Lx supplies U-Boot source, prebuilt early firmware, and the cross compiler. You use these components to boot Zephyr. The installer is 4.5 GB and unpacks to 11 GB. Download version 12.01.00.05.03 from the [TI Processor SDK download page](https://www.ti.com/tool/download/AM62L-LINUX-SDK/12.01.00.05.03): +The TI Processor SDK Linux for AM62Lx supplies U-Boot source, prebuilt early firmware, and the cross compiler. You'll use these components to boot Zephyr. The installer is 4.5 GB and unpacks to 11 GB. + +Download version 12.01.00.05.03 from the [TI Processor SDK download page](https://www.ti.com/tool/download/AM62L-LINUX-SDK/12.01.00.05.03): ```bash curl -L -o $WORK/ti-processor-sdk-linux-am62lxx-evm-12.01.00.05.03-Linux-x86-Install.bin https://dr-download.ti.com/software-development/software-development-kit-sdk/MD-YjEeNKJJjt/12.01.00.05.03/ti-processor-sdk-linux-am62lxx-evm-12.01.00.05.03-Linux-x86-Install.bin @@ -178,14 +197,18 @@ aarch64-oe-linux-gcc (GCC) 15.3.0 ... ``` -Download TI's SD card image to preserve the boot partition layout expected by the AM62L boot ROM. The download is about 1.3 GB. Leave it compressed; when you prepare the boot media, you'll extract the boot partition and replace its files: +Download TI's SD card image to preserve the boot partition layout expected by the AM62L boot ROM: ```bash curl -L -o $WORK/tisdk-default-image.wic.xz https://dr-download.ti.com/software-development/software-development-kit-sdk/MD-YjEeNKJJjt/12.01.00.05.03/tisdk-default-image-am62lxx-evm-12.01.00.05.03.rootfs.wic.xz ``` +The download is about 1.3 GB. Leave it compressed. When you prepare the boot media, you'll extract the boot partition and replace its files. + {{< /tab >}} {{< /tabpane-normal >}} ## What you've accomplished and what's next -You've installed the Zephyr host tools and U-Boot build packages, obtained your target's U-Boot source and cross compiler, and created a reusable environment file. For the AM62L EVM, you also have the early firmware and SD card image. Next, you'll import the AArch64 toolchain, create a West workspace, and build a small Zephyr application for your chosen target. +You've installed the Zephyr host tools and U-Boot build packages, obtained your target's U-Boot source and cross compiler, and created a reusable environment file. For the AM62L EVM, you've also set up the early firmware and SD card image. + +Next, you'll import the AArch64 toolchain, create a West workspace, and build a small Zephyr application for your chosen target. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md index fafa53ae01..0dba724f4f 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md @@ -9,7 +9,7 @@ layout: learningpathall ## Open Workbench for Zephyr -Use Workbench for Zephyr to import an AArch64 toolchain, create a Zephyr workspace, and build your application. Both targets follow the same steps; select the board that matches your target. +Use Workbench for Zephyr to import an AArch64 toolchain, create a Zephyr workspace, and build your application. The steps are the same for both targets. Select the board that matches your target. Open VS Code on your working directory: @@ -20,7 +20,7 @@ code $HOME/zephyr-secure-boot Select the **Workbench for Zephyr** icon in the Activity Bar. Its panel contains the **Applications**, **West workspaces**, **Toolchains**, and **Host tools** views. {{% notice Note %}} -The screenshots show Windows paths, a globally installed SDK, and the AM62L EVM. On Ubuntu, use your own paths and the SDK location you choose. If you chose QEMU, select `qemu_cortex_a53` wherever a board is requested. +The screenshots show Windows paths, a globally installed SDK, and the AM62L evaluation module (EVM). On Ubuntu, use your own paths and the SDK location that you choose. If you chose QEMU, select `qemu_cortex_a53` wherever a board is requested. {{% /notice %}} ## Import the AArch64 toolchain @@ -29,58 +29,62 @@ Use the Zephyr SDK's `aarch64-zephyr-elf` compiler for your Cortex-A53 target. S In the **Workbench for Zephyr** panel, select **Add Toolchain** and fill in the form: -- **Toolchain family**: **Zephyr SDK** -- **Source**: **Official** -- **Destination**: **Custom location** -- **SDK Type**: **Minimal** -- **Version**: v1.0.1 -- Select **aarch64** and clear the other architecture checkboxes -- **Location**: a parent directory where Workbench creates the SDK folder, for example `$HOME/zephyr-secure-boot`. Workbench adds a versioned subdirectory such as `zephyr-sdk-1.0.1` inside it. +1. For **Toolchain family**, select **Zephyr SDK**. +2. For **Source**, select **Official**. +3. For **Destination**, select **Custom location**. +4. For **SDK Type**, select **Minimal**. +5. For **Version**, select **v1.0.1**. +6. Select **aarch64** and clear the other architecture checkboxes. +7. For **Location**, specify a parent directory where Workbench creates the SDK folder, such as `$HOME/zephyr-secure-boot`. Workbench adds a versioned subdirectory such as `zephyr-sdk-1.0.1` inside it. ![Workbench for Zephyr Add Toolchain form with Zephyr SDK 1.0.1, the Minimal SDK type, and aarch64 selected. These settings provide the compiler for both Cortex-A53 targets.#center](images/wz-add-toolchain.webp "Import the AArch64 toolchain") -Select **Import**. The download takes a few minutes. When it finishes, the **Toolchains** view shows `Zephyr SDK 1.0.1` with a `GNU` entry and `aarch64-zephyr-elf` under it. +8. Select **Import**. + +The download takes a few minutes. When it finishes, the **Toolchains** view shows `Zephyr SDK 1.0.1` with a `GNU` entry and `aarch64-zephyr-elf` under it. ## Add a West workspace Create a Zephyr 4.4.2 workspace for your chosen target. The same workspace supports QEMU and the AM62L EVM. Select **Add West Workspace** and fill in the form: -- **Source location**: **From template** -- Select **Minimal** under the **Path** field -- **Template**: **Texas Instruments**, for either target -- **Revision**: v4.4.2, or a later 4.x release -- **Location**: `$HOME/zephyr-secure-boot` (shown expanded, such as `/home/ubuntu/zephyr-secure-boot`) -- **Subfolder**: `zephyrproject` +1. For **Source location**, select **From template**. +2. Under **Path**, select **Minimal**. +3. For **Template**, select **Texas Instruments** for either target. +4. For **Revision**, select **v4.4.2** or a later 4.x release. +5. For **Location**, specify **`$HOME/zephyr-secure-boot`** (shown expanded, such as `/home/ubuntu/zephyr-secure-boot`). +6. For **Subfolder**, select **`zephyrproject`**. ![Workbench for Zephyr Add West Workspace form using the Minimal option, Texas Instruments template, and Zephyr v4.4.2. The workspace is named zephyrproject and supports either target.#center](images/wz-add-west-workspace.webp "Create the Zephyr 4.4.2 workspace") -Select **Import**. Workbench downloads Zephyr, the vendor's hardware abstraction layer (HAL), and other modules into `zephyrproject/deps`. This can take several minutes. When it finishes, confirm that `zephyrproject` appears in the **West workspaces** view. +7. Select **Import**. + +Workbench downloads Zephyr, the vendor's hardware abstraction layer (HAL), and other modules into `zephyrproject/deps`. This can take several minutes. When it finishes, confirm that `zephyrproject` appears in the **West workspaces** view. ## Create the application Select **Add Application** and fill in the wizard: -- **Select West Workspace**: `zephyrproject` -- **Select Toolchain**: `zephyr-sdk-1.0.1` -- **SDK Variant**: **GNU GCC** -- **Select Board**: type `qemu` and select **QEMU Emulation for ARM Cortex-A53**, or type `am62l` and select **TI AM62L Evaluation Module (EVM)** -- **New or existing application?**: **Create new application** -- **Select template**: `hello_world`, under `deps/zephyr/samples/hello_world` -- **Project Name**: `hello` -- **Application type**: **West workspace application** -- **Project Location**: `zephyrproject/applications/hello`, filled in by the wizard - -Check that the board identifier matches `BOARD` in your environment file: `qemu_cortex_a53` for QEMU or `am62l_evm/am62l3/a53` for the AM62L EVM. - +1. For **Select West Workspace**, select **`zephyrproject`**. +2. For **Select Toolchain**, select **`zephyr-sdk-1.0.1`**. +3. For **SDK Variant**, select **GNU GCC**. +4. For **Select Board**, enter **qemu** and select **QEMU Emulation for ARM Cortex-A53**, or enter **am62l** and select **TI AM62L Evaluation Module (EVM)**. +5. For **New or existing application?**, select **Create new application**. +6. For **Select template**, select **`hello_world`**, under **`deps/zephyr/samples/hello_world`**. +7. For **Project Name**, enter **`hello`**. +8. For **Application type**, select **West workspace application**. +9. For **Project Location**, ensure the value is **`zephyrproject/applications/hello`**, filled in by the wizard. + + Check that the board identifier matches `BOARD` in your environment file: `qemu_cortex_a53` for QEMU or `am62l_evm/am62l3/a53` for the AM62L EVM. +9. Select **Create**. ![Workbench for Zephyr Add Application wizard creating hello from the hello_world sample with the zephyrproject workspace and Zephyr SDK 1.0.1. The AM62L EVM is selected; the callout identifies the alternative QEMU Cortex-A53 board.#center](images/wz-add-application.webp "Create hello for your chosen target") -Select **Create**. The application `hello` appears in the **Applications** view, marked `[with zephyrproject]`, and `zephyrproject/applications/hello` holds the sample's `CMakeLists.txt`, `prj.conf` and `src/main.c`. +The application `hello` appears in the **Applications** view, marked `[with zephyrproject]`. `zephyrproject/applications/hello` holds the sample's `CMakeLists.txt`, `prj.conf` and `src/main.c`. ## Replace the sample's files Leave `CMakeLists.txt` as it is and replace the other two files. -Replace the contents of `prj.conf` with these four lines: +Replace the contents of `prj.conf` with the following four lines: ```text CONFIG_ARMV8_A_NS=y @@ -91,7 +95,7 @@ CONFIG_AARCH64_IMAGE_HEADER=y `CONFIG_PRINTK` enables console output with `printk()`. `CONFIG_BOOT_BANNER` prints the `*** Booting Zephyr OS build ... ***` line, confirming that Zephyr has started. -Replace the contents of `src/main.c` with the following code. Its banner identifies image A and the key you'll use to sign it. This helps you distinguish the images during the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). +Replace the contents of `src/main.c` with the following code. Its banner identifies image A and the key that you'll use to sign it. This helps you distinguish the images during the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). ```c #include @@ -119,11 +123,11 @@ Save both files. ## Configure Non-secure execution and the arm64 header -`CONFIG_ARMV8_A_NS=y` tells Zephyr that it runs in the Non-secure world, the one U-Boot hands it. Without it, the driver of the GICv3 (Generic Interrupt Controller) never programs the Non-secure registers, the timer interrupt never arrives, and Zephyr hangs right after its banner. +`CONFIG_ARMV8_A_NS=y` tells Zephyr that it runs in the Non-secure world, the one U-Boot hands it. Without it, the driver of the Generic Interrupt Controller (GICv3) never programs the Non-secure registers. The timer interrupt never arrives, and Zephyr hangs right after its banner. -`CONFIG_AARCH64_IMAGE_HEADER=y` puts a 64-byte arm64 header at the start of `zephyr.bin`, in the same format as a Linux kernel image. The header's first instruction is `b __start`, a branch to Zephyr's real entry point. U-Boot only needs that branch at offset 0: without the header, `go` jumps into whatever the linker placed there. +`CONFIG_AARCH64_IMAGE_HEADER=y` puts a 64-byte arm64 header at the start of `zephyr.bin`, in the same format as a Linux kernel image. The header's first instruction is `b __start`, a branch to Zephyr's real entry point. U-Boot needs that branch only at offset 0. Without the header, `go` jumps into whatever the linker placed there. -The configurations for `qemu_cortex_a53` and `am62l_evm/am62l3/a53` already set both options; repeating them in `prj.conf` protects you on a board whose configuration doesn't. +The configurations for `qemu_cortex_a53` and `am62l_evm/am62l3/a53` already set both options. Repeating them in `prj.conf` protects you on a board whose configuration doesn't. ## Build the application @@ -138,10 +142,10 @@ Memory region Used Size Region Size %age Used ![Workbench for Zephyr showing hello configured for the AM62L EVM and the build terminal's memory report. The report appears near the end of the build; the generated zephyr.bin is checked in the next step.#center](images/wz-build.webp "Build hello for the AM62L EVM") -The result is `$WORK/zephyrproject/applications/hello/build/primary/zephyr/zephyr.bin`, a raw binary linked at `ZEPHYR_ADDR`, the start of the target's `zephyr,sram` memory node. It is about 37 KB for `qemu_cortex_a53`, whose memory report shows 128 MB of RAM, and about 58 KB for the AM62L EVM, which reports 2016 MB. +The result is `$WORK/zephyrproject/applications/hello/build/primary/zephyr/zephyr.bin`, a raw binary linked at `ZEPHYR_ADDR`, the start of the target's `zephyr,sram` memory node. The binary is about 37 KB for `qemu_cortex_a53`, whose memory report shows 128 MB of RAM. It's about 58 KB for the AM62L EVM, which reports 2016 MB of RAM. -{{% notice Troubleshooting %}} -On an `aarch64` host, the build can fail with `exec format error` when it invokes `cmake` from `~/.zinstaller`. Some versions of the Workbench for Zephyr host tools install `x86_64` builds of CMake and Ninja, which can't run on Arm. Verify Host Tools can also report a misleading error, such as `-255 package(s) are not installed`, for the same reason. +{{% notice Note %}} +On an `aarch64` host, the build can fail with `exec format error` when it invokes `cmake` from `~/.zinstaller`. Some versions of the Workbench for Zephyr host tools install `x86_64` builds of CMake and Ninja, which can't run on Arm. Verify that Host Tools can also report a misleading error, such as `-255 package(s) are not installed`, for the same reason. Confirm the architecture of the installed tools: @@ -163,8 +167,8 @@ Rebuild the application. The Zephyr SDK compiler is a native Arm binary and does Open a terminal with **Terminal > New Terminal** in VS Code, or use an existing shell. Load your target's environment file: -- **QEMU**: `source $HOME/zephyr-secure-boot/env-qemu.sh` -- **AM62L EVM**: `source $HOME/zephyr-secure-boot/env-am62l.sh` +- QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` +- AM62L EVM: `source $HOME/zephyr-secure-boot/env-am62l.sh` Print the header's magic number at offset `0x38`: @@ -182,4 +186,6 @@ The expected output is: ## What you've accomplished and what's next -You've built a Zephyr image for your target's Cortex-A53, linked at `ZEPHYR_ADDR`, and checked its arm64 header. Next, you'll create the signing keys and package the image in a signed FIT for U-Boot to verify. +You've built a Zephyr image for your target's Cortex-A53, linked at `ZEPHYR_ADDR`, and checked its arm64 header. + +Next, you'll create the signing keys and package the image in a signed Flattened Image Tree (FIT) for U-Boot to verify. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md index a8a42431ce..aa8418bfc2 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md @@ -11,10 +11,10 @@ layout: learningpathall Open a terminal and load your target's environment file: -- **QEMU**: `source $HOME/zephyr-secure-boot/env-qemu.sh` -- **AM62L EVM**: `source $HOME/zephyr-secure-boot/env-am62l.sh` +- QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` +- AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` -Build `mkimage` to create and sign FIT images, and `fit_check_sign` to verify them on the host. Use your target's U-Boot source tree so the host tools match the U-Boot version you'll run. +Build `mkimage` to create and sign Flattened Image Tree (FIT) images, and `fit_check_sign` to verify them on the host. Use your target's U-Boot source tree so that the host tools match the U-Boot version that you'll run. Before building the tools, generate `.config` from your target's default configuration. Run the target named by `UBOOT_DEFCONFIG` in your environment file: @@ -24,7 +24,7 @@ make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" $UBOOT_DEFCO `UBOOT_CC` stores the compiler command. For QEMU, it names the cross compiler installed from Ubuntu. For the AM62L EVM, it also includes `--sysroot` to locate the SDK's headers and libraries. Keep `CC="$UBOOT_CC"` on every `make` command, including when you build U-Boot later. -Then build the host tools: +Then, build the host tools: ```bash make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" tools @@ -42,7 +42,7 @@ The output is similar to: mkimage version 2026.01-g5fb294342321 ``` -The version string identifies your U-Boot source tree. This example uses the AM62L EVM's TI tree, version 2026.01. For the QEMU setup, expect `mkimage version 2025.07`. +The version string identifies your U-Boot source tree. The example output indicates AM62L EVM's TI tree, version 2026.01. For the QEMU setup, expect `mkimage version 2025.07`. {{% notice Note %}} If the tools build reports a missing `pylibfdt` dependency, `swig`, or `gnutls/gnutls.h`, check the packages installed during [host-tool setup](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools/). Run the shared `apt install` command again, then retry the tools build. @@ -50,7 +50,7 @@ If the tools build reports a missing `pylibfdt` dependency, `swig`, or `gnutls/g ## Create two signing key pairs -Use the private key to sign the image and keep it on the host. You'll embed only the public key in U-Boot during the next lesson. +Use the private key to sign the image and keep it on the host. You'll embed only the public key in U-Boot. Create two key pairs. You'll configure U-Boot to trust `key-a` and leave out the public key for `key-b`. The optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/) use `key-b` to demonstrate rejection of an image signed with an untrusted key. @@ -72,17 +72,17 @@ The expected output is: key-a.crt key-a.key key-b.crt key-b.key ``` -`mkimage -k ` expects these files in the key directory: +`mkimage -k ` expects the following files in the key directory: -- `.key` holds the private key -- `.crt` is a self-signed certificate containing the public key -- The shared file-name stem, ``, matches `key-name-hint` in the FIT source +- `.key` holds the private key. +- `.crt` is a self-signed certificate containing the public key. +- The shared file-name stem, ``, matches `key-name-hint` in the FIT source. -These 2048-bit keys are generated on the build host for this demonstration. The later section, [Review what is verified and what production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/), covers production key handling. +These 2048-bit keys are generated on the build host for this demonstration. The later section, [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/), covers production key handling. ## Write the FIT source -Describe the FIT in an image tree source (`.its`) file. `mkimage` compiles and signs it to produce an image tree blob (`.itb`). Create the source with this command. The unquoted `EOF` delimiter lets the shell expand `$WORK` and `$ZEPHYR_ADDR`: +Describe the FIT in an image tree source (`.its`) file. `mkimage` compiles and signs it to produce an image tree blob (`.itb`). Create the source with the following command. The unquoted `EOF` delimiter lets the shell expand `$WORK` and `$ZEPHYR_ADDR`: ```bash cat > $FIT/zephyr-a.its < $WORK/signature.dtsi ``` -`-K` writes the public key into `scratch.dtb`, and `-r` marks the key as required. The `sed` command removes the `/dts-v1/;` header so the resulting `.dtsi` can be included after the main `.dts` header. +`-K` writes the public key into `scratch.dtb`, and `-r` marks the key as required. The `sed` command removes the `/dts-v1/;` header so that the resulting `.dtsi` can be included after the main `.dts` header. Check the key name and required-signature setting: @@ -97,21 +99,21 @@ The expected output is: key-name-hint = "key-a"; ``` -Confirm that `key-name-hint` is `key-a` and `required` is `conf`. Leave out `key-b` so U-Boot doesn't trust its signatures. +Confirm that `key-name-hint` is `key-a` and `required` is `conf`. Leave out `key-b` so that U-Boot doesn't trust its signatures. -The build incorporates `signature.dtsi` into U-Boot's control device tree. Use `mkimage -K` only with the scratch DTB in this step. Adding the key directly to a finished `u-boot.dtb` would lose it when `make` rebuilds that file. +The build incorporates `signature.dtsi` into U-Boot's control device tree. Use `mkimage -K` only with the scratch DTB. Adding the key directly to a finished `u-boot.dtb` would lose it when `make` rebuilds that file. ## Write a boot command that fails closed -An unverified boot command loads `zephyr.bin` and jumps to it. With your QEMU target values, it looks like this: +An unverified boot command loads `zephyr.bin` and jumps to it. With your QEMU target values, the command looks like the following: ```console => fatload virtio 0:1 0x40000000 zephyr.bin; dcache flush; icache flush; dcache off; icache off; go 0x40000000 ``` -On the AM62L EVM the same line reads `fatload mmc 1:1 0x82000000 zephyr.bin` and ends `go 0x82000000`. +On the AM62L EVM, the same line reads `fatload mmc 1:1 0x82000000 zephyr.bin` and ends `go 0x82000000`. -This command doesn't verify the image between `fatload` and `go`. Add `bootm` verification before the handover. The verified command chain uses the same QEMU target values and is split into lines for readability: +The command doesn't verify the image between `fatload` and `go`. Add `bootm` verification before the handover. The verified command chain uses the same QEMU target values and is split into lines for readability: ```text fatload virtio 0:1 0x48000000 ${fit} && @@ -130,9 +132,9 @@ The command chain loads, verifies, and starts Zephyr: - The cache commands flush and disable the caches. On arm64, `dcache off` also disables the memory management unit (MMU), preparing the state Zephyr expects at entry. - `go 0x40000000` jumps to `ZEPHYR_ADDR` without performing verification. Using `bootm start` and `bootm loados` stops before the OS-specific boot code that a plain `bootm` would run. -For QEMU, `BOOT_DEV` is `virtio 0:1`, the disk image's FAT partition. On the AM62L EVM, it is `mmc 1:1`, the SD card's first partition. The board loads the FIT at `0x90000000` and copies Zephyr to `0x82000000`. +For QEMU, `BOOT_DEV` is `virtio 0:1`, the disk image's File Allocation Table (FAT) partition. On the AM62L EVM, it's `mmc 1:1`, the SD card's first partition. The board loads the FIT at `0x90000000` and copies Zephyr to `0x82000000`. -Failing closed means stopping before Zephyr starts if any command fails. The `&&` operators enforce this: `a && b` runs `b` only if `a` succeeds. Separating the commands with `;` would allow execution to continue after a failed check. In this application, `go` doesn't return, so the refusal message prints only when an earlier command fails. +Failing closed means stopping before Zephyr starts if any command fails. The `&&` operators enforce this condition: `a && b` runs `b` only if `a` succeeds. Separating the commands with `;` would allow execution to continue after a failed check. In this application, `go` doesn't return, so the refusal message prints only when an earlier command fails. Store the chain in the environment variable `zboot`. Three wrapper commands select which FIT it loads: @@ -143,7 +145,7 @@ Store the chain in the environment variable `zboot`. Three wrapper commands sele | `b` | `setenv fit zephyr-b.itb; run zboot` | | `t` | `setenv fit zephyr-tampered.itb; run zboot` | -`a` boots the trusted image. `b` and `t` select the images you'll create during the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). +`a` boots the trusted image. `b` and `t` select the images that you'll create during the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). Autoboot runs `bootcmd` after a countdown. `CONFIG_PREBOOT` defines `zboot` and its wrappers before the countdown, making them available if you interrupt it. `CONFIG_BOOTCOMMAND="run a"` selects the trusted image by default. `CONFIG_BOOTDELAY=3` gives you three seconds to interrupt autoboot. @@ -169,13 +171,15 @@ CONFIG_BOOTDELAY=3 EOF ``` -Keep the `\"` sequences around the `echo` text; they represent literal quotes inside the Kconfig string. Run `grep ^CONFIG_PREBOOT $UBOOT_OUT/.config` and check that your target's device and addresses appear in the command. +Keep the `\"` sequences around the `echo` text. The sequences represent literal quotes inside the Kconfig string. Run `grep ^CONFIG_PREBOOT $UBOOT_OUT/.config` and check that your target's device and addresses appear in the command. -Select your target's tab and add its device-tree and boot settings: +Follow the instructions for your target to add its device-tree and boot settings: {{< tabpane-normal >}} {{< tab header="QEMU" >}} -QEMU normally supplies U-Boot's device tree at runtime, so `CONFIG_DEVICE_TREE_INCLUDES` has no source tree to modify. Instead, you'll create a control device tree containing your key and pass it to the build. Add these settings to enable that approach, disable unsigned legacy images, enable cache commands, and keep the environment from being saved to flash: +QEMU normally supplies U-Boot's device tree at runtime, so `CONFIG_DEVICE_TREE_INCLUDES` has no source tree to modify. Instead, you'll create a control device tree containing your key and pass it to the build. + +Add the following settings to enable that approach and disable unsigned legacy images. The settings also enable cache commands and keep the environment from being saved to flash: ```bash cat >> $UBOOT_OUT/.config <<'EOF' @@ -189,7 +193,7 @@ CONFIG_ENV_IS_NOWHERE=y EOF ``` -`CONFIG_OF_BOARD` and `CONFIG_OF_OMIT_DTB` off make U-Boot carry a control device tree of its own, the one your key goes into. `CONFIG_LEGACY_IMAGE_FORMAT` off closes the older image format, which carries no signature. `CONFIG_CMD_CACHE` adds the `dcache` and `icache` commands the boot command uses, and `CONFIG_ENV_IS_NOWHERE` keeps the environment out of flash, so nothing saved at the prompt can replace your boot command. +`CONFIG_OF_BOARD` and `CONFIG_OF_OMIT_DTB` off make U-Boot carry a control device tree of its own, the one your key goes into. `CONFIG_LEGACY_IMAGE_FORMAT` off closes the older image format, which carries no signature. `CONFIG_CMD_CACHE` adds the `dcache` and `icache` commands that the boot command uses. `CONFIG_ENV_IS_NOWHERE` keeps the environment out of flash, so nothing saved at the prompt can replace your boot command. {{< /tab >}} {{< tab header="AM62L EVM" >}} TI's U-Boot tree builds its control device tree from source. Set `CONFIG_DEVICE_TREE_INCLUDES` to include your public-key node in that build: @@ -222,28 +226,33 @@ These override warnings are expected because your settings replace default value ## Build U-Boot +Follow the instructions for your target to build U-Boot. + {{< tabpane-normal >}} {{< tab header="QEMU" >}} -Export the device tree for the QEMU machine you'll boot later. This keeps U-Boot's drivers, console, and memory sizing consistent with the machine. QEMU writes the file and exits: +Export the device tree for the QEMU machine that you'll boot later: ```bash qemu-system-aarch64 -machine virt,gic-version=3,dumpdtb=$WORK/qemu-virt.dtb -cpu cortex-a53 -m 1G -nographic ``` +This keeps U-Boot's drivers, console, and memory sizing consistent with the machine. QEMU writes the file and exits. -Add your public-key node by decompiling the tree, appending `signature.dtsi`, and recompiling it. The device tree compiler (`dtc`) merges the repeated root nodes, adding `/signature` to the exported tree: +Add your public-key node by decompiling the tree, appending `signature.dtsi`, and recompiling it: ```bash dtc -I dtb -O dts -q $WORK/qemu-virt.dtb > $WORK/uboot-control.dts cat $WORK/signature.dtsi >> $WORK/uboot-control.dts dtc -I dts -O dtb -q -o $WORK/uboot-control.dtb $WORK/uboot-control.dts ``` +The device tree compiler (`dtc`) merges the repeated root nodes, adding `/signature` to the exported tree. -Build U-Boot with `EXT_DTB` pointing to your control device tree. Specify `u-boot.bin` and `u-boot.dtb` as the build targets. U-Boot's `scripts/check-of.sh` rejects the default `all` target for this machine, which normally receives its device tree from a prior stage: +Build U-Boot with `EXT_DTB` pointing to your control device tree. Specify `u-boot.bin` and `u-boot.dtb` as the build targets: ```bash make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" -j$(nproc) \ EXT_DTB=$WORK/uboot-control.dtb u-boot.bin u-boot.dtb ``` +U-Boot's `scripts/check-of.sh` rejects the default `all` target for this machine, which normally receives its device tree from a prior stage. The build takes a couple of minutes. Check the two files: @@ -358,4 +367,6 @@ The tool also checks for device-tree and ramdisk subimages. The two `Could not f ## What you've accomplished and what's next -You've built U-Boot with the public key for `key-a` and a boot command that starts Zephyr only after verification succeeds. The trusted FIT passes the host check against the embedded key. Next, you'll prepare the boot media and watch U-Boot verify and start Zephyr on your chosen target. +You've built U-Boot with the public key for `key-a` and a boot command that starts Zephyr only after verification succeeds. The trusted FIT passes the host check against the embedded key. + +Next, you'll prepare the boot media and watch U-Boot verify and start Zephyr on your chosen target. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md index 3508887413..76f8869a76 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md @@ -11,15 +11,17 @@ layout: learningpathall Open a terminal and load your target's environment file: -- **QEMU**: `source $HOME/zephyr-secure-boot/env-qemu.sh` -- **AM62L EVM**: `source $HOME/zephyr-secure-boot/env-am62l.sh` +- QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` +- AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` -The AM62L boot ROM reads the first-stage file from a FAT partition on the SD card. Start with TI's card image to preserve the expected layout. QEMU loads `u-boot.bin` from the command line, so its disk image needs only the signed FIT. +The AM62L boot ROM reads the first-stage file from a File Allocation Table (FAT) partition on the SD card. Start with TI's card image to preserve the expected layout. QEMU loads `u-boot.bin` from the command line, so its disk image needs only the signed Flattened Image Tree (FIT). On either target, U-Boot's `fatload` reads `zephyr-a.itb` from the partition selected by `BOOT_DEV`. ## Build the boot media +Follow the instructions for your target to build the boot media. + {{< tabpane-normal >}} {{< tab header="QEMU" >}} Create a 64 MiB disk image with one FAT16 partition starting at sector 2048. Use a master boot record (MBR) partition table and partition type `0x0e`, which specifies FAT16 with logical block addressing (LBA). These commands don't need root privileges: @@ -52,9 +54,9 @@ zephyr-a itb 38742 2026-09-17 22:11 Confirm that the volume contains `zephyr-a.itb`. The partition is accessed as `virtio 0:1`, matching `BOOT_DEV` in `env-qemu.sh`. {{< /tab >}} {{< tab header="AM62L EVM" >}} -The boot ROM reads `tiboot3.bin` from the card's first FAT partition. Preserve TI's FAT16 partition layout and replace its files. The supplied partition starts at sector 2048 and spans 262144 sectors; these values determine the extraction size in the command. +The boot ROM reads `tiboot3.bin` from the card's first FAT partition. Preserve TI's FAT16 partition layout and replace its files. The supplied partition starts at sector 2048 and spans 262144 sectors. These values determine the extraction size in the command. -Start from the `.wic.xz` you downloaded. Extract the first 1 MiB, which holds the partition table, plus the 128 MiB partition into a new image file: +Start from the `.wic.xz` that you downloaded. Extract the first 1 MiB, which holds the partition table, plus the 128 MiB partition into a new image file: ```bash xz -dc $WORK/tisdk-default-image.wic.xz | head -c $(( (2048+262144)*512 )) > $WORK/sdcard.img @@ -104,6 +106,8 @@ Confirm that the volume contains the three boot files and `zephyr-a.itb`. ## Start the target +Follow the instructions for your target to start the target. + {{% notice Warning %}} The AM62L EVM steps write to a whole disk with `dd`. Replace `/dev/sdX` with your card, for example `/dev/sdb`, never a partition such as `/dev/sdb1`. `dd` erases everything on the target, so a wrong device name erases the wrong disk. {{% /notice %}} @@ -148,9 +152,9 @@ Move the SD card to the board, then connect a USB-C Power Delivery (PD) supply t {{< /tab >}} {{< /tabpane-normal >}} -In QEMU, the log starts with U-Boot because no TF-A or SPL stage runs first. The messages `Bloblist at 0 not found (err=-2)` and `Warning: Unexpected devicetree source (not from a prior stage)` are consistent with this setup. `Loading Environment from nowhere... OK` indicates that U-Boot is using its built-in environment. +In QEMU, the log starts with U-Boot because no TF-A or Secondary Program Loader (SPL) stage runs first. The messages `Bloblist at 0 not found (err=-2)` and `Warning: Unexpected devicetree source (not from a prior stage)` are consistent with this setup. `Loading Environment from nowhere... OK` indicates that U-Boot is using its built-in environment. -The AM62L EVM also prints messages from its early firmware stages. Its log up to the autoboot countdown is similar to this example. Your dates, version strings, and countdown will differ. +The AM62L EVM also prints messages from its early firmware stages. Its log up to the autoboot countdown is similar to the following example. Your dates, version strings, and countdown will differ: ```output NOTICE: Booting Trusted Firmware @@ -189,20 +193,20 @@ Net: eth0: ethernet@8000000port@1, eth1: ethernet@8000000port@2 Hit any key to stop autoboot: 3 ``` -Use these messages to identify the boot stages and selected devices: +Use the following messages to identify the boot stages and selected devices: -- `NOTICE: BL1:` and `BL31:` identify TF-A running from `tiboot3.bin` and `tispl.bin` -- `Authentication passed` reports successful authentication by TI's security firmware -- `SoC: AM62LX SR1.1 HS-FS` identifies the SoC's development state -- `MMC:` lists the eMMC as device zero and the SD card as device one +- `NOTICE: BL1:` and `BL31:` identify TF-A running from `tiboot3.bin` and `tispl.bin`. +- `Authentication passed` reports successful authentication by TI's security firmware. +- `SoC: AM62LX SR1.1 HS-FS` identifies the SoC's development state. +- `MMC:` lists the eMMC as device zero and the SD card as device one. -The `Agent 0 Protocol 0x10 Message 0x7: not supported` errors appear in this successful boot log. They don't prevent Zephyr from starting in this example. +The `Agent 0 Protocol 0x10 Message 0x7: not supported` errors appear in this successful boot log. They don't prevent Zephyr from starting. This log comes from a board running TI's prebuilt first two stages, so its `U-Boot SPL` line shows TI's build date instead of yours. ## Watch the trusted image boot -After the three-second countdown, autoboot runs `run a`, the trusted-image command built into U-Boot. This example shows the AM62L EVM; QEMU uses different load addresses and image sizes. Your timings and hash values will differ. The output is similar to: +After the three-second countdown, autoboot runs `run a`, the trusted-image command built into U-Boot. The following example output shows the AM62L EVM. Your timings and hash values will differ. QEMU uses different load addresses and image sizes. The output is similar to: ```output 60198 bytes read in 1 ms (57.4 MiB/s) @@ -241,36 +245,38 @@ started by : U-Boot 'go' after FIT signature verification this image was verified by U-Boot before it ran. ``` -Confirm verification and startup using these messages: +Confirm verification and startup using the following messages: -- `sha256,rsa2048:key-a+ OK` confirms that the signature verifies with U-Boot's embedded public key -- `sha256+ OK` confirms that the payload hash matches -- `Loading Kernel Image to 82000000` shows `bootm loados` copying Zephyr to its link address -- `## Starting application at 0x82000000 ...` shows `go` handing control to Zephyr +- `sha256,rsa2048:key-a+ OK` confirms that the signature verifies with U-Boot's embedded public key. +- `sha256+ OK` confirms that the payload hash matches. +- `Loading Kernel Image to 82000000` shows `bootm loados` copying Zephyr to its link address. +- `## Starting application at 0x82000000 ...` shows `go` handing control to Zephyr. Zephyr then prints its boot banner and `Hello from ZEPHYR IMAGE A`. On the AM62L EVM, `Secondary CPU core 1 (MPID:0x1) is up` also reports startup of the second core. -For QEMU, expect `FIT Image at 48000000`, `Data Size: 37040 Bytes`, `Loading Kernel Image to 40000000`, and `board : qemu_cortex_a53/qemu_cortex_a53`. Its board configuration starts one core, so there is no secondary-core startup message. +For QEMU, expect `FIT Image at 48000000`, `Data Size: 37040 Bytes`, `Loading Kernel Image to 40000000`, and `board : qemu_cortex_a53/qemu_cortex_a53`. Its board configuration starts one core, so there's no secondary-core startup message. ## Troubleshoot boot and console output +Consider the following guidance to troubleshoot issues with your target. + {{< tabpane-normal >}} {{< tab header="QEMU" >}} Check the symptom and try the corresponding step: -1. Nothing prints, or startup hangs after the banner: check that the control device tree matches the machine. Rebuild it from a fresh `dumpdtb` with the same `-machine`, `-cpu`, and `-m` used to start QEMU. +1. Nothing prints, or startup hangs after the banner: Check that the control device tree matches the machine. Rebuild it from a fresh `dumpdtb` with the same `-machine`, `-cpu`, and `-m` used to start QEMU. 2. `Failed to load 'zephyr-a.itb'`: U-Boot found the volume but not the file. List it on the host with `mdir -i $BOOT_IMG ::`. -3. `** Bad device specification virtio 0 **`: check the partition type with `sfdisk -l $WORK/disk.img`. If it isn't `0x0e`, rebuild the disk image with the specified type. -4. `Unknown command 'dcache'`: `CONFIG_CMD_CACHE` did not make it into `.config`; add it and build U-Boot again. +3. `** Bad device specification virtio 0 **`: Check the partition type with `sfdisk -l $WORK/disk.img`. If it isn't `0x0e`, rebuild the disk image with the specified type. +4. `Unknown command 'dcache'`: `CONFIG_CMD_CACHE` didn't make it into `.config`. Add it and build U-Boot again. {{< /tab >}} {{< tab header="AM62L EVM" >}} If the terminal stays empty, check the console connection and whether the ROM loads `tiboot3.bin`: -1. Try all four serial ports that **J7** creates; the console isn't always the first one. -2. Check **SW3**, or switch to the full pincount setting, which uses all three switch banks: BOOTMODE `0x0E43` in the same guide. +1. Try all four serial ports that **J7** creates. The console isn't always the first one. +2. Check **SW3**, or switch to the full pincount setting, which uses all three switch banks. BOOTMODE `0x0E43` in the same guide. 3. Check that the card's first partition is still TI's FAT16 partition, not reformatted. 4. Flash TI's unchanged `.wic.xz` to a card and boot it. If that also produces no output, check the boot switches, serial port, and power supply before investigating your custom boot files. -5. If TI's card boots but yours never shows the SPL banner, copy TI's prebuilt first two stages over yours with `mcopy -o -i $BOOT_IMG $PREBUILT/tiboot3.bin $PREBUILT/tispl.bin ::`, then write the card again with the same `dd`. `u-boot.img` still carries the key and the boot command. +5. If TI's card boots but yours never shows the SPL banner, copy TI's prebuilt first two stages over yours with `mcopy -o -i $BOOT_IMG $PREBUILT/tiboot3.bin $PREBUILT/tispl.bin ::`. Then, write the card again with the same `dd`. `u-boot.img` still carries the key and the boot command. {{< /tab >}} {{< /tabpane-normal >}} @@ -279,4 +285,6 @@ If Zephyr prints its boot banner but no application output, check that the [Zeph ## What you've accomplished and what's next -You've prepared the boot media and watched U-Boot verify the FIT signed with `key-a` before starting Zephyr. Next, you can run the optional wrong-key and tampered-image tests to confirm that verification failures prevent startup. You'll then review the trust boundary and the additional work needed for production. +You've prepared the boot media and watched U-Boot verify the FIT signed with `key-a` before starting Zephyr. + +Next, you can run the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/) to confirm that verification failures prevent startup. You can also skip to review [the trust boundary and the additional work needed for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md index c1dfba77ca..119cf8180c 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md @@ -1,6 +1,6 @@ --- -title: Test that U-Boot refuses a wrong key and a tampered image -description: "Optional: test on the host and target that U-Boot rejects Zephyr FIT images signed with an untrusted key or modified after signing." +title: (Optional) Test that U-Boot refuses a wrong key and a tampered image +description: "Optionally test on the host and target that U-Boot rejects Zephyr FIT images signed with an untrusted key or modified after signing." weight: 8 ### FIXED, DO NOT MODIFY @@ -9,16 +9,16 @@ layout: learningpathall ## Test rejection of untrusted and tampered images -These tests are optional. Create one FIT signed with an untrusted key and another modified after signing. Check both on the host, then confirm that U-Boot refuses to start them on your target. The `b` and `t` commands are already built into U-Boot to select these images. +The following tests are optional. Create one Flattened Image Tree (FIT) signed with an untrusted key and another modified after signing. Check both on the host, then confirm that U-Boot refuses to start them on your target. The `b` and `t` commands are already built into U-Boot to select these images. Open a terminal and load your target's environment file: -- **QEMU**: `source $HOME/zephyr-secure-boot/env-qemu.sh` -- **AM62L EVM**: `source $HOME/zephyr-secure-boot/env-am62l.sh` +- QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` +- AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` ## Build a second Zephyr image -Give the wrong-key image a distinct banner so you can identify it if it unexpectedly starts. +Give the wrong-key image a distinct banner so that you can identify it if it unexpectedly starts. In Workbench for Zephyr, select **Add Application**. Use the same workspace, toolchain, board, and sample as the [trusted image](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr/). Enter `hello_b` as the **Project Name**. Copy `prj.conf` and `src/main.c` from `hello`, then replace these two banner lines: @@ -31,7 +31,9 @@ In the **Applications** view, open the context menu for `hello_b` and select **B ## Sign the second image with the untrusted key -Use `key-b`, the second key pair created during [FIT signing](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr/). Copy the FIT source with `sed`, replacing `key-a` with `key-b` and the `hello` application path with `hello_b`. Then sign the new FIT: +Use `key-b`, the second key pair that you created during [FIT signing](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr/). Copy the FIT source with `sed`, replacing `key-a` with `key-b` and the `hello` application path with `hello_b`. + +Then, sign the new FIT: ```bash sed 's/key-a/key-b/g; s#/hello/#/hello_b/#' $FIT/zephyr-a.its > $FIT/zephyr-b.its @@ -92,7 +94,7 @@ The output is similar to: If `cmp` prints nothing, the selected byte was already `0xff`. Choose another offset inside the payload, such as `seek=32800`, then repeat the `dd` and `cmp` commands. -Expect the signature check to pass and the payload hash check to fail. The signature covers the unchanged configuration and `hash-1` node. The hash covers the payload bytes you modified. +Expect the signature check to pass and the payload hash check to fail. The signature covers the unchanged configuration and `hash-1` node. The hash covers the payload bytes that you modified. ## Check both images on the host @@ -114,7 +116,7 @@ Signature check bad (error 1) Check for `sha256,rsa2048:key-b-` and `Failed to verify required signature 'key-key-a'`. The final verdict, `Signature check bad (error 1)`, confirms rejection. The exit code is one. -Then check the tampered image: +Then, check the tampered image: ```bash $UBOOT_OUT/tools/fit_check_sign -f $FIT/zephyr-tampered.itb -k $UBOOT_OUT/u-boot.dtb @@ -197,10 +199,10 @@ This example lists the AM62L EVM's six files: three boot files and three FITs. T {{< tabpane-normal >}} {{< tab header="QEMU" >}} -Restart QEMU with the same command used to boot the trusted image. QEMU reads the updated `disk.img` directly; no physical media needs to be written. +Restart QEMU with the same command used to boot the trusted image. QEMU reads the updated `disk.img` directly. No physical media needs to be written. {{< /tab >}} {{< tab header="AM62L EVM" >}} -Write the updated image to the card. Confirm the card's device name before replacing `/dev/sdX`; `dd` overwrites the entire selected disk: +Write the updated image to the card. Confirm the card's device name before replacing `/dev/sdX`. `dd` overwrites the entire selected disk: ```bash sudo dd if=$WORK/sdcard.img of=/dev/sdX bs=4M conv=fsync status=progress @@ -212,7 +214,7 @@ Move the card to the board, open the console with `picocom`, and power the board ## Run the wrong-key test -Press a key during the three-second countdown to stop autoboot. If you miss it, U-Boot starts image A; start the target again and try once more. At the prompt, run the wrong-key test: +Press a key during the three-second countdown to stop autoboot. If you miss it, U-Boot starts image A. Start the target again and try once more. At the prompt, run the wrong-key test: ```console => run b @@ -232,9 +234,9 @@ ERROR -2: can't get kernel image! *** REFUSED: Zephyr was NOT started *** ``` -Check for `sha256,rsa2048:key-b- error!` and `Failed to verify required signature 'key-key-a'`. The `-` indicates failure: the image's signature doesn't satisfy the required `key-a` check. +Check for `sha256,rsa2048:key-b- error!` and `Failed to verify required signature 'key-key-a'`. The `-` indicates failure, as the image's signature doesn't satisfy the required `key-a` check. -When `bootm start` fails, the `&&` chain skips `go` and prints `*** REFUSED: Zephyr was NOT started ***`. Confirm that no Zephyr banner appears. `Bad Data Hash` and `ERROR -2: can't get kernel image!` can appear for either rejection test; use the preceding messages to identify which check failed. +When `bootm start` fails, the `&&` chain skips `go` and prints `*** REFUSED: Zephyr was NOT started ***`. Confirm that no Zephyr banner appears. `Bad Data Hash` and `ERROR -2: can't get kernel image!` can appear for either rejection test. Use the preceding messages to identify which check failed. ## Run the tampered-image test @@ -281,4 +283,6 @@ To boot the trusted image again, type `run a`. ## What you've accomplished and what's next -You've confirmed that U-Boot rejects the wrong-key image at the signature check and the tampered image at the payload hash check. Neither reaches `go` or starts Zephyr. Next, you'll review what these tests establish and what a production device still needs. +You've confirmed that U-Boot rejects the wrong-key image at the signature check and the tampered image at the payload hash check. Neither reaches `go` or starts Zephyr. + +Next, you'll review what these tests establish and what a production device still needs. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md index 6bf1cf54b9..a5da8f6c82 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md @@ -1,5 +1,5 @@ --- -title: Review what is verified and what production needs +title: Review what you verified and what you need for production description: Review the trust boundary of U-Boot's Zephyr FIT verification and the key provisioning, boot controls, and release signing needed for production. weight: 9 @@ -9,29 +9,31 @@ layout: learningpathall ## Understand the verification boundary -You've configured U-Boot to verify the Zephyr payload, the last link in the boot chain. U-Boot reads `zephyr-a.itb`, verifies `conf-1` with the embedded public key for `key-a`, and checks the payload hash before jumping to `ZEPHYR_ADDR`. +You've configured U-Boot to verify the Zephyr payload, the last link in the boot chain. U-Boot reads `zephyr-a.itb` and verifies `conf-1` with the embedded public key for `key-a`. It checks the payload hash before jumping to `ZEPHYR_ADDR`. -If you ran the optional [refusal tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/), you also confirmed two rejection cases. The wrong-key FIT fails with `Failed to verify required signature 'key-key-a'`. The modified payload fails with `Bad hash value for 'hash-1'`. Neither starts Zephyr. +If you ran the optional [refusal tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/), you also confirmed two rejection cases. The wrong-key Flattened Image Tree (FIT) fails with `Failed to verify required signature 'key-key-a'`. The modified payload fails with `Bad hash value for 'hash-1'`. Neither starts Zephyr. The earlier stages aren't authenticated against your key in either setup. QEMU loads `u-boot.bin` directly, without a boot ROM, security firmware, or eFuses to authenticate it. -The AM62L EVM has those earlier stages, but you've left it in TI's High Security, Field Securable (HS-FS) development state. In this state, the ROM and vendor firmware check boot files but accept any signing key. The U-Boot banner identifies it as `SoC: AM62LX SR1.1 HS-FS`. Provisioning your key into the one-time-programmable eFuses moves the device to High Security, Security Enforced (HS-SE). +The AM62L evaluation module (EVM) has those earlier stages, but you've left it in TI's High Security, Field Securable (HS-FS) development state. In this state, the ROM and vendor firmware check boot files but accept any signing key. The U-Boot banner identifies it as `SoC: AM62LX SR1.1 HS-FS`. Provisioning your key into the one-time-programmable eFuses moves the device to High Security, Security Enforced (HS-SE). -On the EVM, the trusted public key is inside `u-boot.img` on an unprotected FAT partition. Anyone who can replace that file can replace the key and boot command. Production needs an authenticated U-Boot and controls that prevent bypassing its verification step. +On the EVM, the trusted public key is inside `u-boot.img` on an unprotected File Allocation Table (FAT) partition. Anyone who can replace that file can replace the key and boot command. Production needs an authenticated U-Boot and controls that prevent bypassing its verification step. ## What production needs +For production, you need the following: + ### Fuse your key and move to the production state TI's one-time-programmable (OTP) Keywriter tool, called Keywriter Lite on the AM62L, burns the public-key hash into the eFuses and moves the chip to HS-SE. You then re-sign `tiboot3.bin`, `tispl.bin`, and `u-boot.img` with that key. -The ROM and security firmware then require boot files signed with your key, including U-Boot. This authenticates the U-Boot image containing the FIT public key. Key provisioning is vendor-specific and isn't covered by these steps. +The ROM and security firmware then require boot files signed with your key, including U-Boot. This authenticates the U-Boot image containing the FIT public key. Key provisioning is vendor-specific and isn't covered in these steps. ### Keep the environment built in `bootcmd` selects the autoboot command. `preboot` defines `zboot` and the `a`, `b`, and `t` wrappers before autoboot starts. -Both builds use `CONFIG_ENV_IS_NOWHERE=y`: you added it for QEMU, and the AM62L default configuration supplies it. This prevents `saveenv` from writing a persistent environment, so boot settings are loaded from the binary you built. Check that your board's `.config` includes the same setting. +Both builds use `CONFIG_ENV_IS_NOWHERE=y`: you added it for QEMU, and the AM62L default configuration supplies it. This prevents `saveenv` from writing a persistent environment, so boot settings are loaded from the binary that you built. Check that your board's `.config` includes the same setting. {{% notice Warning %}} Don't enable `CONFIG_ENV_IS_IN_FAT` for this boot configuration. It stores the environment in `uboot.env` on the boot media. A saved environment can override `bootcmd` and `preboot`, allowing someone with write access to the card to bypass verification. @@ -41,11 +43,11 @@ Don't enable `CONFIG_ENV_IS_IN_FAT` for this boot configuration. It stores the e With `CONFIG_BOOTDELAY=3`, someone with serial-console access can interrupt autoboot and run `fatload` and `go` without verification. Set `CONFIG_BOOTDELAY=-2` to remove the delay and keyboard check, or use `CONFIG_AUTOBOOT_KEYED` to require a known string to interrupt autoboot. -These settings cover only the countdown. If `bootcmd` returns after rejecting an image, U-Boot still opens the `=>` prompt. In a production build, add `reset` after the refusal `echo` in `zboot`, so a failed boot restarts the board instead of opening the console. +These settings cover only the countdown. If `bootcmd` returns after rejecting an image, U-Boot still opens the `=>` prompt. In a production build, add `reset` after the refusal `echo` in `zboot`. This ensures that a failed boot restarts the board instead of opening the console. ### Protect production keys and sign during release -The demonstration uses `sha256,rsa2048`; the AM62L's own boot chain uses `sha512,rsa4096`. To use the latter for your FIT: +You used `sha256,rsa2048`. The AM62L's own boot chain uses `sha512,rsa4096`. To use the latter for your FIT: - Generate keys with `rsa_keygen_bits:4096`. - Set `algo = "sha512,rsa4096"` in both `zephyr-a.its` and `key.its`. @@ -58,14 +60,14 @@ Generate production keys in a hardware security module (HSM), or at least away f Start by updating the target values and paths in your environment file: - `BOARD` is the Zephyr board identifier, from `west boards` or the Workbench board list. The board needs the two settings from [Build a Zephyr image that U-Boot can start](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr/): the Non-secure world and the arm64 image header. -- `ZEPHYR_ADDR` is the start of the memory node that the board's device tree selects as `zephyr,sram`. It is Zephyr's link address, the FIT `load` and `entry`, and the `go` target, so one value serves all three. -- `FIT_ADDR` is any free address clear of `ZEPHYR_ADDR` and of the firmware regions; otherwise `bootm loados` copies Zephyr over the FIT it is still reading. -- `BOOT_DEV` is the U-Boot device and partition that hold the files. `mmc 1:1` is the SD card's first partition on the AM62L EVM, while `mmc 0` is the eMMC; `mmc list` at the U-Boot prompt shows your board's numbering. +- `ZEPHYR_ADDR` is the start of the memory node that the board's device tree selects as `zephyr,sram`. It's Zephyr's link address, the FIT `load` and `entry`, and the `go` target, so one value serves all three. +- `FIT_ADDR` is any free address clear of `ZEPHYR_ADDR` and of the firmware regions. Otherwise, `bootm loados` copies Zephyr over the FIT it is still reading. +- `BOOT_DEV` is the U-Boot device and partition that hold the files. `mmc 1:1` is the SD card's first partition on the AM62L EVM, while `mmc 0` is the eMMC. `mmc list` at the U-Boot prompt shows your board's numbering. - `UBOOT_DEFCONFIG` selects the board's U-Boot default configuration. Check for `CONFIG_FIT=y`, `CONFIG_FIT_SIGNATURE=y`, and `CONFIG_RSA=y`. Add missing settings to the [U-Boot configuration fragment](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot/). Disable legacy images with `# CONFIG_LEGACY_IMAGE_FORMAT is not set`. -- `UBOOT_SRC`, `CROSS` and `UBOOT_CC` point at the U-Boot source and the compiler that builds it, with `SDK`, `PREBUILT` and `SYSROOT` added when they come from a vendor SDK, as on the AM62L. -- `BOOT_IMG` is the boot volume `mcopy` writes into: the card image on the EVM, the disk image in QEMU, each with the `@@` offset of its FAT partition. +- `UBOOT_SRC`, `CROSS`, and `UBOOT_CC` point at the U-Boot source and the compiler that builds it. `SDK`, `PREBUILT`, and `SYSROOT` are added when they come from a vendor SDK, as on the AM62L. +- `BOOT_IMG` is the boot volume that `mcopy` writes into: the card image on the EVM, the disk image in QEMU, each with the `@@` offset of its FAT partition. -Also adapt the U-Boot build command and boot-media preparation. The build inputs depend on the target: `EXT_DTB` for QEMU, or `BL1`, `BL31`, `TEE`, and `BINMAN_INDIRS` for the AM62L EVM. Output names also vary, often including `u-boot.img` or `u-boot.itb` and an SPL file. Follow the target's requirements for media layout, boot switches, and console access. +Also adapt the U-Boot build command and boot-media preparation. The build inputs depend on the target: `EXT_DTB` for QEMU, or `BL1`, `BL31`, `TEE`, and `BINMAN_INDIRS` for the AM62L EVM. Output names also vary, often including `u-boot.img` or `u-boot.itb` and a Secondary Program Loader (SPL) file. Follow the target's requirements for media layout, boot switches, and console access. Check how the target obtains its control device tree. `CONFIG_DEVICE_TREE_INCLUDES` adds the key node when the tree is built from source with `CONFIG_OF_SEPARATE=y` or `CONFIG_OF_EMBED=y`, as on the AM62L EVM. @@ -73,8 +75,11 @@ For a board using a tree from a prior stage (`CONFIG_OF_BOARD=y`), follow the QE Reuse the FIT signing and verification workflow, adapting the target values in the FIT source and boot command as needed. -## Where to go from here +## What you've accomplished + +You've established verification of the Zephyr payload and learned how you can extend the workflow to production and to another Cortex-A board. + +Before using this approach in production, authenticate the earlier boot stages. Also protect the boot environment and console and move signing into a controlled release process. To sign your own application for the same target, point `data` in `zephyr-a.its` to its `zephyr.bin` and sign the FIT again. To use another Cortex-A board, adapt the environment, build inputs, and boot media using the checklist in this section. -You've established verification of the Zephyr payload. Before using this approach in production, authenticate the earlier boot stages, protect the boot environment and console, and move signing into a controlled release process. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md index f5615391cf..db7eb5c81c 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md @@ -1,10 +1,6 @@ --- title: Boot a signed Zephyr image with U-Boot on Arm Cortex-A -draft: true -cascade: - draft: true - description: Sign a Zephyr FIT image and configure U-Boot to verify its signature and payload hash before booting on Arm Cortex-A in QEMU or on a TI AM62L EVM. minutes_to_complete: 120 @@ -12,10 +8,10 @@ minutes_to_complete: 120 who_is_this_for: This is an advanced topic for embedded developers who boot Zephyr from U-Boot on an Arm Cortex-A processor and want U-Boot to verify the Zephyr image before starting it. learning_objectives: - - Identify where U-Boot verifies Zephyr in the Arm Cortex-A boot chain - - Build and sign a Flattened Image Tree (FIT) containing Zephyr, and embed the public key in U-Boot without changing its source - - Configure U-Boot to verify Zephyr before booting, and optionally test rejection of wrong-key and tampered images - - Explain the verification boundary in QEMU and on a development board, and how fusing your key extends trust in production + - Identify where U-Boot verifies Zephyr in the Arm Cortex-A boot chain. + - Build and sign a Flattened Image Tree (FIT) containing Zephyr, and embed the public key in U-Boot without changing its source. + - Configure U-Boot to verify Zephyr before booting, and optionally test rejection of wrong-key and tampered images. + - Identify the verification boundary in QEMU and on a development board, and how fusing your key extends trust in production. prerequisites: - One of two targets - QEMU, which needs no hardware, or a TI [AM62L EVM](https://www.ti.com/tool/TMDS62LEVM) with accessories to power it, write an SD card, and attach a serial console From 063e068358d2e94fc973bde359828e16a1a28109 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Tue, 6 Oct 2026 13:26:05 -0500 Subject: [PATCH 2/5] adding summary and FAQs --- .../6-boot-the-target.md | 2 +- .../8-production.md | 4 +- .../_index.md | 48 ++++++++++++++++++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md index 76f8869a76..c4dbd3f072 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md @@ -1,5 +1,5 @@ --- -title: Boot the target +title: Boot your QEMU or TI AM62L EVM target description: Prepare boot media for QEMU or the TI AM62L EVM and confirm that U-Boot verifies the signed Zephyr FIT before starting the application. weight: 7 diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md index a5da8f6c82..b36154fe52 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md @@ -19,9 +19,9 @@ The AM62L evaluation module (EVM) has those earlier stages, but you've left it i On the EVM, the trusted public key is inside `u-boot.img` on an unprotected File Allocation Table (FAT) partition. Anyone who can replace that file can replace the key and boot command. Production needs an authenticated U-Boot and controls that prevent bypassing its verification step. -## What production needs +## What you need for production -For production, you need the following: +For production, ensure that you complete the following steps: ### Fuse your key and move to the production state diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md index db7eb5c81c..1f1e9392b6 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md @@ -19,13 +19,59 @@ prerequisites: - Visual Studio Code with the [Workbench for Zephyr extension](https://marketplace.visualstudio.com/items?itemName=Ac6.zephyr-workbench) installed - Basic knowledge of U-Boot and the Linux command line +# START generated_summary_faq +generated_summary_faq: + template_version: summary-faq-v3 + generated_at: '2026-10-06T18:12:37Z' + generator: ai + ai_assisted: true + ai_review_required: true + model: gpt-5 + prompt_template: summary-faq-v3 + source_hash: d29bf65cd5b55f7b412beeb0a62873a02eec10189fb6c259f2a5f84f9d016416 + summary_generated_at: '2026-10-06T18:12:37Z' + summary_source_hash: d29bf65cd5b55f7b412beeb0a62873a02eec10189fb6c259f2a5f84f9d016416 + faq_generated_at: '2026-10-06T18:12:37Z' + faq_source_hash: d29bf65cd5b55f7b412beeb0a62873a02eec10189fb6c259f2a5f84f9d016416 + summary: >- + You'll build a Zephyr image for Arm Cortex-A and configure U-Boot to verify its signed FIT before booting. After choosing QEMU or a TI AM62L evaluation module (EVM), you'll set up the host + tools, build Zephyr, sign the FIT, and embed the trusted public key in U-Boot. You'll then boot + the image, optionally test rejection of untrusted or tampered images, and examine what remains + outside the verification boundary. + faqs: + - question: Do I need an AM62L EVM to follow this Learning Path? + answer: >- + No. You can use QEMU without hardware. If you have an AM62L EVM, follow its target-specific + setup and boot-media instructions instead. + - question: Why does U-Boot need the public key in its control device tree? + answer: >- + You'll embed the trusted public key in U-Boot's control device tree so that it can verify the FIT + configuration signature. The key's `required = "conf"` setting makes U-Boot reject a FIT + without a valid signature from that key. + - question: How can I check the signed FIT before booting the target? + answer: >- + Use U-Boot's `fit_check_sign` with your signed FIT and built `u-boot.dtb`. This checks the + FIT against the public key in the control device tree before you prepare the boot media. + - question: How do I confirm that verification succeeded on the target? + answer: >- + Look for `sha256,rsa2048:key-a+ OK` in U-Boot's output, followed by the Zephyr image A banner. + You can also run the optional wrong-key and tampered-image tests to check that U-Boot refuses + to start either image. + - question: Does this setup authenticate U-Boot as well as Zephyr? + answer: >- + No. In QEMU, you run U-Boot without an earlier stage that authenticates it. On the AM62L EVM, + you leave the device in High Security, Field Securable (HS-FS) development state, where earlier stages accept boot files + signed with any key. To extend trust to U-Boot in production, you need to provision your key, + move the device to High Security, Security Enforced (HS-SE), and sign the earlier boot files. +# END generated_summary_faq + author: - Roy Jamil - Odin Shen # New Learning Paths are opted in for the next manual generated summary/FAQ run. # The generator resets this to false after a successful write. -generate_summary_faq: true +generate_summary_faq: false # Optional one-shot controls: set either field to true to regenerate just that # generated section the next time the summary/FAQ tool runs. The tool resets From bea0ea756a130bab53eabb49e38a200a4ee59534 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Tue, 6 Oct 2026 13:41:32 -0500 Subject: [PATCH 3/5] assisted edits --- .../1-boot-chain.md | 2 +- .../2-set-up-tools.md | 14 +++++++------- .../3-build-zephyr.md | 7 ++++--- .../4-sign-zephyr.md | 2 +- .../6-boot-the-target.md | 4 ++-- .../8-production.md | 6 +++--- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md index fb0fcb23ef..43b5d2a425 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md @@ -82,7 +82,7 @@ If you choose QEMU as your target, there's no key to fuse and nothing checks U-B If you choose AM62L EVM as your target, leave it in its development state without fusing your key into the chip. In that state, the ROM and vendor firmware accept boot files signed with any key. U-Boot's check of Zephyr is enforced either way. -You'll review what a production device needs in [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). +You'll review [U-Boot's Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/) after booting the image. ## What you've learned and what's next diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md index 7eb439916e..a4b9255fd5 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md @@ -18,12 +18,12 @@ To install host tools on Visual Studio Code: 1. Open Visual Studio Code and select **Workbench for Zephyr** in the Activity Bar. 2. In its panel, select **Install Host Tools** to install the dependencies used to build Zephyr: -- Python -- CMake -- Ninja -- Git -- Device Tree Compiler -- West + - Python + - CMake + - Ninja + - Git + - Device Tree Compiler + - West 3. When installation finishes, select **Verify Host Tools**. Resolve any missing-tool errors before continuing. @@ -108,7 +108,7 @@ mkdir -p $KEYS $FIT {{< /tab >}} {{< /tabpane >}} -The variables are available only in the shell where you load the environment file. If you open a new terminal, you'll have to load the environment file again. If you adapt the workflow to another board, you'll learn how to choose its target values and paths in [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). +The variables are available only in the shell where you load the environment file. If you open a new terminal, you'll have to load the environment file again. If you adapt the workflow to another board, you'll learn how to choose its target values and paths in the [optional board-adaptation guidance](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). {{% notice Note %}} Example output shows paths under `/home/user/`, the home directory of the account that produced it. The paths in your output will reflect your own username. On a standard Ubuntu cloud instance, for example, they appear under `/home/ubuntu/`. The commands use `$HOME` and `$WORK`, so they adapt to your account automatically. Only the printed paths in the output might differ. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md index 0dba724f4f..e686b5d660 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md @@ -74,9 +74,10 @@ Select **Add Application** and fill in the wizard: 8. For **Application type**, select **West workspace application**. 9. For **Project Location**, ensure the value is **`zephyrproject/applications/hello`**, filled in by the wizard. - Check that the board identifier matches `BOARD` in your environment file: `qemu_cortex_a53` for QEMU or `am62l_evm/am62l3/a53` for the AM62L EVM. -9. Select **Create**. -![Workbench for Zephyr Add Application wizard creating hello from the hello_world sample with the zephyrproject workspace and Zephyr SDK 1.0.1. The AM62L EVM is selected; the callout identifies the alternative QEMU Cortex-A53 board.#center](images/wz-add-application.webp "Create hello for your chosen target") + Check that the board identifier matches `BOARD` in your environment file: `qemu_cortex_a53` for QEMU or `am62l_evm/am62l3/a53` for the AM62L EVM. +10. Select **Create**. + + ![Workbench for Zephyr Add Application wizard creating hello from the hello_world sample with the zephyrproject workspace and Zephyr SDK 1.0.1. The AM62L EVM is selected; the callout identifies the alternative QEMU Cortex-A53 board.#center](images/wz-add-application.webp "Create hello for your chosen target") The application `hello` appears in the **Applications** view, marked `[with zephyrproject]`. `zephyrproject/applications/hello` holds the sample's `CMakeLists.txt`, `prj.conf` and `src/main.c`. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md index aa8418bfc2..abd690e90a 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md @@ -78,7 +78,7 @@ key-a.crt key-a.key key-b.crt key-b.key - `.crt` is a self-signed certificate containing the public key. - The shared file-name stem, ``, matches `key-name-hint` in the FIT source. -These 2048-bit keys are generated on the build host for this demonstration. The later section, [Review what you verified and what you need for production](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/), covers production key handling. +These 2048-bit keys are generated on the build host for this demonstration. The later section on [U-Boot's Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/) covers production key handling. ## Write the FIT source diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md index c4dbd3f072..09eab839a1 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md @@ -1,5 +1,5 @@ --- -title: Boot your QEMU or TI AM62L EVM target +title: Boot the signed Zephyr FIT with U-Boot on QEMU or the TI AM62L EVM description: Prepare boot media for QEMU or the TI AM62L EVM and confirm that U-Boot verifies the signed Zephyr FIT before starting the application. weight: 7 @@ -273,7 +273,7 @@ Check the symptom and try the corresponding step: If the terminal stays empty, check the console connection and whether the ROM loads `tiboot3.bin`: 1. Try all four serial ports that **J7** creates. The console isn't always the first one. -2. Check **SW3**, or switch to the full pincount setting, which uses all three switch banks. BOOTMODE `0x0E43` in the same guide. +2. Check **SW3**, or switch to the full pin-count setting, which uses all three switch banks. See BOOTMODE `0x0E43` in the AM62L EVM User's Guide. 3. Check that the card's first partition is still TI's FAT16 partition, not reformatted. 4. Flash TI's unchanged `.wic.xz` to a card and boot it. If that also produces no output, check the boot switches, serial port, and power supply before investigating your custom boot files. 5. If TI's card boots but yours never shows the SPL banner, copy TI's prebuilt first two stages over yours with `mcopy -o -i $BOOT_IMG $PREBUILT/tiboot3.bin $PREBUILT/tispl.bin ::`. Then, write the card again with the same `dd`. `u-boot.img` still carries the key and the boot command. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md index b36154fe52..0d67b93011 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md @@ -1,5 +1,5 @@ --- -title: Review what you verified and what you need for production +title: Review U-Boot's Zephyr FIT verification boundary and production needs description: Review the trust boundary of U-Boot's Zephyr FIT verification and the key provisioning, boot controls, and release signing needed for production. weight: 9 @@ -55,9 +55,9 @@ You used `sha256,rsa2048`. The AM62L's own boot chain uses `sha512,rsa4096`. To Generate production keys in a hardware security module (HSM), or at least away from the build host. Sign during the release process and restrict private-key access to that process. -## Adapt the workflow to another Cortex-A board +## Optional follow-up: Adapt the workflow to another Cortex-A board -Start by updating the target values and paths in your environment file: +If you want to use another Cortex-A board, start by updating the target values and paths in your environment file: - `BOARD` is the Zephyr board identifier, from `west boards` or the Workbench board list. The board needs the two settings from [Build a Zephyr image that U-Boot can start](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr/): the Non-secure world and the arm64 image header. - `ZEPHYR_ADDR` is the start of the memory node that the board's device tree selects as `zephyr,sram`. It's Zephyr's link address, the FIT `load` and `entry`, and the `go` target, so one value serves all three. From 9f1012586bbc5a15e6b268692817fd7e51379e31 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Tue, 6 Oct 2026 13:44:07 -0500 Subject: [PATCH 4/5] nit --- .../zephyr-signed-fit-uboot-cortex-a/8-production.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md index 0d67b93011..edbc526139 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md @@ -55,7 +55,7 @@ You used `sha256,rsa2048`. The AM62L's own boot chain uses `sha512,rsa4096`. To Generate production keys in a hardware security module (HSM), or at least away from the build host. Sign during the release process and restrict private-key access to that process. -## Optional follow-up: Adapt the workflow to another Cortex-A board +## Adapt the workflow to another Cortex-A board If you want to use another Cortex-A board, start by updating the target values and paths in your environment file: From bbeb0c2d939b7fce92ecd60b0406577137e75c52 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Tue, 6 Oct 2026 15:23:38 -0500 Subject: [PATCH 5/5] another pass --- .../1-boot-chain.md | 40 +++++++++---------- .../2-set-up-tools.md | 14 +++---- .../3-build-zephyr.md | 32 ++++++++------- .../4-sign-zephyr.md | 20 +++++----- .../5-build-uboot.md | 22 +++++----- .../6-boot-the-target.md | 28 ++++++------- .../7-test-the-checks.md | 12 +++--- .../8-production.md | 19 +++++---- .../_index.md | 18 ++++----- 9 files changed, 103 insertions(+), 102 deletions(-) diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md index 43b5d2a425..196a456b18 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/1-boot-chain.md @@ -1,5 +1,5 @@ --- -title: Learn where Zephyr sits in the Cortex-A boot chain +title: Understand where U-Boot verifies Zephyr in the Cortex-A boot chain description: Learn why Zephyr on a Cortex-A processor is a payload that U-Boot can verify, what a FIT image contains, and how the boot chain hands control to it. weight: 2 @@ -7,9 +7,9 @@ weight: 2 layout: learningpathall --- -## Zephyr is the last stage, not the first +## Where Zephyr fits in the Cortex-A boot chain -On a microcontroller (MCU), Zephyr runs first, so secure boot means adding a bootloader such as MCUboot. A Cortex-A processor starts in a read-only memory (ROM) inside the system on chip (SoC), and several firmware stages run before your code. Zephyr is the last stage, so the stage before it, usually U-Boot, can check it before starting it. +On a microcontroller (MCU), Zephyr runs first, so secure boot means adding a bootloader such as MCUboot. A Cortex-A processor starts in a read-only memory (ROM) inside the system on chip (SoC), and several firmware stages run before your code. Zephyr is the last stage, so the stage before it — usually U-Boot — can check it before starting it. You'll package Zephyr in a Flattened Image Tree (FIT) with a signature that U-Boot verifies before starting the image. @@ -17,13 +17,13 @@ You'll build and boot a verified Zephyr image either in QEMU without hardware, o ## The boot chain on a Cortex-A board -On an Armv8-A board using U-Boot, boot proceeds from the SoC's boot ROM through early firmware to U-Boot. U-Boot then loads and starts the payload: Zephyr in your setup. +On an Armv8-A board using U-Boot, boot proceeds from the boot ROM of the SoC through early firmware to U-Boot. U-Boot then loads and starts the payload. -The early firmware is usually the Secondary Program Loader (SPL), a small U-Boot that loads the full one. In addition, Trusted Firmware-A (TF-A) and Open Portable Trusted Execution Environment (OP-TEE) run in the Secure world. Many SoCs add the vendor's own security firmware, which checks the later stages. +The early firmware is usually the Secondary Program Loader (SPL), a small U-Boot that loads the full one. In addition, Trusted Firmware-A (TF-A) and Open Portable Trusted Execution Environment (OP-TEE) run in the Secure world. Many SoCs add security firmware from the vendor, which checks the later stages. -You'll build the SPL with U-Boot. The rest comes prebuilt in the vendor's SDK. +You'll build the SPL with U-Boot. The rest comes prebuilt in the SDK from the vendor. -![Cortex-A boot chain from boot ROM through early firmware and U-Boot to a signed Zephyr FIT image. U-Boot verifies Zephyr; trust in the earlier stages depends on the platform's secure-boot configuration.#center](images/boot-chain-generic.svg "U-Boot verifies Zephyr in the Cortex-A boot chain") +![Cortex-A boot chain from boot ROM through early firmware and U-Boot to a signed Zephyr FIT image. U-Boot verifies Zephyr; trust in the earlier stages depends on the secure-boot configuration of the platform.#center](images/boot-chain-generic.svg "U-Boot verifies Zephyr in the Cortex-A boot chain") ## Choose your target @@ -33,56 +33,56 @@ Choose between QEMU and AM62L EVM. QEMU is the default target for which you need |---|---|---| | Hardware | None | The board, a micro-SD card and reader, a micro-USB cable, and a USB-C PD supply | | Download | U-Boot source, 32 MB | TI Processor SDK, 4.5 GB, unpacks to 11 GB | -| Stages before U-Boot | None: QEMU starts `u-boot.bin` directly | Boot ROM, `tiboot3.bin`, `tispl.bin` | +| Stages before U-Boot | None, as QEMU starts `u-boot.bin` directly | Boot ROM, `tiboot3.bin`, `tispl.bin` | | Zephyr board | `qemu_cortex_a53` | `am62l_evm/am62l3/a53` | | Boot media | File Allocation Table (FAT) partition in a 64 MiB disk image, `virtio 0:1` | FAT partition on a micro-SD card, `mmc 1:1` | | Console | The terminal that you start QEMU in | USB serial at 115200 baud | ### The boot chain in QEMU -QEMU's `virt` machine has no boot ROM and no vendor firmware. It loads the file that you pass to `-bios` and starts the Cortex-A53 on it, so the chain is two links long: +The QEMU `virt` machine has no boot ROM and no vendor firmware. It loads the file that you pass to `-bios` and starts the Cortex-A53 on it, so the chain is two links long: ```output QEMU -bios u-boot.bin -> U-Boot -> Zephyr inside a FIT image ``` -QEMU runs U-Boot's FIT verifier, but nothing authenticates U-Boot itself. +QEMU runs the FIT verifier in U-Boot, but nothing authenticates U-Boot itself. ### The boot chain on the AM62L EVM -On the AM62L, the early stages are two files. `tiboot3.bin` holds TF-A's first stage and TI Foundational Security (TIFS), TI's security firmware. `tispl.bin` holds the rest of TF-A, OP-TEE, and the SPL. You'll build them together with `u-boot.img` when you build U-Boot. The EVM ships in TI's High Security, Field Securable (HS-FS) development state. +On the AM62L, the early stages are two files. `tiboot3.bin` holds the first stage of TF-A and TI Foundational Security (TIFS), TI's security firmware. `tispl.bin` holds the rest of TF-A, OP-TEE, and the SPL. You'll build them together with `u-boot.img` when you build U-Boot. The EVM ships in TI's High Security, Field Securable (HS-FS) development state. ![AM62L boot chain from boot ROM through `tiboot3.bin`, `tispl.bin`, and `u-boot.img` to the Zephyr FIT image. In HS-FS development mode, the early stages accept any signing key; U-Boot verifies Zephyr against your key before starting it.#center](images/boot-chain.svg "The same chain on the AM62L, with TI's file names") ## What a FIT image is -A FIT is U-Boot's container format for boot images. It's a device tree blob (DTB) whose nodes hold images instead of hardware descriptions. +A FIT is a container format for U-Boot boot images. It's a device tree blob (DTB) whose nodes hold images instead of hardware descriptions. -The signed FIT that you'll build contains: +The signed FIT that you'll build contains the following: -- The image itself, which is Zephyr's `zephyr.bin` +- The image itself, which is the Zephyr binary `zephyr.bin` - A hash of that image, so that U-Boot can tell if a byte changed - A configuration that names the image to use (`kernel = "kernel-1"`) and carries a signature -`mkimage`, a U-Boot host tool, builds the FIT from a text source `.its` file and signs it with your private key. On the target, U-Boot's `bootm` command parses the FIT, verifies the signature and the hash, and copies the image to its load address. +`mkimage`, a U-Boot host tool, builds the FIT from a text source `.its` file and signs it with your private key. On the target, the U-Boot `bootm` command parses the FIT, verifies the signature and the hash, and copies the image to its load address. You'll sign the FIT configuration with `sha256,rsa2048`, which combines SHA-256 hashing with a 2048-bit RSA key. -The public key lives inside U-Boot's own device tree, the control device tree, under a `/signature` node. That key node carries `required = "conf"`. Every configuration in every FIT must carry a valid signature by this key, or U-Boot refuses to load it. Without `required`, a FIT with no signature still boots. +The public key lives under a `/signature` node in the U-Boot control device tree. That key node carries `required = "conf"`. Every configuration in every FIT must carry a valid signature by this key, or U-Boot refuses to load it. Without `required`, a FIT with no signature still boots. -![Signed FIT image beside U-Boot's control device tree, which holds the required public key. The signature covers the FIT configuration and payload hash; the hash covers the Zephyr image bytes.#center](images/fit-signature.svg "What the signature and the hash each cover in a FIT image") +![Signed FIT image beside the U-Boot control device tree, which holds the required public key. The signature covers the FIT configuration and payload hash; the hash covers the Zephyr image bytes.#center](images/fit-signature.svg "What the signature and the hash each cover in a FIT image") The signature doesn't cover the image bytes. It covers the configuration node plus the hash node, and the hash covers the bytes. ## Verify Zephyr before starting it -Configure U-Boot to verify the Zephyr FIT before starting Zephyr with `go`, U-Boot's command for jumping to an address. +Configure U-Boot to verify the Zephyr FIT before starting Zephyr with `go`, a U-Boot command for jumping to an address. If you choose QEMU as your target, there's no key to fuse and nothing checks U-Boot at all. -If you choose AM62L EVM as your target, leave it in its development state without fusing your key into the chip. In that state, the ROM and vendor firmware accept boot files signed with any key. U-Boot's check of Zephyr is enforced either way. +If you choose AM62L EVM as your target, leave it in its development state without fusing your key into the chip. In that state, the ROM and vendor firmware accept boot files signed with any key. U-Boot verifies Zephyr either way. -You'll review [U-Boot's Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/) after booting the image. +After booting the image, you'll review [the Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). ## What you've learned and what's next diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md index a4b9255fd5..ecbf9a4936 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools.md @@ -7,7 +7,7 @@ weight: 3 layout: learningpathall --- -## What you need +## What you need to set up You need Zephyr host tools, U-Boot source, and a cross compiler for your chosen target. For QEMU, download U-Boot source and install the emulator and compiler from Ubuntu packages. For the AM62L evaluation module (EVM), the TI Processor SDK supplies U-Boot source, the cross compiler, and prebuilt early firmware. @@ -37,12 +37,12 @@ Install the additional packages used to build U-Boot, sign images, and prepare t sudo apt install -y build-essential bison flex swig python3-dev python3-setuptools libssl-dev libgnutls28-dev uuid-dev device-tree-compiler openssl mtools dosfstools xz-utils curl picocom ``` -If you chose QEMU as your target, install the emulator and U-Boot cross compiler with this command: +If you chose QEMU as your target, install the emulator and U-Boot cross compiler: ```bash sudo apt install -y qemu-system-arm gcc-aarch64-linux-gnu ``` -For the AM62L EVM, skip installing the emulator. You'll get the cross compiler from the TI SDK +For the AM62L EVM, skip installing the emulator. You'll get the cross compiler from the TI SDK. ## Create the working directory and environment file @@ -61,7 +61,7 @@ export BOARD=qemu_cortex_a53 # Zephyr board identifier export ZEPHYR_ADDR=0x40000000 # Zephyr link address, FIT load and go target export FIT_ADDR=0x48000000 # where U-Boot loads the FIT, clear of ZEPHYR_ADDR export BOOT_DEV="virtio 0:1" # U-Boot device and partition that hold the files -export UBOOT_DEFCONFIG=qemu_arm64_defconfig # the target's U-Boot configuration +export UBOOT_DEFCONFIG=qemu_arm64_defconfig # U-Boot configuration for the target # No vendor SDK: U-Boot from the U-Boot project, cross compiler from Ubuntu export UBOOT_SRC=$WORK/u-boot-2025.07 @@ -87,7 +87,7 @@ export BOARD=am62l_evm/am62l3/a53 # Zephyr board identifier export ZEPHYR_ADDR=0x82000000 # Zephyr link address, FIT load and go target export FIT_ADDR=0x90000000 # where U-Boot loads the FIT, clear of ZEPHYR_ADDR export BOOT_DEV="mmc 1:1" # U-Boot device and partition that hold the files -export UBOOT_DEFCONFIG=am62lx_evm_defconfig # the target's U-Boot configuration +export UBOOT_DEFCONFIG=am62lx_evm_defconfig # U-Boot configuration for the target # Vendor SDK: U-Boot source, firmware that runs before U-Boot, cross compiler and its libraries export SDK=$WORK/tisdk @@ -111,7 +111,7 @@ mkdir -p $KEYS $FIT The variables are available only in the shell where you load the environment file. If you open a new terminal, you'll have to load the environment file again. If you adapt the workflow to another board, you'll learn how to choose its target values and paths in the [optional board-adaptation guidance](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/). {{% notice Note %}} -Example output shows paths under `/home/user/`, the home directory of the account that produced it. The paths in your output will reflect your own username. On a standard Ubuntu cloud instance, for example, they appear under `/home/ubuntu/`. The commands use `$HOME` and `$WORK`, so they adapt to your account automatically. Only the printed paths in the output might differ. +Example output shows paths under `/home/user/`, the home directory of the account that produced it. The paths in your output will reflect your own username. For example, on a standard Ubuntu cloud instance, they appear under `/home/ubuntu/`. The commands use `$HOME` and `$WORK`, so they adapt to your account automatically. Only the printed paths in the example outputs differ. {{% /notice %}} ## Get the U-Boot source and the cross compiler @@ -209,6 +209,6 @@ The download is about 1.3 GB. Leave it compressed. When you prepare the boot med ## What you've accomplished and what's next -You've installed the Zephyr host tools and U-Boot build packages, obtained your target's U-Boot source and cross compiler, and created a reusable environment file. For the AM62L EVM, you've also set up the early firmware and SD card image. +You've installed the Zephyr host tools and U-Boot build packages. You've also obtained the U-Boot source and cross compiler for your target, and created a reusable environment file. For the AM62L EVM, you've additionally set up the early firmware and SD card image. Next, you'll import the AArch64 toolchain, create a West workspace, and build a small Zephyr application for your chosen target. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md index e686b5d660..80f3e76997 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr.md @@ -11,7 +11,7 @@ layout: learningpathall Use Workbench for Zephyr to import an AArch64 toolchain, create a Zephyr workspace, and build your application. The steps are the same for both targets. Select the board that matches your target. -Open VS Code on your working directory: +Open Visual Studio Code on your working directory: ```bash code $HOME/zephyr-secure-boot @@ -20,12 +20,12 @@ code $HOME/zephyr-secure-boot Select the **Workbench for Zephyr** icon in the Activity Bar. Its panel contains the **Applications**, **West workspaces**, **Toolchains**, and **Host tools** views. {{% notice Note %}} -The screenshots show Windows paths, a globally installed SDK, and the AM62L evaluation module (EVM). On Ubuntu, use your own paths and the SDK location that you choose. If you chose QEMU, select `qemu_cortex_a53` wherever a board is requested. +The screenshots show Windows paths, a globally installed SDK, and the AM62L evaluation module (EVM). On Ubuntu, use your own paths and SDK location. If you chose QEMU, select `qemu_cortex_a53` wherever a board is requested. {{% /notice %}} ## Import the AArch64 toolchain -Use the Zephyr SDK's `aarch64-zephyr-elf` compiler for your Cortex-A53 target. Select the **Minimal** SDK type and **aarch64** architecture to download that toolchain. +Use the `aarch64-zephyr-elf` compiler from the Zephyr SDK for your Cortex-A53 target. Select the **Minimal** SDK type and **aarch64** architecture to download that toolchain. In the **Workbench for Zephyr** panel, select **Add Toolchain** and fill in the form: @@ -58,7 +58,7 @@ Create a Zephyr 4.4.2 workspace for your chosen target. The same workspace suppo 7. Select **Import**. -Workbench downloads Zephyr, the vendor's hardware abstraction layer (HAL), and other modules into `zephyrproject/deps`. This can take several minutes. When it finishes, confirm that `zephyrproject` appears in the **West workspaces** view. +Workbench downloads Zephyr, the hardware abstraction layer (HAL) from the vendor, and other modules into `zephyrproject/deps`. This can take several minutes. When it finishes, confirm that `zephyrproject` appears in the **West workspaces** view. ## Create the application @@ -79,9 +79,9 @@ Select **Add Application** and fill in the wizard: ![Workbench for Zephyr Add Application wizard creating hello from the hello_world sample with the zephyrproject workspace and Zephyr SDK 1.0.1. The AM62L EVM is selected; the callout identifies the alternative QEMU Cortex-A53 board.#center](images/wz-add-application.webp "Create hello for your chosen target") -The application `hello` appears in the **Applications** view, marked `[with zephyrproject]`. `zephyrproject/applications/hello` holds the sample's `CMakeLists.txt`, `prj.conf` and `src/main.c`. +The application `hello` appears in the **Applications** view, marked `[with zephyrproject]`. `zephyrproject/applications/hello` holds the `CMakeLists.txt`, `prj.conf` and `src/main.c` files for the sample. -## Replace the sample's files +## Replace files in the sample Leave `CMakeLists.txt` as it is and replace the other two files. @@ -96,7 +96,7 @@ CONFIG_AARCH64_IMAGE_HEADER=y `CONFIG_PRINTK` enables console output with `printk()`. `CONFIG_BOOT_BANNER` prints the `*** Booting Zephyr OS build ... ***` line, confirming that Zephyr has started. -Replace the contents of `src/main.c` with the following code. Its banner identifies image A and the key that you'll use to sign it. This helps you distinguish the images during the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). +Replace the contents of `src/main.c` with the following code: ```c #include @@ -120,19 +120,21 @@ int main(void) } ``` +Its banner identifies image A and the key that you'll use to sign it. This helps you distinguish the images if you run the optional [wrong-key and tampered-image tests](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks/). + Save both files. ## Configure Non-secure execution and the arm64 header `CONFIG_ARMV8_A_NS=y` tells Zephyr that it runs in the Non-secure world, the one U-Boot hands it. Without it, the driver of the Generic Interrupt Controller (GICv3) never programs the Non-secure registers. The timer interrupt never arrives, and Zephyr hangs right after its banner. -`CONFIG_AARCH64_IMAGE_HEADER=y` puts a 64-byte arm64 header at the start of `zephyr.bin`, in the same format as a Linux kernel image. The header's first instruction is `b __start`, a branch to Zephyr's real entry point. U-Boot needs that branch only at offset 0. Without the header, `go` jumps into whatever the linker placed there. +`CONFIG_AARCH64_IMAGE_HEADER=y` puts a 64-byte arm64 header at the start of `zephyr.bin`, in the same format as a Linux kernel image. The first instruction in the header is `b __start`, a branch to the real entry point of Zephyr. U-Boot needs that branch only at offset 0. Without the header, `go` jumps into whatever the linker placed there. The configurations for `qemu_cortex_a53` and `am62l_evm/am62l3/a53` already set both options. Repeating them in `prj.conf` protects you on a board whose configuration doesn't. ## Build the application -In the **Applications** view, open the context menu for `hello` and select **Build**. Workbench runs `west build` in the terminal and writes the build outputs to the application's `build/primary` directory. Near the end, the linker prints a memory report similar to: +In the **Applications** view, open the context menu for `hello` and select **Build**. Workbench runs `west build` in the terminal and writes the build outputs to the `build/primary` directory for the application. Near the end, the linker prints a memory report similar to: ```output Memory region Used Size Region Size %age Used @@ -141,9 +143,9 @@ Memory region Used Size Region Size %age Used IDT_LIST: 0 B 32 KB 0.00% ``` -![Workbench for Zephyr showing hello configured for the AM62L EVM and the build terminal's memory report. The report appears near the end of the build; the generated zephyr.bin is checked in the next step.#center](images/wz-build.webp "Build hello for the AM62L EVM") +![Workbench for Zephyr showing hello configured for the AM62L EVM and a memory report in the build terminal. The report appears near the end of the build; the generated zephyr.bin is checked in the next step.#center](images/wz-build.webp "Build hello for the AM62L EVM") -The result is `$WORK/zephyrproject/applications/hello/build/primary/zephyr/zephyr.bin`, a raw binary linked at `ZEPHYR_ADDR`, the start of the target's `zephyr,sram` memory node. The binary is about 37 KB for `qemu_cortex_a53`, whose memory report shows 128 MB of RAM. It's about 58 KB for the AM62L EVM, which reports 2016 MB of RAM. +The result is `$WORK/zephyrproject/applications/hello/build/primary/zephyr/zephyr.bin`, a raw binary linked at `ZEPHYR_ADDR`, the start of the `zephyr,sram` memory node for the target. The binary is about 37 KB for `qemu_cortex_a53`, whose memory report shows 128 MB of RAM. It's about 58 KB for the AM62L EVM, which reports 2016 MB of RAM. {{% notice Note %}} On an `aarch64` host, the build can fail with `exec format error` when it invokes `cmake` from `~/.zinstaller`. Some versions of the Workbench for Zephyr host tools install `x86_64` builds of CMake and Ninja, which can't run on Arm. Verify that Host Tools can also report a misleading error, such as `-255 package(s) are not installed`, for the same reason. @@ -154,7 +156,7 @@ Confirm the architecture of the installed tools: file ~/.zinstaller/tools/cmake-*/bin/cmake ~/.zinstaller/tools/ninja/ninja ``` -If the output reports `x86-64`, point the two tools at your system's Arm builds, after installing them with `sudo apt install -y cmake ninja-build`: +If the output reports `x86-64`, point the two tools at the Arm builds on your system, after installing them with `sudo apt install -y cmake ninja-build`: ```bash ln -sf "$(command -v cmake)" ~/.zinstaller/tools/cmake-*/bin/cmake @@ -166,12 +168,12 @@ Rebuild the application. The Zephyr SDK compiler is a native Arm binary and does ## Check the arm64 image header -Open a terminal with **Terminal > New Terminal** in VS Code, or use an existing shell. Load your target's environment file: +Open a terminal with **Terminal > New Terminal** in Visual Studio Code, or use an existing shell. Load the environment file for your target: - QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` - AM62L EVM: `source $HOME/zephyr-secure-boot/env-am62l.sh` -Print the header's magic number at offset `0x38`: +Print the magic number in the header at offset `0x38`: ```bash od -An -c -j 0x38 -N4 $WORK/zephyrproject/applications/hello/build/primary/zephyr/zephyr.bin @@ -187,6 +189,6 @@ The expected output is: ## What you've accomplished and what's next -You've built a Zephyr image for your target's Cortex-A53, linked at `ZEPHYR_ADDR`, and checked its arm64 header. +You've built a Zephyr image for the Cortex-A53 in your target, linked at `ZEPHYR_ADDR`, and checked its arm64 header. Next, you'll create the signing keys and package the image in a signed Flattened Image Tree (FIT) for U-Boot to verify. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md index abd690e90a..aff90c6cda 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/4-sign-zephyr.md @@ -1,28 +1,28 @@ --- title: Create signing keys and sign the Zephyr image into a FIT -description: Build U-Boot's signing tools, generate RSA key pairs with OpenSSL, and package Zephyr in a signed FIT image for U-Boot to verify. +description: Build the U-Boot signing tools, generate RSA key pairs with OpenSSL, and package Zephyr in a signed FIT image for U-Boot to verify. weight: 5 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Build U-Boot's host tools +## Build the U-Boot host tools -Open a terminal and load your target's environment file: +Open a terminal and load the environment file for your target: - QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` - AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` -Build `mkimage` to create and sign Flattened Image Tree (FIT) images, and `fit_check_sign` to verify them on the host. Use your target's U-Boot source tree so that the host tools match the U-Boot version that you'll run. +Build `mkimage` to create and sign Flattened Image Tree (FIT) images, and `fit_check_sign` to verify them on the host. Use the U-Boot source tree for your target so that the host tools match the U-Boot version that you'll run. -Before building the tools, generate `.config` from your target's default configuration. Run the target named by `UBOOT_DEFCONFIG` in your environment file: +Before building the tools, generate `.config` from the default configuration for your target. Run the target named by `UBOOT_DEFCONFIG` in your environment file: ```bash make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" $UBOOT_DEFCONFIG ``` -`UBOOT_CC` stores the compiler command. For QEMU, it names the cross compiler installed from Ubuntu. For the AM62L EVM, it also includes `--sysroot` to locate the SDK's headers and libraries. Keep `CC="$UBOOT_CC"` on every `make` command, including when you build U-Boot later. +`UBOOT_CC` stores the compiler command. For QEMU, it names the cross compiler installed from Ubuntu. For the AM62L EVM, it also includes `--sysroot` to locate the headers and libraries in the SDK. Keep `CC="$UBOOT_CC"` on every `make` command, including when you build U-Boot later. Then, build the host tools: @@ -42,7 +42,7 @@ The output is similar to: mkimage version 2026.01-g5fb294342321 ``` -The version string identifies your U-Boot source tree. The example output indicates AM62L EVM's TI tree, version 2026.01. For the QEMU setup, expect `mkimage version 2025.07`. +The version string identifies your U-Boot source tree. The example output indicates the TI tree for the AM62L EVM, version 2026.01. For the QEMU setup, expect `mkimage version 2025.07`. {{% notice Note %}} If the tools build reports a missing `pylibfdt` dependency, `swig`, or `gnutls/gnutls.h`, check the packages installed during [host-tool setup](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/2-set-up-tools/). Run the shared `apt install` command again, then retry the tools build. @@ -78,7 +78,7 @@ key-a.crt key-a.key key-b.crt key-b.key - `.crt` is a self-signed certificate containing the public key. - The shared file-name stem, ``, matches `key-name-hint` in the FIT source. -These 2048-bit keys are generated on the build host for this demonstration. The later section on [U-Boot's Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/) covers production key handling. +These 2048-bit keys are generated on the build host for this demonstration. The later section on [the Zephyr FIT verification boundary and production needs](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production/) covers production key handling. ## Write the FIT source @@ -122,7 +122,7 @@ EOF The FIT source defines how U-Boot handles the payload: - `os = "u-boot"` marks Zephyr as a standalone program, so U-Boot verifies and copies it without looking for a Linux kernel header or device tree. -- `signature-1` sits under the configuration, because the `required = "conf"` rule checks the configuration U-Boot boots. With `sign-images = "kernel"`, the signature also covers the image's `hash-1` node, and `key-name-hint` names the key in `$KEYS`. +- `signature-1` sits under the configuration, because the `required = "conf"` rule checks the configuration U-Boot boots. With `sign-images = "kernel"`, the signature also covers the `hash-1` node of the image, and `key-name-hint` names the key in `$KEYS`. - `load` and `entry` are `ZEPHYR_ADDR`, where U-Boot copies the verified payload and where `go` jumps. ## Sign the image @@ -165,7 +165,7 @@ Check `Sign algo: sha256,rsa2048:key-a` and the final `Signature written to . The example output is for the AM62L EVM build. For the QEMU build, expect `Data Size: 37040 Bytes` and `Load Address: 0x40000000`. -Omit `mkimage -K` when signing this FIT. You'll add the public key to U-Boot's control device tree during the U-Boot build. +Omit `mkimage -K` when signing this FIT. You'll add the public key to the U-Boot control device tree during the build. ## What you've accomplished and what's next diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot.md index d06296cad9..6b68fed60d 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot.md @@ -9,7 +9,7 @@ layout: learningpathall ## Check that U-Boot can verify signatures -Open a terminal and load your target's environment file: +Open a terminal and load the environment file for your target: - QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` - AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` @@ -53,7 +53,7 @@ Create `key.its` using the same layout as `zephyr-a.its`, with the placeholder p cat > $WORK/key.its <<'EOF' /dts-v1/; / { - description = "carrier used only to emit key-a's public key"; + description = "carrier used only to emit the public key for key-a"; #address-cells = <1>; images { kernel-1 { @@ -101,7 +101,7 @@ The expected output is: Confirm that `key-name-hint` is `key-a` and `required` is `conf`. Leave out `key-b` so that U-Boot doesn't trust its signatures. -The build incorporates `signature.dtsi` into U-Boot's control device tree. Use `mkimage -K` only with the scratch DTB. Adding the key directly to a finished `u-boot.dtb` would lose it when `make` rebuilds that file. +The build incorporates `signature.dtsi` into the U-Boot control device tree. Use `mkimage -K` only with the scratch DTB. Adding the key directly to a finished `u-boot.dtb` would lose it when `make` rebuilds that file. ## Write a boot command that fails closed @@ -132,7 +132,7 @@ The command chain loads, verifies, and starts Zephyr: - The cache commands flush and disable the caches. On arm64, `dcache off` also disables the memory management unit (MMU), preparing the state Zephyr expects at entry. - `go 0x40000000` jumps to `ZEPHYR_ADDR` without performing verification. Using `bootm start` and `bootm loados` stops before the OS-specific boot code that a plain `bootm` would run. -For QEMU, `BOOT_DEV` is `virtio 0:1`, the disk image's File Allocation Table (FAT) partition. On the AM62L EVM, it's `mmc 1:1`, the SD card's first partition. The board loads the FIT at `0x90000000` and copies Zephyr to `0x82000000`. +For QEMU, `BOOT_DEV` is `virtio 0:1`, the File Allocation Table (FAT) partition in the disk image. On the AM62L EVM, it's `mmc 1:1`, the first partition on the SD card. The board loads the FIT at `0x90000000` and copies Zephyr to `0x82000000`. Failing closed means stopping before Zephyr starts if any command fails. The `&&` operators enforce this condition: `a && b` runs `b` only if `a` succeeds. Separating the commands with `;` would allow execution to continue after a failed check. In this application, `go` doesn't return, so the refusal message prints only when an earlier command fails. @@ -153,7 +153,7 @@ The commands are compiled into U-Boot rather than stored on the card, where anyo ## Configure U-Boot -Reset to your target's default configuration before adding the custom settings: +Reset to the default configuration for your target before adding the custom settings: ```bash make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" $UBOOT_DEFCONFIG @@ -171,13 +171,13 @@ CONFIG_BOOTDELAY=3 EOF ``` -Keep the `\"` sequences around the `echo` text. The sequences represent literal quotes inside the Kconfig string. Run `grep ^CONFIG_PREBOOT $UBOOT_OUT/.config` and check that your target's device and addresses appear in the command. +Keep the `\"` sequences around the `echo` text. The sequences represent literal quotes inside the Kconfig string. Run `grep ^CONFIG_PREBOOT $UBOOT_OUT/.config` and check that the device and addresses for your target appear in the command. Follow the instructions for your target to add its device-tree and boot settings: {{< tabpane-normal >}} {{< tab header="QEMU" >}} -QEMU normally supplies U-Boot's device tree at runtime, so `CONFIG_DEVICE_TREE_INCLUDES` has no source tree to modify. Instead, you'll create a control device tree containing your key and pass it to the build. +QEMU normally supplies the U-Boot device tree at runtime, so `CONFIG_DEVICE_TREE_INCLUDES` has no source tree to modify. Instead, you'll create a control device tree containing your key and pass it to the build. Add the following settings to enable that approach and disable unsigned legacy images. The settings also enable cache commands and keep the environment from being saved to flash: @@ -235,7 +235,7 @@ Export the device tree for the QEMU machine that you'll boot later: ```bash qemu-system-aarch64 -machine virt,gic-version=3,dumpdtb=$WORK/qemu-virt.dtb -cpu cortex-a53 -m 1G -nographic ``` -This keeps U-Boot's drivers, console, and memory sizing consistent with the machine. QEMU writes the file and exits. +This keeps the U-Boot drivers, console, and memory sizing consistent with the machine. QEMU writes the file and exits. Add your public-key node by decompiling the tree, appending `signature.dtsi`, and recompiling it: @@ -252,7 +252,7 @@ Build U-Boot with `EXT_DTB` pointing to your control device tree. Specify `u-boo make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" -j$(nproc) \ EXT_DTB=$WORK/uboot-control.dtb u-boot.bin u-boot.dtb ``` -U-Boot's `scripts/check-of.sh` rejects the default `all` target for this machine, which normally receives its device tree from a prior stage. +The `scripts/check-of.sh` script in U-Boot rejects the default `all` target for this machine, which normally receives its device tree from a prior stage. The build takes a couple of minutes. Check the two files: @@ -263,7 +263,7 @@ ls -l $UBOOT_OUT/u-boot.bin $UBOOT_OUT/u-boot.dtb `u-boot.bin` is about 1.4 MB and ends with the bytes of `u-boot.dtb`, the control device tree with your key inside. {{< /tab >}} {{< tab header="AM62L EVM" >}} -TI's U-Boot tree uses binman, U-Boot's image packaging tool, to package the early stages. Point `BL1`, `BL31`, and `TEE` to the SDK's prebuilt TF-A and OP-TEE binaries. Set `BINMAN_INDIRS` to the SDK directory containing TI's system firmware: +TI's U-Boot tree uses binman, the U-Boot image packaging tool, to package the early stages. Point `BL1`, `BL31`, and `TEE` to the prebuilt TF-A and OP-TEE binaries in the SDK. Set `BINMAN_INDIRS` to the SDK directory containing TI's system firmware: ```bash make -C $UBOOT_SRC O=$UBOOT_OUT CROSS_COMPILE=$CROSS CC="$UBOOT_CC" -j$(nproc) \ @@ -307,7 +307,7 @@ With the long values shortened, the output is similar to: The `rsa,` properties contain the public key for `key-a`. Check that the node includes `required = "conf"`, which makes U-Boot require a valid configuration signature. -Verify the trusted FIT on the host using the key in that DTB. `fit_check_sign` uses U-Boot's verification code. `-f` selects the FIT, and `-k` selects the DTB containing the public key: +Verify the trusted FIT on the host using the key in that DTB. `fit_check_sign` uses the verification code in U-Boot. `-f` selects the FIT, and `-k` selects the DTB containing the public key: ```bash $UBOOT_OUT/tools/fit_check_sign -f $FIT/zephyr-a.itb -k $UBOOT_OUT/u-boot.dtb diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md index 09eab839a1..ce5a273c8c 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/6-boot-the-target.md @@ -9,14 +9,14 @@ layout: learningpathall ## What your target boots from -Open a terminal and load your target's environment file: +Open a terminal and load the environment file for your target: - QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` - AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` The AM62L boot ROM reads the first-stage file from a File Allocation Table (FAT) partition on the SD card. Start with TI's card image to preserve the expected layout. QEMU loads `u-boot.bin` from the command line, so its disk image needs only the signed Flattened Image Tree (FIT). -On either target, U-Boot's `fatload` reads `zephyr-a.itb` from the partition selected by `BOOT_DEV`. +On either target, the `fatload` of U-Boot reads `zephyr-a.itb` from the partition selected by `BOOT_DEV`. ## Build the boot media @@ -32,7 +32,7 @@ printf 'label: dos\nstart=2048, size=129024, type=e\n' | sfdisk $WORK/disk.img mkfs.vfat --offset 2048 -F 16 -n ZEPHYRFIT $WORK/disk.img ``` -Copy the signed FIT into the partition and list its contents. `BOOT_IMG` includes `@@1048576`, telling `mtools` that the volume starts 1 MiB into the image. `::` identifies the volume's root directory: +Copy the signed FIT into the partition and list its contents. `BOOT_IMG` includes `@@1048576`, telling `mtools` that the volume starts 1 MiB into the image. `::` identifies the root directory of the volume: ```bash mcopy -o -i $BOOT_IMG $FIT/zephyr-a.itb :: @@ -54,7 +54,7 @@ zephyr-a itb 38742 2026-09-17 22:11 Confirm that the volume contains `zephyr-a.itb`. The partition is accessed as `virtio 0:1`, matching `BOOT_DEV` in `env-qemu.sh`. {{< /tab >}} {{< tab header="AM62L EVM" >}} -The boot ROM reads `tiboot3.bin` from the card's first FAT partition. Preserve TI's FAT16 partition layout and replace its files. The supplied partition starts at sector 2048 and spans 262144 sectors. These values determine the extraction size in the command. +The boot ROM reads `tiboot3.bin` from the first FAT partition on the card. Preserve TI's FAT16 partition layout and replace its files. The supplied partition starts at sector 2048 and spans 262144 sectors. These values determine the extraction size in the command. Start from the `.wic.xz` that you downloaded. Extract the first 1 MiB, which holds the partition table, plus the 128 MiB partition into a new image file: @@ -109,12 +109,12 @@ Confirm that the volume contains the three boot files and `zephyr-a.itb`. Follow the instructions for your target to start the target. {{% notice Warning %}} -The AM62L EVM steps write to a whole disk with `dd`. Replace `/dev/sdX` with your card, for example `/dev/sdb`, never a partition such as `/dev/sdb1`. `dd` erases everything on the target, so a wrong device name erases the wrong disk. +The AM62L EVM steps write to a whole disk with `dd`. Replace `/dev/sdX` with your card – for example, `/dev/sdb` — rather than a partition such as `/dev/sdb1`. `dd` erases everything on the target, so a wrong device name erases the wrong disk. {{% /notice %}} {{< tabpane-normal >}} {{< tab header="QEMU" >}} -Start QEMU with the U-Boot binary and disk image you prepared. `-bios` selects the binary, and `-nographic` displays the serial console in your terminal. The `-drive` and `-device` options attach `disk.img` as the virtio device containing `virtio 0:1`: +Start QEMU with the U-Boot binary and disk image that you prepared. `-bios` selects the binary, and `-nographic` displays the serial console in your terminal. The `-drive` and `-device` options attach `disk.img` as the virtio device containing `virtio 0:1`: ```bash qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a53 -m 1G -nographic -no-reboot \ @@ -126,7 +126,7 @@ qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a53 -m 1G -nographic Use the same `-machine`, `-cpu`, and `-m` settings as the device-tree export used to [build U-Boot](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot/). U-Boot should begin printing in the terminal. To exit QEMU, press **Ctrl+A**, then **X**. {{< /tab >}} {{< tab header="AM62L EVM" >}} -Run `lsblk` before and after inserting the micro-SD card. Identify the newly listed disk and confirm its size matches the card. Replace `/dev/sdX` with that disk's device name and write the image to the whole card: +Run `lsblk` before and after inserting the micro-SD card. Identify the newly listed disk and confirm its size matches the card. Replace `/dev/sdX` with the device name of that disk and write the image to the whole card: ```bash sudo dd if=$WORK/sdcard.img of=/dev/sdX bs=4M conv=fsync status=progress @@ -134,7 +134,7 @@ sudo dd if=$WORK/sdcard.img of=/dev/sdX bs=4M conv=fsync status=progress If you transfer the prepared image to Windows or macOS, you can write `sdcard.img` with balenaEtcher. Alternatively, write TI's unchanged `.wic.xz` image to the card. Open its first partition, remove `Image`, `uEnv.txt`, and the `EFI` directory, then copy in the three boot files and `zephyr-a.itb`. -Set **SW3** using the table. This is the reduced pin-count setting from the [AM62L EVM User's Guide](https://www.ti.com/lit/pdf/SPRUJG8), where the ROM ignores **SW2** and **SW4**. The **ON** position is toward the **ON** label on the switch bank. +Set **SW3** using the table. This is the reduced pin-count setting from the [AM62L EVM user guide](https://www.ti.com/lit/pdf/SPRUJG8), where the ROM ignores **SW2** and **SW4**. The **ON** position is toward the **ON** label on the switch bank. | Switch | 1 | 2 | 3 | 4 | |---|---|---|---|---| @@ -197,7 +197,7 @@ Use the following messages to identify the boot stages and selected devices: - `NOTICE: BL1:` and `BL31:` identify TF-A running from `tiboot3.bin` and `tispl.bin`. - `Authentication passed` reports successful authentication by TI's security firmware. -- `SoC: AM62LX SR1.1 HS-FS` identifies the SoC's development state. +- `SoC: AM62LX SR1.1 HS-FS` identifies the development state of the system on chip (SoC). - `MMC:` lists the eMMC as device zero and the SD card as device one. The `Agent 0 Protocol 0x10 Message 0x7: not supported` errors appear in this successful boot log. They don't prevent Zephyr from starting. @@ -206,7 +206,7 @@ This log comes from a board running TI's prebuilt first two stages, so its `U-Bo ## Watch the trusted image boot -After the three-second countdown, autoboot runs `run a`, the trusted-image command built into U-Boot. The following example output shows the AM62L EVM. Your timings and hash values will differ. QEMU uses different load addresses and image sizes. The output is similar to: +After the three-second countdown, autoboot runs `run a`, the trusted-image command built into U-Boot. The following example output shows the AM62L EVM. Your timings and hash values will differ. The output is similar to: ```output 60198 bytes read in 1 ms (57.4 MiB/s) @@ -247,14 +247,14 @@ this image was verified by U-Boot before it ran. Confirm verification and startup using the following messages: -- `sha256,rsa2048:key-a+ OK` confirms that the signature verifies with U-Boot's embedded public key. +- `sha256,rsa2048:key-a+ OK` confirms that the signature verifies with the public key embedded in U-Boot. - `sha256+ OK` confirms that the payload hash matches. - `Loading Kernel Image to 82000000` shows `bootm loados` copying Zephyr to its link address. - `## Starting application at 0x82000000 ...` shows `go` handing control to Zephyr. Zephyr then prints its boot banner and `Hello from ZEPHYR IMAGE A`. On the AM62L EVM, `Secondary CPU core 1 (MPID:0x1) is up` also reports startup of the second core. -For QEMU, expect `FIT Image at 48000000`, `Data Size: 37040 Bytes`, `Loading Kernel Image to 40000000`, and `board : qemu_cortex_a53/qemu_cortex_a53`. Its board configuration starts one core, so there's no secondary-core startup message. +QEMU uses different load addresses and image sizes. For QEMU, expect `FIT Image at 48000000`, `Data Size: 37040 Bytes`, `Loading Kernel Image to 40000000`, and `board : qemu_cortex_a53/qemu_cortex_a53`. Its board configuration starts one core, so there's no secondary-core startup message. ## Troubleshoot boot and console output @@ -273,8 +273,8 @@ Check the symptom and try the corresponding step: If the terminal stays empty, check the console connection and whether the ROM loads `tiboot3.bin`: 1. Try all four serial ports that **J7** creates. The console isn't always the first one. -2. Check **SW3**, or switch to the full pin-count setting, which uses all three switch banks. See BOOTMODE `0x0E43` in the AM62L EVM User's Guide. -3. Check that the card's first partition is still TI's FAT16 partition, not reformatted. +2. Check **SW3**, or switch to the full pin-count setting, which uses all three switch banks. See BOOTMODE `0x0E43` in the AM62L EVM User Guide. +3. Check that the first partition of the card is still TI's FAT16 partition, not reformatted. 4. Flash TI's unchanged `.wic.xz` to a card and boot it. If that also produces no output, check the boot switches, serial port, and power supply before investigating your custom boot files. 5. If TI's card boots but yours never shows the SPL banner, copy TI's prebuilt first two stages over yours with `mcopy -o -i $BOOT_IMG $PREBUILT/tiboot3.bin $PREBUILT/tispl.bin ::`. Then, write the card again with the same `dd`. `u-boot.img` still carries the key and the boot command. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md index 119cf8180c..7f01b64bc3 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/7-test-the-checks.md @@ -11,7 +11,7 @@ layout: learningpathall The following tests are optional. Create one Flattened Image Tree (FIT) signed with an untrusted key and another modified after signing. Check both on the host, then confirm that U-Boot refuses to start them on your target. The `b` and `t` commands are already built into U-Boot to select these images. -Open a terminal and load your target's environment file: +Open a terminal and load the environment file for your target: - QEMU: `source $HOME/zephyr-secure-boot/env-qemu.sh` - AM62L evaluation module (EVM): `source $HOME/zephyr-secure-boot/env-am62l.sh` @@ -67,7 +67,7 @@ Created: Fri Sep 11 19:14:00 2026 Signature written to '/home/user/zephyr-secure-boot/fit/zephyr-b.itb', node '/configurations/conf-1/signature-1' ``` -Check for `Sign algo: sha256,rsa2048:key-b`. The `Hash value` differs from image A's because the application banner changed. This FIT has a signature from `key-b`, but U-Boot trusts only `key-a` and must reject it. +Check for `Sign algo: sha256,rsa2048:key-b`. The `Hash value` differs from that of image A because the application banner changed. This FIT has a signature from `key-b`, but U-Boot trusts only `key-a` and must reject it. ## Make a tampered copy of the trusted image @@ -195,14 +195,14 @@ ZEPHYR~1 ITB 60198 2026-09-15 16:49 zephyr-tampered.itb 130 643 968 bytes free ``` -This example lists the AM62L EVM's six files: three boot files and three FITs. The QEMU disk image contains only the three FITs. +This example lists the six files of the AM62L EVM: three boot files and three FITs. The QEMU disk image contains only the three FITs. {{< tabpane-normal >}} {{< tab header="QEMU" >}} Restart QEMU with the same command used to boot the trusted image. QEMU reads the updated `disk.img` directly. No physical media needs to be written. {{< /tab >}} {{< tab header="AM62L EVM" >}} -Write the updated image to the card. Confirm the card's device name before replacing `/dev/sdX`. `dd` overwrites the entire selected disk: +Write the updated image to the card. Confirm the device name of the card before replacing `/dev/sdX`. `dd` overwrites the entire selected disk: ```bash sudo dd if=$WORK/sdcard.img of=/dev/sdX bs=4M conv=fsync status=progress @@ -214,7 +214,7 @@ Move the card to the board, open the console with `picocom`, and power the board ## Run the wrong-key test -Press a key during the three-second countdown to stop autoboot. If you miss it, U-Boot starts image A. Start the target again and try once more. At the prompt, run the wrong-key test: +Press a key during the three-second countdown to stop autoboot. If you miss the countdown, U-Boot starts image A. Start the target again and try again. At the prompt, run the wrong-key test: ```console => run b @@ -234,7 +234,7 @@ ERROR -2: can't get kernel image! *** REFUSED: Zephyr was NOT started *** ``` -Check for `sha256,rsa2048:key-b- error!` and `Failed to verify required signature 'key-key-a'`. The `-` indicates failure, as the image's signature doesn't satisfy the required `key-a` check. +Check for `sha256,rsa2048:key-b- error!` and `Failed to verify required signature 'key-key-a'`. The `-` indicates failure, because the signature of the image doesn't satisfy the required `key-a` check. When `bootm start` fails, the `&&` chain skips `go` and prints `*** REFUSED: Zephyr was NOT started ***`. Confirm that no Zephyr banner appears. `Bad Data Hash` and `ERROR -2: can't get kernel image!` can appear for either rejection test. Use the preceding messages to identify which check failed. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md index edbc526139..bca39e226c 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/8-production.md @@ -1,6 +1,6 @@ --- -title: Review U-Boot's Zephyr FIT verification boundary and production needs -description: Review the trust boundary of U-Boot's Zephyr FIT verification and the key provisioning, boot controls, and release signing needed for production. +title: Review the Zephyr FIT verification boundary and production needs +description: Review the trust boundary for Zephyr FIT verification in U-Boot and the key provisioning, boot controls, and release signing needed for production. weight: 9 ### FIXED, DO NOT MODIFY @@ -33,7 +33,7 @@ The ROM and security firmware then require boot files signed with your key, incl `bootcmd` selects the autoboot command. `preboot` defines `zboot` and the `a`, `b`, and `t` wrappers before autoboot starts. -Both builds use `CONFIG_ENV_IS_NOWHERE=y`: you added it for QEMU, and the AM62L default configuration supplies it. This prevents `saveenv` from writing a persistent environment, so boot settings are loaded from the binary that you built. Check that your board's `.config` includes the same setting. +Both builds use `CONFIG_ENV_IS_NOWHERE=y`: you added it for QEMU, and the AM62L default configuration supplies it. This prevents `saveenv` from writing a persistent environment, so boot settings are loaded from the binary that you built. Check that the `.config` for your board includes the same setting. {{% notice Warning %}} Don't enable `CONFIG_ENV_IS_IN_FAT` for this boot configuration. It stores the environment in `uboot.env` on the boot media. A saved environment can override `bootcmd` and `preboot`, allowing someone with write access to the card to bypass verification. @@ -47,7 +47,7 @@ These settings cover only the countdown. If `bootcmd` returns after rejecting an ### Protect production keys and sign during release -You used `sha256,rsa2048`. The AM62L's own boot chain uses `sha512,rsa4096`. To use the latter for your FIT: +You used `sha256,rsa2048`. The boot chain of the AM62L uses `sha512,rsa4096`. To use the latter for your FIT: - Generate keys with `rsa_keygen_bits:4096`. - Set `algo = "sha512,rsa4096"` in both `zephyr-a.its` and `key.its`. @@ -60,14 +60,14 @@ Generate production keys in a hardware security module (HSM), or at least away f If you want to use another Cortex-A board, start by updating the target values and paths in your environment file: - `BOARD` is the Zephyr board identifier, from `west boards` or the Workbench board list. The board needs the two settings from [Build a Zephyr image that U-Boot can start](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/3-build-zephyr/): the Non-secure world and the arm64 image header. -- `ZEPHYR_ADDR` is the start of the memory node that the board's device tree selects as `zephyr,sram`. It's Zephyr's link address, the FIT `load` and `entry`, and the `go` target, so one value serves all three. -- `FIT_ADDR` is any free address clear of `ZEPHYR_ADDR` and of the firmware regions. Otherwise, `bootm loados` copies Zephyr over the FIT it is still reading. -- `BOOT_DEV` is the U-Boot device and partition that hold the files. `mmc 1:1` is the SD card's first partition on the AM62L EVM, while `mmc 0` is the eMMC. `mmc list` at the U-Boot prompt shows your board's numbering. -- `UBOOT_DEFCONFIG` selects the board's U-Boot default configuration. Check for `CONFIG_FIT=y`, `CONFIG_FIT_SIGNATURE=y`, and `CONFIG_RSA=y`. Add missing settings to the [U-Boot configuration fragment](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot/). Disable legacy images with `# CONFIG_LEGACY_IMAGE_FORMAT is not set`. +- `ZEPHYR_ADDR` is the start of the memory node that the device tree of the board selects as `zephyr,sram`. It's the link address of Zephyr, the FIT `load` and `entry`, and the `go` target, so one value serves all three. +- `FIT_ADDR` is any free address clear of `ZEPHYR_ADDR` and of the firmware regions. Otherwise, `bootm loados` copies Zephyr over the FIT it's still reading. +- `BOOT_DEV` is the U-Boot device and partition that hold the files. `mmc 1:1` is the first partition of the SD card on the AM62L EVM, while `mmc 0` is the eMMC. `mmc list` at the U-Boot prompt shows the numbering of your board. +- `UBOOT_DEFCONFIG` selects the U-Boot default configuration of the board. Check for `CONFIG_FIT=y`, `CONFIG_FIT_SIGNATURE=y`, and `CONFIG_RSA=y`. Add missing settings to the [U-Boot configuration fragment](/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/5-build-uboot/). Disable legacy images with `# CONFIG_LEGACY_IMAGE_FORMAT is not set`. - `UBOOT_SRC`, `CROSS`, and `UBOOT_CC` point at the U-Boot source and the compiler that builds it. `SDK`, `PREBUILT`, and `SYSROOT` are added when they come from a vendor SDK, as on the AM62L. - `BOOT_IMG` is the boot volume that `mcopy` writes into: the card image on the EVM, the disk image in QEMU, each with the `@@` offset of its FAT partition. -Also adapt the U-Boot build command and boot-media preparation. The build inputs depend on the target: `EXT_DTB` for QEMU, or `BL1`, `BL31`, `TEE`, and `BINMAN_INDIRS` for the AM62L EVM. Output names also vary, often including `u-boot.img` or `u-boot.itb` and a Secondary Program Loader (SPL) file. Follow the target's requirements for media layout, boot switches, and console access. +Also adapt the U-Boot build command and boot-media preparation. The build inputs depend on the target: `EXT_DTB` for QEMU, or `BL1`, `BL31`, `TEE`, and `BINMAN_INDIRS` for the AM62L EVM. Output names also vary, often including `u-boot.img` or `u-boot.itb` and a Secondary Program Loader (SPL) file. Follow the requirements of the target for media layout, boot switches, and console access. Check how the target obtains its control device tree. `CONFIG_DEVICE_TREE_INCLUDES` adds the key node when the tree is built from source with `CONFIG_OF_SEPARATE=y` or `CONFIG_OF_EMBED=y`, as on the AM62L EVM. @@ -82,4 +82,3 @@ You've established verification of the Zephyr payload and learned how you can ex Before using this approach in production, authenticate the earlier boot stages. Also protect the boot environment and console and move signing into a controlled release process. To sign your own application for the same target, point `data` in `zephyr-a.its` to its `zephyr.bin` and sign the FIT again. To use another Cortex-A board, adapt the environment, build inputs, and boot media using the checklist in this section. - diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md index 1f1e9392b6..85db90bd15 100644 --- a/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr-signed-fit-uboot-cortex-a/_index.md @@ -14,7 +14,7 @@ learning_objectives: - Identify the verification boundary in QEMU and on a development board, and how fusing your key extends trust in production. prerequisites: - - One of two targets - QEMU, which needs no hardware, or a TI [AM62L EVM](https://www.ti.com/tool/TMDS62LEVM) with accessories to power it, write an SD card, and attach a serial console + - One of two targets - QEMU, which needs no hardware, or a Texas Instruments (TI) [AM62L EVM](https://www.ti.com/tool/TMDS62LEVM) with accessories to power it, write an SD card, and attach a serial console - A Linux host running Ubuntu 22.04 or 24.04, with about 20 GB of free disk space; QEMU runs on x86_64 or arm64, while the AM62L EVM needs x86_64 for the TI SDK - Visual Studio Code with the [Workbench for Zephyr extension](https://marketplace.visualstudio.com/items?itemName=Ac6.zephyr-workbench) installed - Basic knowledge of U-Boot and the Linux command line @@ -43,24 +43,24 @@ generated_summary_faq: answer: >- No. You can use QEMU without hardware. If you have an AM62L EVM, follow its target-specific setup and boot-media instructions instead. - - question: Why does U-Boot need the public key in its control device tree? + - question: Do I need to patch the U-Boot source to add the trusted key? answer: >- - You'll embed the trusted public key in U-Boot's control device tree so that it can verify the FIT - configuration signature. The key's `required = "conf"` setting makes U-Boot reject a FIT - without a valid signature from that key. + No. You'll generate a public-key node in `signature.dtsi` and include it when you build + U-Boot. For the AM62L EVM, use `CONFIG_DEVICE_TREE_INCLUDES`. For QEMU, add the node to the + control device tree supplied with `EXT_DTB`. You don't need to change the U-Boot source files. - question: How can I check the signed FIT before booting the target? answer: >- - Use U-Boot's `fit_check_sign` with your signed FIT and built `u-boot.dtb`. This checks the + Use the U-Boot `fit_check_sign` tool with your signed FIT and built `u-boot.dtb`. This checks the FIT against the public key in the control device tree before you prepare the boot media. - question: How do I confirm that verification succeeded on the target? answer: >- - Look for `sha256,rsa2048:key-a+ OK` in U-Boot's output, followed by the Zephyr image A banner. + Look for `sha256,rsa2048:key-a+ OK` in the U-Boot output, followed by the Zephyr image A banner. You can also run the optional wrong-key and tampered-image tests to check that U-Boot refuses to start either image. - question: Does this setup authenticate U-Boot as well as Zephyr? answer: >- - No. In QEMU, you run U-Boot without an earlier stage that authenticates it. On the AM62L EVM, - you leave the device in High Security, Field Securable (HS-FS) development state, where earlier stages accept boot files + No. In QEMU, you'll run U-Boot without an earlier stage that authenticates it. On the AM62L EVM, + you'll leave the device in High Security, Field Securable (HS-FS) development state, where earlier stages accept boot files signed with any key. To extend trust to U-Boot in production, you need to provision your key, move the device to High Security, Security Enforced (HS-SE), and sign the earlier boot files. # END generated_summary_faq