Files
hammer/scripts/kde/run-qemu-desktop.sh
T
sergioandClaude Opus 5 8c3bd323d5 audio: ALSA encendido en el kernel — y el muro real es libudev-zero, no el stack de audio
ALSA =y en linux-metal (b3:613bca15): HDA legacy + codecs (lo que emula QEMU y usan las
máquinas pre-SOF), SOF para TigerLake (el laptop del target NO suena por la ruta legacy:
Intel movió el audio al DSP) y SND_USB_AUDIO. Todo =y porque el producto es monolítico.
⚠ Falta inyectar el FIRMWARE de SOF en la imagen (intel/sof/*.ri, sof-tplg/*.tplg), igual
que metal-firmware.sh hace con los tgl_* de i915: sin blobs el driver carga y falla.

FUNCIONÓ LA MITAD: en la VM `/dev/snd` ya trae controlC0 + pcmC0D0p/c y /sys/class/sound
lista card0. El kernel detecta la tarjeta. Pero wpctl sigue con `Devices:` vacío.

**Y LA CAUSA ES ESTRUCTURAL, no una propiedad que falte.** `get_card_nr` de SPA
(alsa-udev.c:178-183) sólo acepta el device CARD —`/sys/.../sound/card0`—, que es un
device de CLASE: sin major:minor, sin nodo en /dev. Y `udev_enumerate_scan_devices` de
libudev-zero recorre EXCLUSIVAMENTE /sys/dev/block y /sys/dev/char (udev_enumerate.c:281),
o sea sólo devices CON nodo; el udev real enumera /sys/class entero. **El device que SPA
necesita nunca entra en la enumeración**: no hay guarda que sacar, falta la mitad del
espacio de búsqueda. Salidas: (a) enseñarle a libudev-zero a recorrer /sys/class —radio 51
sellados— o (b) empaquetar eudev. Es decisión de arquitectura, no parche.

CORRIJO ALGO QUE ESCRIBÍ ANTES: el parche `pipewire-sound-initialized.patch` se hizo
creyendo que SOUND_INITIALIZED era el bloqueo, y NO lo era — con el parche aplicado el
resultado no cambió. Se conserva porque la incompatibilidad que describe es real (sin
udevd nadie pone esa propiedad y SPA descartaría toda tarjeta en cuanto la enumeración
funcione), pero su prosa ahora empieza avisando que no es la solución. Sacarlo del camino
importa: dejarlo presentado como el arreglo mandaría al próximo a buscar en el lugar
equivocado.

Dos arreglos de andamiaje que costaron un ciclo cada uno:
- **`-nic none` por defecto.** Agregar la tarjeta de sonido CORRIÓ LAS RUTAS PCI, la entrada
  de disco cacheada en las VARS de OVMF dejó de coincidir, y la firmware se fue al orden por
  defecto: PXE v4, PXE v6, HTTP… minutos de timeouts. Con un TIMEOUT corto eso se lee como
  «la VM no arrancó» y el serial sólo dice `PXE-E16: No valid offer received`.
- El filtro del log de wireplumber era `alsa|udev|sound|card|monitor` con `tail -40`, y se
  llenó de bluez/v4l2/libcamera —tres monitores que avisan que su plugin no está— dejando
  fuera justo las líneas de ALSA. **Un filtro ancho con cola corta es peor que ninguno.**
  Ahora filtra `alsa` y además copia el log entero a la raíz ext4 (tmpfs muere con la VM).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 21:59:18 -04:00

82 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# run-qemu-desktop.sh — arranca la imagen KDE en QEMU (virtio-gpu + software GL) de forma REPRODUCIBLE.
# Antes era un comando ad-hoc. Por defecto headless (DISPLAY=none) para diagnóstico por serial sin
# interferir con la sesión mirada del laptop; DISP=gtk para ver la ventana (necesita DISPLAY=:0 Xwayland,
# y cada restart de mirada mata la ventana).
#
# scripts/kde/run-qemu-desktop.sh # headless, serial → work/qemu-desktop-serial.log
# DISP=gtk scripts/kde/run-qemu-desktop.sh # ventana gráfica (virtio-gpu por gtk)
# TIMEOUT=90 scripts/kde/run-qemu-desktop.sh # mata QEMU a los 90s (diagnóstico automático)
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
IMG="${IMG:-work/hammer-kde-qemu.img}"
SERIAL="${SERIAL:-work/qemu-desktop-serial.log}"
OVMF_CODE="${OVMF_CODE:-/usr/share/edk2/x64/OVMF_CODE.4m.fd}"
OVMF_VARS_SRC="${OVMF_VARS_SRC:-/usr/share/edk2/x64/OVMF_VARS.4m.fd}"
VARS="${VARS:-work/qemu-desktop-OVMF_VARS.fd}"
DISP="${DISP:-none}"
MEM="${MEM:-4G}"
SMP="${SMP:-4}"
[ -r "$IMG" ] || { echo "falta $IMG — corré scripts/kde/qemu-desktop-image.sh" >&2; exit 1; }
[ -r "$OVMF_CODE" ] || { echo "falta OVMF_CODE ($OVMF_CODE)" >&2; exit 1; }
# copia escribible de las VARS (pflash necesita rw; la del sistema es read-only)
[ -r "$VARS" ] || cp "$OVMF_VARS_SRC" "$VARS"
case "$DISP" in
gtk) DISPLAY_ARGS=(-display gtk -device virtio-gpu-pci) ;;
none) DISPLAY_ARGS=(-display none -device virtio-gpu-pci) ;;
*) DISPLAY_ARGS=(-display "$DISP" -device virtio-gpu-pci) ;;
esac
# serial nuevo cada corrida (el diagnóstico depende de que no se mezcle con boots viejos)
: > "$SERIAL"
QEMU_ARGS=(
-machine q35 -accel kvm -cpu host
-m "$MEM" -smp "$SMP"
-vga none # virtio-gpu-pci (abajo) es el ÚNICO display: sin esto QEMU añade una VGA estándar por
# defecto y OVMF pinta el GOP ahí ⇒ simpledrm (card1) muestra el framebuffer EFI y kwin
# pinta en virtio-gpu (card0, otro device que no se ve) ⇒ pantalla congelada en TianoCore.
# Con -vga none, OVMF usa virtio-gpu ⇒ virtio-gpu-DRM expulsa simpledrm ⇒ un solo output.
-drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on
-drive if=pflash,format=raw,unit=1,file="$VARS"
-drive file="$IMG",format=raw,if=virtio
"${DISPLAY_ARGS[@]}"
-serial "file:$SERIAL"
-monitor "unix:${MON:-work/qemu-monitor.sock},server,nowait"
-no-reboot
)
# AUDIO=1 (default): darle a la VM una tarjeta de sonido EMULADA. No es para oír nada —el backend es
# `none`, que descarta las muestras— sino para que HAYA UN DISPOSITIVO QUE ENUMERAR.
#
# Sin esto, `wpctl status` sale con «Devices:» vacío y un único sink `auto_null`, y ese resultado es
# AMBIGUO: se lee igual si wireplumber funciona sobre una VM sin hardware que si wireplumber no
# funciona. Con una ich9-intel-hda emulada, el árbol de /sys/class/sound existe y la respuesta
# distingue las dos cosas. AUDIO=0 para volver al caso sin tarjeta.
if [ "${AUDIO:-1}" = 1 ]; then
QEMU_ARGS+=(-audiodev none,id=snd0 -device ich9-intel-hda -device hda-duplex,audiodev=snd0)
fi
# NET=none (default): SIN tarjeta de red. No es sólo ahorro — QEMU añade una e1000 por defecto, y OVMF
# la usa para crear entradas de arranque PXE/HTTP (IPv4 e IPv6). Cuando la entrada de disco que OVMF
# tenía cacheada en sus VARS deja de coincidir —y basta AGREGAR UN DISPOSITIVO PCI, como la tarjeta de
# sonido de arriba, para que las rutas se corran— la firmware cae al orden por defecto y se pasa un
# par de minutos en timeouts de PXE antes de llegar al disco. Con un TIMEOUT corto eso se ve como
# «la VM no arrancó», y el serial sólo muestra `PXE-E16: No valid offer received`. Pasó de verdad.
# Este escritorio no necesita red; `NET=user` si algún día hace falta.
if [ "${NET:-none}" = none ]; then
QEMU_ARGS+=(-nic none)
fi
echo "==> QEMU (DISP=$DISP, serial=$SERIAL)"
echo " imagen: $IMG"
if [ -n "${TIMEOUT:-}" ]; then
echo " TIMEOUT=${TIMEOUT}s (auto-kill)"
exec timeout --signal=KILL "${TIMEOUT}" qemu-system-x86_64 "${QEMU_ARGS[@]}"
else
exec qemu-system-x86_64 "${QEMU_ARGS[@]}"
fi