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
148 lines
9.5 KiB
Markdown
148 lines
9.5 KiB
Markdown
# pmOS Modem Fix — Implementation Plan (autoselect, EFS-persisted)
|
|
|
|
Consolidates the 2026-06-20 live-Android + binary-RE session. This is the build plan for the
|
|
pmOS side. Evidence is cited to live capture lines or binary addresses; nothing here is inferred
|
|
without a source.
|
|
|
|
## The mechanism (works — but is NOT the gate)
|
|
|
|
> **🟡 RE-STAMPED 2026-06-29.** The MCFG auto-select-by-UIM mechanism is real and PDC configs do go
|
|
> Active (`qcril-autoselect` runs, Set Feature accepted) — but this is **proven NOT to be the gate**:
|
|
> the modem parks OFFLINE / model 0 and refuses every pre-RF write (online→52, low_power→60,
|
|
> NAS SSP→25) regardless of provisioning state. Choreography is downstream of the OFFLINE state.
|
|
> See `modem.md` eliminated-leads ledger. Kept as the mechanism reference (how MCFG/EFS autoselect
|
|
> works), not as a live fix path.
|
|
|
|
The modem provisions itself by **MCFG auto-selection keyed on the SIM (UIM)**, applied at the
|
|
modem's own firmware RF-init, and **persisted in the modem's EFS** (`modemst1/2`, which is
|
|
**shared** between the Android and pmOS slots — `sdf3/sdf4`, not slotted).
|
|
|
|
1. **Persistent form (community-proven on SDM845 / OnePlus 6/6T):** an EFS NV item
|
|
`/nv/item_files/mcfg/mcfg_autoselect_by_uim` plus the mcfg uploaded into EFS. Written over
|
|
DIAG (EfsTools). Once set, the modem self-selects + self-applies every boot.
|
|
2. **Runtime form (reverse-engineered from `libril-qc-hal-qmi.so`):**
|
|
`pdc_enable_auto_selection(enable, id)` @ `0x1d45c40` builds an 80-byte
|
|
`pdc_set_feature_req_msg_v01` (feature value `3` when enabling, `0` when disabling) and calls
|
|
`pdc_set_feature` @ `0x1d45ac0`, which issues **QMI_PDC_SET_FEATURE**:
|
|
- **message ID `0x2E` (46)** (`mov w1,#0x2e` at `0x1d45b4c`)
|
|
- request length `0x50` = 80 bytes (`mov w3,#0x50`), response 8 bytes (`mov w5,#0x8`),
|
|
timeout 10000 ms (`mov w6,#0x2710`).
|
|
|
|
## Live-Android ground truth (this session, device 89JX0AAJP)
|
|
|
|
- Modem fully working: `dumpsys telephony` → IN_SERVICE, LTE, Fido 302/720, voice+data.
|
|
- **Self-persist confirmed:** blanked `persist.vendor.radio.cnv.ver_info`, restarted live
|
|
`qcrild`. `is_modem_mbn_updated` logged `version info updated` (prev empty), `start_mbn_update`
|
|
fired — but QCRIL only queried `get_active_config_info` (`config_version=0x801481a`, CNV
|
|
`0x48`=72), re-synced, and **never loaded/activated**. The modem already held the config in its
|
|
own NV. → userspace is reconcile-only; the modem persists. (`/tmp/qcril-re/live-firstprov.txt`)
|
|
- **Online-arm reference captured** (the step that returns `DeviceNotReady` on pmOS):
|
|
airplane toggle → `dms_handle_modem_operating_mode → "operating mode needs to be changed" →
|
|
SETTING_OP_MODE → modem ONLINE`. (`/tmp/qcril-re/airplane-arm.txt`)
|
|
- `/data/vendor/modem_config/` does **not exist** on this device — QCRIL reads MBNs straight from
|
|
`/vendor/rfs/msm/mpss/readonly/vendor/mbn/` (the readonly vendor tree), not a `/data` cache.
|
|
|
|
## Why pmOS fails, and what the fix must do
|
|
|
|
pmOS boots with the modem at 0/0 configs and `DeviceNotReady`. The Android-equivalent state is:
|
|
modem set to auto-select by UIM + the mcfg tree reachable at RF-init + EFS writable so the modem
|
|
persists what it applied. The fix must guarantee all three on pmOS:
|
|
|
|
1. **mcfg tree served to the modem at RF-init** — `tqftpserv` serving
|
|
`/mnt/vendor/persist/rfs/readonly/vendor/mbn/` (present, per modem.md). Verify the modem's
|
|
requested path matches.
|
|
2. **EFS writable** — `rmtfs -P -s` (read-write, drop `-r`) so the modem can commit/persist its
|
|
applied config (frontier #4; the read-only `-r` shadow is why nothing persisted before).
|
|
3. **Auto-selection enabled** — set it so the modem self-applies. Two routes below.
|
|
|
|
## Build — two routes (do A first; B is the persistent backstop)
|
|
|
|
### Route A — runtime QMI via PDC Set Feature (ALREADY AVAILABLE in pmOS's libqmi fork)
|
|
**This is the path. It is not new work — the pmOS community already built the libqmi side.**
|
|
|
|
Stock libqmi PDC has no Set Feature. But the **openimsd libqmi fork**
|
|
(`https://gitlab.postmarketos.org/modem/openimsd/libqmi`, base 1.39.0) already defines
|
|
**`QMI_PDC_SET_FEATURE` at id `0x2E`** — the *exact* message ID we independently reverse-engineered
|
|
from `pdc_set_feature` (`0x1d45b4c: mov w1,#0x2e`). Two sources, same message. Its request TLVs
|
|
(`data/qmi-service-pdc.json`, "since 1.40"):
|
|
|
|
| TLV | id | type | meaning |
|
|
|---|---|---|---|
|
|
| Slot ID | common-ref | guint32 | slot |
|
|
| Token | common-ref | guint32 | request token |
|
|
| **Selection Mode** | 0x11 | guint32 | **set to 3 = auto-select-by-UIM** (matches the `enable→feature 3` in `pdc_enable_auto_selection`) |
|
|
| Refresh Mode | 0x14 | gboolean | refresh on change |
|
|
| IMS | 0x19 | gboolean | ims feature |
|
|
|
|
Output: Operation Result (+ a Set Feature *indication* carrying the Token).
|
|
|
|
Implementation on pmOS:
|
|
- Build/install the **openimsd libqmi fork** (it generates `Qmi.MessagePdcSetFeatureInput` with
|
|
`set_selection_mode` / `set_refresh_mode` / `set_ims` / `set_slot_id` / `set_token`).
|
|
- Call it from **python-GI** — the fork's **qmicli has no `--pdc-set-feature` CLI**, so do it the
|
|
way `qcom-imsd` does (Qmi GI over `qrtr://0`), not via a qmicli flag. Set Selection Mode = 3,
|
|
Refresh Mode on. This is the runtime equivalent of QCRIL's `pdc_enable_auto_selection`.
|
|
- pmOS boot service: enable auto-select, let the modem self-provision from the served mbn tree.
|
|
|
|
Note: the fork still carries the **load-config `g_free` segfault at `qmicli-pdc.c:1130`** (it's
|
|
1.39.0). Only relevant if we fall back to explicit `--pdc-load-config`; the autoselect path
|
|
shouldn't need it. Our one-line patch + `tools/build-qmicli.sh` still apply if so.
|
|
|
|
**Prior art / proof:** `qcom-imsd` (same fork, libqmi-GI over qrtr PDC) is **known-working on
|
|
Pixel 3a (sargo)** — blueline's SDM845 sister. It does IMS-layer PDC (select/activate/register);
|
|
we add the lower-layer Set Feature autoselect. The pmOS PDC-over-qrtr approach is proven on this
|
|
silicon.
|
|
|
|
### Route B — persistent EFS NV item (DIAG, the community method)
|
|
Write `/nv/item_files/mcfg/mcfg_autoselect_by_uim` (enable) into the modem EFS via a DIAG-EFS2
|
|
client on pmOS. pmOS diag is **not** HAL-locked the way the production-Android Pixel gadget is
|
|
(this session: the Pixel USB gadget HAL reverted configfs to adb-only, blocking USB-diag;
|
|
`/dev/diag` local access remained available). Because `modemst` is shared, this is a one-time
|
|
write that both slots inherit. Tooling: EfsTools (Linux/.NET — `dotnet` is available) or a small
|
|
DIAG-EFS2 client against pmOS `/dev/diag`.
|
|
|
|
## Test loop (on pmOS, next boot)
|
|
1. Confirm rmtfs `-P -s` (rw) + tqftpserv serving the mbn tree.
|
|
2. Apply Route A (or B) to enable auto-selection.
|
|
3. Reboot; check `qmicli --dms-get-capabilities` → `Networks` non-empty = RF armed.
|
|
4. If armed: confirm it survives a second reboot (persistence). If not, apply Route B so the
|
|
modem commits to EFS.
|
|
|
|
## LIVE RESULT 2026-06-20 (Route A run on pmOS hardware — config blocker SOLVED)
|
|
|
|
Ran the full fix on pmOS slot B (kernel 7.1.0-rc1-sdm845), live modem over qrtr://0:
|
|
|
|
1. Built + installed the **openimsd libqmi fork** on-device (Alpine); `Qmi.MessagePdcSetFeatureInput
|
|
present: True`.
|
|
2. Ran `qcril-autoselect.py` → PDC client allocated, **Set Feature (0x2E) accepted**. Signal names
|
|
`set-feature`/`get-feature` were correct (indications arrived; only a strict-parse warning:
|
|
the modem's Get Feature indication omits the mandatory Result TLV 0x02 libqmi expects — cosmetic).
|
|
3. **Immediately after Set Feature, the modem self-loaded its configs: PDC 0/0 → 2 platform
|
|
(SS-LA-SDM845 ACTIVE) + 25 software (Rogers_Canada).** It pulled them itself from the
|
|
tqftpserv-served mbn tree. This is the modem auto-selecting by UIM — the mechanism working.
|
|
4. **Rebooted with nothing enabled → the modem self-loaded 2+25 again at RF-init, platform ACTIVE.**
|
|
So the autoselect **persisted** (Set Feature is sticky, not just runtime). This is the documented
|
|
project blocker (0/0 every cold boot, frontier #3/#4) **SOLVED**: blueline's modem now
|
|
self-provisions MCFG persistently on mainline pmOS — believed a first for Pixel 3.
|
|
|
|
**Remaining wall (NEW, deeper than config):** despite firmware up (mba+mpss booted, IPA running,
|
|
handover signaled), platform config ACTIVE, and ModemManager seeing the configs,
|
|
`--dms-set-operating-mode=online` still returns **DeviceNotReady (QMI 52)**; modem stays offline,
|
|
Networks ''. `low-power` → InvalidTransition (already LPM). A full reboot with configs active did
|
|
NOT arm RF — so it is not a re-init-count problem.
|
|
|
|
**Leading hypothesis for the remaining wall → Route B (firmware-level autoselect via EFS NV).**
|
|
Our Set Feature operates at the **PDC/RIL layer** (post-firmware-boot): the modem loads+activates
|
|
the config in PDC, but the **firmware RF-init at ~12s already ran without it**, so PDC-ACTIVE ≠
|
|
RF-consumed. The Android/OnePlus mechanism writes the EFS NV item
|
|
`/nv/item_files/mcfg/mcfg_autoselect_by_uim` so the **firmware itself** auto-selects at its
|
|
earliest RF-init, before RF comes up. Next step: write that EFS NV item on pmOS (diag/EfsTools —
|
|
not HAL-locked here) so the firmware applies MCFG at RF-init. Alternative to rule out: a genuinely
|
|
separate non-config blocker (cal/IMEI) — but the same modem arms on Android, so config-apply timing
|
|
is the stronger lead.
|
|
|
|
## Artifacts from this session
|
|
`/tmp/qcril-re/`: `live-firstprov.txt` (qcrild restart, reconcile-only proof),
|
|
`airplane-arm.txt` (online-arm reference), `auto_sel.txt` + objdump of
|
|
`pdc_enable_auto_selection` / `pdc_set_feature` (msg 0x2E). EFS clones already in repo:
|
|
`efs-postandroid/`, `efs-backup-20260618/` (`modemst1/2`, `fsg`, `fsc`).
|