6.1. Secure world and coprocessors (TZ, HYP, trustlets)

Structural reverse engineering of the images PIL loads beside and below the HLOS: the TrustZone secure monitor (tz_a), the hypervisor (hyp_a), the TZ device config (devcfg_a), the QSEE trustlets (keymaster, uefisecapp, featenabler, mdtpsecapp), and the two service coprocessors (aop_a, qupfw_a). The exception-level narrative and where these sit in the boot order is in Boot chain and exception-level hand-off (PBL → XBL → ABL); this page is the per-image evidence — ELF container, load geometry, and the disassembly that pins each one to its exception level or processor. The ADSP/CDSP DSPs are a separate subsystem in ADSP and CDSP firmware; the signing envelope common to all of these is in Secure boot and image signing.

Every image below is an MBN/ELF whose PH0 is the Qualcomm hash-table segment (p_flags top byte 0x07) and whose second PT_NULL (0x02200000) carries the signature + certificate chain. On this unit that chain is the public Qualcomm test key throughout (Generated Test Root CA / General Use Test Key (for testing only) / SecTools Test User; attestation root QSEE Attestation Root CA 4 SubCA 10) — identical to XBL/ABL (Secure boot and image signing).

6.1.1. Exception-level / processor map

Image

ELF

Entry

Runs at

Evidence

tz_a (QSEE)

AArch64

0x14680000

EL3 resident monitor

entry writes scr_el3 / sctlr_el3, reads mpidr_el1

hyp_a (QHEE)

AArch64

0x8004a000

EL2 hypervisor

entry writes vbar_el2 / mair_el2 / vmpidr_el2

devcfg_a

AArch64

0x1c003000

EL3 data (TZ)

all-RW segments, no code; config namespace consumed by TZ

keymaster_a

AArch64 DYN

(reloc)

EL1 secure (QSEE app)

ATTESTATION_APPLICATION_ID / Keymaster attest strings

uefisecapp_a

ARM32 DYN

(reloc)

EL1 secure (QSEE app)

descriptor n=qcom.tz.uefisecapp;p=8:…

featenabler_a

AArch64 DYN

(reloc)

EL1 secure (QSEE app)

MBN DYN app, test-key chain

mdtpsecapp_a

— (blank)

EL1 secure (QSEE app)

partition all-zero on this unit (MDTP not provisioned)

aop_a

ARM32 (Thumb)

0xb000008

Cortex-M (Always-On)

Thumb entry (ldr/blx/bx trampoline), code TCM 0x0b000000

qupfw_a

Hexagon (QDSP6)

0x0

QUPv3 micro-DSP

e_machine = 164 (QDSP6); 9 paged code segments

6.1.2. TZ — tz_a (QSEE, EL3 resident monitor)

tz_a.bin is a 4 MB AArch64 ELF, entry ``0x14680000``, 23 program headers. It loads in two disjoint regions:

  • an EL3 monitor stub in IMEM — executable at 0x14680000 (0xc034) and 0x14690000 (0x1818), immediately adjacent to XBL’s own IMEM footprint (0x146xxxxx); and

  • the QSEE secure OS in the ``0x1c00_0000`` window — executable segments at 0x1c00e000, 0x1c032000, 0x1c301000, 0x1c35d000 plus large RW data/heap segments spanning 0x1c0190000x1c3d4000 (~3.5 MB).

The entry establishes an EL3 environment — disassembly at 0x14680000:

0x14680000: msr  tpidr_el0, x0
0x14680004: msr  tpidr_el1, x1
0x14680020: mov  x0, #0xe00
0x14680024: msr  scr_el3, x0        ; Secure Config Register (NS handling)
0x14680028: isb
0x1468002c: mov  x0, #0x1c0
0x14680030: msr  daif, x0           ; mask D/A/I/F
0x14680034: mrs  x0, sctlr_el3
0x14680040: msr  sctlr_el3, x0      ; MMU/cache control at EL3
0x14680064: mrs  x0, cntpct_el0
0x14680068: mrs  x1, mpidr_el1      ; per-CPU affinity → boot vs secondary

