Síntoma en metal ajeno: la pantalla se congela justo tras `sdc: sdc1 sdc2 sdc3 sdc4` / `Attached SCSI removable disk`. No estaba colgado. Prueba de que el root nunca se montó: con `ignore_loglevel` un montaje ext4 imprime `EXT4-fs (...): mounted filesystem` en pantalla sí o sí, y no aparecía. Dos causas encadenadas: 1. CARRERA. El rdinit arranca en cuanto se desempaqueta el initramfs, pero el bus USB enumera asíncrono y tarda segundos (reset de hub, settling de 1s por dispositivo, scan SCSI). Los 5 reintentos de 1s no alcanzaban. En QEMU el disco es virtio y está desde el instante cero ⇒ la carrera NUNCA se veía en validación. Es el `rootwait` que no podemos usar porque no hay root= en el cmdline. Ahora espera 60s. 2. CEGUERA. El cmdline horneado es `console=tty0 console=ttyS0,115200` y /dev/console = la ÚLTIMA `console=` ⇒ el serial. El `exec sh` de rescate nacía invisible. Es el MISMO bug que costó el 1er viaje físico de KDE, una capa más temprano: allá se arregló para después del switch_root (getty en tty1) y el initramfs quedó ciego. Ahora el log del pivote va a /dev/tty0, el marcador INIT-OK también, y el rescate abre shell en tty1 listando los bloques visibles. + `timeout 15` a `hammer boot menu`: corre ANTES del exec de arje-zero ⇒ colgarse ahí deja un arranque sin PID1 ni pantalla, indistinguible de un kernel muerto. El `|| true` protegía del fallo, no del bloqueo. Validado arrancando la imagen COMO USB (qemu-xhci + usb-storage, -serial null, con pantalla): marcadores del pivote visibles, motd y prompt `/ #`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
152 lines
8.9 KiB
Bash
Executable File
152 lines
8.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# metal-desktop-image.sh — imagen de disco EFI del escritorio COSMIC para METAL REAL, con
|
|
# **aceleración de hardware Intel (iris)**. Hermano de scripts/kde/metal-desktop-image-dual.sh, pero
|
|
# con una diferencia de fondo que es el motivo de existir.
|
|
#
|
|
# ── POR QUÉ ESTA IMAGEN ES HW-ACCEL Y LA DE KDE ES SOFTWARE ─────────────────────────────────────
|
|
# La de KDE va por `mesa-llvmpipe` a propósito: tenía que aguantar DOS máquinas (Intel y una NVIDIA
|
|
# Pascal) y la mesa HW de nouveau sólo existe como binario Alpine, o sea rompiendo soberanía.
|
|
#
|
|
# Acá el objetivo es otro y por eso la decisión se invierte: **cerrar el frente de ScreenCast**. El
|
|
# diagnóstico del 2026-08-05 (ver el runbook) midió que la cadena entera del portal funciona —el nodo
|
|
# `cosmic-screencast` existe en el grafo de pipewire— y que lo que falla es el COMPOSITOR en una
|
|
# llamada EGL, 8 ms antes de que el stream quede en `Paused`, porque en QEMU mesa es `kms_swrast`:
|
|
# software, **sin exportación dmabuf**. Un stream de vídeo continuo la necesita; una captura de una
|
|
# sola toma no (por eso `cosmic-screenshot` sí anda, va por shm).
|
|
#
|
|
# El `mesa` del corpus se construye con `-Dgallium-drivers=iris` y **ya está en el rootfs de COSMIC**
|
|
# (`usr/lib/dri/iris_dri.so`). En QEMU nunca se usaba; en un TigerLake es el driver correcto y trae
|
|
# dmabuf de verdad. O sea que este viaje no es «lo mismo pero en metal»: es la única forma de saber si
|
|
# ScreenCast está bien.
|
|
#
|
|
# ⚠ POR ESO NO SE INYECTA llvmpipe ACÁ. Mezclarlos no es aditivo: llvmpipe trae su propio
|
|
# `libgbm`/`libEGL`/`libgallium` y sobrescribirlos DESACTIVA iris. Si esta máquina no tuviera Intel,
|
|
# la imagen correcta sería la de KDE, no ésta con un parche.
|
|
#
|
|
# ── LO QUE **NO** HACE FALTA INYECTAR, Y ES MEDIBLE ─────────────────────────────────────────────
|
|
# La imagen de KDE inyecta `libLLVM.so.18`, `libgcc_s.so.1` y `libstdc++.so.6` porque el JIT de
|
|
# llvmpipe los NEEDea. Acá NO: `iris_dri.so` pide sólo `libglapi`, `libdrm`, `libz`, `libzstd` y
|
|
# `libc` —mesa va con `-Dllvm=disabled`— y `cosmic-comp` sólo `libdisplay-info`, `libgbm`, `libseat`,
|
|
# `libudev`, `libinput`, `libpixman`, `libxkbcommon` y `libc`. **Cero C++ y cero libgcc**: la imagen
|
|
# COSMIC de metal no arrastra un solo binario ajeno de Alpine. Verificado con clausura ELF completa
|
|
# del rootfs: 42 raíces de runtime, 0 con NEEDED sin proveedor.
|
|
#
|
|
# work/metal-rootfs base: arje-zero PID1 + busybox + firmware i915 (estática ⇒ inyectar musl)
|
|
# work/cosmic-rootfs COSMIC runtime-completo (89 recetas: compositor, apps, portal, pipewire,
|
|
# wireplumber, portal-probe) — ya trae iris_dri.so
|
|
# + kernel linux-metal-dual (i915 builtin)
|
|
# → work/hammer-cosmic-metal.img
|
|
#
|
|
# Uso: scripts/cosmic/metal-desktop-image.sh
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
|
|
|
BASE="${BASE:-work/metal-rootfs}"
|
|
COSMIC="${COSMIC:-work/cosmic-rootfs}"
|
|
KERNEL="${KERNEL:-$(ls -dt store/*-linux-metal-dual/boot/bzImage 2>/dev/null | head -1)}"
|
|
MERGED="${MERGED:-work/cosmic-metal-rootfs}"
|
|
IMG="${IMG:-work/hammer-cosmic-metal.img}"
|
|
|
|
for x in "$BASE" "$COSMIC"; do [ -d "$x" ] || { echo "falta $x (corré scripts/cosmic/hydrate-cosmic.sh)" >&2; exit 1; }; done
|
|
[ -n "$KERNEL" ] && [ -r "$KERNEL" ] || { echo "falta linux-metal-dual (hammer build recipes/linux-metal-dual.toml)" >&2; exit 1; }
|
|
|
|
echo "==> fundiendo rootfs por hardlinks (base metal + COSMIC)"
|
|
rm -rf "$MERGED"
|
|
cp -al "$BASE" "$MERGED"
|
|
cp -al --remove-destination "$COSMIC"/. "$MERGED"/
|
|
|
|
. "$ROOT/scripts/lib/pid1-desde-store.sh"
|
|
inyectar_pid1 "$MERGED" "$BASE"
|
|
|
|
# El driver HW tiene que estar SÍ O SÍ: si no está, esta imagen no tiene razón de ser y es mejor
|
|
# fallar acá que descubrirlo con el USB en la mano frente a una pantalla negra.
|
|
[ -r "$MERGED/usr/lib/dri/iris_dri.so" ] || { echo " ✗ falta iris_dri.so — sin GPU Intel esta imagen no sirve" >&2; exit 1; }
|
|
echo "==> GL por HARDWARE: $(ls "$MERGED"/usr/lib/dri/ | tr '\n' ' ')"
|
|
|
|
echo "==> inyectando musl (loader + libc) — COSMIC es dinámico, la base metal es estática"
|
|
MUSL="${MUSL:-/usr/lib/musl/lib/libc.so}"
|
|
[ -r "$MUSL" ] || { echo "no encuentro musl libc ($MUSL)" >&2; exit 1; }
|
|
mkdir -p "$MERGED/usr/lib/musl/lib" "$MERGED/lib"
|
|
cp -a "$MUSL" "$MERGED/usr/lib/musl/lib/libc.so"
|
|
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/lib/ld-musl-x86_64.so.1"
|
|
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.so"
|
|
|
|
# ── el arranque del escritorio ──────────────────────────────────────────────────────────────────
|
|
# Se instala EL MISMO script que se validó en QEMU, y no una variante: nada de lo que hace es
|
|
# específico del emulador. Levanta XDG_RUNTIME_DIR, seatd, el bus de sistema, el shim de logind,
|
|
# pipewire, wireplumber, el compositor y los clientes — todos pasos de escritorio, no de QEMU. Que
|
|
# corra el mismo fichero es lo que hace que «validado en QEMU» signifique algo para el metal.
|
|
echo "==> instalando /usr/bin/cosmic-start (el MISMO script validado en QEMU)"
|
|
install -Dm755 scripts/cosmic/cosmic-start-qemu.sh "$MERGED/usr/bin/cosmic-start"
|
|
|
|
# ── getty en tty1: el prompt TIENE que salir por la PANTALLA ────────────────────────────────────
|
|
# Lección del 1er viaje físico de KDE, que costó un USB quemado: el CMDLINE horneado es
|
|
# `console=tty0 console=ttyS0,115200 …` y el kernel hace /dev/console = la ÚLTIMA `console=` ⇒ ttyS0.
|
|
# La seed card de la base supervisa un solo getty, sobre `console` ⇒ en un metal sin puerto serie el
|
|
# shell nace INVISIBLE: la pantalla se congela en el último printk y parece que el arranque murió,
|
|
# cuando está vivo. Nunca se vio en QEMU porque siempre se validaba con `-nographic`, donde el serial
|
|
# ES la pantalla.
|
|
#
|
|
# Se arregla acá y no en el cmdline: un getty sobre tty1 no depende del cmdline (en metal siempre hay
|
|
# VT) y no obliga a re-sellar el kernel. El getty de `console` se conserva para debug por serie.
|
|
echo '==> añadiendo getty en tty1 (el prompt de `console` va al SERIAL, invisible en metal)'
|
|
cat > "$MERGED/usr/bin/console-login" <<'LOGIN'
|
|
#!/bin/sh
|
|
# arje-zero lanza los getty con envp VACÍO ⇒ sin PATH no se resuelve ni `cat` ni `cosmic-start`.
|
|
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
|
export HOME=/root TERM=linux
|
|
[ -r /etc/motd ] && /bin/busybox cat /etc/motd
|
|
exec /bin/sh
|
|
LOGIN
|
|
chmod 0755 "$MERGED/usr/bin/console-login"
|
|
python3 - "$MERGED/ente/seed.card.json" <<'PY'
|
|
# OJO: $MERGED es un árbol de HARDLINKS a la base metal ⇒ escribir in-place mutaría también
|
|
# work/metal-rootfs (y toda otra imagen que comparta el inodo). Se escribe a un temporal y se
|
|
# os.replace ⇒ se reemplaza la ENTRADA de directorio, el inodo compartido queda intacto.
|
|
import json, sys, copy, os
|
|
p = sys.argv[1]
|
|
card = json.load(open(p))
|
|
gen = card["genesis"]
|
|
gen[:] = [g for g in gen if g["label"] != "tty1-getty"] # idempotente
|
|
base = next(g for g in gen if g["label"] == "console-getty")
|
|
tty1 = copy.deepcopy(base)
|
|
tty1["id"] = "01HQAR53D4M2NBV8KZTYXFQA04"
|
|
tty1["label"] = "tty1-getty"
|
|
tty1["payload"]["Native"]["argv"] = ["getty", "-n", "-l", "/usr/bin/console-login", "38400", "tty1"]
|
|
gen.append(tty1)
|
|
json.dump(card, open(p + ".new", "w"), indent=2, sort_keys=True)
|
|
os.replace(p + ".new", p)
|
|
print(" ✓ genesis: " + ", ".join(g["label"] for g in gen))
|
|
PY
|
|
|
|
# `rm -f` antes del heredoc para ROMPER EL HARDLINK: `cat >` escribiría el inodo COMPARTIDO con
|
|
# work/metal-rootfs y le cambiaría el motd a todas las demás imágenes.
|
|
rm -f "$MERGED/etc/motd"
|
|
cat > "$MERGED/etc/motd" <<'MOTD'
|
|
|
|
#-- hammer :: escritorio COSMIC (metal, Intel i915 + iris HW) ---------------
|
|
GL por HARDWARE (iris). Es la diferencia con la imagen de KDE, y el motivo
|
|
de este viaje: en QEMU mesa era software y ScreenCast no podía exportar
|
|
dmabuf.
|
|
|
|
Arrancar el escritorio: cosmic-start
|
|
Probar el portal: portal-probe version
|
|
portal-probe screencast <-- LO QUE VINIMOS A VER
|
|
GPU detectada: ls /dev/dri ; dmesg | grep -iE 'i915|drm'
|
|
Logs si algo falla: /tmp/cosmic-session.log /tmp/pipewire.log
|
|
---------------------------------------------------------------------------
|
|
|
|
MOTD
|
|
|
|
mkdir -p "$MERGED/root/.config" "$MERGED/root/.cache" "$MERGED/run/user/0" "$MERGED/tmp"
|
|
chmod 1777 "$MERGED/tmp"
|
|
|
|
echo "==> rootfs fundido: $(du -sh "$MERGED" | cut -f1)"
|
|
need_mb=$(du -sm "$MERGED" | cut -f1)
|
|
ROOT_SIZE="${ROOT_SIZE:-$(( need_mb + 1536 ))}"
|
|
echo "==> ROOT_SIZE=${ROOT_SIZE} MiB · kernel: $(basename "$(dirname "$(dirname "$KERNEL")")")"
|
|
|
|
export ROOTFS="$MERGED" IMG ROOT_SIZE KERNEL
|
|
export ESP_MB="${ESP_MB:-160}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-768}"
|
|
exec ./scripts/install-image-efi.sh
|