Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/saf/device/evidence/secure_load_tz_frontier.md
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00

259 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PAF · Secure-load / TrustZone frontier
> **🔴 SUPERSEDED 2026-06-29.** Secure-load is **RESOLVED** for the modem — the MSS loads clean
> (MBA boots, MPSS loads, `remoteproc running`, **zero 22 on the modem path**) via DELTA-1
> (`c2923cb49` MPSS assign-ordering). This doc is kept as the **historical 22 / fastrpc_mem
> investigation record**. The 22 that still floods the logs is the **SLPI's** SDSP heap, not the
> modem's — see `slpi.md`. The current frontier is the firmware-internal OFFLINE/52 park, not
> secure-load. (Body below is the 2026-06-26 investigation as-written.)
## 2026-06-26 (OPUS session) — mem-protect SKIP broke the boot on hardware; reverted. LOS does mem-protect differently, not skip it.
**Platform is now clean and reproducible (this part is solid, keep it):**
- ONE canonical branch **`blueline`** (was split across `mobian-sdm845-7.1` + `blueline-slpi-build`,
neither complete — consolidated). It = Mobian `mobian-sdm845-7.1` base (mainline 7.1.1 tag +
full 179-patch sdm845 device series: camera/imx sensors, q6voice, haptics, fuel-gauge, panels)
+ our 6 fixes. Other branches renamed `reference/mobian-7.1.1-base`, `archive/superseded-*`.
- Guard against drift: **`tools/verify-fixes.sh`** (13 checks, asserts SOURCE CONTENT not commit
messages; covers our 6 fixes AND the inherited Mobian migrations). Run before every build.
- Build: `pmbootstrap build --src=references/linux-7.1.1-sdm845-CANONICAL linux-postmarketos-qcom-sdm845`
(host `make` is NOT the path — build.md:7). Deploy: on-device `apk add --allow-untrusted`
`boot-deploy` auto-flashes `boot_a`. `uname -r = 7.1.1-sdm845`. Rollback image:
`build-output/boot_a-rollback-20260626-1605.img.gz`.
- **Found + fixed the silent killer behind every prior "flash and test":** the phone's kernel and
its `/lib/modules` were ABI-mismatched — `qcom_q6v5_mss` gave `Exec format error`, the modem
driver never loaded, so the modem was dead regardless of any fix. Matched build → driver loads,
modem remoteproc `4080000.remoteproc` now registers.
**The mem-protect skip (`need_mem_protection = false` for sdm845) is REFUTED — likely roll back:**
- It removed the `-22` from the modem path as designed — but the modem now fails EARLIER:
`Booting .../mba.mbn → PBL returned unexpected status 0xEF110000 → can't start rproc: -22`.
It never reaches "MBA booted".
- The r2 baseline (below) had the modem boot MBA then XPU-crash-loop at 52. So the skip REGRESSED
the boot. `qcom_scm_assign_mem` (`q6v5_xfer_mem_ownership`, qcom_q6v5_mss.c:463/489) transfers the
MBA region HLOS→MSS_MSA so the modem PBL can read MBA; skipping starves PBL. **The assign is
load-bearing. The real gate is WHY TrustZone returns -22 (EINVAL), not the call's existence.**
**The LOS claim in `HANDOFF_20260626_OPUS.md` was unverified inference — treat as RETRACTED:**
- It blended mainline (`need_mem_protection`) with downstream (`subsys_vmid` / `qcom,mem-protect-id`)
concepts into one story.
- LOS Pixel 3 runs the **downstream msm-google 4.9 kernel**; its modem loader is `subsys-pil-msa`,
NOT mainline `qcom_q6v5_mss.c`. We have NOT pulled that source (Tier 1 still open) — so what LOS
does was never read off real code.
- Hardware contradicts the inference: if LOS did no mem-setup and MBA self-unlocked XPU, the skip
would have worked. It made things worse.
**PRINCIPLE (Casey, 2026-06-26): LineageOS is the ONLY known-working modem reference on this device.
Other sdm845 devices (op6 / enchilada / beryllium / shift) are IRRELEVANT to the secure-load / XPU
question — do not cite them as modem-bringup evidence. The downstream Pixel-3 stack is the authority.**
**Current phone state:** booted on `blueline` 7.1.1 (the skip build). Modem PBL-fails every boot;
SLPI crash-loops ~10s (the `-22` spam every 10s is the SDSP/SLPI hyp-assign, NOT the modem).
**OPTIONS — left for Casey to choose (not picking one):**
1. **Revert the skip** → restore the MBA-boots-then-XPU-52 baseline on the clean 7.1.1 platform,
then work secure-load Tier 0/1 from a known state.
2. **Pull `msm-google` downstream kernel** → diff `subsys-pil-msa` mem-setup + hyp-assign vs
mainline. Answers "what does LOS actually do" with real code (Tier 1).
3. **Downstream-kernel hybrid** (Droidian / Halium pattern) — this doc's honest realistic
12 week path to working telephony.
4. **Chase the TZ `-22` directly** — why does mainline's `qcom_scm_assign_mem` get EINVAL on
blueline (VMID / mem-protect-id / TZ expectation)? Open-ended.
---
## 2026-06-26 — TRIGGER RESOLVED: this doc is the plan. Hard secure-memory evidence captured.
The trigger condition below ("still 52, modem boots then refuses RF → the gate is the
secure-load/TZ layer → this doc is the plan") is now MET, with a concrete error string instead of
inference. On the rebuilt r2 LLVM kernel (slot A, live ssh), `dmesg` shows the modem **crash-looping
on a hardware secure-memory protection fault**:
```
qcom-q6v5-mss 4080000.remoteproc: fatal error: modem_xpu_int.c:456:[modem_sec_xpu_I]XPU violation
(also crash #1: "SFR Init: wdog or kernel error suspected")
```
and EVERY modem + slpi restart logs the shared TZ rejection:
```
qcom_scm firmware:scm: Assign memory protection call failed -22 (qcom_scm_assign_mem → -EINVAL)
SDSP fastrpc hyp-assign rejected by TZ (-22)
```
**XPU = eXtreme Protection Unit**, the hw memory guard TZ programs. `modem_sec_xpu XPU violation` =
the modem firmware touched a region the XPU forbids → its secure memory regions aren't assigned
right for mainline → crash → q6v5 recovers → repeat → never RF-inits → **52**. The fastrpc/SLPI
`assign -22` is the same mechanism (TZ refusing mainline's hyp-assign); fastrpc tolerates it, the
modem can't. **The gate is concretely the secure-memory-assign / XPU region setup — pull the
`assign_mem -22` thread.** (See modem.md TOP LEAD #11, slpi.md.)
CAVEAT (don't overclaim): this XPU crash-loop was captured on **7.1.1 r2**. The 6.16.7 / 7.1rc1
captures recorded the modem "up + QMI registers" (lead #10) — QMI still answers here too, in the
up-windows between crashes, so a single-sample `running` looked fine before. OPEN: re-check whether
6.16.7 *also* XPU-crash-loops (i.e. always-present, just not noticed) or whether 7.1.1 worsened it —
diff `journalctl -p err` across both kernels before assuming XPU is identical on the older tree.
Original status (pre-2026-06-26): **alternative, not primary.** The primary lever was Opus's
reserved-memory geometry fix (`modem_dt_rf_analysis_20260622.md` candidate #1: revert the
`sdm845-google-common.dtsi` override so MPSS = `0x7800000` / MBA = `0x96500000`, matching both
working devices). That swing did not clear the 52; the secure-load/TZ layer (this doc) is now primary.
It is written assuming the reader has `modem.md`, `modem_dt_rf_analysis_20260622.md`,
`tools/modem-online-provisioner/RESULTS.md`, and `android-capture-20260622/EFS_FINDINGS.md` in head.
## Trigger condition (the decision point)
Flash the reserved-memory DT fix to `boot_a`, cold-boot pmOS, one `--dms-set-operating-mode=online`:
- **online works** → geometry was the gate. Stay mainline; push the fix upstream (sdm845-mainline /
pmaports), bisect the `google-common` override. **This doc is not needed.**
- **modem fails to load** (`remoteproc Boot failed`) → the firmware was signed for the old geometry;
the override existed for a reason. Revert; geometry is load-bearing-correct as-is. Come here.
- **still 52 (modem boots clean, refuses RF)** → the gate is **not** the DT geometry. It is in the
secure-load / TrustZone / subsystem-coordination layer. **This doc is the plan.**
## The gate, precisely (today's hard proof — do not re-derive)
Source: `tools/modem-online-provisioner/RESULTS.md` (raw QMI over `AF_QIPCRTR`, 2026-06-22).
- Modem is in **op-mode 3 = OFFLINE** (deepest non-persistent off state). Not LPM, not transient.
- **Accepts** every read, non-RF writes (DMS/NAS indication registration), and **DMS Set Operating
Mode = RESET (0x002E mode 4) → OK**.
- **Refuses every RF-requiring transition**: online → **52 DeviceNotReady**; low_power → **60
InvalidTransition**; NAS Set System Selection Preference (0x0033) → **25 DeviceUnsupported**; DMS
ATEL UI-ready (0x0064) → **58** (arg-rejected, message id confirmed correct).
- After the accepted **RESET**, firmware re-initialises **straight back to OFFLINE** and refuses
again, with **zero** sys-info/serving-system indications in an 8 s listen. The firmware is inert
on RF by decision, not attempting and failing.
**Conclusion (raw-level, not inference):** no AP-side QMI message or ordering unlocks RF. The
choreography-replay path (`qcril_online_sequence.md`) is closed: the modem rejects the pre-online
writes *themselves* before we reach the online flip. QCRIL only succeeds on Android because the
firmware has **already self-completed RF-init** there; on pmOS it never does.
## Why this points at secure-load / TZ (the RESET argument)
A QMI RESET re-initialises the modem firmware **without re-doing the cold-boot setup** — PIL image
auth, the TZ/SCM state, the bootloader (ABL/XBL) modem init, and sibling-subsystem coordination are
all established **once at cold boot** and persist through a QMI reset. The RESET reproducing OFFLINE
tells us the gate lives in that **persistent cold-boot environment**, not in a one-shot race or a
userspace omission. That environment is exactly four things, in suspect order:
1. **DT reserved-memory geometry** — Opus's test (may already settle it).
2. **Sibling subsystem / Protection-Domain coordination** — the modem RF-init can gate on a PD
registered over glink/pd-mapper by ADSP/CDSP/**SLPI**. pmOS DT has **no SLPI region at all**
(absent in the `modem_dt_rf_analysis` table; Android + enchilada both carry `slpi@0x96700000`).
Never confirmed up on pmOS. Mainline-fixable if so — *not* TZ.
3. **PIL / SCM secondary auth** — image auth clearly succeeded (modem boots), but a non-fatal
secondary secure step (a hash-table segment, a secure-regulator vote, a TUST handshake) may not
have completed, leaving the firmware in a degraded RF-locked mode.
4. **Bootloader / verified-boot state** — pmOS boots a hand-built `--header_version 0` image with a
custom cmdline. If ABL sees an unverified/inconsistent chain, it can skip modem secure-env init
that stock Android gets.
## Ranked investigation — cheapest discriminator first
### Tier 0 — free, same boot (run the instant reserved-memory fails, before any build)
1. **Mine dmesg for the secure/PD layer.** Image auth succeeded, so look for *non-fatal* warnings:
`dmesg | grep -iE 'pas|scm|auth|hash|mba|qcom_q6v5|remoteproc|glink|pdr|pil'`.
A non-zero `qcom_scm_pas_*` return, a PDR restart-notification timeout, or a glink intent-failure
is a citable pointer into #2/#3.
2. **Confirm sibling DSPs are up and their PDs registered.**
`for r in /sys/class/remoteproc/remoteproc*; do printf '%s: %s %s\n' "$r" "$(cat $r/name 2>/dev/null)" "$(cat $r/state 2>/dev/null)"; done`
and `qrtr-lookup | grep -iE 'adsp|slpi|cdsp|sns|domain'`. If SLPI/ADSP is `offline`/absent and
the modem waits on its PD, **that is the gate and it is mainline-fixable** (firmware path +
remoteproc node + a `pd-mapper` entry), not TZ. This is the highest-value cheap check — the whole
elimination tracked `remoteproc2` (modem) closely and never verified the siblings.
3. **Timing/missed-response.** `strace -f -p $(pidof pd-mapper)` and rmtfs during a QMI RESET. If
the modem's RF-init window closes before pd-mapper/rmtfs answer a request, you'll see the missed
response. (Likely already excluded — services are confirmed up post-boot — but cheap to confirm.)
4. **LDO13 rail state — the one rail NOT on the eliminated list.** Unlike the refuted #9 LDO set
(ldo4/6/8/9/10/11/15/16/18/23/27, which were *absent* from pmOS), `ldo13` IS defined in
`dt-work/blueline-pmos.dts:5466`, and on SDM845 LDO13 feeds RFFE (per OpenStick prior art — the
`l13: voltage operation not allowed` line is benign on MSM8917 but not automatically so here).
Static dumps show a state delta: pmOS `ldo13 … 0 0 0 …` vs Android `pm8998_l13 … 0 1 0 …`, and
there is **no** `l13`/`voltage operation not allowed` line in the captured pmOS dmesg. **Live
check at the moment of `online`:**
`for r in /sys/class/regulator/regulator.*/; do n=$(cat $r/name 2>/dev/null); [ "$n" = ldo13 ] && echo "$n state=$(cat $r/state) @ $(cat $r/microvolts)uV"; done`
— is it `on` @ 1.8 V while the modem is booted-but-refusing-RF? Then retry `online` and watch
whether L13 flips. Likely falls to the same "modem votes RF via RPMh, not the AP framework"
refutation as #9 — but it's the one rail never explicitly probed, so confirm live before closing.
Plus `dmesg | grep -iE 'l13|voltage operation not allowed'` on the same boot.
### Tier 1 — diff the downstream kernel (the real working reference for secure-load)
Enchilada proves the mainline *stack* works on SDM845; it does **not** prove the secure-load code
paths work on blueline's exact modem. The authority for those is **Google's downstream Pixel-3
kernel** (`msm-google`, 4.4-era — confirm the exact branch against `boot_a`'s kernel version on
`android.googlesource.com/kernel/msm-google` before cloning). Pull it and diff, against mainline,
exactly three things:
- `drivers/remoteproc/qcom_q6v5_mss.c` — the PAS auth + mba mem-setup + reset sequence.
- `drivers/soc/qcom/{scm,pdr_interface,smem}` — the secure-channel and PD-restart path.
- modem `reserved-memory` + `qcom,smem-states` + `power-domains` in the DT.
The reserved-memory hit is the first output of this method; the SCM/auth/PDR delta is the next.
This is the strongest "honest swing" if reserved-memory alone fails — methodical, sourced, no RE
of opaque blobs. **Artifact we have but haven't used this way:** `android-reference/vendor-stack-20260621/`
(vendor RIL + MBN tree). **Artifact we still need:** the downstream kernel source tree.
### Tier 2 — instrument the firmware's own RF-init (the only inside view)
Every capture so far is userspace (QCRIL/radio logs). Nobody has captured the **MPSS firmware's own
RF-init trace** — the ordered set of things it reads and waits for. On rooted Android (slot A),
QCSuper continuous diag over **`/dev/diag`** (local — confirmed working; USB-diag is HAL-locked on
this production Pixel, per `pmos_fix_plan.md`) captures the F3/log stream during a cold boot. An
open F3 decoder (linux-msm / sdm845-mainline ecosystem; QCSuper has partial decode) turns it into
the firmware's RF-init step list. Diff which of those steps can't complete on pmOS. This is the one
instrument that can name the gate from inside the firmware; everything on pmOS only observes the
refusal. **Read-only capture — do not write EFS.**
### Tier 3 — TZ / SCM RE (the hard pole, deprioritize)
If Tiers 02 point at a specific SCM call or secure state: disassemble the QSEE trustlets or diff
XBL/ABL's modem init. Long, uncertain, opaque. Keep as the escalation, not the plan.
## The strategic fork (be honest about the 12 week telephony goal)
Mainline-native secure-load RE (Tier 23) is realistically **not** a 12 week path to working
telephony/SMS/data — it's open-ended research. If Tier 0 + reserved-memory don't clear 52, the
fastest route to "telephony on Linux like I have on rooted Android" is to use the stack that already
works on this silicon:
- **Downstream-kernel hybrid (Droidian / Halium / pmOS-downstream pattern):** boot the downstream
`msm-google` kernel under a Linux userspace, where the modem firmware gets the exact cold-boot
environment it expects so RF-init completes, then drive it with the vendor `qcrild` already pulled
in `android-reference/`. Trades mainline purity for a known-good outcome. This is the realistic
12 week path.
- **WRONG TURN — do not burn time on this:** "run vendor QCRIL on the *mainline* kernel via
libhybris" will **not** fix it. QCRIL does not trigger RF-init (the firmware self-arms on Android;
QCRIL only queries/confirms — proven by today's raw results). The gate is the cold-boot
environment, so only changing that environment (DT → subsystems → TZ → bootloader) **or** booting
the downstream kernel helps. Vendor-RIL-on-mainline addresses a different (already-solved) layer.
Net: **reserved-memory fix + Tier 0 (free) → if clear, stay mainline; if not, decide
mainline-secure-load-research vs downstream-kernel-hybrid on evidence, not on momentum.**
## Artifacts
- **Have:** `android-reference/vendor-stack-20260621/` (libril-qc-hal-qmi.so + 174-file MBN tree +
selection DB); `tools/modem-online-provisioner/{qrtr_raw.py,qrtr_seq.py}` (send any QMI PDU over
AF_QIPCRTR — validated against DMS 0x002D); QCSuper efs-shell + diag over `/dev/diag` on rooted
slot A; `slotb-backup-20260621/pmos-7.1-boot.img` recovery; 6.16.7 known-good kernel; EFS clones.
- **Need (not yet pulled):** downstream `msm-google` kernel source (Tier 1 ground truth); an open
Hexagon F3/diag decoder (Tier 2); possibly a devcoredump/minidump parser if SSR ever yields one
(today it did not — modem doesn't crash, it deliberates).
## Guardrails (secure-load-specific)
- pmOS-side secure-load investigation is **read-only**: `dmesg`, `/sys/class/remoteproc/*`,
`/sys/kernel/debug/{remoteproc,msm_subsys}/*`, `qrtr-lookup`. Safe.
- diag/F3 capture is on **rooted slot A `/dev/diag`** — read-only capture. Never write EFS or NV
from these probes (shared unslotted `modemst1/2` — a write is seen by both slots).
- **Never flash/patch TZ, trustlets, XBL, or ABL** — brick territory. `references/edl-pixel` exists
as last-resort recovery but **assume no EDL safety net**; behave as if a bad flash is permanent.
- Only ever touch `boot_a` / pmOS. Never slot B, `system_a`, the shared EFS, or userdata.
- Recovery image: `slotb-backup-20260621/pmos-7.1-boot.img`. Document every slot switch + flash.
- One `online` attempt per boot (a failed attempt poisons the modem until a power cycle).
- Standard hard constraints apply: pmOS is Alpine/ash (no `[[ ]]`/arrays); `rmtfs -P -s` (never
`-r` alone); never add `pmic@4`/`pmic@5` SPMI nodes; sudo pw `147147`.
## On link-in
Not yet referenced from `START-HERE.md` or `PAF/README.md` (left for the Opus handoff to wire, to
avoid colliding with in-flight edits). If reserved-memory fails, point START-HERE's "actual
frontier" at this doc and demote the reserved-memory lever to the trigger-condition note above.