Writing SCR_EL3 and SCTLR_EL3 is only possible at EL3. This is the resident secure monitor: after XBL’s PILDxe loads and authenticates it (Boot chain and exception-level hand-off (PBL → XBL → ABL)), TZ takes ownership of EL3 from the XBL “Sec” monitor (The EL3 “Sec” monitor and the EL1 hand-off) and owns it for the rest of runtime — every SMC from the kernel, ABL, or the hypervisor lands here. The SCR value 0xe00 matches the value XBL Sec programs, i.e. the same secure-monitor configuration is carried across the hand-off.

Version TZ.XF.5.10-00304-1, variant SAJAANAAA (Onyx Boox Note Air5 C (Qualcomm SM6350)).

6.1.3. HYP — hyp_a (QHEE, EL2 hypervisor)

hyp_a.bin is a 512 KB AArch64 ELF, entry ``0x8004a000``, one RWX load segment at 0x8004a000 (file 0x60e08, reserving 0x23f000 ≈ 2.3 MB). The entry establishes an EL2 environment — disassembly:

0x8004a000: bl … bl            ; PC-relative reloc trampoline (chained bl)
0x8004a048: msr  vbar_el2, x4  ; EL2 vector base
0x8004a04c: mrs  x3, vmpidr_el2
0x8004a08c: msr  mair_el2, x4  ; EL2 memory attributes
0x8004a090: mrs  x4, id_aa64pfr1_el1

VBAR_EL2 / MAIR_EL2 / VMPIDR_EL2 are EL2-only. This is the Qualcomm hypervisor (QHEE): it installs itself at EL2, which is why the Linux kernel on this SoC is entered at EL1, never EL2 (Boot chain and exception-level hand-off (PBL → XBL → ABL)). Its string set shows a “hyp manager” that brokers SMC traffic to trustlets — e.g. hyp_manager_lookup_mssecapp_id / qcom.tz.mssecapp (the modem secure app). HYP is built from the same package as TZ (version TZ.XF.5.10-00304-1).

After the reloc trampoline the init path (0x8004a044) sets VBAR_EL2 = 0x80090000, lays out a per-CPU stack (sp = 0x801f5000 0x2000·affinity, the affinity taken from VMPIDR_EL2), programs MAIR_EL2, probes ID_AA64PFR1_EL1 for MTE, brings up the EL2 stage-1 MMU (TTBR0_EL2 / TCR_EL2 / SCTLR_EL2 = 0x8100f = M|A|C|SA|I|WXN) and sets CNTHCTL_EL2 = 3 so EL1 keeps the physical counter/timer.

6.1.3.1. The EL2 vector table

VBAR_EL2 points at a standard 16-entry AArch64 vector table at 0x80090000 (0x80 stride) — QHEE’s primary EL2 dispatch table. The twelve IRQ / FIQ / SError slots are stubs that push x30/x0, load a numeric exception index (0x90x17) and tail-call a common handler at 0x8004f638; the four Sync slots have real handlers:

+0x000 Sync  EL2t       -> b 0x8004a400
+0x200 Sync  EL2h       -> b 0x8004b004
+0x400 Sync  lower A64  -> HLOS trap dispatch (below)   <- the kernel's gate
+0x600 Sync  lower A32  -> same shape as +0x400
+0x080..+0x780 IRQ/FIQ/SError (EL2t/EL2h/lowerA64/lowerA32)
                          -> mov x0,#{9..0x17}; bl 0x8004f638  (common sink)

6.1.3.2. HLOS trap dispatch and stage-2 protection

The lower-EL AArch64 Sync entry (0x80090400) is where the EL1 kernel traps into the hypervisor. It reads the VMPIDR_EL2 affinity, indexes a per-CPU byte table (0x801cbed0) for a short settle/erratum spin, dsb nsh; isb, then decodes ESR_EL2.EC:

