Agenda
Platform Overview
SoC · board · software stack
Build System Architecture
Top-level Makefile · component layout
Make Targets
Build targets and their outputs
U-Boot SPL
SWIV · qtestsign (local, no CASS)
OP-TEE TEE
BL32 — Secure World Kernel
OP-TEE client
libteec.so · tee-supplicant daemon
OP-TEE xtests
OP-TEE test suite on the board
U-Boot
BL33 — UEFI bootloader
Linux Kernel
EL2 device tree · EFI_ZBOOT
Buildroot
Root filesystem → initramfs · br-ext
UKI Assembly
Unified Kernel Image → efi.bin
Flashing
QDL / Firehose · flash-loader vs flash-kernel
Boot Chain
PBL → XBL → XBL-SEC → U-Boot SPL → TF-A BL31 → OP-TEE → U-Boot → Linux
Boot Load Map & DTBs
Stage load addresses + how the DTBs are used
Runtime Exception Levels
EL3 / S-EL1 / EL2 at runtime
Yocto Integration
Optional BSP for firmware blobs
Blobs: Direct Download
Skip Yocto — fetch blobs directly
Extending Buildroot
Adding a package via br-ext
Tests
On-board validation · FastRPC · video · stress-ng
Summary
Key facts and commands
Lemans
Build · Flash · Boot
How the firmware stack is assembled from source,
programmed onto the board, and brought to life.
Target hardware: Qualcomm IQ-9075 Evaluation Kit (EVK).
Part of the OP-TEE build.git project, extended for Qualcomm TZ open firmware development — work is being upstreamed to github.com/OP-TEE.
Platform Overview
SoC
- Qualcomm SA8775P (QCS9075)
- 8 × Kryo CPU cores (AArch64)
- Adreno GPU
- Hexagon DSP
- Automotive-grade security domains
Board
- IQ-9075-EVK (Lemans EVK)
- Engineering validation kit
- UFS storage
- Serial: ttyMSM0
- USB EDL / QDL flash
Software Stack
- U-Boot SPL (chosen over TF-A BL2 — both open-source)
- OP-TEE OS (BL32, loaded by SPL)
- U-Boot proper (BL33 / UEFI)
- Linux + Buildroot initramfs
- Packaged as Unified Kernel Image
Notable specifics: SPL signed locally via qtestsign (open-source — no QTI CASS access required); U-Boot proper loaded at 0xaf000000.
Build System Architecture
Entry Point
lemans.mk— top-level GNU Make- Calls into
common.mkfor shared targets - Toolchain:
aarch64-none-linux-gnu-
Key Directories
lemans/input/— pre-built blobs & flash supportlemans/output/— generated artifactslemans/security/— SWIV annotation tool (local qtestsign signing)lemans/ukify/— EFI stub for UKIbr-ext/— external Buildroot package tree
make bootimage
—Bootloader pipeline→
make flash-loader
→ tz.mbn
→ uefi.elf
make efi
—Kernel + Root pipeline→
make flash-kernel
Make Targets
| Target | Output | Notes |
|---|---|---|
| Main Targets | ||
all |
Builds every component + produces efi.bin | Start here for a clean build |
bootimage
→ flash-loader
|
tz.mbn
— qtestsign-signed U-Boot SPL uefi.elf — SPL_ATF FIT: BL31 + OP-TEE + U-Boot proper |
Runs optee-os → tfa → u-boot → u-boot-proper → spl → uefi. Signing is local (no CASS needed). |
efi
→ flash-kernel
|
efi.bin — FAT32 image containing uki.efi | UKI bundles kernel + initramfs + DTB + cmdline into one EFI binary. |
flash-loader |
Programs tz.mbn + uefi.elf + Qualcomm blobs via QDL/Firehose (LUNs 1-5) | After any OP-TEE / TF-A / U-Boot change; needs bootimage |
flash-kernel |
Programs efi.bin (EFI partition only, LUN 0) via QDL | Fast iteration — skips firmware; needs efi |
| Component Builds (invoked by the main targets) | ||
optee-os |
tee-raw.bin / tee.elf — OP-TEE OS (BL32) @ 0x1c300000 | Embedded into the uefi FIT as the BL32 loadable |
tfa |
bl31.bin — TF-A BL31 Secure Monitor @ 0x1c200000 | Firmware image in the uefi FIT; no BL2 (we use SPL instead) |
u-boot |
spl/u-boot-spl.elf — U-Boot SPL (qcom_lemans_spl_defconfig) | Input to spl → tz.mbn |
u-boot-proper |
u-boot.bin — U-Boot proper (BL33) @ 0xaf000000 (qcom_lemans_defconfig) | Input to uefi; carries the control DTB (OP-TEE node) |
spl |
tz.mbn — SWIV-annotated, qtestsign-signed SPL | Local signing; auto-fetches qtestsign |
uefi |
uefi.elf — SPL_ATF FIT (mkimage): BL31 + OP-TEE + U-Boot proper + FDT | The image the SPL loads from the uefi partition |
linux |
Image + vmlinuz.efi + lemans-evk-el2.dtb | Input to efi |
buildroot |
out-br/images/rootfs.cpio.gz — compressed initramfs | Input to efi. Depends on linux-firmware. |
linux-firmware |
Stages upstream linux-firmware (qcom/sa8775p: *.mbn/*.jsn/*.elf, incl. qupv3fw.elf) into the rootfs overlay at /lib/firmware/ |
Prerequisite of buildroot (hence efi). Standalone — independent of fetch-blobs. |
| Source Overlays (local u-boot / linux patches, not committed upstream) | ||
u-boot-overlayslinux-overlays |
Apply lemans/patches/{u-boot,linux}/*.patch to the working tree (idempotent) |
Auto-run by the builds; enable the OP-TEE DT node + CONFIG_TEE/OPTEE. Revert with *-overlays-revert. |
| Other Flash / Support | ||
efi-kernel-only |
efi.bin with a local-kernel UKI (root=PARTLABEL=rootfs) |
Boots the on-disk Yocto rootfs; needs flash-yocto. Flash with flash-kernel. |
fetch-blobs |
Downloads Qualcomm firmware blobs into lemans/blobs/ |
No Yocto build needed; required before first flash |
flash-yocto |
Programs the complete unmodified Yocto release (all 6 LUNs) via QDL | Verify default hardware against the stock BSP (needs make yocto) |
U-Boot SPL SWIV annotation · qtestsign signing (local)
Inputs
- SPL ELF: u-boot/.output/spl/u-boot-spl.elf
- TF-A BL31: arm-trusted-firmware/build/lemans_evk/release/bl31/bl31.elf
- OP-TEE: tee.elf (embedded in SPL FIT image at build time)
- SWIV tool: lemans/security/swiv_build_utility.py
- Signing: msm8916-mainline/qtestsign
Outputs
- u-boot-spl.elf → SWIV →
u-boot-spl-swiv.elf - u-boot-spl-swiv.elf → qtestsign →
tz.mbn - uefi.elf assembled separately by
make uefi(mkimage FIT: BL31 + OP-TEE + U-Boot proper)
SPL Signing — Two-Stage Pipeline (make spl)
python3 lemans/security/swiv_build_utility.py \ u-boot/.output/spl/u-boot-spl-swiv.elf \ u-boot/.output/spl/u-boot-spl.elf \ lemans # Input: u-boot-spl.elf (raw U-Boot SPL output) # Output: u-boot-spl-swiv.elf (SPL + SWIV segment)
qtestsign -v6 tz \ -o u-boot/.output/spl/u-boot-spl.mbn \ u-boot/.output/spl/u-boot-spl-swiv.elf # Cloned from msm8916-mainline/qtestsign # No CASS / remote signing server needed
qtestsign is auto-fetched by make spl if not already present at $(ROOT)/qtestsign.
OP-TEE TEE BL32 — Secure World Kernel
OP-TEE is an open-source Trusted Execution Environment that runs in the Arm TrustZone Secure World (EL1-S). It hosts Trusted Applications (TAs) and handles Secure Monitor Calls (SMCs) from the Normal World.
Configuration
- Platform: qcom-lemans
- Output: optee_os/out/arm/core/tee.elf
- Passed to U-Boot as: TEE= (embedded in SPL FIT image)
U-Boot SPL loads TF-A BL31, OP-TEE (BL32), and U-Boot proper (BL33) from the SPL FIT image. TF-A BL31 runs at EL3 as Secure Monitor.
The Linux kernel communicates with OP-TEE via the
tee-supplicant daemon and the
CONFIG_OPTEE driver, both
enabled in the kernel defconfig.
OP-TEE client Normal World Runtime
The TEE Client API library. User-space applications call it to open sessions with Trusted Applications and invoke commands across the Normal/Secure World boundary.
- TEEC_InitializeContext / TEEC_FinalizeContext
- TEEC_OpenSession — open a channel to a TA
- TEEC_InvokeCommand — call a TA entry point
- TEEC_CloseSession
Buildroot Package
- Package:
optee_client_ext(br-ext) - Init script:
/etc/init.d/S30optee(auto-start) - User
tee— runs supplicant, owns/dev/teepriv0 - Group
teeclnt— client apps; includes usertest
Runs in Normal World as a privileged daemon. Acts as the bridge between the OP-TEE Secure World and REE filesystem / hardware resources.
-
TA loading — reads
/lib/optee_armtz/*.taand passes TA binaries to the Secure World on demand - Secure storage — mediates RPMB and REE-filesystem secure storage RPCs from OP-TEE OS
- Socket / time RPCs — handles other Secure World RPC calls that need REE access (entropy, sockets, time)
Without tee-supplicant running, TA loading and secure storage fail silently — always verify it is active before running xtest.
OP-TEE xtests OP-TEE Test Suite
What it covers
- Core TEE OS functionality (panics, memory, threads)
- GlobalPlatform TEE Internal Core API
- GlobalPlatform TEE Client API
- Cryptographic operations — AES, RSA, ECC, hash, ECDH
- Secure Storage — RPMB and REE-filesystem backends
- Regression suite and benchmarks
Buildroot Package
- Package:
optee_test_ext(br-ext, on by default) - Depends on:
optee_client_ext, openssl - TAs installed to:
/lib/optee_armtz/ - Init:
S30test-arm-ffa-userfor ARM FF-A user tests - Source:
OP-TEE/optee_test.git(via manifest)
Connect via serial (ttyMSM0 115200) or SSH. Verify
tee-supplicant is running before starting.
# Full test suite xtest # Regression tests only xtest -t regression # Single test case by number xtest 1001 # List all test identifiers xtest -l # Help xtest -h
Test results show OK / FAILED per case. A clean run ends with "RESULT: regression tests PASSED".
U-Boot SPL + proper — First open-source boot stage
Build — two defconfigs
- SPL: qcom_lemans_spl_defconfig → .output/spl/u-boot-spl.elf (→ tz.mbn)
- Proper (BL33): qcom_lemans_defconfig → .output-proper/u-boot.bin @ 0xaf000000
- Cross-compiler: aarch64-none-linux-gnu-
- SPL is built with SPL_LOAD_FIT + SPL_ATF: it reads the uefi partition as a FIT and hands off to BL31 → OP-TEE → U-Boot proper
- OP-TEE enabled in proper via source overlay: /firmware/optee node + CONFIG_TEE/OPTEE
Why U-Boot?
U-Boot is configured in UEFI mode so the system presents a standard UEFI firmware interface. This lets the EFI partition be read using standard UEFI boot discovery — no bespoke boot config needed.
- Reads the EFI system partition (FAT32
efi.bin) - Falls back to
EFI/BOOT/bootaa64.efias the UEFI fallback path - Discovers and launches
EFI/Linux/uki.efi(the Unified Kernel Image) - Hands kernel execution over at EL2 once the UKI is loaded
Linux Kernel + EL2 Device Tree
Build Config
- Defconfig: defconfig (override via LINUX_DEFCONFIG)
- Auto-enabled: CONFIG_TEE, CONFIG_OPTEE
- Auto-enabled: CONFIG_EFI_BOOT, CONFIG_EFI_ZBOOT
- Auto-enabled: CONFIG_DEVTMPFS, CONFIG_QCOM_PAS_TEE
- Output: arch/arm64/boot/Image
- EFI_ZBOOT: arch/arm64/boot/vmlinuz.efi
Console
console=ttyMSM0,115200 qcom_scm.download_mode=1 arm-smmu.disable_bypass=0 clk_ignore_unused pd_ignore_unused
lemans-evk-el2.dtb is a special Device Tree
variant required when running Linux at EL2 without the Gunyah hypervisor.
- Enables the Qualcomm watchdog at EL2
- Disables the GPU Zap shader (not needed at EL2)
- Remaps IOMMU streams for ADSP, CDSP, WPSS remoteprocs
- Adjusts power domain topology for EL2 operation
The DTB is bundled into the UKI alongside the kernel Image and the Buildroot initramfs — no separate flash step required.
Buildroot Root Filesystem → Initramfs
Target Format
Buildroot produces a compressed CPIO archive
(out-br/images/rootfs.cpio.gz). It is embedded
directly into the UKI as an initramfs, loaded
entirely into RAM at boot.
Firmware Overlay
The kernel is built CONFIG_MODULES=n
(all drivers are built-in, so the PAS remoteprocs can probe without
waiting on late-loaded modules) — there are no .ko files.
Buildroot's only root overlay is the DSP/remoteproc firmware staged
into lemans/overlay/, so it
lands in /lib/firmware inside the initramfs.
- Busybox (core utilities, watchdog support)
- OpenSSH server + key utilities
- OpenSSL CLI
- DHCPCD (networking), Ethtool, xinetd
- GStreamer 1.x + v4l-utils — V4L2 video decode/encode pipeline
- optee_client_ext — libteec.so + tee-supplicant
- optee_test_ext — xtest binary + TAs (on by default)
Login banner: "OP-TEE embedded distrib for lemans"
br-ext — External Package Tree
All OP-TEE packages use br-ext/, which points to local
source checkouts. Stock BR2_PACKAGE_OPTEE_* packages are
explicitly disabled — always use the _ext variants.
UKI Assembly Unified Kernel Image → efi.bin
ukify build → uki.efiBundles four inputs into a single PE/COFF EFI binary — no grub.cfg, no extlinux.conf. UEFI loads and verifies it in one shot.
| EFI stub | lemans/ukify/linuxaa64.efi.stub |
| Kernel | linux/arch/arm64/boot/Image |
| DTB | lemans-evk-el2.dtb |
| Initramfs | out-br/images/rootfs.cpio.gz |
| Cmdline | console=ttyMSM0,115200 … |
mkfs.fat + mcopy → efi.binA blank 512 MB file is formatted as FAT32, then populated with two files using mtools (no loop-mount needed):
truncate -s 512M lemans/output/efi.bin mkfs.fat -F 32 -S 4096 lemans/output/efi.bin mmd -i efi.bin ::/EFI/BOOT ::/EFI/Linux mcopy -i efi.bin bootaa64.efi ::/EFI/BOOT/ # UEFI fallback mcopy -i efi.bin uki.efi ::/EFI/Linux/ # UKI
efi.bin (FAT32, 512 MB) ├── EFI/BOOT/bootaa64.efi ← UEFI fallback entry └── EFI/Linux/uki.efi ← Unified Kernel Image
Flashing QDL — Qualcomm Download Protocol
The board is held in EDL (Emergency Download Mode) over USB.
The host sends a firehose programmer ELF, then uses XML manifests
to write partition images directly via the Sahara/Firehose protocol.
For the full Linux procedure — installing qdl, entering EDL mode, and
provisioning the UFS — see Qualcomm's official
Flash over QLI guide.
make flash-loader
Programs the full bootloader stack: firmware blobs, XBL, GPT tables, U-Boot SPL (tz.mbn), and the SPL_ATF boot FIT (uefi.elf, carrying TF-A BL31 + OP-TEE + U-Boot proper). Programs LUNs 1–5 (rawprogram1–5, with rawprogram4 patched to fill the qupfw slots).
Use after a full rebuild, first-time provisioning, or any U-Boot SPL / OP-TEE change. Follow with make flash-kernel to also write the kernel.
make flash-kernel
Programs only the EFI partition (efi.bin).
Generates a filtered rawprogram0-only-kernel.xml
from the full rawprogram0.xml.
Use for fast kernel / initramfs / TA iteration — avoids re-flashing firmware.
make efi-kernel-only
Builds a UKI from the locally-built kernel (no initramfs) with
root=PARTLABEL=rootfs rw rootwait and injects it into a copy of the Yocto
efi.bin (replacing its stock UKI). Build only — flash the result with
make flash-kernel.
Boots the on-disk Yocto rootfs with your own kernel — unlike make efi, which boots the Buildroot initramfs. The matching Yocto rootfs.img must already be flashed (make flash-yocto).
Flash Artifacts — Source
flash-loader / flash-kernel stage every stock firmware file
strictly from the fetched blob set — no Yocto or
hand-placed copy can shadow them. Built images come from the local output:
(make fetch-blobs)
tz.mbn · uefi.elf · efi.bin
Flash Procedure — Step by Step
-
1Enter EDL mode Hold the EDL button while connecting USB, or issue
adb reboot edl. The host sees a QDL USB device. -
2Load the firehose programmer QDL uploads
prog_firehose_ddr.elfinto SRAM via the Sahara protocol. The programmer initialises DDR and the UFS controller. -
3Write GPT partition tables
gpt_main*.bin / gpt_backup*.binare written first to lay out the partition map across UFS LUNs 1–5. -
4Flash partition images via rawprogram XML The XML manifests map each image file to a partition.
flash-loaderuses rawprogram1–5 (LUNs 1–5);flash-kerneluses only the filtered rawprogram0-only-kernel.xml. -
5Apply patches (patch*.xml) GPT corrections and CRC patches are applied. Board resets and boots from the freshly written images.
Boot Chain
Boot Loader Map Load Addresses & Device Trees
| Stage | Image / partition | Load / entry | EL | Where it comes from |
|---|---|---|---|---|
| U-Boot SPL | tz.mbn (tz) |
0x1c100000 |
EL3 | CONFIG_SPL_TEXT_BASE; loads uefi FIT to 0xB0800000 |
| TF-A BL31 | bl31.bin (FIT: atf) |
0x1c200000 |
EL3 | Secure Monitor — stays resident after boot |
| OP-TEE OS (BL32) | tee-raw.bin (FIT: optee) |
0x1c300000 |
S-EL1 | Headerless pager binary linked at this address |
| U-Boot proper (BL33) | u-boot.bin (FIT: uboot) |
0xaf000000 |
EL2 | CONFIG_TEXT_BASE; UEFI environment for the UKI |
| Linux | Image in uki.efi |
relocatable | EL2 | Placed by U-Boot's EFI loader from the ESP |
BL31 boots OP-TEE (BL32) and U-Boot proper (BL33); OP-TEE stays resident at S-EL1 while U-Boot loads Linux.
Control DTB — U-Boot (fdt-1 in the uefi FIT)
- The SPL reads it so it records the FIT loadables into
/fit-images, lettingspl_invoke_atf()discover the OP-TEE (os="tee") and U-Boot (os="u-boot") entry points. u-boot.binships as nodtb + appended control DTB; U-Boot proper uses its own embedded DTB viaboard_fdt_blob_setup().- BL31 hands off with
x0 = MPIDR(not an fdt pointer), so the appended DTB is required.
Linux DTB — lemans-evk-el2.dtb
- Bundled into the UKI next to the kernel Image and initramfs — no separate flash step.
- EL2-specific variant needed to run Linux at EL2 without the Gunyah hypervisor.
- Enables the EL2 watchdog, disables the GPU Zap shader, and remaps IOMMU streams for the remoteprocs.
The three FIT payloads (BL31 · OP-TEE · U-Boot) live on the uefi partition; the signed SPL (tz.mbn) on tz. Loadable order matters — uboot must precede optee so fdt_addr is set before OP-TEE is recorded.
Arm Exception Levels at Runtime
Unlike the transient boot stages (PBL, XBL, U-Boot SPL), these are the persistent images that keep executing on a running system — each resident at its own exception level after the board has booted.
EL3 — Secure Monitor (TF-A BL31)
Highest privilege. Handles SMCs between Normal and Secure worlds. TF-A BL31 is loaded by U-Boot SPL and remains resident as the Secure Monitor after boot.
Secure EL1 — OP-TEE OS
Runs in TrustZone Secure World. Hosts Trusted Applications. Communicates with Linux via the TEE subsystem SMC interface.
Normal EL2 — Linux Kernel
Linux runs at EL2 (hypervisor level) in the Normal World. The EL2 DTB overlay enables this — it remaps IOMMU streams that behave differently without Gunyah.
Normal EL0 — User Space
Buildroot initramfs processes (Busybox, OpenSSH, tee-supplicant). OP-TEE client calls travel up through EL1 → EL3 → Secure EL1.
Yocto Integration Optional reference BSP for regression testing
Why Yocto?
Yocto builds Qualcomm's official BSP — a complete, known-good working system you can flash and run as a reference. It lets you confirm the board and firmware are healthy on a trusted baseline, and compare the open firmware stack against it when hunting regressions.
It is not required to build or flash the open stack — for that
always use make fetch-blobs, which downloads just the firmware blobs
in minutes and keeps the open boot firmware stack functional.
make yocto — full BSP (hours)
- Clones
qualcomm-linux/meta-qcomfrom GitHub - Builds via
kasusingiq-9075-evk.yml - Produces
yocto/build/tmp/deploy/images/iq-9075-evk/ - Consumed only by
make flash-yocto—flash-loader/flash-kernelnever read from here
Use make fetch-blobs instead to skip the build entirely.
Note: flashing the Yocto BSP image programs the
traditional Qualcomm boot stack (closed XBL / ABL / UEFI),
not the open firmware stack this repo builds (U-Boot SPL → TF-A → OP-TEE → U-Boot).
Its purpose here is a working reference stack to evaluate regressions against —
for the open firmware stack always use make fetch-blobs to keep it functional.
From fetch-blobs | From this repo |
|---|---|
| XBL + XBL config | U-Boot SPL (tz.mbn) |
| AOP firmware | Boot FIT (uefi.elf) |
| ADSP / CDSP FW | Linux kernel |
| WPSS firmware | Buildroot initramfs |
| Prog firehose ELF | UKI (uki.efi) |
| GPT tables | efi.bin (FAT32) |
| rawprogram XMLs | |
| devcfg.mbn, cpucp.elf, … |
Yocto Blobs Skipping the build — direct download
Both upstream URLs are publicly accessible — no Qualcomm account required.
make fetch-blobs automates all three steps below and populates
lemans/blobs/, which flash-loader/flash-kernel stage from exclusively.
① Boot Binaries — 18 MB
XBL, XBL config, AOP, ADSP/CDSP/WPSS FW, prog_firehose.elf, devcfg.mbn, sec.dat, rawprogram XMLs
curl -LO https://softwarecenter.qualcomm.com/nexus/generic/\ product/chip/tech-package/QCS9100_bootbinaries.1.0/\ qcs9100_bootbinaries.1.0-test-device-public/\ 00132/QCS9100_bootbinaries_00132.zip
sha256: be297c43…f12f9db
② CDT File — 380 KB
Customer Device Tree — board-specific hardware config blob needed by XBL
curl -LO https://artifacts.codelinaro.org/artifactory/\ codelinaro-le/Qualcomm_Linux/QCS9100/cdt/\ rb8_core_kit.zip
sha256: a252244f…9f15bfa
③ GPT Tables & rawprogram XMLs
The github.com/qualcomm-linux/qcom-ptool repo ships no pre-generated
tables — only a partitions.conf under
platforms/iq-9075-evk/ufs/. make fetch-blobs shallow-clones
the repo, installs ptool into a venv, then runs gen_partition
(conf → XML) followed by ptool (XML → GPT bins + rawprogram XMLs).
sha256-verified checksums are applied to the two downloaded zips before extraction.
Extending Buildroot Adding a package via br-ext
Directory layout
br-ext/package/mypkg/ ├── Config.in ← Kconfig menu entry └── mypkg.mk ← build rules
Mirror the pattern from br-ext/package/optee_client_ext/.
Register with:
source "$BR2_EXTERNAL_BR_EXT_PATH/package/mypkg/Config.in"
in br-ext/package/Config.in.
Enable in lemans.mk
# In lemans.mk — package selection block BR2_PACKAGE_MYPKG ?= y BR2_PACKAGE_MYPKG_SITE ?= $(ROOT)/mypkg
The ?= operator allows command-line overrides without editing the file.
MYPKG_VERSION = 1.0 MYPKG_SITE = $(BR2_PACKAGE_MYPKG_SITE) MYPKG_SITE_METHOD = local MYPKG_INSTALL_STAGING = YES MYPKG_CONF_OPTS += -DENABLE_TESTS=OFF define MYPKG_INSTALL_TAS @$(foreach f,$(wildcard $(@D)/ta/out/*.ta), \ $(INSTALL) -m 444 $$f \ $(TARGET_DIR)/lib/optee_armtz/ &&) true endef MYPKG_POST_INSTALL_TARGET_HOOKS += MYPKG_INSTALL_TAS $(eval $(cmake-package))
TAs installed to /lib/optee_armtz/ are loaded dynamically
by tee-supplicant on demand.
Build & flash
# Full rootfs rebuild: make buildroot efi flash-kernel # Rebuild just one package: make -C ../buildroot O=$(ROOT)/out-br \ mypkg-rebuild make efi flash-kernel
Tests On-board validation from the Normal World
Once the board boots, validate the stack from the Normal World serial console
(ttyMSM0 115200) or over SSH. These programs ship in the
Buildroot rootfs — the stock Yocto rootfs does not include them.
qcom-tests — bundled bring-up runner
# Interactive runner — pick step(s); PASS/FAIL per step qcom-tests # 1) ADSP FastRPC 2) CDSP FastRPC # 3) VIDEO round-trip 4) CPU stress (stress-ng) Choice> 1 3 # blank = all # multi-hour CPU soak via stress-ng — logs load + # thermal-zone temps each minute (watch for throttle) STRESS_SECS=14400 qcom-tests # 4h, then pick 4
We also use stress-ng for performance
metrics — its per-stressor throughput report (bogo-ops/s) gives a repeatable CPU benchmark.
xtest — OP-TEE test suite
# full OP-TEE regression suite xtest # a single test, or list the options xtest 1004 # run one test xtest -h # selection / levels / loops
fastrpc_test — CPU↔DSP / OP-TEE PAS
# CDSP brought up via remoteproc → OP-TEE PAS, then: fastrpc_test -d 3 -U 0 # -d 3 = CDSP domain. A passing run means OP-TEE ran # the PAS reset sequence correctly.
Video codec — OP-TEE PAS + GStreamer (optional)
# iris firmware loads lazily on first open — trigger it: exec 3<> /dev/video0 ; exec 3>&- # optional H.264 encode → decode (hardware v4l2) gst-launch-1.0 videotestsrc num-buffers=100 ! \ videoconvert ! v4l2h264enc ! h264parse ! \ v4l2h264dec ! fakesink -v
Summary
Build
- 5 components built from source: OP-TEE, TF-A BL31, U-Boot (SPL + proper), Linux, Buildroot
- SPL SWIV-annotated then signed locally via qtestsign (no CASS required)
- All packed into a single UKI EFI binary inside a FAT32 image
make allbuilds everything;make bootimagerebuilds the boot chain
Flash
make flash-loader— full bootloader provisioning (rawprogram 1–5)make flash-kernel— EFI partition only (fast iteration)- Uses QDL / Firehose protocol over USB in EDL mode
- Stock firmware: staged strictly from
make fetch-blobs(lemans/blobs/)
Boot
- PBL → XBL → XBL-SEC → SPL (EL3) → BL31 (EL3); BL31 boots OP-TEE (S-EL1) + U-Boot (EL2) → UKI → Linux (EL2)
- XBL-SEC verifies qtestsign signature on tz.mbn before SPL runs
- EL2 DTB overlay required for Linux without Gunyah
- Initramfs is embedded — no block storage mount needed
Key files
lemans.mk— top-level build orchestrationlemans/output/tz.mbn— qtestsign-signed U-Boot SPLlemans/output/uefi.elf— SPL_ATF boot FIT (BL31 + OP-TEE + U-Boot proper)lemans/output/efi.bin— FAT32 EFI partition image