diff --git a/mkosi.profiles/surface-arm64/ADR.md b/mkosi.profiles/surface-arm64/ADR.md new file mode 100644 index 00000000..ba6797d5 --- /dev/null +++ b/mkosi.profiles/surface-arm64/ADR.md @@ -0,0 +1,22 @@ +# ADR: Surface ARM64 Snapdragon X Elite - Design Decisions + +## 1. Upstream kernel (no linux-surface) +x1e80100 DTBs (romulus13/15) merged upstream since 6.12. +linux-surface provides no aarch64 packages. +Trade-off: camera (MIPI/IPU6) and full audio non-functional until upstreamed. +Source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom + +## 2. SignExpectedPcr=no +Qualcomm fTPM unavailable during initrd phase -> PCR measurement hang. +Disk encryption works without PCR binding; policy just less boot-state-tied. +Source: linux-surface/linux-surface#1590, community testing. + +## 3. sbctl firstboot, no MokManager +Surface NX Mode freezes MokManager at UEFI logo. +ParticleOS UKI + systemd-boot never touches shim/MokManager. +sbctl generates keys on firstboot; PK exported for direct UEFI db enrollment. +Source: https://github.com/linux-surface/linux-surface/issues/1590 + +## 4. s2idle only (SuspendState=freeze) +Snapdragon X Elite PSCI/ACPI exposes only s2idle on Linux; S3 unavailable. +Trade-off: higher suspend battery drain than Windows. diff --git a/mkosi.profiles/surface-arm64/README.md b/mkosi.profiles/surface-arm64/README.md new file mode 100644 index 00000000..9c5a4738 --- /dev/null +++ b/mkosi.profiles/surface-arm64/README.md @@ -0,0 +1,39 @@ +# Surface ARM64 - Snapdragon X Elite (Surface Laptop 7) + +ParticleOS profile for Surface Laptop 7 (x1e80100, arm64). +Design priorities: bootable images first, TPM enrollment quirks resolved, upstream kernel only. +See ADR.md for full rationale. + +## Hardware status (kernel 6.15+) + +| Component | Status | Notes | +|---|---|---| +| Boot (systemd-boot + UKI) | Works | Direct UEFI, no shim | +| CPU (Oryon 12-core) | Works | Full cpufreq | +| NVMe (PCIe Gen 4) | Works | | +| Display (eDP 120Hz) | Works | Freedreno/DRM | +| WiFi (WCN785x/ath12k) | Works | Needs linux-firmware blobs | +| USB-A / USB-C | Works | USB4/TB limited | +| Suspend (s2idle) | Works | No S3; higher drain | +| TPM2 disk encryption | Works | No PCR binding (fTPM quirk) | +| Secure Boot | Manual setup | See below | +| Audio | Partial | Windows firmware blobs needed | +| Camera | Not working | IPU6/MIPI unmerged | +| Touchscreen | Not working | HID-over-SPI unmerged | + +## Build + + mkosi --profile obs-repos --profile desktop --profile gnome --profile surface-arm64 build + +Cross-building from x86-64: requires qemu-user-static + binfmt-misc. + +## Secure Boot enrollment + +1. Disable Secure Boot in Surface UEFI (Volume Up + Power -> Security). +2. Boot ParticleOS. surface-sb-enroll.service runs on first boot. +3. cat /var/lib/surface-sb-enroll/ENROLL_SECURE_BOOT.md +4. Enroll ParticleOS-PK.cer in Surface UEFI. +5. Re-enable Secure Boot. + +MokManager never used. Surface NX Mode freezes it. +Ref: https://github.com/linux-surface/linux-surface/issues/1590 diff --git a/mkosi.profiles/surface-arm64/mkosi.conf b/mkosi.profiles/surface-arm64/mkosi.conf new file mode 100644 index 00000000..3f4ccbf2 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.conf @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Surface Laptop 7 / Snapdragon X Elite (arm64) profile +# Activate with: mkosi --profile surface-arm64 +# +# TPM/Secure Boot design notes: +# - SignExpectedPcr=no: Qualcomm fTPM unavailable during initrd PCR measurements. +# Disabling avoids boot-time hang. Source: linux-surface/issues/1590 +# - NX Mode quirk: Surface UEFI NX Mode breaks MokManager. Profile uses +# UKI + systemd-boot (no shim). Enrollment via sbctl + direct UEFI db. +# - Upstream kernel only - bootability over full hardware support. + +[Match] +Profile=surface-arm64 + +[Distribution] +Architecture=arm64 + +[Validation] +# Inherit SecureBoot=yes from root; override PCR signing (Qualcomm fTPM quirk). +SignExpectedPcr=no + +[Content] +Packages= + qrtr + pd-mapper + linux-firmware + tpm2-tools + tpm2-tss + sbctl + efivar + efitools + +# Snapdragon X Elite kernel command line +# clk_ignore_unused/pd_ignore_unused prevent clock/power-domain framework from +# disabling unattached clocks during init - critical on Qualcomm bringup. +# Source: Linaro Snapdragon X Elite bring-up documentation +KernelCommandLine= + clk_ignore_unused + pd_ignore_unused + +# DRM, HID, and TPM CRB modules needed in initrd +KernelInitrdModules=/drivers/gpu/drm + /drivers/hid/hid-multitouch.ko + /drivers/hid/hid-generic.ko + /drivers/tpm/tpm_crb.ko diff --git a/mkosi.profiles/surface-arm64/mkosi.conf.d/audio.conf b/mkosi.profiles/surface-arm64/mkosi.conf.d/audio.conf new file mode 100644 index 00000000..8292c097 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.conf.d/audio.conf @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Surface Laptop 7 audio DSP additions for Snapdragon X Elite +# Extends the base surface-arm64 profile. + +[Match] +Profile=surface-arm64 + +[Content] +# Qualcomm LPASS/Q6DSP audio stack +Packages= + alsa-utils + alsa-ucm-conf + pipewire + wireplumber + pipewire-pulseaudio diff --git a/mkosi.profiles/surface-arm64/mkosi.conf.d/debian/mkosi.conf b/mkosi.profiles/surface-arm64/mkosi.conf.d/debian/mkosi.conf new file mode 100644 index 00000000..57bb78b6 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.conf.d/debian/mkosi.conf @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Debian ARM64 for Snapdragon X Elite. +# Requires debian unstable for kernel >= 6.12 (x1e80100 DTB support). + +[Match] +Distribution=debian +Architecture=arm64 + +[Distribution] +Release=unstable + +[Content] +Packages= + linux-image-arm64 + linux-headers-arm64 + firmware-qcom-soc + firmware-linux-nonfree + tpm2-tools + tpm2-abrmd + sbctl diff --git a/mkosi.profiles/surface-arm64/mkosi.conf.d/fedora/mkosi.conf b/mkosi.profiles/surface-arm64/mkosi.conf.d/fedora/mkosi.conf new file mode 100644 index 00000000..9f13ea8f --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.conf.d/fedora/mkosi.conf @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Fedora ARM64 for Snapdragon X Elite. +# Fedora rawhide aarch64 ships x1e80100-microsoft-romulus13/15.dtb since kernel 6.12. +# Source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus13.dts + +[Match] +Distribution=fedora +Architecture=arm64 + +[Content] +Packages= + kernel-core + kernel-modules + kernel-modules-extra + qrtr-tools + pd-mapper + qcom-firmware diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64-audio.conf b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64-audio.conf new file mode 100644 index 00000000..6ae8f466 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64-audio.conf @@ -0,0 +1,12 @@ +# Audio module options for Snapdragon X Elite (Surface Laptop 7) +# Supplements surface-arm64.conf. + +# snd_soc_sc8280xp: Qualcomm LPASS driver family, upstream since kernel 6.11. +options snd_soc_sc8280xp auto_soc=1 + +# Q6ASM: Q6 Audio Stream Manager, needed for DSP firmware loading via QRTR. +options snd_soc_qcom_q6asm debug=0 + +# HDMI/DP audio via USB4 (Surface Laptop 7 display output) +install snd_soc_hdmi_codec /sbin/modprobe --ignore-install snd_soc_hdmi_codec && \ + /sbin/modprobe snd_soc_sc8280xp_common diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64.conf b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64.conf new file mode 100644 index 00000000..d718fcce --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/modprobe.d/surface-arm64.conf @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Module options for Snapdragon X Elite (Surface Laptop 7) + +# Force CRB interface for Qualcomm fTPM. +# X Elite fTPM registers as a CRB device; tpm_tis/tpm_tis_spi conflict with it. +# Source: TCG TPM PC Client Firmware Profile specification +blacklist tpm_tis +blacklist tpm_tis_spi +options tpm_crb force_locality=0 + +# No PC speaker hardware on Snapdragon +blacklist pcspkr +blacklist snd_pcsp + +# Increase QRTR socket buffer for Qualcomm subsystem IPC +options qrtr recv_buf_size=131072 diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/surface/sb-enroll.sh b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/surface/sb-enroll.sh new file mode 100644 index 00000000..4add6094 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/surface/sb-enroll.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# Surface Laptop 7 Secure Boot enrollment helper +# Source: https://github.com/Foxboron/sbctl +# Source: https://github.com/linux-surface/linux-surface/issues/1590 + +set -euo pipefail + +INSTRUCTIONS_DIR=/var/lib/surface-sb-enroll +mkdir -p "$INSTRUCTIONS_DIR" + +echo "[surface-sb-enroll] Generating sbctl Secure Boot keys..." +sbctl create-keys + +for uki in /efi/EFI/Linux/*.efi /boot/EFI/Linux/*.efi; do + [ -f "$uki" ] || continue + echo "[surface-sb-enroll] Signing: $uki" + sbctl sign "$uki" +done + +if [ -f /var/lib/sbctl/keys/PK/PK.pem ]; then + openssl x509 -in /var/lib/sbctl/keys/PK/PK.pem -outform DER -out "$INSTRUCTIONS_DIR/ParticleOS-PK.cer" + echo "[surface-sb-enroll] Platform Key exported: $INSTRUCTIONS_DIR/ParticleOS-PK.cer" +fi + +cat > "$INSTRUCTIONS_DIR/ENROLL_SECURE_BOOT.md" << HEREDOC +# ParticleOS Secure Boot Enrollment - Surface Laptop 7 + +Keys generated. To enable Secure Boot: + +1. Copy Platform Key to EFI partition: + cp /var/lib/surface-sb-enroll/ParticleOS-PK.cer /efi/ParticleOS-PK.cer + +2. Enter Surface UEFI: hold Volume Up + Power while powering on. + +3. Navigate to Security -> Secure Boot -> disable, then Reset to Setup Mode. + +4. Enroll Platform Key from file (select ParticleOS-PK.cer). + OR from Linux (SB disabled): sbctl enroll-keys --microsoft + +5. Re-enable Secure Boot. Firmware should show Custom Key Configuration. + +Verify: bootctl status | grep -i secure && sbctl status + +WHY NOT MokManager: Surface NX Mode causes MokManager to hang (black screen). +ParticleOS uses UKI + systemd-boot with no shim, so MokManager is never invoked. +Ref: https://github.com/linux-surface/linux-surface/issues/1590 +HEREDOC + +echo "[surface-sb-enroll] Done. Read: $INSTRUCTIONS_DIR/ENROLL_SECURE_BOOT.md" diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/sleep.conf.d/surface-arm64.conf b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/sleep.conf.d/surface-arm64.conf new file mode 100644 index 00000000..5a868a4a --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/sleep.conf.d/surface-arm64.conf @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Snapdragon X Elite: S3 (deep) not supported. s2idle (freeze) only. +# Source: Phoronix Surface Laptop 7 Linux coverage +[Sleep] +SuspendState=freeze +SuspendMode= diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system-preset/15-particleos-surface-arm64.preset b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system-preset/15-particleos-surface-arm64.preset new file mode 100644 index 00000000..c10f5986 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system-preset/15-particleos-surface-arm64.preset @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +enable qrtr-ns.service +enable pd-mapper.service +enable surface-sb-enroll.service diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/pd-mapper.service b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/pd-mapper.service new file mode 100644 index 00000000..e9fb607c --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/pd-mapper.service @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Qualcomm Protection Domain Mapper +# Needed for WiFi (ath12k) and audio DSP firmware bring-up. +# Source: https://github.com/andersson/pd-mapper + +[Unit] +Description=Qualcomm Protection Domain Mapper +After=qrtr-ns.service +Requires=qrtr-ns.service + +[Service] +Type=simple +ExecStart=/usr/libexec/pd-mapper +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/qrtr-ns.service b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/qrtr-ns.service new file mode 100644 index 00000000..aec03296 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/qrtr-ns.service @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Qualcomm IPC Router Namespace daemon +# Required for WiFi (ath12k/WCN785x), audio DSP, modem subsystem IPC. +# Source: https://github.com/andersson/qrtr + +[Unit] +Description=Qualcomm IPC Router Namespace Daemon +After=local-fs.target +Before=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/qrtr-ns +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/surface-sb-enroll.service b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/surface-sb-enroll.service new file mode 100644 index 00000000..f31aa3f0 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/lib/systemd/system/surface-sb-enroll.service @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Secure Boot enrollment helper - Surface Laptop 7 / Snapdragon X Elite +# +# Runs once on first boot. Generates sbctl keys, signs UKIs, writes +# enrollment instructions. No MokManager - Surface NX Mode firmware +# freezes when MokManager loads. UKI + systemd-boot needs no shim. +# Source: https://github.com/linux-surface/linux-surface/issues/1590 + +[Unit] +Description=Surface Secure Boot Key Enrollment (First Boot) +After=local-fs.target +ConditionFirstBoot=yes +ConditionPathExists=!/var/lib/sbctl/guid + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/surface/sb-enroll.sh + +[Install] +WantedBy=first-boot-complete.target diff --git a/mkosi.profiles/surface-arm64/mkosi.extra/usr/share/wireplumber/main.lua.d/91-surface-arm64-qcom.lua b/mkosi.profiles/surface-arm64/mkosi.extra/usr/share/wireplumber/main.lua.d/91-surface-arm64-qcom.lua new file mode 100644 index 00000000..ee8f6360 --- /dev/null +++ b/mkosi.profiles/surface-arm64/mkosi.extra/usr/share/wireplumber/main.lua.d/91-surface-arm64-qcom.lua @@ -0,0 +1,14 @@ +-- WirePlumber policy for Qualcomm Q6DSP on Snapdragon X Elite +-- /usr/share/wireplumber/main.lua.d/91-surface-arm64-qcom.lua + +rule = { + matches = { + { { "node.name", "matches", "alsa_output.platform*sc8280xp*" } }, + }, + apply_properties = { + ["audio.rate"] = 48000, + ["audio.format"] = "S16LE", + ["resample.quality"] = 4, + ["priority.session"] = 1100, + }, +}