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
24 KiB
PAF · The modem userspace CONSUMER CHAIN — why the modem stays OFFLINE (2026-06-26, Opus)
SESSION-3 UPDATE (2026-06-27, Opus) — SLPI SAR CRASH LOOP FIXED;
PROVEN the SLPI does NOT gate the modem 52TL;DR
Built the missing AP-side SNS registry provider (a patched
hexagonrpcd) that feeds the SLPI its sensor registry over FastRPCapps_std. The SLPI'ssar.cc:27:chre_utils fatalcrash-loop (150+ crashes/boot) is broken — SLPI now stays up indefinitely (0 crashes over multiple 25–40s windows). Then enabled the modem anyway → stillQMI error 52 DeviceNotReady. So the SLPI/SAR subsystem is independent of the modem-52 wall. That question (could not be answered by disabling SLPI — only by making it actually work) is now settled: error 52 is not SLPI-gated.🟠 SUPERSEDED 2026-06-29 (Casey) — this conclusion is INVALID. The "SLPI fixed / 0 crashes / stays up" above was only remoteproc-not-crashing: this doc's own body (search "never exposes an SNS QMI service") shows the SLPI firmware never completed CHRE init / never exposed SNS QMI — i.e. not a functioning sensor stack. The reasoning "disabling couldn't answer it, only making it work can" was correct — but "making it work" was never achieved, only "stopped crashing." If the modem's RF-init queries the SLPI and gets silence from a never-initialized sensor stack, it parks OFFLINE regardless. The SLPI is a candidate root-cause, NOT proven-independent. See
slpi.mdtop banner +HANDOFF.md.HOW the SLPI was fixed (the real consumer chain Android calls
sscrpcd)The SLPI boots → makes FastRPC reverse calls (
apps_stdfopen/fread) back to the AP to read/persist/sensors/registry/.... pmOS shipped no AP-side listener, so the registry sensor starved and the SAR (sx932x) CHRE nanoapp fataled → crash loop. The pmOS-native listenerhexagonrpcd(linux-msm, already in the repo,-s= attach sensorspd on/dev/fastrpc-sdsp) is the right tool but had two gaps:
- Ran as
User=fastrpc→ couldn't read the persist registry files. Fixed with a systemd drop-inUser=root(/etc/systemd/system/hexagonrpcd-sdsp.service.d/10-root.conf).construct_root_dir()(rpcd_builder.c) only mappedregistry/registry/*— its virtual FS had no nodes for the top-levelsns_reg_config/sns_reg_version/sns_reg_ctrlthat blueline's SLPI requests at/persist/sensors/registry/<file>. hexagonfs is node-based (no real-FS fallthrough), so those ENOENT'd no matter what was on disk. Patched to add those three nodes (hfs_map_or_empty). NOTE:hfs_map_or_emptypresents a missing physical file as an empty directory (S_IFDIR), which still fails a file open — so the physical file must EXIST (even 0 bytes).sns_reg_versionis absent from the Android dump →touchan empty one and it serves as a regular empty file, which satisfies the SLPI.- Registry DATA staged to
/usr/share/qcom/sensors/registry/(hexagonrpcd's default-Rroot; the 177 groups from the LineageOS persist dump +sns_reg_config, emptysns_reg_version,sns_reg_ctrl). Persist files alsochmod -R a+rX(they were0600 casey:caseyfrom a tar restore).STATE OF THE FIXES — now converted from live temps to REAL in-code fixes (2026-06-27)
All of the live drop-in/temp changes have been turned into aport sources so a clean
pmbootstrap installreproduces them (idempotent fresh + upgrade). What's in code now:
- hexagonrpcd patch → local aport
pmaports/temp/hexagonrpcd/(fork of Alpine community aport,pkgrel=4, addshexagonrpcd-blueline-registry-nodes.patch, checksums regenerated).pmbootstrap build hexagonrpcdproduces the patched binary instead of the live hand-installed/usr/bin/hexagonrpcdoverwrite.- root drop-in →
device-google-blueline/hexagonrpcd-sdsp-root.conf, installed to/usr/lib/systemd/system/hexagonrpcd-sdsp.service.d/10-root.conf(APKBUILDpackage()).- registry data → NOT shipped as blobs.
blueline-sns-registry-stage.sh+.service(oneshot,Before=hexagonrpcd-sdsp, ordered after persist mount) stage the registry from the device's OWN/mnt/vendor/persist/sensors/registryinto/usr/share/qcom/sensors/registry(hexagonrpcd's served root; persist layout is off-by-one for a single-R). Touches the emptysns_reg_version. Idempotent, ships no proprietary calibration.- service enable → preset enables
blueline-sns-registry-stage.service+hexagonrpcd-sdsp.service.- persist perms: handled by the stage script's
chmod -R a+rXon the served copy; the persistchmodI did live is NOT needed by the real fix (hexagonrpcd reads/usr/share/qcom, not persist).REMAINING build/verify steps (need device + reflash — do NOT half-run unattended):
pmbootstrap build hexagonrpcd(local aport) +pmbootstrap build device-google-blueline.- Install/upgrade on device (
pmbootstrapsideload or apk add the built .apk) — replaces the hand-installed binary + lands the drop-in/stage-service/preset.- Reboot clean and VERIFY idempotency: SLPI stays up (0
crash #delta), provider active,blueline-sns-registry-stagepopulated/usr/share/qcom/sensors/registry.- Revert the hand-installed temps once the packages own them: restore
/usr/bin/hexagonrpcd.origis NOT needed (apk upgrade overwrites), remove the manualsystemctl enable(preset handles it).
- Kernel DT vmid change (
sdm845.dtsisdsp fastrpcqcom,vmids = <HLOS SSC_Q6>): I hand-patched the DTB into boot_a to test the TZ hyp-assign theory. LOGGED RESULT: with<3 5>live (confirmed viadtcdecompile of/sys/firmware/fdt),dmesgstill printsSDSP fastrpc hyp-assign rejected by TZ (-22); registering node without reserved-heap assignment(32 occurrences). So the vmid change did NOT change the TZ result — the crash fix was the registry serving, not the heap. The change is harmless but unnecessary.
- Orig boot.img backups: scratchpad
boot.img+/tmp/boot-backup_a.imgon device.- NOTE on a reboot during testing:
lsusbshowed18d1:d001and SSH returnedNetwork is unreachable; root cause was the HOST ifaceenp0s20f0u6 DOWN(perip -br addr), fixed byip link set up+ip addr add 172.16.42.2/24→ phone answered,uptime= up 2 min. The phone had booted normally; it was a host USB-net enumeration issue, not a device boot failure.THE REMAINING WALL — modem
QMI 52 DeviceNotReady, now provably INDEPENDENT of SLPIWith SLPI fully up + sensors registry served,
mmcli -m 0 -estill fails at DMSset-operating-modewith QMI 52. modem0 enumerates (QUALCOMM, SIM present, slot 2 active), sitsdisabled / power off, enable →enabling → (QMI 52) → disabled. The MSS remoteproc (4080000.remoteproc) isrunning. LOGGED:mmcli -m 0 -e→state changed (disabled -> enabling),couldn't enable interface: 'Couldn't set operating mode: QMI protocol error (52): DeviceNotReady',state changed (enabling -> disabled). So 52 comes from the modem path, with the SLPI fully up — the two are independent. Scope note: the goal is the WHOLE device, not just telephony. The SLPI/sensors fix is a real bringup win on its own (sensors infra now functional). For the 52 specifically, the SLPI is not the lever. Next session for 52: modem NV/EFS/identity (themodel 0/ LOW_POWER hypothesis from session 2), rmtfs/EFS sync, or modem firmware-init.Open loose end (minor): hexagonrpcd reconnect churn
Provider shows
activatingwith ~18 restarts/min — it exits on FastRPC "Broken pipe" when the SLPI closes the session after serving, thenRestart=alwaysreattaches. SLPI stays up regardless (0 crashes), so it's cosmetic, but worth aRestartSec/keepalive tweak later.
SESSION-2 UPDATE (2026-06-26 late, Opus) — CHAIN BUILT + WORKING; wall is now the modem 52 / SLPI-SAR firmware crash
What got BUILT this session (all in pmaports
device/testing/device-google-blueline/, deployed live + wired into APKBUILD/preset — idempotent)The whole consumer chain now comes up automatically on a clean boot and ModemManager starts + creates the modem. Verified on hardware.
modem-qrtr-ready.service+modem-qrtr-ready.sh(NEW) — the pmOS equivalent of Android'swait_for_prop vendor.qcom.devup 1. Blocks until modem QMI answers and is stable (2 probes/3s) before releasing consumers. Killed the boot race (node with id 0 not found in QRTR bus). VERIFIED: gate waits, then releases.- UIM-selection fix —
blueline-uim-select.sh(NEW) wraps the stock binary: it selects the SIM app fine but then a trailing QMI op times out (SLPI/XPU churn) and exits 1 — a false negative that failed MM's hardRequires=. Wrapper treats "app selected" as success.uim-wait.confrewritten: gate on modem-qrtr-ready, Type=oneshot, run the wrapper. VERIFIEDmsm-modem-uim-selectionnow = active.qcril-prov.py— fully fixed (was crashing onout.get_configs()):
list_configs+get_selected_configreworked to read the PDC indication (IndicationPdc*Output.get_configs()/get_active_id()), not the response.- GI array-length args fixed (
set_id(id),set_type_with_id_v2(t,id)).- Targets configs by sha1(.mbn) == PDC config id; selects+activates HW + Rogers SW.
- Skip-if-already-active: checks get_selected_config; if the inherited config is already active, skips select/activate → 0 modem restarts (was 2). VERIFIED: "HW/SW already SELECTED+ACTIVE — no restart".
- Deadlock fix: exits 0 after provisioning even if RF not armed (RF arming is MM's job, and MM is gated behind this service — requiring RF here deadlocked). VERIFIED exit 0.
blueline-dpm-open-port.service/qcril-prov.service— gated on modem-qrtr-ready + retry.- Kernel: mem-protect skip reverted (
980c4ae1f); on clean baseline 7.1.1;verify-fixes.shgreen.THE WALL NOW (single, precise)
Full chain runs → ModemManager starts, creates
modem0(qcom-soc plugin, 3 ports), reads the SIM ATR, goesdisabled → enabling→ calls set-operating-mode →QMI error 52 DeviceNotReady→ falls back todisabled. This is the SAME 52 from day one. The modem is OFFLINE, model0(up-but-unprovisioned) and refuses to enable even when driven correctly by MM. So the entire userspace plumbing is now proven-good; the wall is the modem itself refusing RF.SLPI / SAR — the suspected gate (Casey's thesis), what we proved
- SLPI crash-loops
sar.cc:27:chre_utils fatalevery ~10s (crash #15+). SAR = Semtech SX932x, the modem's RF SAR/TX-power sensor.- It is a CHRE nanoapp crash INSIDE the SLPI firmware at init, and qrtr-lookup is empty — the SLPI never exposes an SNS QMI service before it dies. So an AP-side QMI "SAR consumer" has nothing to attach to; the producer fatals first. A downstream subscribe-consumer is NOT the missing piece.
- The real missing piece is whatever feeds the SLPI its sensor registry / CHRE settings at init: the SAR registry data (
sx932x_0.sar,.config,_platform.*) IS present at/persist/sensors/registry/registry/but is NOT delivered to the SLPI (its RFS dir/persist/rfs/msm/slpiis empty; tqftpserv serves only/persist/rfs, not/sensors).- Android's consumer stack (proprietary, NO open-source equivalent):
chre_daemon_msm+sensors.qti+sscrpcd(inandroid-reference/vendor-stack-.../vendor/bin/), plus the registry underandroid-reference/persist-sensors-20260625/. Ourdrivers/soc/qcom/qcom_ssc_sensors.cis a passive ABI shim — it does NOT deliver the registry or run CHRE, so it cannot prevent the firmware crash. This is the "shim lacking components LineageOS has" Casey referenced.NEXT ANGLE (Casey's call — start here next session)
- DECISIVE CHEAP TEST FIRST — is SAR actually the modem gate? Stop the SLPI remoteproc so it is NOT crash-looping (
echo stop > /sys/class/remoteproc/remoteproc2/state), then let MM try to enable the modem (orqmicli --dms-set-operating-mode=onlineonce). If still 52 → SLPI/SAR is NOT the modem gate (independent symptoms) → stop chasing SAR for telephony and look elsewhere for the 52. If it goes online → the SLPI churn was the blocker and the SAR/CHRE consumer becomes critical. Run this before building anything.- If SAR IS the gate: the buildable "consumer" is a registry/CHRE provider that feeds the SLPI at boot (reverse the SNS/CHRE QMI registry protocol; or port pieces; or boot SLPI on-demand AFTER preparing its env, like LineageOS
sensors_ssc.cdoes — it does NOT auto-boot the SLPI raw). Investigatechre_daemon_msm/sscrpcdbehaviour + how the registry reaches the SLPI on Android (RFS path? SNS QMI? direct?).- Independent of SAR: chase why the modem boots OFFLINE/model-0 (vs Android's LOW_POWER). model
0= NV/identity not fully loaded — possible EFS/NV or firmware-init issue.- Fallback: downstream-kernel hybrid (Droidian/Halium) — the realistic telephony path if mainline SLPI/CHRE proves intractable.
SAR consumer — EXACT mechanism (from slpi.mbn strings) + the build blocker
The SLPI firmware reveals precisely what the consumer must be:
- Reads registry from
/persist/sensors/registry/registry(+sns_reg_config,sns_reg_version).Sending registry request for group name:%s/SNS_REG_INIT/Decoding registry group %s/Error decoding registry event→ the SLPI requests registry groups over the SNS QMI service and expects encoded registry-event responses. The SAR (sx932x) nanoapp fatals (sar.cc:27 chre_utils fatal) when it can't get its group → crash-loop.- Fallback strings exist:
Registry disabled, leaving default mode enabled/LPI Registry Disabled— there may be a registry-disabled mode worth forcing (SAR likely still needs its device config though).- The consumer = an SNS registry provider (QRTR/QMI daemon) that reads
/persist/sensors/registry/registry/<group>and answers the SLPI's requests. On Android this issensors.qti+sscrpcd+chre_daemon_msm(binary-only inandroid-reference/vendor-stack-20260621/vendor/bin/).- BUILD BLOCKER (why it's not done): the SNS protocol is Qualcomm proprietary protobuf (
sns_client.proto/sns_registry); there are NO .proto defs or SNS source anywhere in the tree — only the registry DATA and the binary daemons. A working provider needs that encoding; building blind yields non-functional code. Options: (a) extract/RE the SNS protobuf from the vendor .so (libsnsapi/sensors.qti) — multi-day; (b) find an open SNS impl to port; (c) run the vendorsscrpcd/sensors.qtibinaries under a libhybris/Halium shim; (d) downstream-kernel hybrid (sidesteps mainline SLPI entirely).CLEAN decisive test to run next boot (settles whether SAR even gates the modem — do BEFORE any SNS build)
The session test was contaminated (modem already poisoned by prior online attempts). Clean version:
systemctl mask ModemManager qcril-prov qcril-autoselect blueline-dpm-open-port→ reboot → on boot immediatelyecho stop > /sys/class/remoteproc/remoteproc2/state(kill SLPI before it crash-loops) → wait for modem QMI up → ONEqmicli -p -d qrtr://0 --dms-set-operating-mode=online.
- Still 52 with SLPI cleanly stopped from boot → SLPI/SAR is NOT the modem gate (the 52 / model-0 is independent — chase modem NV/EFS/firmware-init instead; don't invest in the SNS build).
- Goes online → SLPI/SAR churn WAS the blocker → the SNS registry provider is worth the build. Unmask afterwards:
systemctl unmask ModemManager qcril-prov qcril-autoselect blueline-dpm-open-port.Files touched this session (for the next agent)
references/linux-7.1.1-sdm845-CANONICAL@980c4ae1f(revert skip);tools/verify-fixes.sh(skip-absent check)- pmaports
device/testing/device-google-blueline/:qcril-prov.py,modem-qrtr-ready.sh+.service,blueline-uim-select.sh,uim-wait.conf,blueline-dpm-open-port.service,qcril-prov.service,APKBUILD,80-device-google-blueline.preset. All also deployed live to the phone.- NOTE: APKBUILD
sha512sumsNOT yet regenerated for the new/changed sources — runpmbootstrap checksum device-google-bluelinebefore the next package build.
THE session that reframed the whole problem. The modem-online blocker is not (only) a kernel/secure-load issue — it is that the userspace consumer chain that drives the modem is half-built / failing, exactly as Casey kept saying. Everything below is VERIFIED LIVE on the reverted-baseline 7.1.1 build, not inference.
TL;DR causal chain (verified end to end)
- Modem firmware boots, MBA loads MPSS, modem reaches
running. It has identity (IMEI 990012001581294, ESN 8074BB5D, MEID, SWg845-00194-210812). The assign/-22/secure-load is NOT the modem blocker — the modem loads. (The only-22s are fastrpc + ath10k wifi, both tolerated.) One XPU violation at boot, self-recovers (Casey was right). - BUT the modem comes up op-mode OFFLINE (3), model
0= up-but-unprovisioned/not-ready.--dms-set-operating-mode=online→ QMI 52 DeviceNotReady. Forcing online does nothing. - SLPI crash-loops every ~10s:
err_qdi.c:456:EF:sensor_process:1:sar.cc:27:chre_utils fatal→ recover → up → crash. SAR (Semtech SX932x) is the modem's RF SAR/TX-power sensor. - The modem+SLPI instability makes the QRTR node flap, so the boot-time consumer services
race an unready modem and fail:
msm-modem-uim-selection.service→node with id 0 not found in QRTR bus(boot) /Transaction timed out(later). This is a hardRequires=of ModemManager.blueline-dpm-open-port.service→node with id 0 not foundat boot (succeeds if re-run later).qcril-prov.service→ crashed on a code bug (now FIXED, see below).
- Because
msm-modem-uim-selection(hard dep) failed → ModemManager never started at boot. So nothing ever drove the modem: enable → set-power → register. It just sits OFFLINE. - Started MM manually (bypassing deps): it DOES reach the modem over qrtr://0, creates
modem0, reads the SIM ATR — then fails:couldn't start parent initialization: Couldn't get primary portandcouldn't load carrier config: Operation timed out. MM can't initialize a modem that's OFFLINE/flapping.
What is SOLID now (do not redo)
- On reverted-baseline 7.1.1 (
bluelinebranch, mem-protect skip reverted980c4ae1f). Built, flashedboot_a, deployed.verify-fixes.shgreen (13 checks; mem-protect check now asserts the skip is ABSENT). Android slot B / EFS / userdata untouched. pd-mapper: in-kernelWRONG (corrected 2026-06-29). The pmaports config setsCONFIG_QCOM_PD_MAPPER=m, module loaded … pd-mapper is fine — ruled out.=m, but the running kernel has# CONFIG_QCOM_PD_MAPPER is not set— the in-treearch/arm64/configs/sdm845.configcarries the upstream=nandmerge_config.sh -mapplies it after the pmaports config, so=nwins every build. Userspace pd-mapper is also uninstalled ⇒ no pd-mapper of either kind runs. Caught via the wifi outage (nowlan0; ath10k_snoc bound but probe defers with no wlan PD). The Mobian 0171 observation stands, but "pd-mapper is fine" did not. Fixed: in-tree fragment →=m(commit pending), then rebuild+reflash. Whether this also unblocks the modem-52 is now an open re-test, not a closed lead.- Infra present & correct:
rmtfs -P -s(block EFS),tqftpserv(serves/persist/rfs→ modem mcfg), sensor registry 177 files at/mnt/vendor/persist/sensors/registry/registry/, all mcfg carrier configs inclmcfg_sw/generic/NA/Rogers/Commercial/CA/mcfg_sw.mbn. - udev tags MM correctly:
ID_MM_QCOM_SOC=1,ID_MM_CANDIDATE=1on rmnet_ipa0; MM qcom-soc plugin loads. Transport (QMI-over-QRTR) works — MM exchanges QMI with the modem.
FIXED this session — qcril-prov.py (the MBN provisioner)
Source: pmaports/device/testing/device-google-blueline/qcril-prov.py (also live-deployed to
/usr/bin/qcril-prov.py on phone). Was crashing; now runs end-to-end and provisions Rogers.
Bugs fixed (all real, in code):
list_configsread configs from the response (out.get_configs()— doesn't exist;MessagePdcListConfigsOutputonly hasget_result). The config list arrives via thelist-configsINDICATION →IndicationPdcListConfigsOutput.get_configs(); each element has.id+.config_typeonly. Reworked to indication-driven (mirrors the workingload-config).- GI array-length args:
set_id(cfg_id, len)→set_id(cfg_id);set_type_with_id_v2(t,id,len)→set_type_with_id_v2(t,id). (set_config_chunkwas already correct.) - Strategy: blueline INHERITS Android's full mcfg set (1 platform + 25 software) on shared
persist. Don't delete+reload (delete is a no-op; reload → error 41 "already exists"). Instead:
compute target id = sha1 of the .mbn file (== the PDC config id, verified: HW sha1
6fe571a9…matched the on-modem id), confirm present, select + activate by sha1. Treat load error_code=41 as success. Helpers added:_sha1_id,_hex,_id_present. Result: provisioner selects+activates HW (platform) and Rogers (software) configs cleanly. The modem still ends OFFLINE afterward (carrier config alone doesn't lift it — needs MM to drive it).
THE PLAN (next session — ordered)
Goal: get ModemManager to fully initialize the modem and drive OFFLINE → online → registered. Two intertwined blockers: (A) modem won't initialize while OFFLINE/flapping; (B) SLPI crash-loop.
-
Make MM actually manage the modem (primary blocker).
- Why
Couldn't get primary port? Check MM qcom-soc plugin port expectations for a pure-QRTR SDM845 modem; check nothing else holds the QMI client (our qcril-* one-shots, the straydbus-monitor, manualqmicli -p). Try MM with everything else stopped. - Fix the boot ORDERING/retry so
msm-modem-uim-selection+blueline-dpm-open-port+qcril-provdon't race the unready modem: add wait-for-QRTR-node / Restart=on-failure / properAfter=on a "modem-qrtr-up" condition. This is how the chain stays up like Lineage (Lineage's RIL waits for the modem to be ready before UIM select / PDC). - Once MM inits: it should set-power-up and the OFFLINE→online may resolve via MM's sequence
(it owns DMS set-operating-mode). The manual
online=52 is because nothing did the proper enable sequence first.
- Why
-
SLPI SAR crash-loop (
sar.cc:27). SAR = SX932x, governs RF TX-power; Casey's position is it gates modem RF. The SLPI sensor REGISTRY (/persist/sensors/registry) is NOT served to the SLPI — tqftpserv serves/persist/rfsonly (sibling tree). Leads:- Does the SLPI read registry via tqftpserv (needs
/sensorsserved too) or a different path? The tqftp log shows only modem mcfg requests, no/sensorsrequests → SAR may crash BEFORE requesting registry (early init / SX932x i2c on the SLPI bus). Investigate how LineageOSsensors_ssc.c+ sensor HAL bring SAR up (registry delivery + SX932x i2c/GPIO). - Our
qcom_ssc_sensors.cis a passive ABI shim; it does NOT boot or feed the SLPI. Mainline auto-boots the SLPI (DTS firmware-name) with no consumer → SAR talks to nobody → crash. LineageOS boots SLPI ON DEMAND after the sensor HAL is up.
- Does the SLPI read registry via tqftpserv (needs
-
Verify on a clean boot: fix the services so the whole chain comes up at boot (not manually), reboot, confirm MM auto-starts, modem → registered. One online attempt per boot still applies.
Hard constraints (unchanged)
- pmOS = slot A; flash ONLY boot_a. NEVER touch Android slot B / EFS (modemst1/2,fsg,fsc) /
userdata / TZ-XBL-ABL. rmtfs
-P -s. No pmic@4/5 SPMI nodes. Oneonlineattempt per boot. sudo pw 147147. USB 172.16.42.1 (host iface enp0s20f0u6 →ip addr add 172.16.42.10/24). - pmOS is Alpine/ash: embedded
sh -c "...(...)..."with parens fails — use script files via scp.