13. Open questions and limits of analysis¶
Scope of this page is the boot chain and hardware below Android userspace. It records which questions the static, single-dump analysis cannot answer, why, and what access would resolve each. Every partition below Android userspace has been opened or accounted for; the remaining unknowns are values that exist only at runtime or in silicon, not in any partition.
Each hardware-silicon question below has been driven to its exact static limit: everything the images do contain (register maps, code paths, config bytes, the precise structural reason a value is absent) has been extracted, so the residual is only the physical read itself. One item (OQ5, the PON reset-type enum) turned out to be fully determined by architecture and is no longer live-gated. The per-item static end, exact residual and read procedure are in Static end of the hardware-silicon ropes.
13.1. Open questions¶
# |
Question |
Status |
Resolution path |
|---|---|---|---|
1 |
Exact VolDown EFI scancode |
Inferred |
Observe the key event on a live device (non-critical). |
2 |
XBL SBL1 |
Getter→branch edge is in a runtime-populated GOT with no static resolution (0 of 1643 ADRPs reach the relevant string pages). An EDL peek of the GOT slot on 2026-09-19 was inconclusive/likely negative (EDL runs a different PBL branch than XBL→ABL, so a normal-boot GOT value isn’t expected to survive into it). Full detail: OQ2 under Static end of the hardware-silicon ropes. |
A live memory read during a normal (non-EDL) boot — e.g. a JTAG/debug halt after XBL relocation but before ABL hand-off — not an EDL peek, which runs a different PBL branch entirely. |
3 |
D+→GND electrical outcome |
Whether a hard D+→GND short yields |
Bench cable + serial/EDL observation. |
4 |
PMIC S1 reset-timer OTP default (the ~8 s) |
Narrowed to the S1 timer alone: XBL writes reset type/enable and the RESIN S2 timer, but leaves both S1 timers and the KPDPWR S2 timer at PMIC OTP default. Full detail: OQ4 under Static end of the hardware-silicon ropes. |
PMIC OTP read (SPMI) or UART. |
5 |
PON S2 reset-type field |
Resolved (deterministic). The QPNP 4-bit S2 reset-type field admits
only |
None — architecturally fixed. |
6 |
Secure-boot fuse state ( |
|
Done via Sahara |
8 |
XBL→ABL boot latency (behind the “~8 s” recovery hold) |
Live-read, 2026-09-19 (EDL peek). |
Further live reads to map field order to name (e.g. correlate against
|
11 |
Matching Android-11 ABL source tag |
Advanced by RE. The ABL binary self-identifies its build tree: 41
embedded Jenkins paths, all rooted at
|
Onyx/CAF publishing the |
Rows 7 (Firehose programmer availability), 9 (“modem” MPSS = ADSP, not cellular)
and 10 (userdata out of scope) were resolved and have been retired from this
table; their findings live in Firehose fuse read and secure-boot confirmation, ADSP and CDSP firmware
and Partition map and checksums respectively. Surviving row numbers are left
unchanged so existing OQ2/OQ4/OQ6/OQ8/OQ11 cross-references
stay valid.
The runtime-log route is closed: rawdump.bin and logdump.bin are 100%
zero and logfs.bin is an empty FAT12 volume (MSDOS5.0 / LOGFS, no
logs), so no captured boot log exists to recover runtime values.
13.2. Resolved by targeted reverse-engineering¶
These items concern what a minimal ABL replacement still needs to know. Each
was closed statically from the dump in ../_READONLY/ — no live device
required.
XBL→ABL app-dispatch mechanism and the LinuxLoader FFS identity. Resolved by parsing
abl_a.bin(not XBLCore): the inner DXE FV holds oneEFI_FV_FILETYPE_APPLICATIONfile, GUIDf536d559-459f-48fa-8bbc-43b554ecae8d, with anEFI_SECTION_USER_INTERFACEname “LinuxLoader”. BDS dispatches by that UI name (the config token is the string"LinuxLoader", not a GUID). A replacement must be an application FFS whose UI section readsLinuxLoaderin the ABOOT FV; the file GUID need not match. See XBL → ABL hand-off contract (bounded) Q1.No nested / EL3-enforced sub-image in the ABL path.
abl_a.binis a single ELF/MBN: one hash-table segment (PT_NULL,0x94bytes) plus the UEFI FVPT_LOADat0x9fa00000; only one ELF magic in the partition, and no embedded EL3 monitor / vector table /smc-container (the soleQSEEstring is a Keymaster call reference, not a payload). The nested-EL3 signature wrinkle proven for the Firehose programmer container does not apply to XBL→ABL: EL3 here istz_a, signed and loaded separately by PBL. So a rehashed, test-key-signed replacement faces only XBL’s integrity/hash gate (unfused, bypassable — Secure boot and image signing).GPT partition-type GUIDs. Extracted directly from
gpt_main{0..5}.binfor all 6 LUNs (type GUID, unique GUID, and disk GUID per partition). The full table belongs in Partition map and checksums; notable is that every_bslot shares one placeholder type GUID77036cd4-03d5-42bb-8ed1-37e5a88baa34while each_aslot carries a distinct type GUID. Name-based lookup (as stock ABL does) needs none of this; it is here for a GUID-based replacement.Console UART pinout. The active console is the DTB node
qcom,qup_uart@98c000—compatible = "qcom,msm-geni-console",status = "ok", QUPv3 SE9,reg = <0x98c000 0x4000>, GIC SPI0x164. Its pin groupqupv3_se9_2uartmuxes GPIO25 = TX, GPIO26 = RX (TLMM functionqup13_f2, 2 mA, 2-wire, no CTS/RTS), 115200 8N1 (console=ttyMSM0). The live/chosen/bootargssetsearlycon=msm_geni_serial,0x98c000to match. Note theboot_aimage header carries a staleearlycon=…,0x888000— but0x888000is SE2, wired asi2c@888000/spi@888000on this board, and the second console-compatible node@984000(SE8) isstatus = "disabled"; the DTB/chosenoverrides the stale value at runtime, so0x98c000is the real port. XBL containsboot_logger_uart.cand aUARTLogBufferSizelog buffer, so probing GPIO25/26 is the concrete channel to capture live XBL/ABL boot output — the resolution path behind OQ8 (boot latency) and a live-observation route for OQ2/OQ4/OQ5. Physical test-point location on the PCB is still unverified (requires opening the device).
13.3. Low-level components examined¶
All components carrying a signing chain are test-key-signed
(General Use Test Key (for testing only)), consistent with
Secure boot and image signing.
- TZ (
tz_a,TZ.XF.5.10-00304-1) QSEE. Config-item names
/secboot/anti_rollback,allow_erase_in_secure_mode,oem_image_encryption_key1_sel/oem_image_encryption_key1(selectors/names, not key material — keys are fused/runtime). Carries the QSEE attestation keybox (QSEE Attestation Root CA 4 SubCA 1). No plaintext keys or secure-boot fuse value.- HYP (
hyp_a,TZ.XF.5.10-00304-1, OEM=CRM) Qualcomm hypervisor; camera stream/PHY secure protection (
CameraSS_DynamicPHYProtect), XPU region unlock plumbing. Does not change the boot-chain findings.- AOP (
aop_a,AOP.HO.2.0-00069) Always-On Processor; build-dated 2024-10-28 (UUID
Q_SENTINEL_{…}_20241028_1806).JTAG_ON/JTAG_OFFpower-collapse gating of JTAG, IPCC. Power/sleep RSC firmware; no boot-mode or security state of interest.- modem (
modem_a,ADSP.VT.5.6-00702.1-BITRA-1, variantbitra.adsp.prodQ) A multi-subsystem NON-HLOS bundle (ADSP + CDSP + MPSS + NPU), not an ADSP-only image: the ADSP sub-image runs sensors/audio, and real MPSS baseband code is present but dormant (no cellular RF front end). The XML block it carries is ePDG / VoWiFi PDN-throttling config, not thermal. Full breakdown in ADSP and CDSP firmware.
- DSP (
dsp_a,CDSP.VT.2.6-00570.1-BITRA-1, built 2024-02-07,bitra.cdsp.prodQ) Compute DSP (Hexagon, C++), SecurePD example. No boot-relevant config.
- devcfg (
devcfg_a) SoC security/memory config: XPU access control (
/ac/xpu,disable_xpu_ac), camera boot protection (enable_cam_phys_boot_protection,boot_protected_cam_phys),/dev/hyp_config_oem, NoC config, and a Widevine OEMCrypto TZ path (tzdrm/widevine_oemcrypto) implying Widevine L1 DRM via TrustZone. Config, not state.- featenabler (
featenabler_a) The feature-license TZ app (
feature license app init, cmnlib) — enables SoC features via signed licenses. Test-key chain.- uefivarstore
Standard UEFI Secure Boot variables (
KEK,SetupMode,SecureBoot,dbx) plus counters (BSPowerCycles≈ 1,RunCycles), indicating a near-factory state. This is UEFI-level Secure Boot, orthogonal to the Qualcomm QFPROM root of trust; it contains no AVB device-state/unlock/verifiedbootstate (those live indevinfo/vbmeta).- Blank / empty (verified)
rawdump(0%),logdump(0%),logfs(empty FAT12),misc/BCB (empty, no pending boot command),apdp(0% — no debug policy stored),secdata(0%),keystore(0%),cdt(0%).mdtp_ahas no readable strings (opaque anti-theft image).- ext4 data partitions
persist(sensor calibration / per-device data, incl. the IMU factory calibration and QSEE secure-storage blobs),metadata(FBE metadata-encryption keystore) andonyxconfig(Onyx device-config fs, incl. the factory production-test record) were all extracted and are documented in Partition map and checksums and The Onyx/Boox platform layer.superwas likewise extracted down to its four logical partitions (vendor_a/system_a/product_a/system_ext_a) and is the source for the entire Android userspace (bridge to the firmware) tree. Onlyuserdataremains untouched — it is not present in this dump at all (a factory/EDL backup does not carry user data).
13.4. Boot-chain firmware versions¶
Full version inventory (XBL/AOP/TZ/HYP/modem, build provenance) is in Onyx Boox Note Air5 C (Qualcomm SM6350); ADSP/CDSP versions and their catalog of capabilities are in ADSP and CDSP firmware; kernel version is in Boot image: kernel, DTB, ramdisk, config.
13.5. Static end of the hardware-silicon ropes¶
For each hardware-silicon question, the point where static analysis of the dump provably stops — the mechanism recovered, and the single value that can only come from silicon or a live read.
13.5.1. OQ6 — secure-boot / QFPROM fuses¶
Recovered statically. The QFPROM window is 0x780000/0x7000 (DTB
qcom,qfprom, read-only). Linux is given only three binning fuse rows —
gpu_speed_bin@6015 (8 bits), feat_conf8@6024 (4 bytes),
gpu_gaming_bin@6026 (bit 5) — plus the USB-PHY trim row 0x780268 (3 bits at
pos 0x19, via the qusb@88e3000 efuse_addr). The security corner is not
mapped to the kernel at all. XBL’s config plane asserts SecurityFlag = 0xC4
(LoadKeymaster|LoadSecApp|CommonMbnLoad; SecBootEnableFlag bit clear —
Platform config (uefiplat.cfg)). ABL’s runtime read path is
ReadSecurityState → SCM ScmSipSysCall → is_secure → prints
SECURE BOOT - <state> / DEVICE STATE - <state>; GetFuse/SetFuse are
SCM protocols; KeyMasterSetRotAndBootState writes TZ_HLOS_IMG_TAMPER_FUSE /
TZ_HLOS_TAMPER_NOTIFY_FUSE. Anti-rollback is AVB
Read/WriteRollbackIndex per location + TZ_UPDATE_ROLLBACK_VERSION_ID,
stored in DeviceInfo / devinfo.bin — all-zero here (factory).
Residual (silicon): the fuse bits themselves — SEC_BOOT enable and
OEM_PK_HASH. Read by: runtime ReadSecurityState or Sahara CMD_EXEC
(OEM_PK_HASH already read non-zero, EDL / Firehose interface); a raw QFPROM
peek at 0x780000 faults (XPU-protected) — reconfirmed live, 2026-09-19,
with a second independent peek-capable loader (USBError(5), identical to the
original finding).
Live-read, 2026-09-19 (``adb shell getprop``, no root). ro.boot.flash.locked
= 1, ro.boot.verifiedbootstate = green, ro.boot.veritymode =
enforcing. This isn’t the raw QFPROM bit, but it answers the practical
question these properties exist for: AVB (software verified boot, via ABL’s
bundled libavb) actively checks vbmeta against a real key and passes
(green, not orange/unverified) on the stock image, and dm-verity is
enforcing on /system. Consistent with — and independent confirmation
of — the ABL device_info.is_unlocked = 0 finding
(AVB enforcement code path (LoadImageAndAuth / libavb)) and the frp OEM-unlock byte reading 0
(Security and DRM userspace): three independently-read signals now agree the
unit is locked at the software/AVB layer, even though the QFPROM SEC_BOOT
fuse itself (the hardware root of trust) is not blown. Prediction for a
hypothetical replacement bootloader, not something actually tested here:
AVB would reject a resigned/modified boot/system under the stock
ABL+vbmeta chain, but since ABL itself is unfused and integrity-only
(Secure boot and image signing), replacing ABL should remove the AVB check
entirely rather than requiring it to be defeated — this follows logically
from the above findings but has not been verified by actually building and
booting a replacement ABL.
13.5.2. OQ4 — PMIC S1 reset-timer default (the ~8 s)¶
Recovered statically. Byte-read of the xbl_config PON table
(PMIC reset timers, charging and reachability): XBL writes 0x842=0x08/0x843=0x80 (KPDPWR S2
type+enable), 0x84A=0x08/0x84B=0x80 (RESIN S2 type+enable),
0x849=0x06 (RESIN S2 timer), 0x85A=0x08 (PS_HOLD), 0x862/0x863 (gen2
S3). It does not write the S1 timers (0x840, 0x848) or the KPDPWR S2
timer (0x841) — those keep the PMIC OTP default. Master PON is
PM6350@USID0 (PMIC reset timers, charging and reachability).
Residual (silicon): the S1-timer OTP magnitude that sets the ~8 s hold-to-reset ceiling. Read by: PMIC OTP/PBS read over SPMI, or timing a live hold.
13.5.3. OQ5 — PON reset-type 0x08 enum¶
Fully determined — no residual. The 4-bit QPNP S2 reset-type field admits only
1=WARM_RESET, 4=SHUTDOWN, 5=DVDD_SHUTDOWN, 7=HARD_RESET, 8=DVDD_HARD_RESET, so
0x08 is DVDD_HARD_RESET. The binary simply carries no ASCII enum string.
13.5.4. OQ8 — XBL→ABL boot latency¶
Recovered statically. Shared IMEM base 0x146aa000 (DTB + uefiplat
SharedIMEMBaseAddr); boot_stats at @6b0 → ``0x146aa6b0`` (32 B).
XBL logs nine named KPI timestamps — pbl_apps_init_timestamp,
bootable_media_detect_timestamp, bl_elf_metadata_loading_timestamp,
bl_hash_seg_auth_timestamp, bl_elf_loadable_segment_loading_timestamp,
bl_elf_segs_hash_verify_timestamp, bl_sec_hash_seg_auth_timestamp,
bl_sec_segs_hash_verify_timestamp and
pbl_populate_shared_data_and_exit_timestamp — through
boot_logger_{ram,timer,uart}.c; ABL adds Load Image %a total time: %lu ms.
Live-read, 2026-09-19 (EDL peek). Two independent 32/40-byte reads at
0x146aa6b0 (across two separate adb reboot edl cycles) each show the
same pattern: 5 of 8-9 u32 slots hold small, plausible tick values that
differ slightly between the two reads (e.g. 0x00024fcb``→``0x00024f6a,
0x0002f8fa``→``0x0002f8a4), consistent with a genuine live per-boot
counter rather than static/cached data. The remaining slots are high-entropy,
and one decoded to the literal pattern ``0xdead4ead`` — a poison/debug
marker — confirming those fields are simply never written on the EDL boot
path (XBL diverts to Sahara/9008 before reaching whatever KPI stage(s)
populate them), not a bad read. This closes “is the struct live and
readable” definitively; it does not close “which offset is which named
timestamp” (the 9 names are known from strings, their field order isn’t).
Residual (runtime, narrowed): the offset→name mapping, and the timestamps
for a normal (non-EDL) boot specifically, since EDL only exercises a subset
of the KPI stages. Read by: a SE9-UART capture during a normal boot
(GPIO25 TX / GPIO26 RX, 0x98c000 — Resolved by targeted reverse-engineering), which would give
both the values and, via the printed KPI names, the offset order.
13.5.5. OQ2 — XBL SBL1 fedl / blue-LED branch¶
Recovered statically. ELF has 16 program headers; the charger getter’s GOT slot
0x148b81f0 lies in PT_LOAD segment 5 (vaddr 0x1487c000,
memsz 0x3d000, filesz 0 — a .bss zero-filled at load, populated by the
loader). The getter 0x80735700 and detect loop 0x8074651c are in the
file-backed RX segment (0x80735000``+``0x4eeef). A capstone sweep of the RX
segments finds 0 of 1624 ADRPs (0 ADR, 0 64-bit literals) reaching the
fedl/LED string pages 0x1481d000 / 0x1481f000. Recovered anyway: the
fedl reason set — pmi_not_detected, vbus_det_err, vbus_low,
chgr_type_det_err, chgr_det_timeout — the blue-LED string
not power_key_press, blue led on! (~``0x1481fb13``), and the fully static
dload path (DloadCookieAddr = 0x01FD3000 / value 0x10).
Live peek attempted, 2026-09-19 — inconclusive/likely negative. EDL peek of
0x148b81f0 (8 B) returned 0x1483db2c: not in XBL’s RX code segment
(0x80735000``+) and adjacent to the address band the EDL programmer's own
nested EL3 image occupies (``0x14950000, Firehose fuse read and secure-boot confirmation), so this
value most likely belongs to the current Sahara/Firehose session’s own use of
that physical memory, not a GOT entry surviving from a prior normal boot. EDL
is architecturally a separate PBL branch from XBL→ABL, so this was always a
long shot; it does not change the static-end analysis above.
Residual (runtime): the getter→branch edge through the runtime-populated GOT. Read by: a live memory read of the GOT during a normal boot specifically (e.g. JTAG halt after XBL relocation, before ABL hand-off) — not an EDL peek.
13.5.6. OQ1 — VolDown scancode¶
Recovered statically. Provider is XBL ButtonsDxe: ButtonsInit runs
ConfigureButtonGPIOs() + InitializeKeyMap(), locates PmicPONProtocol
(PmicDxe), and PollButtonKeys() feeds the SimpleTextInputEx ABL reads.
The map is built programmatically, so there is no static scancode literal by
construction; ABL carries no scancode assignment (only a printf uses 0x102).
Residual (runtime, non-critical): the exact byte. Convention + the sole DTB
RESIN→KEY_VOLUMEDOWN fix VolDown at SCAN_DOWN = 0x02
(Physical keys: power, volume, and the boot-mode dispatcher).
13.5.7. OQ3 — D+→GND electrical outcome¶
Recovered statically. USB HS PHY is qusb@88e3000 (qusb2phy-v2), with
eud_enable_reg = 0x88e2000. XBL’s BC1.2 charger classification is fully
readable — SDP/CDP/DCP sources, usb_dp_toggled_for_cdp,
APSD re-run, detect loop 0x8074651c (CDP = two D+ toggles) → on failure
chgr_type_det_err → fedl.
Residual (bench): the analog response of the BC1.2 front-end to an out-of-spec
D+→GND short — whether it presents as chgr_type_det_err. Read by: a bench
cable + serial/EDL observation.
13.6. Requires a live device or bench — summary¶
After the above, exactly these residuals remain, none in any partition. Two (OQ8, OQ2) were live-peeked over EDL on 2026-09-19 with a user-supplied peek-capable loader — see each item’s entry above for what that did and didn’t resolve:
QFPROM security fuses —
SEC_BOOTenable (OQ6); runtimeReadSecurityStateduring a normal boot, or SE9-UART capture of the printed state. (OEM_PK_HASHitself is already read, and the QFPROMpeekfault is now twice-confirmed live — see OQ6 above.)PMIC S1-timer OTP default — the ~8 s ceiling (OQ4); SPMI OTP read (no flat peek address available, and explicitly bus-hang risk) or a timed hold.
``boot_stats`` offset→name mapping, and normal-boot timestamp values (OQ8, narrowed) — the struct is confirmed live and partially populated on the EDL path (2 EDL peeks done); a normal-boot SE9-UART capture is what’s left.
Runtime GOT contents from a *normal* boot specifically (OQ2, narrowed) — an EDL peek was tried and is inconclusive/likely negative (EDL runs a different PBL branch than XBL→ABL); needs a live read during an actual XBL→ABL boot (e.g. JTAG), not EDL.
D+→GND analog outcome — bench cable + serial/EDL (OQ3).
VolDown scancode confirmation — a keypress on a live device (OQ1, non-critical).
(OQ5, the reset-type enum, is architecturally determined and needs no read.)
- Source:
static analysis of the EDL dump in
../_READONLY/; component version tags and partition contents from the dumped images.- Cross-refs:
Secure boot and image signing, Firehose fuse read and secure-boot confirmation, Onyx Boox Note Air5 C (Qualcomm SM6350), PMIC reset timers, charging and reachability, EDL / 9008 entry and the deep-flash cable.