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
9.1 KiB
PAF · Build & packaging (pmbootstrap, the proper path)
How the blueline kernel + device package are actually built and shipped. This
is the canonical build layer — earlier sessions wasted hours on host make
and on undocumented pmbootstrap behaviours. Build with pmbootstrap; it is
what every other sdm845-mainline contributor uses and what produces installable
APKs. Host make ARCH=arm64 LLVM=1 is not the path (it needs llvm-readelf/nm/
objcopy on the host and does not produce a package).
The two packages — do not conflate them
linux-postmarketos-qcom-sdm845(device/community/) — the KERNEL package. Kernel image (vmlinuz/Image.gz), all modules, the blueline DTB. Userspace never goes here.device-google-blueline(device/testing/) — the DEVICE package. Device userspace: firmware deps, hexagonrpcd/q6voiced confs, the systemd preset, and now the modem PDC self-provisioner (qcril-autoselect.py+.service, enabled via the preset). This is where per-device userspace belongs — modelled on howq6voiced.confis already installed.
Unified 7.1.1 kernel build (2026-06-22)
Base is the sdm845-mainline tree at tag 85f1df2a (= 7.1.1), checked out at
references/linux-7.1.1-sdm845-CANONICAL. All accumulated fixes are now commits in that
tree, not scattered source= patches:
- SLPI keep-proxy-power-on (the
sar.cc:27crash-loop fix — see slpi.md) - SLPI enabled in the blueline DTS
- fastrpc SDSP hyp-assign tolerance
Built via source override:
cd ~/pmos/pmaports
pmbootstrap build --src=$REPO/references/linux-7.1.1-sdm845-CANONICAL \
linux-postmarketos-qcom-sdm845
APK lands in ~/.local/var/pmbootstrap/packages/edge/aarch64/.
pmbootstrap build gotchas (each cost real time — RECORD)
-
The in-tree
arch/arm64/configs/sdm845.configis merged LAST and silently overrides our pmaports config.prepare()runsmerge_config.sh -m <pmaports config-*.aarch64> arch/$_carch/configs/sdm845.config— andmerge_config -mis last-wins. So any symbol set in the in-tree fragment beats the same symbol in the pmaports config, even though the pmaports config "looks" authoritative. This silently broke wifi (2026-06-29): pmaports setCONFIG_QCOM_PD_MAPPER=m, but the upstream sdm845-mainline in-tree fragment carried=n(their "use userspace daemon, poco-f1 mic race" default), so every build shipped pd-mapper OFF → no wlan PD →ath10k_snocprobe defers → nowlan0. The=nrode in via the vanilla import commit310c17cc6, not a deliberate choice. Fix: set the symbol in the in-tree fragment (references/linux-7.1.1-sdm845-CANONICAL/arch/arm64/configs/sdm845.config), not just pmaports. Audit rule: when a built kernel disagrees with the pmaports config,grepthe in-tree fragment first — it wins. Verify on-device withzcat /proc/config.gz | grep <SYMBOL>. -
olddefconfigis mandatory on a version bump. 7.1.1 added Kconfig symbols not in the rc1 fragment config; abuild's build runs non-interactive, so a baremakehits theoldconfigEOF prompt and dies atprepare0. The APKBUILDbuild()now runsmake ARCH=$_carch LLVM=1 olddefconfigfirst, then a serialmake ... -j1 prepare, then the parallel build. -
The
*.bcgitignore drops a tracked kernel source file. pmbootstrap's source-override rsync is gitignore-aware but honors*.bc(line 16) WITHOUT the negation!kernel/time/timeconst.bc(line 180). Sotimeconst.bc— a real bc(1) source needed byprepare0forinclude/generated/timeconst.h— is silently excluded →No rule to make target 'kernel/time/timeconst.bc'. Same class of breakage hits the negated dotfiles (.clang-format, etc.). Fix: the kernel APKBUILDprepare()restores these from the source mount (/mnt/pmbootstrap/source-override/) afterdefault_prepare. -
The persistent build copy poisons incremental builds. pmbootstrap rsyncs the override into
/tmp/pmbootstrap-local-source-copy(inside the native chroot) WITHOUT--delete. A prior interrupted build leaves stale host-tool binaries (scripts/basic/fixdep,scripts/mod/mk_elfconfig) +.cmdfiles; the next build'smakethen trusts the stale stamps, never recompiles them, and failsmk_elfconfig: not foundatprepare0. If you see host-tool "not found" with no precedingHOSTCCline, the copy is dirty. Recovery: let pmbootstrap recreate it cleanly (delete the copy dir; a fresh rsync from the clean host tree rebuilds host tools from scratch). Note:git clean -dfxon the HOST tree does NOT touch this chroot copy.
Kernel-swap / boot.img (from modem.md, kept here for the build flow)
The modem stack is fully modular (qcom_q6v5_mss, qrtr*, qcom_glink_smem,
mhi* all =m), so a kernel swap needs the matching lib/modules/<kver>/ on
the rootfs or the modem silently no-loads (a false 52). UFS + USB-gadget-NCM are
=y, so a module-mismatched boot still reaches rootfs + USB.
Boot image: cat vmlinuz <blueline>.dtb + the standing initramfs, mkbootimg
header v0, base 0x0, kernel_off 0x8000, ramdisk_off 0x1000000, tags 0x100, real
cmdline quiet splash … pmos_boot_uuid=2CE8-836F pmos_root_uuid=26733d78….
Rootfs is found by pmos_root_uuid (the ext4 FS UUID), so the slot LETTER only
decides which block device we write into — the cmdline is slot-agnostic.
SLOT MAP (verified live via fastboot getvar current-slot 2026-06-26):
Android = slot B (current-slot: b, slot-successful:b: yes). pmOS = slot A.
Flash ONLY boot_a (fastboot flash boot_a …; fastboot --set-active=a) and write
the rootfs to system_a. NEVER touch boot_b / system_b (that is Android now),
EFS(modemst1/2), userdata (single SHARED partition, ~119 GB), or TZ/XBL/ABL.
(Earlier revs of this doc had the slots reversed — they were wrong; the device is
authoritative.)
FLASH GOTCHAS (each cost a boot this session — RECORD)
-
system_arejects bootloader-fastboot flash→ must use TWRP cat (or fastbootd).fastboot flash system_afrom the bootloader failsPartition should be flashed in fastbootd. This fastboot/bootloader gates system writes to userspace. We DON'T have a workingreboot fastbootd(binary says "unknown reboot target"), so the path is:fastboot boot ~/Downloads/twrp-3.7.1_12-0-blueline.img, wait for adbrecovery, thenadb shell -T "cat > /dev/block/by-name/system_a; sync" < raw.img(system_a→/dev/block/sda5, a real 2.95 GB physical partition, NOT dynamic). -
pmbootstrap's
google-blueline.imgis ANDROID-SPARSE, not raw — un-sparse before cat. THE bug that gave a kernel-7.1.0rc1 debug-shell boot (initramfs can't find root). deviceinfo hasdeviceinfo_flash_sparse="true", so the final image starts with the sparse magic3a ff 26 ed, not a partition table.cat'ing it raw ontosystem_awrites a sparse container, so there's no GPT/ext4 on the partition → initramfsfindfs UUID=fails → debug shell. Fix:simg2img google-blueline.img raw.imgfirst, THEN catraw.img. Verify: a correct raw image starts with0000, reads as GPT @ 4096-byte sectors (fdisk -b 4096 -l: p1 ≈236M EFI/boot, p2 ext4 root at byte 255852544), and has the ext4 magic53efat255852544+1080. This matches the known-goodslotb-backupbyte-for-byte. (UFS is 4096-sector —fdiskdefault 512 shows NO partitions on the raw image; that's a red herring, not corruption.) -
Quarantine stale
_p<timestamp>kernel apks beforeinstall, or apk grabs the wrong one. A--srcbuild auto-versions as7.1.1_p20260625…, which apk sorts ABOVE the tagged7.1.1-r2(the_ppost-suffix outranks the bare tag).pmbootstrap installthen silently pulls the OLD kernel. Move the_papks out of~/.local/var/pmbootstrap/packages/edge/aarch64/, rebuild the index (apk index *.apk+abuild-signin the native chroot — thepmbootstrap indexwrapper failed on its own quoting), thenpmbootstrap zap(the rootfs chroot has the_pkernel installed and apk won't downgrade) and re-install.
The libqmi fork — packaged as the temp/libqmi override
qcril-autoselect.py needs the openimsd libqmi fork (PDC Set Feature msg
0x2E) via GObject-introspection; stock libqmi lacks both the message and the
typelib. It is packaged as temp/libqmi (pkgname=libqmi, source
gitlab.postmarketos.org/modem/openimsd/libqmi commit b683efb, built with
-Dintrospection=true, provides libqmi + qmi-utils). Because the aport's
pkgname is libqmi, it shadows Alpine's stock libqmi, and device-google-blueline
pulls it in via its libqmi / qmi-utils deps — a fresh pmbootstrap install
lays down kernel + provisioner + fork as one unit. The built apk carries
usr/lib/girepository-1.0/Qmi-1.0.typelib (verified).
Watch-item: the override is pinned at 1.39.0-r0, equal to current Alpine edge.
If Alpine bumps libqmi above this, apk could prefer stock at install — bump the
override's pkgver/pkgrel to stay ahead. (references/openimsd-libqmi +
tools/build-openimsd-libqmi.sh remain as the on-device overlay fallback.)