Files
takana/recipes/firmware-tigerlake.toml
SergioandClaude Opus 5 a8077003c4 wireless-regdb: la base regulatoria del WiFi ya no viene en linux-firmware
`firmware-tigerlake` cortaba con «falta regulatory.db», y no era un fallo suyo: upstream sacó ese
fichero del tarball de linux-firmware y hoy sólo se publica en su propio proyecto de kernel.org.
Comprobado sobre el artefacto sellado de linux-firmware 20260910: `find -name "regulatory*"` no
devuelve nada.

Lo que pasa sin ella no es «no hay WiFi», que sería fácil de notar: cfg80211 arranca, la tarjeta
asocia, y se queda en el dominio `world` —pierde canales de 5 y 6 GHz y emite a la potencia mínima—.
Un WiFi que funciona y va mal.

La receta NO compila nada: el `make` del proyecto regenera la db y la firma con otra clave, y el
kernel valida contra la que lleva compilada, así que regenerarla la rompería. Copia `regulatory.db` y
su `.p7s` tal cual, y corta si la firma falta —sin firma, cfg80211 ignora la base y volvemos al
dominio world, que es justo lo que veníamos a arreglar—.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 21:31:48 +00:00

130 lines
7.5 KiB
TOML

# firmware-tigerlake — los blobs que pide EXACTAMENTE la laptop del usuario, y nada más.
#
# ══ QUÉ MÁQUINA ES ═════════════════════════════════════════════════════════════════════════════
# Medido el 2026-09-16 sobre el metal real (`lspci -nn` + `lsmod`):
#
# 00:02.0 Intel TigerLake-LP GT2 [Iris Xe Graphics] [8086:9a49] ⇒ i915 / xe
# 00:14.3 Intel Wi-Fi 6 AX201 [8086:a0f0] ⇒ iwlwifi
# 00:1f.3 Intel 500 Series On-Package HD Audio [8086:a0c8] ⇒ snd_sof_pci_intel_tgl
#
# Es la misma máquina para la que ya se escribió `scripts/metal-firmware.sh`, que nombra estas tres
# familias y dice por qué: «son las tres familias de blobs que el metal necesita y ninguna se
# construye desde fuente». Esta receta es ese script convertido en artefacto sellado, con el
# firmware viniendo de `linux-firmware` pineado en vez de `/lib/firmware` del host.
#
# ══ POR QUÉ DERIVADA Y NO UN SEGUNDO FETCH ═════════════════════════════════════════════════════
# El árbol completo son ~2 GB extraídos. Esta máquina usa unos 25 MB de eso. Derivar de
# `linux-firmware` cuesta segundos y no mueve su hash, igual que `atuq` sobre `firefox` (SDD 26).
# Otro metal = otra receta derivada de dos líneas, no otro tarball de 648 MB.
#
# ══ SIN COMPRIMIR, A PROPÓSITO ═════════════════════════════════════════════════════════════════
# Los blobs se instalan planos (`.ucode`, `.bin`, `.ri`), no `.zst`. El kernel `linux-metal` **no
# habilita `FW_LOADER_COMPRESS`**, así que un firmware comprimido no se carga y el fallo aparece
# como «no WiFi» sin una línea que lo explique. Es la razón que ya está escrita en
# `metal-firmware.sh` y se repite acá porque es justo el tipo de cosa que se pierde al refactorizar.
#
# ⚠ **PUNTO DE PARTIDA, NO SELLADA.** Escrita desde el laptop, que no tiene lab ni store. Las
# aserciones de abajo están puestas para que el PRIMER BUILD falle ruidoso en vez de producir un
# artefacto flaco: un /lib/firmware a medias no falla al construir, falla meses después en el metal
# como «no hay WiFi» y nadie lo asocia con esta receta.
name = "firmware-tigerlake"
version = "20260910" # sigue a linux-firmware: no tiene versión propia
license = "LicenseRef-linux-firmware-various"
[source]
# No tiene fuente propia: todo su contenido sale de la dep. Se apunta al árbol vacío del repo por
# la misma razón que `atuq` usa `source.dir` — la identidad del artefacto son sus fases + su dep,
# y el `ArtifactHash` ya las incluye.
dir = "firmware-tigerlake"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
strip_debug = false
flags = []
[build.phases]
configure = "echo 'firmware-tigerlake: nada que configurar'"
compile = "echo 'firmware-tigerlake: nada que compilar — son blobs de la dep'"
install = '''
set -e
SRC=/lib/firmware
DST=/out/lib/firmware
# ── LAS ASERCIONES VAN PRIMERO (CLAUDE.md §3) ────────────────────────────────────────────────
# Un derivado que no encuentra su base produciría un /lib/firmware con cuatro ficheros, `Store::has`
# lo daría por presente, y el fallo saldría el día del arranque en metal como «no hay WiFi».
[ -d "$SRC" ] || { echo "firmware-tigerlake: no está el árbol de linux-firmware en $SRC" >&2; exit 1; }
[ -f "$SRC/WHENCE" ] || { echo "firmware-tigerlake: falta WHENCE — la dep no se materializó entera" >&2; exit 1; }
mkdir -p "$DST/intel/iwlwifi" "$DST/i915" "$DST/intel/sof" "$DST/intel/sof-tplg"
# ── 1. WiFi: Intel AX201 ─────────────────────────────────────────────────────────────────────
# El driver elige la API MÁS ALTA que soporta, así que se copian TODAS las revisiones de las dos
# familias y no sólo la última: qué número pide depende del kernel, no de nosotros.
# Upstream movió los .ucode a intel/iwlwifi/ y dejó symlinks en la raíz; se cubren los dos sitios.
wifi=0
for pat in "iwlwifi-QuZ-a0-hr-b0-*.ucode" "iwlwifi-cc-a0-*.ucode"; do
for d in "$SRC/intel/iwlwifi" "$SRC"; do
for f in "$d"/$pat; do
[ -f "$f" ] || continue
cp -L "$f" "$DST/intel/iwlwifi/" && wifi=$((wifi+1))
done
done
done
# El driver busca en /lib/firmware antes que en intel/iwlwifi ⇒ se dejan los dos caminos.
for f in "$DST"/intel/iwlwifi/*.ucode; do
[ -f "$f" ] && cp -L "$f" "$DST/" || true
done
[ "$wifi" -gt 0 ] || { echo "firmware-tigerlake: 0 blobs de iwlwifi — el AX201 no va a asociar" >&2; exit 1; }
# regulatory.db: cfg80211 lo verifica contra la clave built-in del kernel. Sin él el WiFi queda
# limitado al dominio world y en la práctica no ve la mitad de los canales.
for f in regulatory.db regulatory.db.p7s; do
[ -f "$SRC/$f" ] && cp -L "$SRC/$f" "$DST/"
done
[ -f "$DST/regulatory.db" ] || { echo "firmware-tigerlake: falta regulatory.db" >&2; exit 1; }
# ── 2. Gráficos: i915 / xe en TigerLake ──────────────────────────────────────────────────────
# DMC = display microcontroller (sin él no hay ahorro de energía del display ni, en algunos
# kernels, modeset fiable). GuC/HuC = submission y decodificación por hardware.
gfx=0
for f in "$SRC"/i915/tgl_*.bin; do
[ -f "$f" ] || continue
cp -L "$f" "$DST/i915/" && gfx=$((gfx+1))
done
[ "$gfx" -gt 0 ] || { echo "firmware-tigerlake: 0 blobs de i915 tgl — el display va a ir sin DMC" >&2; exit 1; }
# ── 3. Audio: SOF en el DSP de TigerLake ─────────────────────────────────────────────────────
# El SOF **no viene en linux-firmware** — se midió sobre el tarball (0 coincidencias con
# `intel/sof`) y por eso existe `recipes/sof-firmware.toml`, que es dep de esta receta. Acá sólo se
# recoge lo que aquélla ya dejó en su sitio: es la misma jugada que con la dep de linux-firmware.
snd=0
if [ -d "$SRC/intel/sof" ]; then
mkdir -p "$DST/intel/sof/intel-signed"
for f in "$SRC"/intel/sof/intel-signed/sof-tgl*.ri; do
[ -f "$f" ] || continue
cp "$f" "$DST/intel/sof/intel-signed/"
ln -sf "intel-signed/$(basename "$f")" "$DST/intel/sof/$(basename "$f")"
snd=$((snd+1))
done
fi
if [ -d "$SRC/intel/sof-tplg" ]; then
for f in "$SRC"/intel/sof-tplg/sof-hda-generic*.tplg; do
[ -f "$f" ] && cp -L "$f" "$DST/intel/sof-tplg/" && snd=$((snd+1))
done
fi
[ "$snd" -gt 0 ] || { echo "firmware-tigerlake: 0 blobs de SOF — ¿se materializó la dep sof-firmware?" >&2; exit 1; }
n=$(find "$DST" -type f | wc -l)
echo "firmware-tigerlake: $n ficheros (wifi=$wifi i915=$gfx sof=$snd)"
'''
[deps]
# `wireless-regdb` entró el 2026-09-17: `regulatory.db` **ya no viene en linux-firmware** —upstream
# lo sacó, es un proyecto aparte de kernel.org— y esta receta cortaba con «falta regulatory.db».
# Como las deps se materializan en el mismo `/lib/firmware`, el bucle de copia lo encuentra sin
# tocar una línea del guion.
build = ["linux-firmware", "sof-firmware", "wireless-regdb", "busybox"]