Lemans
Platform · Boot · Projects
The condensed tour: what the platform is, how the bootloaders
are laid out in memory, how the boot sequence runs, and the
open-source projects that make up the stack.
Need the full build/flash/Yocto detail? See the comprehensive deck.
Agenda
1 · Platform Overview
SoC, board, and the software stack
2 · Build Outputs
The three flashable images & their contents
3 · Boot Loader Maps
Per-stage load addresses & device trees
4 · Boot Sequence
PBL → XBL → SPL → BL31 → OP-TEE → U-Boot → Linux
5 · Projects
U-Boot · TF-A · TEE · Linux kernel
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)
- TF-A BL31 (EL3 Secure Monitor)
- OP-TEE OS (BL32, loaded by SPL)
- U-Boot proper (BL33 / UEFI)
- Linux + Buildroot initramfs (UKI)
Notable specifics: SPL signed locally via qtestsign (open-source — no QTI CASS access required); U-Boot proper loaded at 0xaf000000.
Build Outputs Three flashable images
1 · tz.mbn
tz partition · signed U-Boot SPL
- U-Boot SPL (chosen over TF-A BL2), the first open-source stage
- SWIV-annotated, then qtestsign-signed (no CASS)
- Built
SPL_LOAD_FIT + SPL_ATF - Runs at EL3, text base
0x1c100000
2 · uefi.elf
uefi partition · SPL_ATF boot FIT (a FIT, despite the .elf name)
- TF-A BL31 — EL3 Secure Monitor @
0x1c200000 - OP-TEE OS (BL32) @
0x1c300000 - U-Boot proper (BL33) @
0xaf000000 - + U-Boot control FDT (
fdt-1) — lets the SPL record loadables
3 · efi.bin
esp partition (LUN 0) · FAT32 EFI system partition
EFI/BOOT/bootaa64.efi— UEFI fallback entryEFI/Linux/uki.efi— Unified Kernel Image, bundling:- • kernel
Image - •
lemans-evk-el2.dtb(EL2 device tree) - • Buildroot initramfs + kernel cmdline
make bootimage → tz.mbn (signed SPL)
make bootimage → uefi.elf (BL31 + OP-TEE + U-Boot FIT)
make efi → efi.bin (ESP: UKI + UEFI fallback)
Boot Loader Maps Load Addresses & Device Trees
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)
Read by the SPL so it records the FIT loadables into /fit-images,
giving BL31 the OP-TEE and U-Boot entry points. u-boot.bin ships
with an appended control DTB because BL31 hands off with x0 = MPIDR,
not an fdt pointer.
Linux DTB — lemans-evk-el2.dtb
The EL2 variant needed to run Linux at EL2 without the Gunyah hypervisor — bundled into the UKI, no separate flash step. Enables the EL2 watchdog, disables the GPU Zap shader, and remaps IOMMU streams for the remoteprocs.
Full per-stage load-address table & DTB details in the comprehensive deck.
Boot Sequence
Projects
The open-source components built from source
1 · U-Boot
SPL (used instead of BL2) + U-Boot proper (BL33)
2 · TF-A
BL31 — the EL3 Secure Monitor
3 · TEE
OP-TEE OS — Secure World kernel (BL32)
4 · Linux Kernel
EL2 device tree + UKI packaging
U-Boot SPL + proper — first open-source boot stage
- U-Boot SPL and TF-A BL2 are both open-source first-stage loaders; for this platform we chose to use SPL.
- Defconfig
qcom_lemans_spl_defconfig, text base0x1c100000, runs at EL3. - Built
SPL_LOAD_FIT + SPL_ATF: reads theuefipartition FIT and jumps to BL31. BL31=bl31.elfandTEE=tee.elfpassed in so the FIT embeds TF-A BL31 + OP-TEE.- SWIV-annotated, then signed locally with qtestsign →
tz.mbn(tz partition). No CASS / remote signing.
SPL signing (make spl)
python3 lemans/security/swiv_build_utility.py \ .output/spl/u-boot-spl-swiv.elf \ .output/spl/u-boot-spl.elf lemans qtestsign -v6 tz \ -o .output/spl/u-boot-spl.mbn \ .output/spl/u-boot-spl-swiv.elf
- Defconfig
qcom_lemans_defconfig, text base0xaf000000, runs at Normal World EL2. - Shipped in the FIT as
u-boot.bin(nodtb + appended control DTB). - Configured in UEFI mode — presents a standard UEFI firmware interface.
Boot behaviour
- Reads the EFI system partition (FAT32
efi.bin). - Falls back to
EFI/BOOT/bootaa64.efi. - Launches
EFI/Linux/uki.efi(the Unified Kernel Image). - Hands kernel execution over at EL2 once the UKI is loaded.
TF-A BL31 — the EL3 Secure Monitor
ARM Trusted Firmware BL31 is the runtime Secure Monitor at EL3 — the highest privilege level. It owns the world switch, dispatching Secure Monitor Calls (SMCs) between the Normal World (Linux) and the Secure World (OP-TEE), and stays resident for the life of the system.
Build — BL31 only
- Platform target:
lemans_evk→build/lemans_evk/release/bl31/bl31.elf. - We use U-Boot SPL in place of TF-A BL2 (both open-source) — only BL31 is built here.
- Passed to U-Boot as
BL31=so the SPL FIT carries it; flatbl31.binis the FITatffirmware.
- Loaded by U-Boot SPL from the FIT to
0x1c200000; SPL jumps to it. - Initialises the Secure Monitor and EL3 runtime services.
- Dispatches OP-TEE (BL32) into Secure EL1.
- Hands off to U-Boot proper (BL33) in the Normal World with
x0 = MPIDR(no fdt pointer). - Remains resident, mediating every Normal ↔ Secure world SMC at runtime.
TEE OP-TEE OS — BL32, Secure World kernel
OP-TEE is an open-source Trusted Execution Environment that runs in the Arm TrustZone Secure World (Secure EL1). It hosts Trusted Applications (TAs) and services Secure Monitor Calls routed through TF-A BL31.
Configuration
- Platform: qcom-lemans
- Output: optee_os/out/arm/core/tee.elf
- FIT payload: tee-raw.bin @
0x1c300000 - Passed to U-Boot as: TEE= (embedded in the SPL FIT)
U-Boot SPL loads TF-A BL31, OP-TEE (BL32), and U-Boot proper (BL33) from the SPL FIT. BL31 dispatches OP-TEE into Secure EL1, then returns to stage U-Boot.
At runtime the Linux kernel talks to OP-TEE via the
tee-supplicant daemon and the
CONFIG_OPTEE driver — SMCs travel
EL0 → EL1 → EL3 → Secure EL1.
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
- Output: arch/arm64/boot/Image → 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 the 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
Bundled into the UKI alongside the kernel Image and the Buildroot initramfs — no separate flash step required.
Summary
Platform
- Qualcomm SA8775P / QCS9075 on the IQ-9075-EVK (Lemans EVK)
- Open firmware: we chose U-Boot SPL over TF-A BL2 (both open-source) as the first open-source stage
- SPL signed locally via qtestsign — no QTI CASS access required
Boot Loader Map
- SPL
0x1c100000· BL310x1c200000· OP-TEE0x1c300000 - U-Boot proper
0xaf000000· Linux via relocatable UKI - uefi FIT carries BL31 + OP-TEE + U-Boot proper on the
uefipartition
Boot Sequence
- PBL → XBL → XBL-SEC → SPL (EL3) → BL31 (EL3 monitor)
- BL31 boots OP-TEE (S-EL1, resident) + U-Boot (EL2) → UKI → Linux (EL2)
- Control DTB → FIT entry points · EL2 DTB for Linux w/o Gunyah
Projects
- U-Boot — SPL (used instead of BL2) + proper (BL33 / UEFI)
- TF-A — BL31, resident EL3 Secure Monitor
- TEE — OP-TEE OS at Secure EL1 (BL32)
- Linux — EL2 kernel packaged as a UKI
Full build, flash, UKI, and Yocto detail lives in the comprehensive deck.