#!/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" # ACCEL/CPU parametrizables: sin /dev/kvm (p.ej. un vServer sin virtualizacion anidada) hay que # caer a TCG, y ahi `-cpu host` no existe. ACCEL=tcg CPU=max para emulacion pura. ACCEL="${ACCEL:-kvm}"; CPU="${CPU:-host}" if [ ! -w /dev/kvm ] && [ "$ACCEL" = kvm ]; then echo "sin /dev/kvm: cayendo a TCG (emulacion pura, lento)" >&2; ACCEL=tcg; CPU=max fi QEMU_ARGS=( -machine q35 -accel "$ACCEL" -cpu "$CPU" -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