Device profile keys
Every key a device profile can set, from profiles/_template/device.env.
Keys marked TRAP encode a lesson from a previous port. Getting one wrong does not produce an error – it produces a confident wrong answer.
Identity
Section: IdentityPORTHOLE_DEVICE_NAME
Section: PORTHOLE_DEVICE_NAMEdefault: (unset)
“Google Pixel 2 XL”
PORTHOLE_VENDOR
Section: PORTHOLE_VENDORdefault: (unset)
“Google”
PORTHOLE_CODENAME
Section: PORTHOLE_CODENAMEdefault: (unset)
must equal this directory’s name
PORTHOLE_YEAR
Section: PORTHOLE_YEARdefault: (unset)
PORTHOLE_SOC
Section: PORTHOLE_SOCdefault: (unset)
“msm8998”
PORTHOLE_ARCH
Section: PORTHOLE_ARCHdefault: aarch64
A/B Slots
Section: A/B SlotsPORTHOLE_RAMBOOT_NEEDS_MODULES
Section: PORTHOLE_RAMBOOT_NEEDS_MODULESdefault: (unset)
From fastboot getvar all: look for slot-count / current-slot. TRAP. Set to any non-empty value if this device CANNOT RAM-boot a rebuilt kernel without its modules – taimen sets it because its initramfs loop-mounts the pmOS subpartition and needs loop.ko. Left blank, porthole build boot will RAM-boot, and on a device that needs modules that lands in a debug shell rather than userspace. Blank means “safe to RAM-boot”, which is the ONE trap key here that fails open – so answer it deliberately rather than leaving it.
PORTHOLE_SLOTS_PROBED
Section: PORTHOLE_SLOTS_PROBEDdefault: (unset)
TRAP If the device has no slots leave PORTHOLE_HAS_AB_SLOTS=0 and skip the rest. set by new-device --from-fastboot.
PORTHOLE_HAS_AB_SLOTS
Section: PORTHOLE_HAS_AB_SLOTSdefault: 0
PORTHOLE_ACTIVE_SLOT
Section: PORTHOLE_ACTIVE_SLOTdefault: (unset)
the slot you keep a known-good image in
PORTHOLE_SLOT_FORBIDDEN
Section: PORTHOLE_SLOT_FORBIDDENdefault: (unset)
TRAP a slot with NO good image. porthole
PORTHOLE_BOOT_RETRIES
Section: PORTHOLE_BOOT_RETRIESdefault: (unset)
TRAP set_active arms a slot with N boot
Traps
Section: TrapsPORTHOLE_USB_LIES_AS_FASTBOOT
Section: PORTHOLE_USB_LIES_AS_FASTBOOTdefault: 0
TRAP 1 if lsusb labels the RUNNING pmOS
PORTHOLE_USB_GADGET_ID
Section: PORTHOLE_USB_GADGET_IDdefault: (unset)
“18d1:d001” — the ID it lies with
PORTHOLE_USB_FASTBOOT_ID
Section: PORTHOLE_USB_FASTBOOT_IDdefault: (unset)
the ID in the real bootloader
PORTHOLE_REBOOT_MODE_VIA_SYSCALL
Section: PORTHOLE_REBOOT_MODE_VIA_SYSCALLdefault: 0
PORTHOLE_WATCHDOG_MAX_S
Section: PORTHOLE_WATCHDOG_MAX_Sdefault: (unset)
TRAP hardware ceiling of the SoC watchdog.
PORTHOLE_PANEL_STAYS_DARK
Section: PORTHOLE_PANEL_STAYS_DARKdefault: 0
TRAP 1 while mainline never lights the
Network
Section: NetworkPORTHOLE_NET_DEVICE_IP
Section: PORTHOLE_NET_DEVICE_IPdefault: 172.16.42.1
The pmOS USB gadget defaults. Only change these if the device differs.
PORTHOLE_NET_HOST_IP
Section: PORTHOLE_NET_HOST_IPdefault: 172.16.42.2
Build
Section: BuildPORTHOLE_DTB
Section: PORTHOLE_DTBdefault: (unset)
TK_PMOS_PASSWORD is an environment variable on purpose and must not be set here — it is the postmarketOS rootfs user password and must never be committed. See AGENTS.md section 3 (“Build passwords”) for how to export it. “qcom/msm8998-google-taimen”
PORTHOLE_DTB_FILE
Section: PORTHOLE_DTB_FILEdefault: (unset)
“msm8998-google-taimen.dtb”
PORTHOLE_DEFCONFIG
Section: PORTHOLE_DEFCONFIGdefault: (unset)
The name the build WRITES the config under, not a file that has to exist in the tree. porthole build copies the aport config (PORTHOLE_KCONFIG_FILE) into arch/*/configs/ under this name every run, so a tree where git show HEAD:arch/arm64/configs/<this> is empty is normal and not rot – it cost a session an hour to establish that on the 7.2 branch. “taimen_defconfig”
PORTHOLE_KERNEL_PKG
Section: PORTHOLE_KERNEL_PKGdefault: (unset)
the aport you build; MUST name the same
PORTHOLE_DEVICE_PKG
Section: PORTHOLE_DEVICE_PKGdefault: (unset)
“device-google-taimen”
PORTHOLE_FW_PKG
Section: PORTHOLE_FW_PKGdefault: (unset)
“firmware-google-taimen”
PORTHOLE_KERNEL_BRANCH
Section: PORTHOLE_KERNEL_BRANCHdefault: (unset)
the branch that is the product
PORTHOLE_CMDLINE
Section: PORTHOLE_CMDLINEdefault: (unset)
kernel cmdline for boot-image experiments
PORTHOLE_PKG_REPO_URL
Section: PORTHOLE_PKG_REPO_URLdefault: (unset)
A signed apk repository of this port’s prebuilt packages, if it has one. The workspace hands it to pmbootstrap as mirrors.pmaports_custom and mirrors.systemd_custom and installs the key into config_apk_keys, but only after fetching the indexes anonymously – a private or aarch64-only repository makes every pmbootstrap command abort, see brain/traps/a-package-mirror-needs-a-host-arch-index.md. Empty: none. base URL;
PORTHOLE_PKG_REPO_SYSTEMD_URL
Section: PORTHOLE_PKG_REPO_SYSTEMD_URLdefault: (unset)
the systemd tree’s base URL, empty if none
PORTHOLE_PKG_REPO_KEY
Section: PORTHOLE_PKG_REPO_KEYdefault: (unset)
its public key, relative to this directory;
PORTHOLE_PMAPORTS_FORK_URL
Section: PORTHOLE_PMAPORTS_FORK_URLdefault: (unset)
Set this if PORTHOLE_KERNEL_PKG above is NOT in upstream postmarketOS pmaports – true of most bring-ups, and of any device archived there under a different package name. porthole init’s “clone a fresh one” clones this URL instead of vanilla postmarketOS/pmaports. Leaving it empty when the aport really is missing upstream means every build fails at the first step with “could not read
Display
Section: DisplayPORTHOLE_SCREEN_WIDTH
Section: PORTHOLE_SCREEN_WIDTHdefault: (unset)
PORTHOLE_SCREEN_HEIGHT
Section: PORTHOLE_SCREEN_HEIGHTdefault: (unset)
Boot Image
Section: Boot ImagePORTHOLE_BOOTIMG_HEADER_VERSION
Section: PORTHOLE_BOOTIMG_HEADER_VERSIONdefault: (unset)
From the downstream mkbootimg args or an unpacked stock boot.img. Do NOT guess these: a wrong offset produces a device that does not boot and gives you no diagnostic at all.
PORTHOLE_BOOTIMG_PAGESIZE
Section: PORTHOLE_BOOTIMG_PAGESIZEdefault: (unset)
PORTHOLE_BOOTIMG_BASE
Section: PORTHOLE_BOOTIMG_BASEdefault: (unset)
PORTHOLE_BOOTIMG_KERNEL_OFFSET
Section: PORTHOLE_BOOTIMG_KERNEL_OFFSETdefault: (unset)
PORTHOLE_BOOTIMG_RAMDISK_OFFSET
Section: PORTHOLE_BOOTIMG_RAMDISK_OFFSETdefault: (unset)
PORTHOLE_BOOTIMG_TAGS_OFFSET
Section: PORTHOLE_BOOTIMG_TAGS_OFFSETdefault: (unset)
PORTHOLE_NEEDS_DTBO
Section: PORTHOLE_NEEDS_DTBOdefault: 0
TRAP 1 if the bootloader reads a device-tree
PORTHOLE_DTS_INCLUDES
Section: PORTHOLE_DTS_INCLUDESdefault: (unset)
extra -I paths for porthole verify, space
PORTHOLE_DTS_DEPS
Section: PORTHOLE_DTS_DEPSdefault: (unset)
.dtsi files the board .dts includes, relative
PORTHOLE_MOD_NO_RELOAD
Section: PORTHOLE_MOD_NO_RELOADdefault: (unset)
modules porthole build mod must NEVER unload,
PORTHOLE_DTC_BASELINE
Section: PORTHOLE_DTC_BASELINEdefault: (unset)
where to keep the dtc warning baseline
PORTHOLE_DTC_IGNORE
Section: PORTHOLE_DTC_IGNOREdefault: (unset)
extra dtc checks to tolerate, space separated
PORTHOLE_KERNEL_TREE
Section: PORTHOLE_KERNEL_TREEdefault: (unset)
the kernel checkout, if not
PORTHOLE_ENVKERNEL
Section: PORTHOLE_ENVKERNELdefault: (unset)
path to pmbootstrap’s helpers/envkernel.sh
PORTHOLE_DTBO_IMG
Section: PORTHOLE_DTBO_IMGdefault: (unset)
path, relative to PORTHOLE_WORKDIR
Timing
Section: TimingPORTHOLE_REBOOT_BUDGET_S
Section: PORTHOLE_REBOOT_BUDGET_Sdefault: 120
Measured, not guessed. porthole doctor --bench prints what you actually get. deadline for a normal reboot to come back
PORTHOLE_FASTBOOT_BUDGET_S
Section: PORTHOLE_FASTBOOT_BUDGET_Sdefault: 60
deadline to reach the bootloader
PORTHOLE_STATE_MAX_AGE_S
Section: PORTHOLE_STATE_MAX_AGE_Sdefault: 300
How old a cached device-state reading may be and still be reported as a fact by porthole next. Past this it says nobody has looked recently, rather than claiming the device was never probed.
PORTHOLE_MATRIX_MAX_AGE_S
Section: PORTHOLE_MATRIX_MAX_AGE_Sdefault: 86400
How old a cached porthole matrix reading may be and still let display, suspend or radios report DONE. Past this it reverts to TODO and says to re-run porthole matrix, rather than trusting a claim that could predate the last two reflashes.
PORTHOLE_PROVENANCE_MAX_AGE_S
Section: PORTHOLE_PROVENANCE_MAX_AGE_Sdefault: 86400
How old a cached kernel-provenance reading (written by porthole brief) may be and still let the kernel-provenance milestone report DONE. Past this it reverts to TODO, same reasoning and same 24h default as PORTHOLE_MATRIX_MAX_AGE_S above: both caches describe device state a flash invalidates, and a done from before the last reflash is not a fact.
PORTHOLE_KCONFIG_FILE
Section: PORTHOLE_KCONFIG_FILEdefault: (unset)
The kernel aport config file name, if it is not config-postmarketos-
Serial
Section: SerialPORTHOLE_EARLYCON
Section: PORTHOLE_EARLYCONdefault: (unset)
A UART is the only channel that works before the kernel reaches driver probe, and the only one that says anything when it dies early. porthole serial hardware explains how to get one onto a phone. e.g. “earlycon=msm_serial_dm,0xc1b0000”
PORTHOLE_SERIAL_BAUD
Section: PORTHOLE_SERIAL_BAUDdefault: 115200
Kconfig
Section: KconfigPORTHOLE_KCONFIG_WATCH
Section: PORTHOLE_KCONFIG_WATCHdefault: (unset)
Symbols that MUST survive config regeneration. olddefconfig resolves an unmet dependency by DROPPING the symbol silently, and the feature is then simply missing at runtime with no diagnostic. porthole kconfig diff fails if any of these vanish. e.g. “CONFIG_ARM_SMMU CONFIG_QCOM_SMD_RPM”
