========================================================= Boot chain and exception-level hand-off (PBL → XBL → ABL) ========================================================= This page is the unified view of the cold-boot chain and **which exception level each stage runs at**, what each stage loads, and what each stage *enforces* on the next. The per-stage internals live elsewhere — XBL internals in :doc:`/xbl/index`, the XBL→ABL hand-off in :doc:`/xbl/handoff`, the register/machine state a post-XBL payload inherits in :doc:`/boot/below-uefi`, the signing chains in :doc:`/boot/secure-boot`, and the EL3 authenticity proof in :doc:`/edl/firehose`. This page ties them together and adds the EL3 evidence for XBL itself. The chain ========= .. code-block:: text PBL (on-die ROM) EL3 immutable; loads + hash-checks XBL from UFS boot LUN │ ▼ XBL "Sec" monitor EL3 xbl_a PH12 @0x14950000, entry 0x14953000 │ (SCR_EL3/VBAR_EL3 install) — signature-enforced ▼ XBLCore / SBL loader EL1 xbl_a entry 0x14817908 (reached via the Sec │ monitor's eret); DDR train, clocks, PMIC, │ then builds the UEFI environment ▼ PIL loads secure world TzeLoader/PILDxe load TZ, HYP, AOP, modem, dsp ├── TZ (QSEE) EL3 tz_a — takes over the EL3 monitor from XBL Sec ├── HYP EL2 hyp_a — Qualcomm hypervisor └── AOP / coprocs aop_a etc. on their own cores │ ▼ XBLCore DXE + BDS EL1 82 DXE drivers; QcomBds launches the boot app │ ▼ ABL "LinuxLoader" EL1 abl_a — loads boot_a, fixups, ExitBootServices │ ▼ Linux kernel EL1 entered with x0=DTB (HYP owns EL2 above it) Stage by stage ============== PBL — Primary Boot Loader (EL3, immutable ROM) On-die mask ROM, not in any flash dump and not modifiable. Out of reset it runs at **EL3**, brings up minimal clocks, reads XBL from the UFS boot LUN, verifies XBL's MBN **hash segment** (SHA-384 per-segment table) and, for the EL3 sub-image, its **signature**, then jumps into XBL. What PBL enforces is the crux of replaceability and is covered under "What each stage enforces" below. PBL is also the agent that drops to EDL/Sahara (9008) when XBL is missing/corrupt or fails its checks (:doc:`/edl/entry`; recovery implications under "Recoverability" below). XBL "Sec" — EL3 secure monitor (evidenced) ``xbl_a.bin`` carries a distinct segment **PH12 at vaddr ``0x14950000``**, file ``0x2be7a0``, size ``0x26000``, with the unusual PT_LOAD flags **``0x05000005``**. Its code entry is at **``0x14953000``** and does exactly what an EL3 secure monitor does — disassembly:: 0x14953000: mov x9, x0 0x14953018: msr scr_el3, x0 ; x0 = 0xe00 (Secure Config Register) 0x14953024: msr vbar_el3, x0 ; EL3 vector base 0x1495302c: msr daif, x0 ; mask D/A/I/F ... ; copy/relocate, then run This is **structurally identical** to the Firehose programmer's nested EL3 monitor documented in :doc:`/edl/firehose` — same vaddr ``0x14950000``, same entry ``0x14953000``, same flags ``0x05000005``, same ``SCR_EL3``/``VBAR_EL3`` install. This segment also carries the ``XBL Sec Attestation Root CA 4`` string (file ``0x2beb87``). It is the highest-privilege root of the on-device image and the piece PBL runs first at EL3. XBLCore / SBL loader (EL1) ELF entry **``0x14817908``** (segment ``0x14817000``) is the EL1 reset stub the Sec monitor ``eret``\ s down to (:doc:`/xbl/el3-monitor`) — its control- register writes are all the EL1 encoding (``sctlr_el1``/``vbar_el1``), with no ``CurrentEL`` check. A boot-MMU library this stub calls into (``0x14818280``) also programs EL3 state (``sctlr_el3``/``ttbr0_el3``/``tcr_el3``/``mair_el3``) unconditionally, back-to-back with the EL1 halves — only a separate SCTLR accessor pair it also calls (``0x14817a08``/``0x14817a28``) is actually ``CurrentEL``-guarded. None of this means XBLCore's own entry starts at EL3 (:doc:`/xbl/el3-monitor` has the disassembly). XBLCore performs the heavy silicon bring-up (DDR training, clock/PLL init — inferred from general Qualcomm SoC bring-up practice, not from a ``HAL_clk_Fabia*``-style string in this binary — and PMIC sequencing), then constructs the UEFI environment for the DXE/BDS phase, still at **EL1**. Full internals: :doc:`/xbl/index`. PIL — Peripheral Image Loader (secure world brought up here) XBL's ``PILDxe``/``PILProxyDxe`` and ``TzeLoader`` load and authenticate the coprocessor/secure-world images to their reserved windows (the ``PIL Reserved`` carve-out ``0x86000000`` size ``0x15800000`` in :doc:`/xbl/handoff` Q4). After this step the exception levels are owned as follows: - **TZ (QSEE)** — ``tz_a`` — installs itself as the resident **EL3** monitor, taking EL3 over from XBL Sec. Confirmed by disassembly: its entry (``0x14680000``) writes ``scr_el3``/``sctlr_el3`` (:doc:`/trustzone/secure-world`). - **HYP** — ``hyp_a`` — the Qualcomm hypervisor at **EL2**; this is why an OS kernel on this SoC is entered at EL1, not EL2. Confirmed by disassembly: its entry (``0x8004a000``) writes ``vbar_el2``/``mair_el2`` and reads ``vmpidr_el2`` (:doc:`/trustzone/secure-world`). - **AOP** (Cortex-M) and the DSP/modem coprocessors run on their own cores (:doc:`/trustzone/secure-world`, :doc:`/audio/dsp-firmware`). Version tags for all of these are in :doc:`/index`; the per-image ELF/segment structure and EL evidence are in :doc:`/trustzone/secure-world`. XBLCore DXE + BDS (EL1, non-secure) The 82 DXE drivers run here (UFS, clocks, PMIC, USB, display, GPT, verified boot, …; enumerated in :doc:`/xbl/dxe`), and ``QcomBds`` launches the boot application by UI name — ``DefaultBDSBootApp = "LinuxLoader"`` (:doc:`/xbl/handoff`). ABL "LinuxLoader" (EL1) ``abl_a`` — a single UEFI application, **no EL3 content of its own** (:doc:`/xbl/handoff` Q2). Loads ``boot_a``, fixes up cmdline/DTB, exits boot services and enters the kernel at **EL1** with ``x0 = DTB`` (:doc:`/abl/bootlinux`). What each stage enforces (and what it means for replacement) ============================================================ Two different gates operate in this chain, and which one applies determines whether a stage can be replaced: Hash-table (integrity) gate — bypassable on this unit PBL→XBL and XBL→ABL both verify the next image's MBN **hash segment** (per-segment SHA-384) and a signature over it that, on this unit, chains only to the public Qualcomm **test** key. ``SEC_BOOT`` is not fused (:doc:`/boot/secure-boot`), so re-computing the hash segment (and re-signing with the public test key) is accepted. This is why, though not empirically verified here by flashing a patched image, **ABL is in principle freely replaceable** — and the EL1/UEFI portions of XBL are too. EL3-authenticity gate — **not** bypassable on the Firehose programmer; inferred, not directly proven, for XBL itself :doc:`/edl/firehose` proves, on-device, that the **nested EL3 image is signature-enforced against the secure-world root of trust unconditionally, regardless of ``SEC_BOOT``** — a clean-room EL3 monitor with a correct hash is rejected; only the stock QTI-signed EL3 monitor, carried byte-for-byte, is accepted. XBL carries exactly such an EL3 segment (**XBL Sec**, above), matching the programmer's nested monitor feature-for-feature. The direct consequence, if the same enforcement applies to XBL Sec as to the proven Firehose case (see the caveat below): **XBL is expected not to be clean-roomable.** A from-scratch XBL whose EL3 Sec segment is your own code is expected to be rejected by PBL even with a perfect hash segment, the same way the clean-room Firehose EL3 monitor was — but this is an inference from the Firehose evidence, not a directly observed rejection of a clean-room XBL. The replaceable surface is the **EL1 side**: keep the stock, signed XBL Sec (and the hash/sign envelope) and substitute the XBLCore/DXE/UEFI payload — i.e. *patch* XBL, not rewrite it. Replacing the EL3 root would require either a secure-world signing key (not present; the test key does not cover the unconditionally-enforced EL3 path) or ``SEC_BOOT`` being in a state that disables the check (not observed). Caveat on directness: the EL3-authenticity enforcement is **proven for the Firehose programmer's nested monitor** and only inferred for XBL Sec, from the identical load address, flags, entry offset and ``SCR_EL3``/``VBAR_EL3`` structure — it has not itself been tested by submitting a clean-room XBL Sec segment to PBL. Byte-comparing XBL Sec against the programmer's monitor needs the external programmer image, which is not in this dump. Recoverability ============== Every stage above ABL is EL-privileged and load-order-critical, but none is a one-way door: **EDL/Sahara is entered by PBL directly** and is independent of XBL, so a bricked or rejected XBL falls through to EDL for reflash (:doc:`/edl/entry`, :doc:`/edl/firehose`). PBL itself is ROM and cannot be bricked. So XBL experiments are recoverable — the limiter on replacing XBL is the EL3-authenticity gate above, not brick risk. :Source: ``_READONLY/lun1/xbl_a.bin`` — program-header/segment layout and Capstone disassembly of the entry (``0x14817908``) and the EL3 Sec monitor (``0x14953000``); cross-referenced against :doc:`/edl/firehose` (EL3 proof), :doc:`/boot/secure-boot` (signing), :doc:`/xbl/handoff` (dispatch/memory map) and :doc:`/index` (version tags). :Cross-refs: :doc:`/xbl/index`, :doc:`/xbl/handoff`, :doc:`/boot/below-uefi`, :doc:`/boot/secure-boot`, :doc:`/edl/firehose`, :doc:`/edl/entry`.