EC 0x17  SMC (AArch64)              -> 0x8004a468   (SMC service path)
EC 0x20  Instruction Abort, lower   -> 0x8004ac38   (stage-2 IABT)
EC 0x24  Data Abort, lower          -> 0x8004adcc   (stage-2 DABT)
EC 0x18  trapped MSR/MRS (A64)      -> 0x8004b19c
EC 0x03  trapped MCR/MRC CP15 (A32) -> 0x8004b19c
else (incl. HVC EC 0x16)            -> 0x8004ad0c

The stage-2 abort handler (0x8004ac38) saves the full GPR frame, re-reads ESR_EL2, checks the ISS fault-status, reads FAR_EL2 (the faulting IPA) and calls a registered handler pointer at [0x8004b408] with the address — this is QHEE’s stage-2 memory-protection check on HLOS accesses. The stage-2 role is confirmed by the string set: AC_VM_HYP (an access-control VM), hyp_enable_dvm (distributed virtual memory), hyp_ipa_based_safe_eco_swa, hyp_secure_mor_PIL_start, the HypXVersion / HypXCodeAddr / HypXSize metadata and a /dev/hyp diag node, plus the “Failed to Hypervisor HLOS Stage 2” fault strings. Full disassembly in artifacts/re_static/item1_aop_hyp.txt.

6.1.4. TZ device config — devcfg_a

devcfg_a.bin (128 KB, AArch64 ELF, entry 0x1c003000) is data, not code — its two load segments are RW only, placed at 0x1c003000 (adjacent to QSEE) and 0x805fd000. The payload is a pointer-linked config blob (a DAL “config-DB” structure, not a flattened DTB — no d00dfeed magic) whose node namespace is TZ’s view of the hardware:

Node

Role

/ac/{heap,smmu,xpu}

access-control: secure heap, SMMU, and XPU (memory-protection) config

/dev/{i2c,spi}, /dev/buses/qupac, /core/hwengines/gpi

bus/DMA devices TZ owns (QUP access-control, GPI DMA engine)

/tlmm/configs

the TLMM pin configurations TZ reserves

/tz/{oem,pmic}

OEM TZ knobs and PMIC access

/dev/hyp_config_oem

OEM hypervisor config handed to HYP

/dev/DDRSSErrorOEM, /dev/NOCErrorOEM

DDR-subsystem and NoC error-reporting policy

It also carries the secure-storage path ACL (/data/vendor/tzstorage/, /mnt/vendor/persist/data/, /data/misc/qsee/) and references trustlet app IDs it gates (qcom.tz.hdcp2p2, qcom.tz.tpm). devcfg is not read-only in the GPT (Partition map and checksums) — it is an updatable per-board config.

6.1.5. QSEE trustlets

The trustlets are ELF ``DYN`` (position-independent) objects that TZ loads into the secure EL1 app space on demand, each authenticated by its own MBN hash+signature (test key). They are addressed by name (qcom.tz.<app>):

Trustlet

ISA

Code size

App ID

Purpose (from strings)

keymaster_a

AArch64

0x3584f

qcom.tz.keymaster

Keymaster/KeyMint — key attestation (ATTESTATION_APPLICATION_ID), consumed by ABL’s AVB path (AVB enforcement code path (LoadImageAndAuth / libavb))

uefisecapp_a

ARM32

0x10173

qcom.tz.uefisecapp

UEFI’s secure-service peer (secure storage / RPMB / fuse access during boot); descriptor p=8:c47728cf3e4089,61,82:6004,b4

featenabler_a

AArch64

0x9a15

qcom.tz.featenabler

SoC feature-enable (fuse-gated capability enablement)

mdtpsecapp_a

blank

qcom.tz.mdtp

Mobile Device Theft Protection — partition all-zero here (not provisioned)

The keymaster PH3 carries the 0x04000006 “pointer/relocation” segment flag characteristic of a QSEE DYN app. uefisecapp being 32-bit while keymaster/featenabler are 64-bit reflects Qualcomm’s mixed QSEE ABI — the UEFI-era app predates the 64-bit trustlet ABI. mssecapp (modem secure app, brokered by HYP above) has no standalone partition — it is bundled with the modem (ADSP and CDSP firmware).

