7.8. AOP — the Always-On Processor (RPMh / power back-end)

aop_a is the firmware for the Always-On Processor, a small Cortex-M micro-controller in the SoC’s always-on (AOSS) power island. It is loaded and authenticated by XBL’s PIL very early (before UEFI) and keeps running underneath every later stage — UEFI, ABL, the kernel, and system sleep (the evidence that this makes it load-bearing, and how strongly it supports that conclusion, is under Relevance to a bootloader replacement below).

This page is the AOP-side counterpart to the AP-side interface documented in Base kernel device tree (the SoC boot contract): there, the kernel’s qcom,rpmh-rsc votes for clocks and regulators through TCS command slots and resolves resource names through qcom,cmd-db; here is the processor that services those votes. Everything below is read from _READONLY/lun4/aop_a.bin (program headers, the Cortex-M vector table, a Thumb disassembly of the reset path, and an image-string census); no code was executed.

7.8.1. Identity

  • QC_IMAGE_VERSION_STRING = AOP.HO.2.0-00069

  • IMAGE_VARIANT_STRING = AAAAANAZO

(Version tag also inventoried in Onyx Boox Note Air5 C (Qualcomm SM6350).)

7.8.2. Image structure and Cortex-M evidence

ELF32, e_machine = 40 (EM_ARM), 7 program headers, MBN-wrapped:

PH

Flags

vaddr

filesz

Role

0

0x07000000

114

MBN hash-table segment (per-segment SHA-384)

1

0x02200000

0x8081d000

0x1a60

signature + cert chain (test-key, see Secure boot and image signing)

2

R-X

0x0b000000

0x142f4

code (the AOP program, ~81 KiB)

3

RW-

0x0b0e0000

0x65b8

private data (RAM adjacent to code)

4

RW-

0x80800000

0x8d50

shared DDR message-RAM window

5

RW-

0x80810000

0x10e0

shared DDR message-RAM window

6

RWX

0x80818000

0x4120

shared DDR message-RAM window (executable scratch)

Cortex-M, Thumb. The code segment begins with a Cortex-M vector table:

  • word[0] = initial SP = ``0x000E8000`` (AOP internal SRAM)

  • word[1] = reset vector = ``0x00000009`` → internal address 0x8 with the Thumb bit set.

The ELF e_entry is 0xb000009 — the same reset handler expressed at the PIL-visible load alias: AOP executes from its own 0x0-based address space, and the ELF maps that code to vaddr 0x0b000000 for loading, so e_entry = 0x0b000000 + 0x8 | 1. Disassembling the entry as Thumb yields a textbook two-stage C startup and an init loop:

