gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1430Shell 145Markdown 87Rust 852973 Definiciones

⎇ fa027e246e93b8f6b42f49fe85690071dad08f6a scripts/probar-firmware-initramfs.sh Shell · 105 líneas · 6.8 KB Historia crudo

feat(instalador): el firmware que el kernel pide ANTES de montar la raiz lo decide la maquina 19df6c148 · sergio ·

1#!/bin/sh
2# probar-firmware-initramfs.sh — ¿entra al initramfs el firmware que ESTE hardware pidió, y sólo ese?
3#
4# Sin root y sin hardware: un `dmesg` de mentira (copiado del arranque real del operador), un árbol
5# de firmware de juguete y un cpio con su `/init`. Lo que se mide es lo que decide si una máquina
6# arranca con red o sin red.
7#
8#   sh scripts/probar-firmware-initramfs.sh
9set -eu
10
11ROOT="$(cd "$(dirname "$0")/.." && pwd)"
12. "$ROOT/scripts/lib/firmware-initramfs.sh"
13
14W=$(mktemp -d); trap 'rm -rf "$W"' EXIT
15fail() { echo "✗ FALLO: $*"; exit 1; }
16
17# ── El dmesg: las tres formas que emite el kernel, más ruido que NO debe casar ─────────────────
18cat > "$W/dmesg.log" <<'EOF'
19[    0.481237] iwlwifi 0000:00:14.3: Detected Intel(R) Wi-Fi 6 AX201 160MHz
20[    0.492003] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-QuZ-a0-hr-b0-77.ucode failed with error -2
21[    0.492101] iwlwifi 0000:00:14.3: no suitable firmware found!
22[    0.501119] i915 0000:00:02.0: Direct firmware load for i915/tgl_dmc_ver2_12.bin failed with error -2
23[    0.511200] platform regulatory.0: firmware: failed to load regulatory.db (-2)
24[    0.521300] r8169 0000:03:00.0: Falling back to sysfs fallback for: rtl_nic/rtl8168h-2.fw
25[    0.600000] usb 1-2: new high-speed USB device number 3 using xhci_hcd
26[    0.610000] EXT4-fs (nvme1n1p2): mounted filesystem with ordered data mode
27EOF
28
29echo "== 1: la lista sale del dmesg, completa y sin ruido =="
30LISTA=$(firmware_pedido_del_dmesg "$W/dmesg.log")
31N=$(printf '%s\n' "$LISTA" | wc -l)
32[ "$N" = 4 ] || { printf '%s\n' "$LISTA"; fail "esperaba 4 pedidos y conté $N"; }
33for esperado in iwlwifi-QuZ-a0-hr-b0-77.ucode i915/tgl_dmc_ver2_12.bin regulatory.db rtl_nic/rtl8168h-2.fw; do
34	printf '%s\n' "$LISTA" | grep -qx "$esperado" || fail "falta «$esperado» en la lista"
35done
36printf '%s\n' "$LISTA" | grep -q "xhci\|EXT4\|Detected\|no suitable" && fail "casó una línea que no es un pedido de firmware"
37echo "  ✓ los 4 pedidos, en los tres formatos, y ninguna línea de ruido"
38
39# ── El árbol de firmware de la imagen y el initramfs de juguete ───────────────────────────────
40mkdir -p "$W/img/lib/firmware/i915" "$W/img/lib/firmware/rtl_nic" "$W/img/lib/firmware/intel/iwlwifi"
41# El wifi vive adentro y se pide por el nombre de la RAÍZ: en la imagen eso es un enlace, igual que
42# los 2415 que `linux-firmware` reconstruye desde WHENCE.
43dd if=/dev/zero of="$W/img/lib/firmware/intel/iwlwifi/iwlwifi-QuZ-a0-hr-b0-77.ucode" bs=1k count=140 2>/dev/null
44ln -s intel/iwlwifi/iwlwifi-QuZ-a0-hr-b0-77.ucode "$W/img/lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode"
45dd if=/dev/zero of="$W/img/lib/firmware/i915/tgl_dmc_ver2_12.bin" bs=1k count=20 2>/dev/null
46dd if=/dev/zero of="$W/img/lib/firmware/regulatory.db" bs=1k count=7 2>/dev/null
47# `rtl_nic/rtl8168h-2.fw` NO se pone: es el caso «el hardware lo pide y la imagen no lo trae».
48
49mkdir -p "$W/ird/bin"
50printf '#!/bin/sh\necho init de juguete\n' > "$W/ird/init"; chmod 755 "$W/ird/init"
51printf 'busybox\n' > "$W/ird/bin/busybox"
52( cd "$W/ird" && find . | cpio -o -H newc --quiet | gzip -9 > "$W/pivote.cpio.gz" )
53ANTES=$(wc -c < "$W/pivote.cpio.gz")
54
55echo "== 2: el injerto pone lo que hay, nombra lo que falta y conserva el /init =="
56SALIDA=$(firmware_al_initramfs "$W/pivote.cpio.gz" "$W/img" "$W/dmesg.log")
57printf '%s\n' "$SALIDA" | sed 's/^/    /'
58echo "$SALIDA" | grep -q "3 blob(s) injertados" || fail "esperaba 3 injertados (el cuarto no está en la imagen)"
59echo "$SALIDA" | grep -q "rtl_nic/rtl8168h-2.fw.*no lo trae" || fail "no nombró el blob que falta"
60
61DENTRO=$(gzip -dc "$W/pivote.cpio.gz" | cpio -t --quiet 2>/dev/null)
62for e in "lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode" "lib/firmware/i915/tgl_dmc_ver2_12.bin" "lib/firmware/regulatory.db" "init" "bin/busybox"; do
63	printf '%s\n' "$DENTRO" | grep -qx "\(\./\)\?$e" || { printf '%s\n' "$DENTRO"; fail "«$e» no quedó dentro del initramfs"; }
64done
65printf '%s\n' "$DENTRO" | grep -q "rtl8168h" && fail "metió un blob que la imagen no tiene"
66echo "  ✓ los 3 adentro, el /init y el busybox intactos, y nada inventado"
67
68# El wifi se pide por el nombre de la raíz y en la imagen es un ENLACE: adentro tiene que ir el
69# CONTENIDO, porque en el initramfs no hay a dónde apuntar. Si viajara como enlace, el driver
70# abriría un symlink roto — que falla igual que un fichero ausente y se diagnostica peor.
71mkdir -p "$W/ver" && ( cd "$W/ver" && gzip -dc "$W/pivote.cpio.gz" | cpio -idm --quiet )
72[ -f "$W/ver/lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode" ] || fail "el .ucode no es un fichero regular adentro"
73[ -L "$W/ver/lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode" ] && fail "viajó como enlace: adentro no hay a dónde apuntar"
74[ "$(wc -c < "$W/ver/lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode")" = "143360" ] || fail "el .ucode llegó truncado"
75echo "  ✓ el blob que en la imagen es un enlace viaja como FICHERO (143360 B)"
76[ "$(wc -c < "$W/pivote.cpio.gz")" -gt "$ANTES" ] || fail "el initramfs no creció"
77[ -r "$W/pivote.cpio.gz.antes-del-firmware" ] || fail "no dejó respaldo del initramfs original"
78echo "  ✓ creció de $ANTES a $(wc -c < "$W/pivote.cpio.gz") bytes, con respaldo del original"
79
80echo "== 3: BRAZO DE CONTROL — una máquina donde no faltó nada no se toca =="
81cat > "$W/dmesg-ok.log" <<'EOF'
82[    0.492003] iwlwifi 0000:00:14.3: loaded firmware version 77.a0a4b1e2.0 op_mode iwlmvm
83[    0.501119] i915 0000:00:02.0: [drm] Finished loading DMC firmware i915/tgl_dmc_ver2_12.bin
84EOF
85( cd "$W/ird" && find . | cpio -o -H newc --quiet | gzip -9 > "$W/limpio.cpio.gz" )
86SUMA_ANTES=$(sha256sum < "$W/limpio.cpio.gz")
87SAL2=$(firmware_al_initramfs "$W/limpio.cpio.gz" "$W/img" "$W/dmesg-ok.log")
88echo "$SAL2" | grep -q "nada que injertar" || { echo "$SAL2"; fail "debió decir que no hay nada que injertar"; }
89[ "$(sha256sum < "$W/limpio.cpio.gz")" = "$SUMA_ANTES" ] || fail "tocó un initramfs que no hacía falta tocar"
90echo "  ✓ sin pedidos fallidos: el initramfs queda BIT A BIT igual"
91
92echo "== 4: lo que no se deja hacer =="
93cat > "$W/dmesg-malo.log" <<'EOF'
94[    0.1] x: Direct firmware load for ../../etc/shadow failed with error -2
95[    0.2] y: Direct firmware load for /etc/passwd failed with error -2
96EOF
97( cd "$W/ird" && find . | cpio -o -H newc --quiet | gzip -9 > "$W/malo.cpio.gz" )
98# ⚠ Con `2>&1`: los avisos de ruta sospechosa van por stderr —son avisos, no salida— y `$(...)`
99# sólo captura stdout. Sin esto el test fallaba sobre un código que hacía lo correcto.
100SAL3=$(firmware_al_initramfs "$W/malo.cpio.gz" "$W/img" "$W/dmesg-malo.log" 2>&1 || true)
101echo "$SAL3" | grep -q "sospechosa" || { echo "$SAL3"; fail "no descartó las rutas con .. ni las absolutas"; }
102echo "  ✓ una ruta con «..» o absoluta se descarta nombrándola (el dmesg es texto, y esto escribe ficheros)"
103
104echo
105echo "✓✓ probar-firmware-initramfs: el firmware que pidió ESTE hardware entra, y sólo ese"