diff --git a/install/hardware/apple/fix-t2.sh b/install/hardware/apple/fix-t2.sh index 16561712..904da06f 100644 --- a/install/hardware/apple/fix-t2.sh +++ b/install/hardware/apple/fix-t2.sh @@ -8,15 +8,10 @@ if lspci -nn | grep -q "106b:180[12]"; then linux-t2-headers \ apple-t2-audio-config \ apple-bcm-firmware \ - t2fanrd \ - tiny-dfr + t2fanrd - # Add user to video group (required for tiny-dfr to access /dev/dri devices) - usermod -aG video "$OMARCHY_INSTALL_USER" - - # Enable T2 services + # Enable T2 fan control systemctl enable t2fanrd.service - systemctl enable tiny-dfr.service mkdir -p /etc/modules-load.d { @@ -40,14 +35,22 @@ EOF mkdir -p /etc/limine-entry-tool.d cat > /etc/limine-entry-tool.d/t2-mac.conf <<'EOF' # Generated by Omarchy installer for T2 Mac support -KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pcie_ports=compat" +KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pm_async=off mem_sleep_default=deep" EOF + # t2fanrd only reads sections for detected fans, so Fan2 is harmless on + # single-fan models and required on dual-fan MacBooks. cat > /etc/t2fand.conf <<'EOF' [Fan1] low_temp=55 high_temp=75 speed_curve=linear always_full_speed=false + +[Fan2] +low_temp=55 +high_temp=75 +speed_curve=linear +always_full_speed=false EOF fi diff --git a/install/omarchy-other.packages b/install/omarchy-other.packages index 9cc298ba..02ac645e 100644 --- a/install/omarchy-other.packages +++ b/install/omarchy-other.packages @@ -71,7 +71,6 @@ apple-t2-audio-config linux-t2 linux-t2-headers t2fanrd -tiny-dfr # Framework 16 qmk-hid diff --git a/migrations/1785944594.sh b/migrations/1785944594.sh new file mode 100644 index 00000000..7f290e11 --- /dev/null +++ b/migrations/1785944594.sh @@ -0,0 +1,57 @@ +echo "Update T2 Mac suspend, Touch Bar, and fan defaults" + +if ! lspci -nn | grep -q "106b:180[12]"; then + exit 0 +fi + +limine_conf="${OMARCHY_T2_LIMINE_CONF:-/etc/limine-entry-tool.d/t2-mac.conf}" +fan_conf="${OMARCHY_T2_FAN_CONF:-/etc/t2fand.conf}" +running_cmdline="${OMARCHY_T2_RUNNING_CMDLINE:-/proc/cmdline}" +repair_marker="${OMARCHY_T2_REPAIR_MARKER:-/var/lib/omarchy/migrations/1785944594}" +needs_limine_rebuild=0 + +if [[ -f $limine_conf ]] && grep -q 'pcie_ports=compat' "$limine_conf"; then + sudo sed -i \ + 's/pcie_ports=compat/pm_async=off mem_sleep_default=deep/' \ + "$limine_conf" + needs_limine_rebuild=1 +fi + +# t2fanrd reads one section per detected fan and fails when a section is +# missing. Extra sections are ignored, so this also remains safe on one-fan +# models. +if [[ -f $fan_conf ]] && ! grep -Eq '^[[:space:]]*\[Fan2\][[:space:]]*$' "$fan_conf"; then + sudo tee -a "$fan_conf" >/dev/null <<'EOF' + +[Fan2] +low_temp=55 +high_temp=75 +speed_curve=linear +always_full_speed=false +EOF +fi + +# The kernel's built-in Boot Camp-style Touch Bar works without tiny-dfr. The +# optional daemon holds stale device descriptors across suspend with t2bce. +if omarchy-pkg-present tiny-dfr; then + sudo systemctl disable --now tiny-dfr.service || true + omarchy-pkg-drop tiny-dfr +fi + +# The current kernel keeps its old command line until reboot. Record a +# successful machine-wide rebuild so another user's migration does not repeat +# it before then, while a missing marker still retries an interrupted rebuild. +if [[ -f $limine_conf ]] && + [[ ! -e $repair_marker ]] && + grep -q 'pm_async=off' "$limine_conf" && + grep -q 'mem_sleep_default=deep' "$limine_conf" && + { [[ ! -r $running_cmdline ]] || + ! grep -Eq '(^| )pm_async=off( |$)' "$running_cmdline" || + ! grep -Eq '(^| )mem_sleep_default=deep( |$)' "$running_cmdline"; }; then + needs_limine_rebuild=1 +fi + +if (( needs_limine_rebuild )); then + sudo limine-mkinitcpio + sudo install -Dm644 /dev/null "$repair_marker" +fi diff --git a/test/shell.d/t2-hardware-test.sh b/test/shell.d/t2-hardware-test.sh new file mode 100644 index 00000000..cd80468c --- /dev/null +++ b/test/shell.d/t2-hardware-test.sh @@ -0,0 +1,181 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +fix_t2="$ROOT/install/hardware/apple/fix-t2.sh" +other_packages="$ROOT/install/omarchy-other.packages" +migration="$ROOT/migrations/1785944594.sh" + +grep -Fq 'KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pm_async=off mem_sleep_default=deep"' "$fix_t2" || + fail "T2 setup installs the suspend kernel parameters" +! grep -q 'pcie_ports=compat' "$fix_t2" || + fail "T2 setup drops the obsolete PCIe compatibility parameter" +(( $(grep -Ec '^\[Fan[12]\]$' "$fix_t2") == 2 )) || + fail "T2 setup configures both possible MacBook fans" +(( $(grep -c '^speed_curve=linear$' "$fix_t2") == 2 )) || + fail "T2 setup preserves the tuned linear curve for both fans" +! grep -q 'tiny-dfr' "$fix_t2" || + fail "T2 setup leaves optional Touch Bar customization uninstalled" +! grep -qx 'tiny-dfr' "$other_packages" || + fail "the ISO no longer caches tiny-dfr" +pass "fresh T2 setup uses t2bce-compatible suspend, fan, and Touch Bar defaults" + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +stub_bin="$test_tmp/bin" +calls="$test_tmp/calls.log" +mkdir -p "$stub_bin" +: >"$calls" + +cat >"$stub_bin/lspci" <<'SH' +#!/bin/bash + +if (( ${T2_HARDWARE:-0} == 1 )); then + echo '01:00.0 Bridge [0680]: Apple Inc. T2 Security Chip [106b:1801]' +fi +SH + +cat >"$stub_bin/sudo" <<'SH' +#!/bin/bash + +printf 'sudo' >>"$TEST_LOG" +printf '\t%s' "$@" >>"$TEST_LOG" +printf '\n' >>"$TEST_LOG" +"$@" +SH + +cat >"$stub_bin/systemctl" <<'SH' +#!/bin/bash + +printf 'systemctl' >>"$TEST_LOG" +printf '\t%s' "$@" >>"$TEST_LOG" +printf '\n' >>"$TEST_LOG" +SH + +cat >"$stub_bin/omarchy-pkg-present" <<'SH' +#!/bin/bash + +(( ${TINY_DFR_INSTALLED:-0} == 1 )) +SH + +cat >"$stub_bin/omarchy-pkg-drop" <<'SH' +#!/bin/bash + +printf 'omarchy-pkg-drop' >>"$TEST_LOG" +printf '\t%s' "$@" >>"$TEST_LOG" +printf '\n' >>"$TEST_LOG" +SH + +cat >"$stub_bin/limine-mkinitcpio" <<'SH' +#!/bin/bash + +echo 'limine-mkinitcpio' >>"$TEST_LOG" +SH + +chmod +x "$stub_bin"/* + +limine_conf="$test_tmp/t2-mac.conf" +fan_conf="$test_tmp/t2fand.conf" +running_cmdline="$test_tmp/cmdline" +repair_marker="$test_tmp/t2-repair-complete" + +cat >"$limine_conf" <<'EOF' +# Generated by Omarchy installer for T2 Mac support +KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pcie_ports=compat" +EOF + +cat >"$fan_conf" <<'EOF' +[Fan1] +low_temp=55 +high_temp=75 +speed_curve=linear +always_full_speed=false +EOF + +echo 'quiet splash intel_iommu=on iommu=pt pcie_ports=compat' >"$running_cmdline" + +PATH="$stub_bin:$PATH" \ + TEST_LOG="$calls" \ + T2_HARDWARE=1 \ + TINY_DFR_INSTALLED=1 \ + OMARCHY_T2_LIMINE_CONF="$limine_conf" \ + OMARCHY_T2_FAN_CONF="$fan_conf" \ + OMARCHY_T2_RUNNING_CMDLINE="$running_cmdline" \ + OMARCHY_T2_REPAIR_MARKER="$repair_marker" \ + bash -euo pipefail "$migration" >/dev/null + +grep -Fq 'KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pm_async=off mem_sleep_default=deep"' "$limine_conf" || + fail "T2 migration updates the Limine suspend parameters" +! grep -q 'pcie_ports=compat' "$limine_conf" || + fail "T2 migration removes the obsolete PCIe compatibility parameter" +(( $(grep -Ec '^[[:space:]]*\[Fan2\][[:space:]]*$' "$fan_conf") == 1 )) || + fail "T2 migration adds exactly one second-fan section" +grep -Fq $'systemctl\tdisable\t--now\ttiny-dfr.service' "$calls" || + fail "T2 migration disables tiny-dfr" +grep -Fq $'omarchy-pkg-drop\ttiny-dfr' "$calls" || + fail "T2 migration removes tiny-dfr" +grep -Fxq 'limine-mkinitcpio' "$calls" || + fail "T2 migration rebuilds the boot image" +[[ -f $repair_marker ]] || fail "T2 migration records the machine-wide repair" +pass "T2 migration repairs existing installs" + +: >"$calls" + +PATH="$stub_bin:$PATH" \ + TEST_LOG="$calls" \ + T2_HARDWARE=1 \ + TINY_DFR_INSTALLED=0 \ + OMARCHY_T2_LIMINE_CONF="$limine_conf" \ + OMARCHY_T2_FAN_CONF="$fan_conf" \ + OMARCHY_T2_RUNNING_CMDLINE="$running_cmdline" \ + OMARCHY_T2_REPAIR_MARKER="$repair_marker" \ + bash -euo pipefail "$migration" >/dev/null + +(( $(grep -Ec '^[[:space:]]*\[Fan2\][[:space:]]*$' "$fan_conf") == 1 )) || + fail "T2 migration remains idempotent" +[[ ! -s $calls ]] || fail "an already repaired T2 install is left unchanged" "$(cat "$calls")" +pass "T2 migration is machine-idempotent before reboot" + +rm -f "$repair_marker" +: >"$calls" + +PATH="$stub_bin:$PATH" \ + TEST_LOG="$calls" \ + T2_HARDWARE=1 \ + TINY_DFR_INSTALLED=0 \ + OMARCHY_T2_LIMINE_CONF="$limine_conf" \ + OMARCHY_T2_FAN_CONF="$fan_conf" \ + OMARCHY_T2_RUNNING_CMDLINE="$running_cmdline" \ + OMARCHY_T2_REPAIR_MARKER="$repair_marker" \ + bash -euo pipefail "$migration" >/dev/null + +grep -Fxq 'limine-mkinitcpio' "$calls" || + fail "T2 migration retries an interrupted boot image rebuild" +[[ -f $repair_marker ]] || fail "a retried T2 repair records completion" +! grep -Eq $'^(sudo\t)?(sed|tee|systemctl|omarchy-pkg-drop)(\t|$)' "$calls" || + fail "T2 rebuild retry leaves completed repair steps alone" "$(cat "$calls")" +pass "T2 migration retries an interrupted boot image rebuild" + +cat >"$limine_conf" <<'EOF' +KERNEL_CMDLINE[default]+=" intel_iommu=on iommu=pt pcie_ports=compat" +EOF +printf '[Fan1]\n' >"$fan_conf" +: >"$calls" + +PATH="$stub_bin:$PATH" \ + TEST_LOG="$calls" \ + T2_HARDWARE=0 \ + TINY_DFR_INSTALLED=1 \ + OMARCHY_T2_LIMINE_CONF="$limine_conf" \ + OMARCHY_T2_FAN_CONF="$fan_conf" \ + OMARCHY_T2_RUNNING_CMDLINE="$running_cmdline" \ + OMARCHY_T2_REPAIR_MARKER="$repair_marker" \ + bash -euo pipefail "$migration" >/dev/null + +grep -q 'pcie_ports=compat' "$limine_conf" || fail "non-T2 Limine configuration is unchanged" +! grep -q '\[Fan2\]' "$fan_conf" || fail "non-T2 fan configuration is unchanged" +[[ ! -s $calls ]] || fail "non-T2 systems skip the repair" "$(cat "$calls")" +pass "T2 migration skips unrelated hardware"