0x0b000008: ldr  r0, [pc, #4]     ; -> C runtime init
0x0b00000a: blx  r0
0x0b00000c: ldr  r0, [pc, #4]     ; -> main
0x0b00000e: bx   r0
...
0x0b000018: push {r3-r7, lr}      ; init loop: iterate a 5-entry
0x0b000020: cmp  r6, #4           ;   handler table at [r7],
0x0b000022: bls  0x0b000028       ;   calling 0x0b0116ce per entry
0x0b000032: bl   0x0b0116ce

The three 0x808xxxxx RW/RWX segments are not private AOP memory — they sit inside the xbl_aop_mem carve-out the AP publishes in its device tree (0x80700000 size 0x1600000x80860000; Base kernel device tree (the SoC boot contract)), with the RPMh cmd-db region at 0x80860000 immediately above. This is the shared message RAM through which the AP and AOP exchange resource state.

7.8.3. What the AOP manages

The image’s string tables name the resource domains and services the AOP runs. These are the RPMh/AOSS back-end functions:

RPMh ARC voltage/clock resources

Rail and clock domains each exposed with a .lvl (voted level/corner) plus internal .mol / .tmr state. The full set is recovered from the resource-name pool at image offset 0xb011c40: cx (digital core rail), mx (memory rail), mmcx (multimedia Cx), lcx / lmx (the “low” Cx/Mx variants), gfx and gpu (GPU), ebi (DDR I/O rail), ddr, mss (modem), qphy (a PHY rail) and xo (crystal oscillator). When the kernel votes through rpmh-rsc, the AOP arbitrates the aggregate request and drives the PMIC to the resulting corner.

VRM / CPR / ACD regulator sublayer

Below the ARC corners, the strings vrm, vrm_client, vrm_tcs, arc / arc_override, m.cx, vrm.mx, bob (a boost-bypass regulator), limits, acd (Adaptive Clock Distribution) and cpr / cprv1 / cprv2 / cprwa name the VRM (Voltage Regulator Manager) that turns a voted ARC corner into concrete PMIC regulator settings, closed around CPR (Core Power Reduction — the process/temperature-adaptive voltage loop) with an acd clock-stretch companion.

RPMh TCS command sequences

The actual write-command sequences the AOP emits are carried in Trigger Command Set slots: vrm_tcs (to the VRM/PMIC) and pdc_tcs (to the wake-up controller, below). ERR:TCS0 / ERR:TCS1 are the error tokens logged when a sequence on TCS ring 0/1 fails or times out; QMP_TOUT guards the AP↔AOP mailbox. So a vote arrives over QMP / shared RAM, the AOP aggregates it across the ARC resources above, and issues the resulting VRM/PDC TCS sequence to the PMIC. (The per-resource command bytes are runtime- and cmd-db-driven, not a static table in this image — cmd-db lives in the shared RAM region below, populated at boot rather than flashed.)

Cx retention finite-state machine

cx_ret_fsm, cx_ret, cx_mol, CX_RET_XO_PENDING, CX_GT_MOL, CXC_LOCK/CXC_UNLK — the logic that lowers the Cx rail to a retention voltage during deep sleep (keeping SRAM/logic state alive at minimum power) and restores it on wake, gated on XO availability.

DDR manager

DDR_MGR, /pm/ddr, DDR_ON/DDR OFF, DDR ISR, Enab DDR, ddr_freq, ddr_temp, ddr_dep, DDRclnCB, AOP DDR Log — the AOP owns DDR frequency scaling, self-refresh entry/exit, DDR thermal (ddr_temp) and the DDR interrupt handler. This is why DDR training done by XBL stays coherent across sleep: the always-on AOP, not the kernel, manages the DRAM low-power states.

PDC (Power Domain / wake-up controller) programming

pdc_global, pdc_seq, pdc_tcs, PDC_IRQ, PDC_WA, wlan_pdc — the AOP programs the PDC TCS sequences so that wake-up interrupts (and per-subsystem wake lines) are armed while the APSS/GIC is powered down.

Subsystem low-power coordination

adsp, cdsp, modem, slpi, ipa_pc (IPA power-collapse), wlan_pdc, MMNOC_ON/MMNoCOFF/MMNOC_TO (multimedia NoC gating) — the AOP coordinates the sleep/collapse of the DSP/modem/WLAN/IPA subsystems and the on-chip interconnect around a system-wide low-power point.

AOSS sleep solver + PMIC path

/sleep/aoss, AOSS, aoss_slp (the sleep-set solver) and PMIC CB / PMICRqCB / pmic (PMIC request callbacks) — the AOP runs the AOSS sleep sequence and issues the resulting PMIC requests.

7.8.4. Communication with the AP

Two channels, both matching the device tree:

  • QMP mailboxQMP_TOUT (Qualcomm Messaging Protocol timeout) and the /sleep/aoss service back the DTB qcom,aop-qmp-clk node: the AP sends clock/sleep messages to the AOP over QMP.

  • Shared message RAM — the 0x808xxxxx windows above, plus the cmd-db database at 0x80860000 that the AOP populates and the AP reads to resolve RPMh resource names to addresses (Base kernel device tree (the SoC boot contract)).

7.8.5. Relevance to a bootloader replacement

The AOP is brought up and authenticated by XBL’s PIL like every other coprocessor image; its signature/cert segment chains to the same test key as the rest of the boot chain (Secure boot and image signing), so it is not a special authenticity gate the way XBL Sec is (Boot chain and exception-level hand-off (PBL → XBL → ABL)). Practically, though, the evidence above strongly suggests it is load-bearing: DDR, the core rails and wake-up all appear to depend on a running AOP. Anything that replaces the EL1/UEFI portion of the boot chain inherits an already-running AOP (XBL starts it before UEFI) and, on that evidence, should preserve the RPMh / message-RAM / cmd-db contract rather than re-implement it — the DDR and rail state the payload runs on is apparently the AOP’s, not the payload’s.

7.8.6. Provenance

Source:

_READONLY/lun4/aop_a.bin (read-only).

Method:

mbn_dump.py for the ELF/MBN program headers; a Python read of the Cortex-M vector table (initial SP, reset vector) and a Capstone Thumb disassembly of the reset trampoline at 0x0b000008; strings census for the version tag, RPMh ARC resource names, Cx-retention FSM, DDR-manager, PDC, PMIC and QMP tokens. No code executed.

Cross-refs:

Base kernel device tree (the SoC boot contract) (AP-side rpmh-rsc / cmd-db / QMP), Secure world and coprocessors (TZ, HYP, trustlets) (coprocessor EL/processor map, PIL load), Boot chain and exception-level hand-off (PBL → XBL → ABL) (PIL bring-up order), Secure boot and image signing (test-key signing), Onyx Boox Note Air5 C (Qualcomm SM6350) (version inventory), PMIC reset timers, charging and reachability (the PMIC the AOP drives).