mirada/USB: telemetría persistente en el pendrive + bump a mirada de hoy (fix musl en tawasuyu)

TELEMETRÍA (el pedido): el rootfs de la imagen es un initramfs = RAM pura y los logs iban a /run (tmpfs)
⇒ al apagar la máquina ajena no sobrevivía NADA. Ahora la imagen lleva 2da partición FAT32 MIRADALOG
(512M), montada por findfs+LABEL con -o sync (un cuelgue de GPU o corte de luz no se lleva los logs).
Cada arranque vuelca run-NNNN/ con: resumen (modo/GPU/driver), hardware (PCI vía sysfs, módulos, DRM,
input, firmware), pantallas (status/modes por conector), dmesg ANTES y DESPUÉS de mirada, seatd, y el log
del compositor+greeter con RUST_LOG=wgpu_core=debug + EGL_LOG_LEVEL=debug + LIBGL_DEBUG=verbose (para ver
por qué wgpu eligió el backend y si hay float16). Shell de rescate + . FAT32 a propósito: el
pendrive se lee después desde cualquier SO.

metal-usb-sdboot.sh gana DATA_MB/DATA_LABEL genéricos (partición de datos opcional en la GPT).

GOTCHAs verificados antes de confiar: el kernel linux-generic SÍ trae VFAT_FS=y + NLS + USB_STORAGE=y
(sin eso no montaba); el busybox de Alpine NO trae el applet 00:00.0 Host bridge: Intel Corporation Tiger Lake-UP3/H35 4 cores Host Bridge/DRAM Registers (rev 01)
00:02.0 VGA compatible controller: Intel Corporation TigerLake-LP GT2 [Iris Xe Graphics] (rev 01)
00:04.0 Signal processing controller: Intel Corporation TigerLake-LP Dynamic Tuning Processor Participant (rev 01)
00:07.0 PCI bridge: Intel Corporation Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #0 (rev 01)
00:08.0 System peripheral: Intel Corporation GNA Scoring Accelerator module (rev 01)
00:0a.0 Signal processing controller: Intel Corporation Tigerlake Telemetry Aggregator Driver (rev 01)
00:0d.0 USB controller: Intel Corporation Tiger Lake-LP Thunderbolt 4 USB Controller (rev 01)
00:0d.2 USB controller: Intel Corporation Tiger Lake-LP Thunderbolt 4 NHI #0 (rev 01)
00:12.0 Serial controller: Intel Corporation 500 Series Chipset Family On-Package Integrated Sensor Hub (rev 20)
00:14.0 USB controller: Intel Corporation 500 Series Chipset Family On-Package USB 3.2 Gen 2x1 (10 Gbs) xHCI Host Controller (rev 20)
00:14.2 RAM memory: Intel Corporation 500 Series Chipset Family On-Package Shared SRAM (rev 20)
00:14.3 Network controller: Intel Corporation Wi-Fi 6 AX201 (rev 20)
00:15.0 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package I2C Controller #0 (rev 20)
00:15.1 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package I2C Controller #1 (rev 20)
00:16.0 Communication controller: Intel Corporation 500 Series Chipset Family On-Package CSME HECI #1 (rev 20)
00:1c.0 PCI bridge: Intel Corporation 500 Series Chipset Family On-Package PCI Express Root Port #5 (rev 20)
00:1d.0 PCI bridge: Intel Corporation 500 Series Chipset Family On-Package PCI Express Root Port #9 (rev 20)
00:1f.0 ISA bridge: Intel Corporation 500 Series Chipset Family On-Package eSPI Controller (rev 20)
00:1f.3 Multimedia audio controller: Intel Corporation 500 Series Chipset Family On-Package High Definition Audio (HD Audio) (rev 20)
00:1f.4 SMBus: Intel Corporation 500 Series Chipset Family On-Package System Management Bus (SMBus) (rev 20)
00:1f.5 Serial bus controller: Intel Corporation 500 Series Chipset Family On-Package SPI (flash) Controller (rev 20)
39:00.0 Non-Volatile memory controller: Kingston Technology Company, Inc. NV2 NVMe SSD [SM2267XT] (DRAM-less) (rev 03)
3a:00.0 Non-Volatile memory controller: ADATA Technology Co., Ltd. IM2P33F3 NVMe SSD (DRAM-less) (rev 03) (sí findfs/blkid) ⇒ el dump de PCI
lee /sys/bus/pci/devices/*/ directo; sintaxis del init validada con busybox ash (no bash).

BUMP mirada: el pin era 9967b02c (18-jun) — 439 commits viejo. Ahora 9a17fefc, que incluye el fix de
portabilidad a musl que hice en tawasuyu (ioctl: glibc usa c_ulong, musl c_int ⇒ las constantes DRM
casteaban mal y mirada-compositor NO compilaba para musl). mirada-compositor ya selló (87ced528);
greeter/ctl en curso.

+ scripts/kde/{metal-desktop-image,plasma-start-metal}.sh del hilo KDE (imagen de escritorio en metal).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 16:20:55 -04:00
co-authored by Claude Opus 4.8
parent 964a6931d2
commit e263b66ec1
8 changed files with 335 additions and 21 deletions
+34
View File
@@ -25,3 +25,37 @@
`hammer --store ./store hydrate b3:fded43c0… <destino>` (o copialo de `store/fded43c0…-linux-generic/boot/bzImage`). Reconstruible: `hammer build recipes/linux-generic.toml` (deps flex/bison/m4/openssl/elfutils + zig-0.13, ya en el worker).
Dudas del kernel (drivers a agregar, cmdline, otra config) → pedímelas y reviso `linux-generic.toml`.
## 📥 Telemetría persistente en el propio pendrive (2026-07-14)
**El problema:** el rootfs de esta imagen es un **initramfs = RAM pura**. Los logs iban a `/run` (tmpfs):
al apagar la máquina ajena no sobrevivía **nada**. Y la GPU a probar está lejos — un viaje sin datos es
un viaje perdido.
**La solución:** la imagen ahora trae una **2da partición FAT32 `MIRADALOG`** (512M, `DATA_MB` en
`scripts/metal-usb-sdboot.sh`, que ganó soporte genérico de partición de datos). FAT32 a propósito: el
pendrive se lee después **desde cualquier SO** (Windows/Mac/Linux) sin herramientas.
`/sbin/init` la monta por `findfs LABEL=MIRADALOG` con **`-o sync`** (cada escritura va al medio: un
cuelgue duro de la GPU o un corte de luz no se lleva los logs) y vuelca todo en `run-NNNN/`
(numerada: cada arranque/reintento tiene su carpeta):
| fichero | qué trae |
|---|---|
| `00-resumen.txt` | modo (hw/sw), cmdline, GPU+driver, DRM, si la telemetría persiste |
| `01-hardware.txt` | uname, cpu, RAM, **PCI vía sysfs** (vendor/device/class/**driver**), módulos, /dev/dri, nouveau sysfs, input, firmware nvidia presente |
| `02-pantallas.txt` | por conector: `status`/`modes`/`enabled` |
| `03-dmesg-early.txt` | dmesg **antes** de mirada → si nouveau bindeó y si el firmware gp106 cargó |
| `04-seatd.log` | seatd (DRM master / sesión) |
| `05-mirada.log` | compositor + greeter, con `RUST_LOG=wgpu_core=debug,wgpu_hal=debug` + `EGL_LOG_LEVEL=debug` + `LIBGL_DEBUG=verbose`**por qué wgpu eligió el backend y si hay float16** |
| `06-dmesg-final.txt` | dmesg **después** + exit code → cuelgues/oops/reset de nouveau |
| `07-estado-final.txt`| procesos, RAM, /dev/dri al final |
**GOTCHA:** el busybox de Alpine **no trae el applet `lspci`** (sí `findfs`/`blkid`). El dump de PCI se
hace leyendo `/sys/bus/pci/devices/*/{vendor,device,class}` + `readlink driver` — más soberano igual.
`vendor 0x10de` = NVIDIA; `class 0x0300*` = VGA.
**En la máquina ajena:** arranca solo. Si el compositor termina/falla, cae a un shell de rescate con la
telemetría ya sincronizada; `relanzar` reintenta y crea un `run-NNNN` nuevo. Se puede apagar sin ceremonia.
**Al volver:** montar la partición `MIRADALOG` y leer `run-NNNN/`.
+2 -2
View File
@@ -2,7 +2,7 @@
# maneja DRM/GBM/EGL/libseat/libinput directo y dentro del cual corre `mirada-greeter` como cliente.
# Cierra la cadena de sesión gráfica de tawasuyu.
#
# Receta Cargo (patrón arje-zero/mirada-greeter): monorepo tawasuyu al commit fijado 9967b02c (reusa
# Receta Cargo (patrón arje-zero/mirada-greeter): monorepo tawasuyu al commit fijado 9a17fefc (reusa
# el árbol vendoreado). `-p mirada-compositor`, link DINÁMICO (smithay enlaza libdrm/gbm/seat/input
# + dlopen de EGL/wayland/xkbcommon).
#
@@ -17,7 +17,7 @@ version = "0.0.1"
[source]
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
commit = "9967b02cf597df6d065edbad8d6669b5653d4928"
commit = "9a17fefcbf63ba74f45cfabc4e608e391e397b17"
[build]
compiler = "zig-cc"
+2 -2
View File
@@ -1,7 +1,7 @@
# mirada-ctl — control del compositor mirada por línea de comandos (estilo swaymsg/hyprctl: dispara
# acciones de escritorio). Del monorepo tawasuyu. Etapa G: poblar el catálogo con apps propias.
#
# Receta Cargo (patrón arje-zero/dominium-cli): source = monorepo tawasuyu a commit fijado 9967b02c
# Receta Cargo (patrón arje-zero/dominium-cli): source = monorepo tawasuyu a commit fijado 9a17fefc
# (Cargo.lock committeado => build --locked reproducible), `-p mirada-ctl`, estático zig-cc. bin==package.
# Es el CLIENTE de control (IPC), no el compositor GPU ⇒ static-musl sano. Comparte el commit => reusa
# el árbol fuente fetcheado.
@@ -11,7 +11,7 @@ version = "0.0.1"
[source]
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
commit = "9967b02cf597df6d065edbad8d6669b5653d4928"
commit = "9a17fefcbf63ba74f45cfabc4e608e391e397b17"
[build]
compiler = "zig-cc"
+2 -2
View File
@@ -4,7 +4,7 @@
# Vulkan). Ver docs/14-mesa-stack.md §«Lado tawasuyu».
#
# Receta Cargo (patrón arje-zero/mirada-ctl): fuente = monorepo tawasuyu al MISMO commit fijado
# 9967b02c ⇒ reusa el árbol fetcheado y vendoreado (cargo vendor vendorea TODO el Cargo.lock del
# 9a17fefc ⇒ reusa el árbol fetcheado y vendoreado (cargo vendor vendorea TODO el Cargo.lock del
# workspace, así que wgpu/winit/naga ya están). `-p mirada-greeter`, bin == package.
#
# link = DYNAMIC (a diferencia de arje-zero estático): wgpu/winit hacen dlopen de libEGL/libGLESv2/
@@ -16,7 +16,7 @@ version = "0.0.1"
[source]
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
commit = "9967b02cf597df6d065edbad8d6669b5653d4928"
commit = "9a17fefcbf63ba74f45cfabc4e608e391e397b17"
[build]
compiler = "zig-cc"
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# metal-desktop-image.sh — arma la IMAGEN DE DISCO EFI con el escritorio KDE completo, para METAL.
#
# Funde dos rootfs y delega el particionado en scripts/install-image-efi.sh (ADR 0010 paso 5: EFI-stub
# soberano, initrd chico de pivote → switch_root a la ext4 real ⇒ el sistema NO vive en RAM, que es lo que
# hace inviable el camino de metal-usb-sdboot.sh con un escritorio de ~7 GB).
#
# work/metal-rootfs base metal: arje-zero PID1 + busybox + firmware (i915 tgl_* + iwlwifi AX201)
# work/kde-metal-rootfs KDE hidratado del store sellado (206 pkgs, cierre runtime completo)
# → work/metal-desktop-rootfs (hardlinks, NO copia: no muta ninguno de los dos)
# → work/hammer-kde-metal.img GPT: ESP(bzImage EFI-stub + initrd pivote) + ext4 / + /store + /var/lib/hammer
#
# Uso: scripts/kde/metal-desktop-image.sh
# BOOT=1 KVM=1 scripts/kde/metal-desktop-image.sh # + arranca en OVMF para validar antes de quemar
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
BASE="${BASE:-work/metal-rootfs}"
KDE="${KDE:-work/kde-metal-rootfs}"
MERGED="${MERGED:-work/metal-desktop-rootfs}"
IMG="${IMG:-work/hammer-kde-metal.img}"
[ -d "$BASE" ] || { echo "falta $BASE (scripts/metal-iso.sh lo arma)" >&2; exit 1; }
[ -d "$KDE" ] || { echo "falta $KDE (hidratá con scripts/kde/hydrate-recipes.py en el worker y bajalo)" >&2; exit 1; }
echo "==> fundiendo rootfs por hardlinks (no muta los originales)"
# Los dos árboles son COMPLEMENTARIOS, no rivales:
# base → musl libc + loader + busybox + arje-zero + firmware (el "sustrato soberano")
# KDE → Qt/KF6/Plasma/apps (complete-closure.sh NO hidrata la libc:
# "los sonames del sustrato base los provee la base del sistema destino")
# Se pone la base primero y KDE encima; en los pocos nombres que coincidan gana KDE.
rm -rf "$MERGED"
cp -al "$BASE" "$MERGED"
cp -al --remove-destination "$KDE"/. "$MERGED"/
echo "==> instalando /usr/bin/plasma-start"
install -Dm755 scripts/kde/plasma-start-metal.sh "$MERGED/usr/bin/plasma-start"
# El escritorio necesita estos dirs runtime; el rootfs es de sólo-lectura hasta que switch_root monta la ext4.
mkdir -p "$MERGED/root/.config" "$MERGED/root/.cache" "$MERGED/run/user/0" "$MERGED/tmp"
chmod 1777 "$MERGED/tmp"
# motd: que el usuario sepa qué correr al llegar al shell.
cat > "$MERGED/etc/motd" <<'MOTD'
#-- hammer :: escritorio KDE Plasma 6 (metal) ------------------------------
Todo construido desde fuente con hammer (musl + zig-cc), sin binarios ajenos.
Arrancar el escritorio: plasma-start
Logs si algo falla: /tmp/kwin.log /tmp/plasmashell.log
Diagnóstico GPU: dmesg | grep -iE 'i915|drm'
---------------------------------------------------------------------------
MOTD
echo "==> rootfs fundido: $(du -sh "$MERGED" | cut -f1) ($(find "$MERGED" -name '*.so*' | wc -l) .so, $(ls "$MERGED"/usr/bin | wc -l) bins)"
# La ext4 de / debe entrar el rootfs + holgura. Se calcula del tamaño real y se redondea hacia arriba.
need_mb=$(du -sm "$MERGED" | cut -f1)
ROOT_SIZE="${ROOT_SIZE:-$(( need_mb + 1536 ))}"
echo "==> ROOT_SIZE=${ROOT_SIZE} MiB (rootfs ${need_mb} MiB + holgura)"
export ROOTFS="$MERGED" IMG ROOT_SIZE
export ESP_MB="${ESP_MB:-128}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-768}"
exec ./scripts/install-image-efi.sh
+72
View File
@@ -0,0 +1,72 @@
#!/bin/sh
# plasma-start — arranca la sesión Plasma en METAL (se instala como /usr/bin/plasma-start en el rootfs).
#
# Derivado de scripts/kde/run-plasma-headless.sh (la sesión VALIDADA headless en el worker), con dos
# cambios para hardware real:
# - kwin_wayland SIN `--virtual`: usa el backend DRM real (/dev/dri/card0, i915 built-in del kernel metal).
# - SIN los overrides de software (swrast/LIBGL_ALWAYS_SOFTWARE/QT_QUICK_BACKEND=software): en la
# TigerLake el driver es **iris** (mesa hidratado trae /usr/lib/dri/iris_dri.so).
#
# NO se autoarranca desde el seed card de arje-zero a propósito: en un bringup, si Plasma falla querés el
# shell de la console-getty para leer los logs, no una pantalla negra. Se lanza a mano desde ese shell.
#
# Logs: /tmp/{kwin,kamd,plasmashell}.log Salir: Ctrl-C (mata la sesión)
set -u
export LD_LIBRARY_PATH=/usr/lib64:/usr/lib/qt6:/usr/lib:/lib
export QT_PLUGIN_PATH=/usr/lib64/qt6/plugins:/usr/lib/qt6/plugins
export QML2_IMPORT_PATH=/usr/lib64/qt6/qml:/usr/lib/qt6/qml
export QML_IMPORT_PATH=$QML2_IMPORT_PATH
export XDG_DATA_DIRS=/usr/share
export XDG_RUNTIME_DIR=/run/user/0
export XDG_CONFIG_HOME=/root/.config
export XDG_CACHE_HOME=/root/.cache
export HOME=/root
export LIBGL_DRIVERS_PATH=/usr/lib/dri
export QT_QPA_PLATFORM=wayland
mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /root
chmod 700 "$XDG_RUNTIME_DIR"
echo "== hammer :: sesión Plasma (metal) =="
echo "-- GPU: $(ls /dev/dri/ 2>/dev/null | tr '\n' ' ')"
[ -e /dev/dri/card0 ] || echo " !! no hay /dev/dri/card0 — ¿i915 no cargó? (dmesg | grep i915)"
echo "-- input: $(ls /dev/input/ 2>/dev/null | tr '\n' ' ')"
# D-Bus de sesión: kwin/plasmashell lo exigen.
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
DBUS_SESSION_BUS_ADDRESS=$(dbus-daemon --session --fork --print-address 2>/dev/null)
export DBUS_SESSION_BUS_ADDRESS
fi
echo "-- dbus: ${DBUS_SESSION_BUS_ADDRESS:-NO ARRANCÓ}"
# Compositor sobre DRM real.
echo "-- lanzando kwin_wayland (DRM)…"
/usr/bin/kwin_wayland >/tmp/kwin.log 2>&1 &
KWIN=$!
i=0
while [ $i -lt 40 ]; do
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && break
kill -0 $KWIN 2>/dev/null || { echo " !! kwin murió:"; tail -25 /tmp/kwin.log; exit 1; }
i=$((i+1)); sleep 0.5
done
if [ -S "$XDG_RUNTIME_DIR/wayland-0" ]; then
echo " compositor OK (wayland-0)"
else
echo " !! kwin no expuso wayland-0:"; tail -25 /tmp/kwin.log; exit 1
fi
export WAYLAND_DISPLAY=wayland-0
# kactivitymanagerd: plasmashell ABORTA si no corre (registra su servicio D-Bus).
KAMD=$(ls /usr/lib*/libexec/kactivitymanagerd 2>/dev/null | head -1)
if [ -n "$KAMD" ]; then "$KAMD" >/tmp/kamd.log 2>&1 & sleep 2; echo "-- kactivitymanagerd lanzado"; fi
echo "-- lanzando plasmashell…"
/usr/bin/plasmashell >/tmp/plasmashell.log 2>&1 &
sleep 8
echo "-- procesos: $(ps axo comm 2>/dev/null | grep -E 'kwin|plasma' | sort -u | tr '\n' ' ')"
echo
echo "Escritorio arriba. Logs en /tmp/{kwin,kamd,plasmashell}.log"
echo "Apps: konsole, dolphin, systemsettings, spectacle, okular… (lanzalas desde otra tty o krunner)"
echo "Ctrl-C para terminar la sesión."
wait $KWIN
+24 -3
View File
@@ -73,13 +73,34 @@ echo "==> ESP poblada ($(du -h "$ESP" | cut -f1)):"
# 4) imagen de disco GPT: GPT primaria (1MiB) + ESP (en sector 2048) + GPT backup
esp_sectors=$(( espkb * 2 )) # KiB→sectores de 512
rm -f "$IMG"; truncate -s "$(( (2048 + esp_sectors + 2048) * 512 ))" "$IMG"
echo "label: gpt
start=2048, size=$esp_sectors, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name=\"EFI System Partition\"" | sfdisk --quiet "$IMG"
# Partición de DATOS opcional (DATA_MB>0): FAT32 con etiqueta, para que el sistema live escriba ahí lo
# que deba SOBREVIVIR al apagado (telemetría/logs). El rootfs de esta imagen es un initramfs = RAM pura:
# sin esta partición NO queda rastro de nada al cortar la luz. FAT32 (no ext4) a propósito: el pendrive
# se lee después desde CUALQUIER máquina (Windows/Mac/Linux) sin herramientas.
DATA_MB="${DATA_MB:-0}"
DATA_LABEL="${DATA_LABEL:-HAMMERLOG}"
data_sectors=0
if [ "$DATA_MB" -gt 0 ]; then
DATA="$WORK/data.img"; rm -f "$DATA"; truncate -s "$(( DATA_MB * 1024 * 1024 ))" "$DATA"
"$MT/mformat" -F -v "$DATA_LABEL" -i "$DATA" ::
data_sectors=$(( DATA_MB * 2048 ))
echo "==> partición de datos FAT32 ${DATA_MB}M etiqueta=$DATA_LABEL (telemetría persistente)"
fi
rm -f "$IMG"; truncate -s "$(( (2048 + esp_sectors + data_sectors + 2048) * 512 ))" "$IMG"
{
echo "label: gpt"
echo "start=2048, size=$esp_sectors, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name=\"EFI System Partition\""
[ "$data_sectors" -gt 0 ] && \
echo "start=$(( 2048 + esp_sectors )), size=$data_sectors, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, name=\"$DATA_LABEL\""
} | sfdisk --quiet "$IMG"
dd if="$ESP" of="$IMG" bs=512 seek=2048 conv=notrunc status=none
[ "$data_sectors" -gt 0 ] && dd if="$DATA" of="$IMG" bs=512 seek=$(( 2048 + esp_sectors )) conv=notrunc status=none
echo
echo "✓ USB metal (systemd-boot): $IMG ($(du -h "$IMG" | cut -f1))"
[ "$data_sectors" -gt 0 ] && echo " + partición $DATA_LABEL (FAT32 ${DATA_MB}M) para telemetría — legible en cualquier SO"
echo " Quemar: sudo dd if=$IMG of=/dev/sdX bs=4M oflag=sync status=progress"
echo " Bootear: el menú de systemd-boot aparece; ENTER arranca. Tecla 'e' = EDITAR la cmdline en vivo."
echo " Secure Boot OFF. WiFi (en consola): wifi-connect \"SSID\" \"CLAVE\""
+134 -12
View File
@@ -61,7 +61,8 @@ done
# 2) busybox + applets
echo "==> busybox"
cp -a "$DEVFS"/bin/busybox "$RFS"/bin/busybox
for a in sh mount umount mkdir ln cp mv rm cat echo sleep ls ps kill chmod chown ip udhcpc dmesg mknod switch_root getty login setsid; do
for a in sh mount umount mkdir ln cp mv rm cat echo sleep ls ps kill chmod chown ip udhcpc dmesg mknod switch_root getty login setsid \
findfs blkid sync tee date uname free df head tail grep sed awk cut tr wc find md5sum dd stat readlink basename; do
ln -sf busybox "$RFS/bin/$a"
done
ln -sf /bin/busybox "$RFS/sbin/init.busybox"
@@ -195,7 +196,9 @@ fi
echo "==> lanzador /sbin/init"
cat > "$RFS/sbin/init" <<'INIT'
#!/bin/sh
# init de la imagen live de mirada (software/swrast). Arranca seatd y el compositor en modo greeter.
# init de la imagen live de mirada. Arranca seatd + el compositor en modo greeter, y — lo importante para
# probar en una GPU AJENA — vuelca TODA la telemetría a la partición FAT32 del propio pendrive, para
# traerlo de vuelta con la información. El rootfs es un initramfs (RAM): sin esto no sobrevive NADA.
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
/bin/busybox mount -t proc proc /proc 2>/dev/null || true
/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true
@@ -205,6 +208,77 @@ export PATH=/usr/bin:/bin:/usr/sbin:/sbin
/bin/busybox mount -t devpts devpts /dev/pts 2>/dev/null || true
/bin/busybox chmod 0700 /run/user/0
# ---------------------------------------------------------------- telemetría persistente al pendrive
# La partición la crea metal-usb-sdboot.sh (DATA_MB/DATA_LABEL). Se monta con -o sync: cada escritura va
# al medio, así un cuelgue duro de la GPU o un corte de luz no se lleva los logs.
LOG=/telemetry
TELOK=0
/bin/busybox mkdir -p $LOG
for try in 1 2 3 4 5 6 7 8 9 10; do
DEV=$(/bin/busybox findfs LABEL=MIRADALOG 2>/dev/null)
[ -n "$DEV" ] && break
/bin/busybox sleep 1 # el USB puede tardar en enumerar
done
if [ -n "$DEV" ] && /bin/busybox mount -t vfat -o rw,sync "$DEV" $LOG 2>/dev/null; then
TELOK=1
else
echo " !! NO pude montar la partición de telemetría (LABEL=MIRADALOG) — los logs quedan sólo en RAM"
LOG=/run
fi
# Cada arranque en su propia carpeta: run-0001, run-0002… (sin RTC confiable, se numera)
N=1
while [ -d "$LOG/run-$(printf %04d $N)" ]; do N=$((N+1)); done
RUN="$LOG/run-$(printf %04d $N)"
/bin/busybox mkdir -p "$RUN"
echo " ## telemetría → $RUN (persistente=$TELOK)"
snap() { # snap <fichero> <titulo> <comando…>
local f="$RUN/$1"; shift; local t="$1"; shift
{ echo "===== $t ====="; "$@" 2>&1; echo; } >> "$f"
/bin/busybox sync
}
# PCI desde sysfs: este busybox NO trae el applet `lspci`. Con vendor/device/class/driver alcanza para
# saber QUÉ GPU hay y, sobre todo, QUÉ DRIVER la bindeó (nouveau vs nada) — que es el dato del viaje.
# vendor 0x10de = NVIDIA · class 0x0300xx = VGA · 0x0302xx = 3D controller
pci_dump() {
for d in /sys/bus/pci/devices/*/; do
[ -r "$d/class" ] || continue
drv=$(/bin/busybox readlink "$d/driver" 2>/dev/null | /bin/busybox sed 's|.*/||')
echo "$(/bin/busybox basename $d) class=$(/bin/busybox cat $d/class) vendor=$(/bin/busybox cat $d/vendor) device=$(/bin/busybox cat $d/device) driver=${drv:-NINGUNO}"
done
}
gpu_line() {
for d in /sys/bus/pci/devices/*/; do
[ -r "$d/class" ] || continue
case "$(/bin/busybox cat $d/class)" in
0x0300*|0x0302*)
drv=$(/bin/busybox readlink "$d/driver" 2>/dev/null | /bin/busybox sed 's|.*/||')
echo "$(/bin/busybox basename $d) vendor=$(/bin/busybox cat $d/vendor) device=$(/bin/busybox cat $d/device) driver=${drv:-NINGUNO}" ;;
esac
done
}
# --- hardware / kernel: qué GPU hay, si nouveau bindeó, si cargó el firmware
snap 01-hardware.txt "uname" /bin/busybox uname -a
snap 01-hardware.txt "cmdline" /bin/busybox cat /proc/cmdline
snap 01-hardware.txt "cpu" /bin/busybox head -20 /proc/cpuinfo
snap 01-hardware.txt "memoria" /bin/busybox free -m
snap 01-hardware.txt "PCI (sysfs; vendor 0x10de=NVIDIA)" pci_dump
snap 01-hardware.txt "modulos" /bin/busybox cat /proc/modules
snap 01-hardware.txt "DRM /dev/dri" /bin/busybox ls -la /dev/dri
snap 01-hardware.txt "DRM /sys" /bin/busybox find /sys/class/drm -maxdepth 1
snap 01-hardware.txt "nouveau sysfs" /bin/busybox find /sys/module/nouveau -maxdepth 2
snap 01-hardware.txt "input" /bin/busybox cat /proc/bus/input/devices
snap 01-hardware.txt "firmware nvidia" /bin/busybox find /lib/firmware/nvidia -type f
for c in /sys/class/drm/card*/status /sys/class/drm/card*/modes /sys/class/drm/card*/enabled; do
[ -r "$c" ] && snap 02-pantallas.txt "$c" /bin/busybox cat "$c"
done
# dmesg TEMPRANO: acá se ve si nouveau bindeó y si el firmware gp106 cargó (o falló).
snap 03-dmesg-early.txt "dmesg (antes de mirada)" /bin/busybox dmesg
export XDG_RUNTIME_DIR=/run/user/0
export LIBGL_DRIVERS_PATH=/usr/lib/dri
export LIBSEAT_BACKEND=seatd
@@ -214,14 +288,21 @@ export MIRADA_GREETER_BIN=/usr/bin/mirada-greeter
export XKB_DEFAULT_LAYOUT=us
export XKB_CONFIG_ROOT=/usr/share/X11/xkb
# GPU: por defecto se INTENTA hardware (nouveau, si el firmware GSP lo deja hacer modeset) y, si no,
# mesa cae a swrast/llvmpipe sobre simpledrm solo. Con `mirada.sw` en la cmdline se FUERZA software
# (necesario en la VM virtio-sin-virgl de validación, donde mesa intentaría el driver virtio-3D y
# fallaría). El compositor (smithay/GlesRenderer) corre en ambos; el greeter (wgpu/Vello) NECESITA la
# capacidad de shaders float16 (SHADER_FLOAT16_IN_FLOAT32) que los rasterizadores software
# (llvmpipe/lavapipe) NO dan ⇒ su login sólo pinta con GPU real (nouveau). Ver HANDOFF/README.
# Telemetría MÁXIMA del stack gráfico: por qué wgpu eligió (o no) el backend, y si hay float16.
export RUST_LOG="${RUST_LOG:-info,wgpu_core=debug,wgpu_hal=debug,mirada=debug,smithay=info}"
export RUST_BACKTRACE=full
export EGL_LOG_LEVEL=debug
export MESA_DEBUG=1
export LIBGL_DEBUG=verbose
# GPU: por defecto se INTENTA hardware (nouveau, si el firmware deja hacer modeset) y, si no, mesa cae a
# swrast/llvmpipe sobre simpledrm. Con `mirada.sw` en la cmdline se FUERZA software (necesario en la VM
# virtio-sin-virgl de validación). El compositor (smithay/GlesRenderer) corre en ambos; el greeter
# (wgpu/Vello) NECESITA shaders float16 (SHADER_FLOAT16_IN_FLOAT32) que llvmpipe/lavapipe NO dan ⇒ su
# login sólo pinta con GPU real (nouveau). Ver HANDOFF/README.
if grep -qw 'mirada.sw' /proc/cmdline 2>/dev/null; then
echo " ## modo SOFTWARE forzado (mirada.sw): compositor sí; greeter no (sin float16)"
MODO="software (mirada.sw)"
export LIBGL_ALWAYS_SOFTWARE=1
export GALLIUM_DRIVER=llvmpipe
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json
@@ -231,24 +312,59 @@ else
# por el backend GL de wgpu sobre gallium-nouveau (que sí da unpackHalf2x16 = float16). Forzamos GL y
# tapamos lavapipe: si dejáramos Vulkan, wgpu caería a lavapipe (software, sin float16) y fallaría.
echo " ## modo HARDWARE (nouveau GL): greeter por gallium-nouveau"
MODO="hardware (nouveau GL)"
export WGPU_BACKEND=gl
export VK_ICD_FILENAMES=/dev/null
fi
{ echo "modo : $MODO"; echo "cmdline : $(/bin/busybox cat /proc/cmdline)"; echo "DRM : $(/bin/busybox ls /dev/dri 2>/dev/null | tr '\n' ' ')";
echo "GPU (PCI) : $(gpu_line)";
echo "persistente: $TELOK"; echo "RUST_LOG : $RUST_LOG"; } > "$RUN/00-resumen.txt"
/bin/busybox sync
echo ""
echo " ## hammer · mirada live"
echo " ## DRM: $(ls /dev/dri 2>/dev/null | tr '\n' ' ')"
echo " ## telemetría: $RUN (persistente=$TELOK)"
echo ""
# seatd en background (gestiona el DRM master y la sesión sobre la VT).
/usr/bin/seatd -g video >/run/seatd.log 2>&1 &
sleep 1
/usr/bin/seatd -g video > "$RUN/04-seatd.log" 2>&1 &
/bin/busybox sleep 1
# El compositor: su salida va A LA VEZ a la pantalla y al pendrive (tee), para verlo y llevárselo.
echo "== lanzando mirada-compositor --drm --greeter =="
/usr/bin/mirada-compositor --drm --greeter 2>&1 | /bin/busybox tee /run/mirada.log
/usr/bin/mirada-compositor --drm --greeter 2>&1 | /bin/busybox tee "$RUN/05-mirada.log"
RC=$?
# --- post-mortem: lo que pasó DESPUÉS de correr mirada (cuelgues de GPU, oops, reset de nouveau)
snap 06-dmesg-final.txt "dmesg (después de mirada)" /bin/busybox dmesg
snap 06-dmesg-final.txt "rc del compositor" echo "exit=$RC"
snap 07-estado-final.txt "procesos" /bin/busybox ps
snap 07-estado-final.txt "memoria" /bin/busybox free -m
snap 07-estado-final.txt "DRM final" /bin/busybox ls -la /dev/dri
/bin/busybox sync
echo ""
echo "== mirada terminó — shell de rescate (logs en /run/mirada.log, /run/seatd.log) =="
echo "== mirada terminó (exit=$RC) — telemetría VOLCADA en $RUN =="
[ "$TELOK" = "1" ] && {
echo " Ficheros en el pendrive (partición MIRADALOG):"
/bin/busybox ls -la "$RUN"
echo ""
echo " >> Podés apagar y traer el pendrive: los logs ya están sincronizados al medio."
echo " >> Si querés reintentar antes de apagar, corré: relanzar"
} || echo " !! sin partición de telemetría: los logs están en RAM y se pierden al apagar"
echo ""
# `relanzar`: reintentar el compositor sin reiniciar; cada intento crea su propio run-NNNN.
cat > /usr/bin/relanzar <<'RL'
#!/bin/sh
echo "relanzando init (nuevo run-NNNN en el pendrive)…"
exec /sbin/init
RL
chmod +x /usr/bin/relanzar
echo "== shell de rescate (telemetría en $RUN; 'relanzar' para reintentar) =="
exec /bin/sh
INIT
chmod +x "$RFS/sbin/init"
@@ -269,9 +385,15 @@ if [ "$PACKAGE" = "1" ]; then
# Default = HARDWARE nouveau (ya horneamos el firmware gp106): nouveau maneja la GTX 1060 y el greeter
# pinta por gallium-nouveau GL. Si nouveau diera problemas, en el menú (tecla 'e') agregá
# `mirada.sw nouveau.modeset=0` para caer a software (compositor sí, greeter no).
# DATA_MB: partición FAT32 de TELEMETRÍA. El rootfs de esta imagen es un initramfs = RAM pura, así que
# sin esta partición no sobrevive ni un log al apagado — y la GPU a probar está en otra máquina, lejos.
# El init la monta por LABEL=MIRADALOG con -o sync y vuelca ahí todo (ver /sbin/init).
# FAT32 ⇒ el pendrive se lee después desde cualquier SO, sin herramientas.
ROOTFS="$RFS" KERNEL="$KGEN" IMG="work/hammer-mirada-usb.img" \
DATA_MB="${DATA_MB:-512}" DATA_LABEL="MIRADALOG" \
OPTIONS="${CMDLINE:-console=tty0 loglevel=4}" \
scripts/metal-usb-sdboot.sh
echo ""
echo "✓ imagen: work/hammer-mirada-usb.img"
echo " Al volver, leé la telemetría montando la partición MIRADALOG (FAT32) — carpetas run-NNNN/."
fi