6.1.5.1. Keymaster/KeyMint trustlet — command interface

The keymaster_a app (descriptor n=keymaster64;o=100;p=8:…, HAL keymaster@4.1-service-qti) is the device’s root key store and attestation authority. Its command dispatcher and internals are recovered from the app’s string table (code segment file offset 0x3000, filesz 0x3584f); the full extraction is in artifacts/re_static/item2_keymaster_interface.txt.

  • Command set. A legacy Keymaster-4 command enum (29 ids: GENERATE_KEY / GET_KEY_CHARACTERISTICS / IMPORT_KEY / EXPORT_KEY / DELETE_KEY / DELETE_ALL_KEYS / BEGIN / UPDATE / FINISH / ATTEST / GET_VERSION / SET_ROT / IMPORT_WRAPPED_KEY / GET_HMAC_SHARING_PARAMS / COMPUTE_SHARING_HMAC / PROVISION_DEVICE_IDS …) and a newer KeyMint KM_NEW_* enum (61 ids) that adds KM_NEW_CONFIGURE / KM_NEW_VERIFY_AUTHORIZATION / KM_NEW_SET_EARLY_BOOT_ENDED / KM_NEW_GET_PRE_SHARED_SECRET and a parallel StrongBox …_SB_* sub-family (SB_GENERATE_KEY / SB_WRAP / SB_UNWRAP / SB_ATTEST_ENCRYPTED …). So one TA services both the KM4 HAL and the KeyMint path.

  • Gatekeeper is integrated here, not a separate trustlet: gk_generate_user_key / gk_wrap_key / gk_unwrap_key / gk_update_km_auth_list / gk_storage_init / open_add_km_partition. (The Android side still exposes a separate gatekeeper@1.0-service-qti HAL, but it is backed by this TA.)

  • Crypto suite: AES, 3DES, HMAC, RSA and ECC, each with the *_generate/_begin/_update/_finish/_import/_export verb set, implemented over the QSEE qsee_SW_* / qsee_rsa_* syscall primitives.

  • Attestation: the TA references the paths /persist/data/rsa_attest_key and /persist/data/ecc_attest_key, but on this unit no such plaintext files exist in the persist backup — /persist/data/ instead holds QSEE secure-storage (SFS) blob directories (obfuscated base64url names, live + .bak pairs), so any provisioned attestation key is inside encrypted secure storage, not on disk in the clear (Partition map and checksums). Provisioning tooling ships in /vendor (bin/KmInstallKeybox, bin/StoreKeybox, libkeymasterprovision.so). Device-ID attestation covers ATTESTATION_ID_{BRAND,DEVICE,PRODUCT,SERIAL,IMEI,MEID,MANUFACTURER,MODEL}; X.509 leaf certs are built in-TA (write_attestation_cert / sign_rsa_tbscert). Android Identity Credential keys are supported.

  • Root of trust & HW binding. SET_ROT / km_set_boot_state / km_set_vbh receive the verified-boot state from ABL (AVB enforcement code path (LoadImageAndAuth / libavb)); KM_ERROR_ROOT_OF_TRUST_ALREADY_SET enforces write-once. Working keys are derived from a SHK (Secure Hardware Key) with per-purpose context strings (KM/GK/UNIQUEID/DEVICEID/FILENAME/ICE “HW Crypto key derived from SHK”). The ICE context and SET_ICE_KEY / KM_TAG_FBE_ICE tie the TA to the inline-crypto FBE path (Security and DRM userspace). Key-blob rollback protection uses RPMB.

6.1.5.2. Keymaster/uefisecapp: function-level disassembly

The command-interface RE above (item2_keymaster_interface.txt) stopped at the string/command-enum level. This section goes one level deeper — actual instruction-level disassembly of keymaster_a.bin (AArch64) and uefisecapp_a.bin (ARM32/Thumb-2), looking for the real crypto primitives, the QSEE command-buffer marshalling, and the top-level SMC/command dispatch shape, the same way The EL3 “Sec” monitor and the EL1 hand-off pins XBL’s SMC dispatch table. Full raw disassembly and methodology: artifacts/re_static/item_tz_trustlet_funcs.txt.

