This is a Qualcomm IPQ8074 in a retail router, the networking-class IPQ line, not a Snapdragon. The device is an Arcadyan AW1000 (sold by Deutsche Telekom as the Speedport Smart 4), the log came off its UART header, and the full boot chain from Boot ROM to OpenWrt is captured in bootintel-4.txt : 723 lines. The interesting parts are the ones Qualcomm-shaped, not the OpenWrt-shaped ones.
The header at the very top of the log is the Qualcomm-specific piece:
Format: Log Type - Time(microsec) - Message - Optional Info
Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
S - QC_IMAGE_VERSION_STRING=BOOT.BF.3.3.1-00163
S - IMAGE_VARIANT_STRING=HAACANAZA
S - OEM_IMAGE_VERSION_STRING=CRM
S - Boot Config, 0x000002e5Every line prefixed B - that follows is a timing event: microseconds since power-on reset. D - is a delta. S - is a statistic that gets emitted at the end of the corresponding stage. This is the SBL1 self-log format: nothing about it is common to non-Qualcomm platforms. If you see this format on a UART capture, you know you're on a Qualcomm IPQ (or a mobile Snapdragon SBL of the same vintage).
The six Qualcomm boot stages (PBL → SBL1 → QSEE → RPM → APPSBL → Linux)
| Stage | Where it runs | What it does |
|---|---|---|
| 1. PBL (Primary Boot Loader) | Cortex-A53 core 0, EL3, executing from on-die Boot ROM | Immutable ROM stage baked into the SoC at manufacture. Locates SBL1 on flash, RSA-verifies its signature against a certificate chain whose root-key SHA is fused into the chip, and jumps. Ends at t=132674μs on this board. |
| 2. SBL1 (Secondary Boot Loader) | Cortex-A53, EL3, running from on-chip SRAM | Qualcomm's SBL: brings up the PMIC (pm_device_init, pm_driver_init), the clock tree (clock_init), boot flash, then trains DDR (PCDDR3 @ 466 MHz on this board). Once DRAM is live, loads and authenticates each subsequent image in turn. |
| 3. QSEE (Qualcomm Secure Execution Environment) | Cortex-A53, EL3 / Secure world (TrustZone) | Qualcomm's TEE. Loaded and authenticated by SBL1 (1.3 MB), then given control briefly to initialise, then it becomes the EL3 runtime that services secure-monitor calls (SMC) from the kernel for the rest of the boot. |
| 4. RPM (Resource Power Manager) + DEVCFG | Cortex-M3 coprocessor for RPM; SBL1 for DEVCFG | RPM firmware (86 KB) runs on a dedicated Cortex-M3 to manage power rails and clocks after Linux hands off. DEVCFG (26 KB) is the device-configuration table SBL1 uses to program the SoC's early pin, clock, and rail state. |
| 5. APPSBL (U-Boot) | Cortex-A53, EL2 / non-secure | On IPQ platforms, APPSBL is U-Boot itself: 572 KB in this build. Loaded and authenticated by SBL1, then invoked as the non-secure bootloader. Reads a FIT image out of UBI-on-NAND and drops to Linux. |
| 6. Linux kernel | Cortex-A53, EL1 | OpenWrt Linux 6.6.37. Talks to QSEE at EL3 via SMC calls (qcom_scm driver). All four A53 cores start at EL1, not EL2: atypical for modern ARM64. |
What the version-string header actually encodes
Owner intuition: those three strings at the top are just "a version number." They are not.
QC_IMAGE_VERSION_STRING=BOOT.BF.3.3.1-00163 is the SBL image family + version. The BOOT prefix is the image kind. BF.3.3.1 is a Qualcomm-internal boot-firmware branch identifier: different chipset generations and product lines use different letter codes (LA for Linux/Android, BF for IPQ boot firmware, among others); the full mapping is not published by Qualcomm. 00163 is a build number within that branch. The exact mapping from branch code to silicon is not documented publicly; the community-authoritative source is the header strings themselves, cross-referenced across leaked BSPs.
IMAGE_VARIANT_STRING=HAACANAZA is an 8-character encoded variant identifier whose internal field layout Qualcomm has not published. The string is known to differ between OEM SKUs of the same silicon. This one, HAACANAZA, is the shape used by IPQ8074/IPQ8074A across multiple OEM builds; you can find identical strings in leaked BSPs for other Qualcomm 802.11ax router SoCs.
OEM_IMAGE_VERSION_STRING=CRM is the build-system tag. CRM is Qualcomm's internal Chipset Release Manager: a value here means the image came off Qualcomm's CI-signed release pipeline rather than an OEM's custom fork. On some OEM builds this field is a vendor tag (e.g. their own release train name) instead.
All three strings are emitted by SBL1 itself. SBL1's signature is RSA-verified by PBL against a certificate chain whose root-key SHA is fused into the SoC at manufacture. So the entire version-string block is signed content: an attacker can't forge the identification without also holding the OEM's SBL signing key.
The SBL1 timing log (and why every stage has one)
Every line starting with B - is a stage-entry or stage-exit marker with a microsecond timestamp. Here's a walk from PBL exit through the SBL1 image-load phase, verbatim from the log:
B - 132674 - PBL, End
B - 145973 - SBL1, Start
B - 198646 - GCC [RstStat:0x10, RstDbg:0x600000] WDog Stat : 0x4
B - 205204 - pm_device_init, Start
B - 331321 - pm_driver_init, Start
B - 337604 - clock_init, Start
B - 341630 - boot_flash_init, Start
B - 380457 - sbl1_ddr_set_params, Start
B - 416996 - DDR Type : PCDDR3
B - 448319 - Image Load, Start
D - 216245 - QSEE Image Loaded, Delta - (1374928 Bytes)
B - 672342 - Image Load, Start
D - 12017 - DEVCFG Image Loaded, Delta - (26148 Bytes)
B - 684450 - Image Load, Start
D - 23058 - RPM Image Loaded, Delta - (86660 Bytes)
B - 707569 - Image Load, Start
D - 89914 - APPSBL Image Loaded, Delta - (572642 Bytes)
B - 797605 - QSEE Execution, Start
B - 803431 - USB D+ check, Start
B - 809805 - SBL1, End
D - 666150 - SBL1, DeltaRead that as a timeline:
- PBL runs for ~132 ms (from power-on to
PBL, End). Most of that is the ELF-segment hash-verify pass on SBL1:elf_segs_hash_verify_entryat t=69818μs is where the actual SHA of SBL1's segments is computed and matched against the signed manifest. - SBL1 runs for ~666 ms. Of that, ~340 ms is image loading (QSEE alone is 216 ms because it's 1.3 MB and gets hash-verified in the same pass), and about ~200 ms is DDR training + PMIC + clock init.
- Five images get loaded and authenticated: QSEE (1.3 MB), SEC (0 bytes here: empty on this SKU), DEVCFG (26 KB), RPM (86 KB), APPSBL (572 KB). Every one is hash-verified against the signing manifest before its stage gets control.
- The
USB D+ checkat t=803 ms is one of Qualcomm's entry points to Emergency Download Mode (EDL): if a USB host is detected on D+ at this point, SBL1 can hand control to the EDL loader (device appears to the host as USB VID/PID 05c6:9008) instead of proceeding to APPSBL. On a shipped consumer router this is normally never entered. On a bricked device this is how you recover.
Total time from PBL to APPSBL invocation: about 810 milliseconds. That's all pre-U-Boot. The Flash Throughput, 6903 KB/s line at the bottom of the SBL1 block is the effective NAND read rate SBL1 measured across that ~2 MB of image loads.
QSEE and the kernel↔TrustZone interface
Once QSEE is running, the kernel talks to it via SMC (Secure Monitor Call). The log makes this visible:
[ 0.000000] psci: PSCIv1.0 detected in firmware.
[ 0.000000] psci: SMC Calling Convention v1.0
[ 0.074209] qcom_scm: convention: smc arm 64
[ 0.013647] CPU: All CPU(s) started at EL1Three things to note:
- PSCIv1.0. Power State Coordination Interface : the standard ARM interface for CPU on/off, idle, and reset. On this device PSCI is served by the Qualcomm EL3 runtime (part of the QSEE/tz image bundle), and the kernel invokes it via SMC. Worth reading alongside the TI K3 post, whose log prints
PSCIv1.1andSMC Calling Convention v1.4against the same Cortex-A53 profile: the Qualcomm EL3 stack is a couple of PSCI revisions behind, which is one reason userspace suspend paths on IPQ routers rely onqcom_scm-specific SMCs instead of standard PSCI features. qcom_scm: convention: smc arm 64. This is the Qualcomm-specific SMC subset for TrustZone services (secure storage, key handling, secure-clock reads, TPM emulation, and so on). The kernel exposes it as theqcom_scmdriver.All CPU(s) started at EL1. Modern ARM64 typically enters the kernel at EL2 to leave the option for KVM/hypervisor open. This board enters at EL1: a consequence of the Qualcomm EL3 stack (QSEE owns EL3 and there is no EL2 hypervisor stub in this image set), not something U-Boot chooses. Consequence: no in-guest virtualisation on this router. For a networking SKU that never runs guests, that's an intentional lockdown; for someone porting mainline U-Boot who assumes EL2 entry, it's a surprise.
The Q6 remoteproc and the "IPQ8074" label
Later in the log the kernel powers up the wireless subsystem:
[ 10.088257] remoteproc remoteproc0: Booting fw image IPQ8074/q6_fw.mdt, size 668
[ 11.094262] remoteproc remoteproc0: remote processor cd00000.q6v5_wcss is now upTwo disclosures:
- The SoC family is IPQ8074: the firmware path
IPQ8074/q6_fw.mdtis loaded from OpenWrt's ath11k firmware tree, which is organized by chipset. This is confirmation from the driver side that matches theconfig@hk09configuration used in the U-Boot FIT image (HK / Hawkeye is the internal Qualcomm codename for the IPQ807x family). - The wireless MAC runs on Q6, Qualcomm's Hexagon DSP architecture: on a dedicated core in the wireless subsystem. On IPQ8074 that core is the WCSS (Wireless Connectivity Subsystem). The kernel doesn't schedule anything on it directly; it hands it a signed firmware blob and lets it run the lower MAC and PHY offload autonomously (ath11k keeps parts of the upper MAC in the host driver).
The full attack surface of this device is therefore not just the A53 cores running OpenWrt. It also includes the Q6 running signed WLAN firmware, the RPM running the M3 power-management firmware, and QSEE running whatever trusted applications the vendor loaded into it. Each is a separate signed-image chain with a separate update cadence.
U-Boot handoff (the OpenWrt-shaped bit)
APPSBL: U-Boot 2016.01, forked heavily by Qualcomm for their QSDK: runs briefly and hands off:
U-Boot 2016.01 (Jul 25 2022 - 17:08:05 +0800)
DRAM: smem ram ptable found: ver: 1 len: 4
1 GiB
...
Hit any key to stop autoboot: 2 1 0
[do_boot_unsignedimg(903)] debug:0
## Loading kernel from FIT Image at 44000000 ...
Using 'config@hk09' configuration
Description: ARM64 OpenWrt Linux-6.6.37Points of interest:
- The build timestamp says 2022, on a device shipped for OpenWrt use in 2024, running a June-2024 kernel. U-Boot 2016.01 upstream is nine years old. QSDK forks live on their own timeline: see the U-Boot 1.1.x post for the broader pattern.
- 2-second interruptable autoboot. The
Hit any key to stop autoboot: 2 1 0counter gives you a two-second window to drop into the U-Boot shell over UART: and there's a whole post about why that's a bigger deal than it sounds. do_boot_unsignedimgis the U-Boot command that loads the FIT image. The name is honest: at this point in the chain, U-Boot itself is not re-verifying the kernel signature. That verification, if it happens, was already done by SBL1 against the composite image manifest. On some OEM builds the kernel is re-verified by U-Boot too; on this OpenWrt build it's not.- FIT image with config
hk09. The device tree loaded isARM64 OpenWrt arcadyan_aw1000 device tree blob: a 50 KB DTB that tells the kernel about the exact hardware layout (four A53s, PCDDR3, QCA8075 gigabit PHYs, xhci controllers, the whole thing).
How this compares to the other chains
| Role | Qualcomm IPQ8074 | TI K3 (AM62A) | Allwinner H616/H618 |
|---|---|---|---|
| Immutable ROM stage | PBL | ROM (loads TIFS + DM) | BROM (eGON search) |
| Vendor-specific secondary loader | SBL1 (proprietary) | R5F SBL (open) | U-Boot SPL (open) |
| EL3 runtime | QSEE (proprietary) | TF-A BL31 (open) | TF-A BL31 (open) |
| Non-secure boot payload | APPSBL (U-Boot fork) | U-Boot SPL as BL33 | U-Boot as BL33 |
| Kernel entry level | EL1 (no in-guest KVM) | EL2 | EL2 |
| Openness | PBL/SBL1/QSEE all closed | TIFS closed, rest open | BROM closed, rest open |
The Qualcomm chain is the most locked-down of the three: everything up to and including the EL3 runtime is Qualcomm proprietary, signed, and (aside from the SBL1 timing log) opaque to the operator. That's a deliberate choice for a radio-heavy platform where regulatory certification requires that end users cannot modify the transmit chain.
What to check on your own Qualcomm device
- The header block. The three version strings identify the SBL image family, the chipset variant, and the build pipeline. If you have UART access and can capture from power-on, those three strings tell you the vendor's exact SBL build: the same way
uname -atells you a kernel build. - The SBL1 timing block. If any of the
*_initstages take an atypical amount of time (delta values in ms), that's a hardware fault indicator. Boards with degraded PMICs, cold-solder DDR, or intermittent flash show up here first. USB D+ check(EDL entry point). If this line appears and boot proceeds normally, EDL is available but wasn't triggered. On a bricked device, holding D+ high during power-on is the vendor-intended recovery path. On a device you don't control physically, this same entry point is what a supply-chain attacker with a modified cable could target.- QSEE A/B slots. The kernel's MTD partition dump on this board (search the log for
qcomsmem partitions) shows both0:qseeand0:qsee_1, Qualcomm's dual-slot pattern that lets a failed QSEE update fall back to the previous image. Same pattern for0:appsblbak. Whether rollback protection is enforced via QFPROM anti-rollback fuses is a separate question, on IPQ networking parts it usually isn't. - The kernel EL level. An IPQ device booting at EL1 is normal. An IPQ device booting at EL2 with mainline U-Boot would be interesting: it means someone replaced the QSDK U-Boot fork with upstream, which usually means the vendor lock has been bypassed.
- Whether the autoboot countdown is interruptable. On this board it's 2 seconds: two seconds of UART access away from a root shell. See the autoboot post.
Related
- Allwinner H616 / H618 boot : the same problem class solved with a fully open firmware stack (TF-A + U-Boot mainline) instead of a proprietary SBL.
- TI K3 DMSC boot on AM62A : TI's equivalent of Qualcomm's SBL: a Cortex-M4F running proprietary firmware that orchestrates the A53 side. Different vendor, same split-plane pattern.
- RISC-V bootloader lifecycle : the same layered privilege pattern with OpenSBI + M-mode instead of QSEE + EL3.
- U-Boot 1.1.x from 2005 is still shipping : QSDK U-Boot 2016.01 is a newer example of the same vendor-fork-frozen-in-time pattern.
- Interruptable autoboot : the U-Boot countdown on this device is 2 seconds.
- Device Fingerprinter : paste a Qualcomm boot log, get the SBL image version, chipset variant, and kernel identified inline. Client-side, no upload.
- Building an inventory of Qualcomm devices and want the "is this SBL build the current OEM release?" question answered without pasting logs one at a time? That's what BootIntel's paid tiers are for.