Both images turn out to have a full dynamic symbol table (DT_SYMTAB/ DT_STRTAB/DT_HASH via PT_DYNAMIC) despite e_shnum == 0 (no section headers) — unlike the kernel Image, which has no kallsyms table at all and had to be symbolized by string/xref heuristics instead (E-ink driver internals (register-level, from the kernel)), these QSEE apps are not fully stripped once you walk the hash chain by hand (no pyelftools/lief/ readelf equivalent ships in this toolchain, so a small DT_HASH walker was used). That recovers, for each file, every imported syscall/library call by name and every locally-defined function.

keymaster_a.bin exports exactly one local function beyond its GP-TA metadata blob — CElfFile_invoke (file vaddr 0x2bd28, 0x314 bytes) — and imports 69 functions from libcmnlib.so (DT_NEEDED): the entire qsee_SW_Cipher*/qsee_SW_Hash*/qsee_SW_Hmac*/ qsee_SW_GENERIC_ECC*/qsee_rsa_* crypto surface, plus GPAppLib_{init,appInit,appShutdown,handleRequest} and CApp_openSession — i.e. the entire GP-TA runtime and command router is an external dependency, not code in this file. libcmnlib.so is not a separate partition on this device (no lun0-5 file named *cmnlib*) but its strings (cmnlib, cmnlib64, cmnlib_init, cmnlib_release) are present, statically embedded, inside tz_a.bin — so Keymaster’s actual per-command switch and its crypto implementation both live inside the resident TZ image, not in the trustlet partition.

CElfFile_invoke disassembles as the standard Qualcomm QSEE GP-TA registration shim, not a command dispatcher: gated on an internal cmd == 0x1200 loader convention (unrelated to the KM4/KeyMint command IDs), it zero-fills a 0xd8-byte “TA properties” struct from linker-provided ta_* symbols (heap/stack address+size, app name, description, storage-file limits, crypto-self-test flag), then calls cmnlib_initGPAppLib_appInit → (an empty, dead init_array walk — no C++ statics on this build) → GPAppLib_init, logging any failure via qsee_log at every step. The same shim, structurally identical (same {0,0xfffe,0xffff}/ cmd==0x1200 gate, same memset-then-cmnlib_init flow), is uefisecapp’s CElfFile_invoke (0xc640, 0x288 bytes, with a smaller 0x68-byte properties struct) — confirming it’s a shared per-TA-recompiled loader convention, not bespoke code.

An automated census (every br/blr/indexed-load instruction across all 48,304 decoded instructions in keymaster_a.bin’s 0x3584f-byte code segment) rules out a monolithic KM4/KeyMint command switch living in this file at all: the largest jump table anywhere in the binary has 24 cases (part of an unrelated internal QSEE-status-code-to-string helper at 0xd84c, used by the qsee_log assertion call sites), there are only 41 blr (indirect call) instructions total, and only 4 pointer-table-indexed loads (one being the dead init_array walk above). The real per-command KM4/KM_NEW_*/SB_* router is GPAppLib_handleRequest, which lives in cmnlib inside tz_a.bin — that dispatch table was not decoded here; decoding it is a larger reverse-engineering task against the 4 MB TZ image.

Crypto primitives — not found to be implemented in either trustlet. Per the task of looking for recognizable constants: a byte-exact scan for the AES forward S-box and the SHA-256 round-constant table finds neither in keymaster_a.bin nor uefisecapp_a.bin — but finds both, byte-exact, plus the SHA-1 initial-hash constant, inside tz_a.bin. Every qsee_SW_Cipher*/qsee_SW_Hash*/qsee_rsa_* call in both trustlets is a real external call into that TZ-resident crypto core; a custom secure monitor replicating this device’s Keymaster crypto surface would need to reimplement (or re-host) code from tz_a.bin, not from either app image.

uefisecapp_a.bin is a different story: 306 dynamic symbols, ~200 locally defined — it statically links its own UEFI authenticated-variable service, X.509 parser, PKCS7 verifier, and a bignum/RSA library (only the actual modular-exponentiation primitive, _secmath_BIGINT_modexp, is imported from cmnlib — everything else, pbl_BIGINT_{Add,Subtract, Multiply,Divide,Square,ModMult,ModExp,...}, is local code, unlike keymaster’s zero local crypto). This directly answers the “what does uefisecapp back” question: TzGetVariable/TzSetVariable/ TzGetNextVariableName/TzQueryVariableInfo/TzDelSecBootVar/ TzSyncVarTables/TzVariableInitialize plus a full TzVariablePolicy{Initialize,Register,Lock,Check,Disable,Dump,IsEnabled, ExitBootServices,IsPrivAuthVarProtectionDisabled,IsSecureBootDisabled} family, backing the PK/KEK/db/dbx UEFI Secure Boot variable store (VariableName{PK,KEK,DB,DBX,SecureBoot,SetupMode}, SetupModeEnabled/SecureBootEnabled) — this is the fastboot-lock/AVB/ UEFI-secure-variable backing service on this device. It also carries gen_key_for_rpmb/ register_pkkey/register_kekkeys for RPMB-backed key material.

Unlike keymaster, uefisecapp’s top-level command dispatcher lives inside the TA itself and was fully located: ``svc_uefi_var_entry`` (file vaddr 0x588 — dynsym value 0x589 with the Thumb bit set, 0x838 bytes, the largest structural find in this file). Its dispatch core:

0x5d8  ldr.w   r0, [sb]              ; r0 = caller's UEFI command ID
0x5dc  sub.w   r0, r0, #0x8000       ; command space is 0x8000-based
0x5e0  cmp     r0, #0x18
0x5e2  bhi.w   #0xc90                ; out of range -> shared "other" block
0x5e6  tbh     [pc, r0, lsl #1]      ; Thumb-2 table-branch-halfword,
                                     ; 25 cases (cmd 0x8000-0x8018)

Decoding the halfword table directly from the file bytes and resolving every case body’s bl target against the recovered dynamic-symbol table gives a concrete command-ID → implementation map — an SMC/QSEE dispatch loop shaped like XBL’s, but one level up the secure-world stack and keyed by UEFI-variable-service command rather than XBL SiP function ID:

Command

Resolved handler

0x8000

TzGetVariable

0x8001

TzSetVariable (0xbe8 bytes — the largest function in the file)

0x8003

TzQueryVariableInfo

0x800a

TzVariablePolicyExitBootServices

0x800b

TzSyncVarTables

0x800c

DumpLogBuffer (a debug/diagnostic command, not a variable op)

0x8017

TzVariablePolicyLock

0x8004,5,7,8,9 / 0x800f-0x8013

converge on a shared block (0xc90) that re-switches internally to TzVariablePolicy{Disable,IsEnabled,Initialize,Register,Dump}, TzVariableInitialize, TzGetNextVariableName

The remaining slots (0x8002, 0x8006, 0x800d, 0x800e, 0x8014, 0x8016, 0x8018) were confirmed to share the same parameter-validation preamble as every resolved case but their specific Tz* callee was not pinned down — see Honest limits. A sibling function, svc_uefi_auth_entry (0xc484, 0x198 bytes, next to the PKCS7/X.509 verification code), is inferred — based on its name and location — to be the authenticated-variable-update (EFI_VARIABLE_AUTHENTICATION_2 / db-dbx signed-update) entry point; this is unconfirmed, as it was not disassembled.

6.1.5.2.1. Honest limits

  • keymaster_a.bin: only its single exported function (CElfFile_invoke) was function-by-function disassembled; the ~35 KB of code implementing the actual per-command KM4/KeyMint crypto/key-management logic has no local symbols to anchor on (this file exports exactly one) and was not walked instruction-by-instruction — the jump-table/indirect-call census (which rules out a dispatcher living here) stands in for full coverage, not full coverage itself. ~20 runs of consecutive function pointers were found in .data via relocation analysis (plausible C++ vtables) but not decoded.

  • uefisecapp_a.bin: 7 of 25 top-level svc_uefi_var_entry command slots are resolved directly, 7 more one level down through the shared 0xc90 block (14/25 effectively identified); the rest were traced structurally but not resolved to a named callee, and svc_uefi_auth_entry was located and sized but not disassembled at all. Neither TA’s RPMB key-derivation call target (inside gen_key_for_rpmb) was resolved to a name.

  • No live-device tracing anywhere — purely static, cross-checked instruction-by-instruction against each file’s own recovered dynamic-symbol and relocation tables, plus a byte-exact constant scan against tz_a.bin.

Source:

artifacts/re_static/item_tz_trustlet_funcs.txt (full disassembly + methodology); _READONLY/lun4/{keymaster,uefisecapp,tz}_a.bin.

Method:

artifacts/re_static/mbn.py/elfdis.py for ELF layout and per-function Capstone disassembly (AArch64 for keymaster, Thumb-2 for uefisecapp — called per-region, not as one linear pass, which desyncs on Thumb: an odd/Thumb-bit-set vaddr passed straight through computes an off-by-one file offset and silently mis-disassembles, the same class of trap as the kernel funcmap nearest-symbol mis-snap); a hand-rolled DT_HASH/DT_SYMTAB/DT_JMPREL/DT_RELA walker for dynamic-symbol and PLT/GOT/relocation recovery in the absence of pyelftools/lief/readelf; a Capstone-based jump-table/indirect-call census script (ad hoc) for the keymaster negative result; a plain byte-exact scan for the AES-sbox/SHA-K constants.

Cross-refs:

The EL3 “Sec” monitor and the EL1 hand-off (the SMC-dispatch-table structural analogy), AVB enforcement code path (LoadImageAndAuth / libavb) (AVB/fastboot-lock consumer of uefisecapp’s UEFI-variable service).

6.1.6. Coprocessors — AOP and QUP

Two service processors are loaded early and outlive the OS boot:

AOP — aop_a (Always-On Processor, Cortex-M)

32-bit ARM ELF, Thumb entry. The AOP is the always-on micro-controller that runs RPMh / resource-state and low-power coordination for the SoC. Version AOP.HO.2.0-00069. Full internals — addresses, the Cortex-M vector table, the RPMh ARC rails, the Cx-retention FSM, the DDR manager and the QMP/message-RAM channel — are in AOP — the Always-On Processor (RPMh / power back-end).

QUP — qupfw_a (QUPv3 serial-engine firmware, Hexagon)

Hexagon QDSP6 ELF (e_machine = 164), 81 KB, nine paged code segments (segment flag 0x08000007) loading from 0x1000. This is the microcode the GENI/QUPv3 serial engines execute to implement I²C/SPI/UART protocols — the firmware side of the GENI hardware documented in QUP/GENI serial-engine bus map (what is wired where). The GENI engines are inert until XBL loads this image, so any bare-metal payload that wants QUP-backed I²C/SPI/UART inherits (or must re-load) it.

Source:

_READONLY/lun4/{tz_a,hyp_a,devcfg_a,keymaster_a,uefisecapp_a, featenabler_a,mdtpsecapp_a,aop_a,qupfw_a}.bin — ELF program headers (mbn_dump.py), Capstone disassembly of the tz_a (0x14680000) and hyp_a (0x8004a000) entries (eldis.py), and image strings for versions / app IDs / cert chain.

Cross-refs:

Boot chain and exception-level hand-off (PBL → XBL → ABL), The EL3 “Sec” monitor and the EL1 hand-off, AOP — the Always-On Processor (RPMh / power back-end), Partition map and checksums, Onyx Boox Note Air5 C (Qualcomm SM6350), ADSP and CDSP firmware, Below UEFI — execution state and hardware register surface, Base kernel device tree (the SoC boot contract), Secure boot and image signing, AVB enforcement code path (LoadImageAndAuth / libavb).