From dafd97be7956af3868b5eef7a327fda25d2ca8d7 Mon Sep 17 00:00:00 2001 From: sergio Date: Sun, 19 Jul 2026 14:21:37 -0400 Subject: [PATCH] kde: pipeline escritorio QEMU (qemu-desktop-image + plasma-start-qemu) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Imagen QEMU booteable con Plasma auto-lanzado: merge base+kde-metal-rootfs, inyección del loader musl (la imagen metal nunca pudo correr KDE dinámico — base estática + KDE sin libc), parche swrast, seed patcheado (console-getty ejecuta plasma-start), PATH/dbus/ fuentes/iconos. HITO: kwin toma DRM master de virtio-gpu y expone wayland-0 (lo que el anidado no podía). Muro pendiente: GBM/EGL de software — mesa es softpipe, falta llvmpipe. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/kde/plasma-start-qemu.sh | 104 ++++++++++++++++++++++++++++++ scripts/kde/qemu-desktop-image.sh | 91 ++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 scripts/kde/plasma-start-qemu.sh create mode 100644 scripts/kde/qemu-desktop-image.sh diff --git a/scripts/kde/plasma-start-qemu.sh b/scripts/kde/plasma-start-qemu.sh new file mode 100644 index 00000000..e052135c --- /dev/null +++ b/scripts/kde/plasma-start-qemu.sh @@ -0,0 +1,104 @@ +#!/bin/sh +# plasma-start-qemu.sh — arranca Plasma en una VM QEMU con render por SOFTWARE (kms_swrast/llvmpipe) +# sobre el DRM de virtio-gpu (/dev/dri/card0). Derivado de plasma-start-metal.sh pero SIN hardware iris: +# en QEMU no hay GPU real, así que kwin presenta por el DRM de virtio con EGL/GBM de software. +# +# Se instala como /usr/bin/plasma-start en la imagen QEMU y lo AUTO-LANZA /etc/profile (console-getty +# autologin). Trae los arreglos de la campaña KDE 2026-07: QT_QUICK_BACKEND=software (plasmashell no crea +# contexto GL sin él), QT_QPA_FONTDIR (mata los tofu; qtbase se construyó sin fontconfig), kdeglobals + +# QT_QPA_PLATFORMTHEME=kde (iconos + estilo Breeze), kactivitymanagerd (plasmashell aborta sin él). +# +# Logs: /tmp/{kwin,kamd,plasmashell}.log + tee a /dev/console. Salir: matar kwin. +set -u +# getty ejecuta este script DIRECTO (no vía login shell) ⇒ PATH viene vacío: mkdir/tr/cat/dbus-daemon +# no se hallan y kwin nunca levanta. Seteamos PATH explícito (busybox + userland KDE) ANTES de todo. +export PATH=/usr/bin:/bin:/usr/sbin:/sbin +# tee a la consola gráfica (tty0) Y al serial (ttyS0) — el host captura ttyS0 con -serial file: +say() { echo "== plasma-qemu :: $*" | tee -a /dev/console /dev/ttyS0 2>/dev/null; } +dump() { echo "---- $1 ----" > /dev/ttyS0 2>/dev/null; cat "$1" > /dev/ttyS0 2>/dev/null; } + +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 + +# --- render por software sobre virtio-gpu --- +export LIBGL_ALWAYS_SOFTWARE=1 +export GALLIUM_DRIVER=llvmpipe +# kms_swrast (NO swrast): kwin abre card0 como dispositivo KMS y crea un gbm device sobre él ⇒ necesita +# el driver de software para KMS (dumb buffers). Con 'swrast' a secas gbm_create_device falla ("Failed +# to create gbm device"). kms_swrast_dri.so está en /usr/lib/dri. +export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast +export LIBGL_DRIVERS_PATH=/usr/lib/dri +export QT_QUICK_BACKEND=software +# KWIN_COMPOSE=Q ⇒ compositor QPainter (software puro, SIN OpenGL/EGL): antes kwin exponía wayland-0 y +# MORÍA al montar la salida GL sobre softpipe/virtio (EGL de software inestable ⇒ pantalla negra). El +# backend QPainter pinta con CPU directo al framebuffer DRM, sin contexto GL — el camino para VM sin GPU. +export KWIN_COMPOSE=Q +export QT_QPA_PLATFORM=wayland +export QT_QPA_PLATFORMTHEME=kde +export QT_QPA_FONTDIR=/usr/share/fonts/dejavu + +mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /run/dbus /root +chmod 700 "$XDG_RUNTIME_DIR" +[ -s /etc/machine-id ] || cat /proc/sys/kernel/random/uuid 2>/dev/null | tr -d - > /etc/machine-id + +# kdeglobals: iconos + estilo Breeze (sin esto Qt cae a hicolor vacío = escritorio pelado) +cat > "$XDG_CONFIG_HOME/kdeglobals" </dev/null | tr '\n' ' ')" +[ -e /dev/dri/card0 ] || say "!! no hay /dev/dri/card0 — ¿virtio-gpu no cargó? (dmesg | grep -i drm)" + +# D-Bus de sesión +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 +say "dbus: ${DBUS_SESSION_BUS_ADDRESS:-NO ARRANCO}" + +# Compositor sobre el DRM de virtio (software EGL/GBM vía kms_swrast). SIN --virtual: presenta al display. +say "lanzando kwin_wayland (DRM virtio, software GL)..." +/usr/bin/kwin_wayland --drm >/tmp/kwin.log 2>&1 & +KWIN=$! +i=0 +while [ $i -lt 60 ]; do + [ -S "$XDG_RUNTIME_DIR/wayland-0" ] && break + kill -0 $KWIN 2>/dev/null || { say "!! kwin murio:"; dump /tmp/kwin.log; exec /bin/sh; } + i=$((i+1)); sleep 0.5 +done +if [ -S "$XDG_RUNTIME_DIR/wayland-0" ]; then + say "compositor OK (wayland-0)" +else + say "!! kwin no expuso wayland-0:"; dump /tmp/kwin.log; exec /bin/sh +fi +export WAYLAND_DISPLAY=wayland-0 + +# kactivitymanagerd: plasmashell ABORTA sin el +KAMD=$(ls /usr/lib*/libexec/kactivitymanagerd 2>/dev/null | head -1) +[ -n "$KAMD" ] && { "$KAMD" >/tmp/kamd.log 2>&1 & sleep 2; say "kactivitymanagerd lanzado"; } + +say "lanzando plasmashell..." +/usr/bin/plasmashell >/tmp/plasmashell.log 2>&1 & +sleep 8 +say "procesos: $(ps axo comm 2>/dev/null | grep -E 'kwin|plasma' | sort -u | tr '\n' ' ')" +say "escritorio arriba (o mira /tmp/plasmashell.log). Ctrl-C mata la sesion." +dump /tmp/plasmashell.log +wait $KWIN +# kwin salió ⇒ volcá su log para saber por qué (backend QPainter, DRM, modeset…) +say "kwin salió (código $?) — volcando kwin.log:" +dump /tmp/kwin.log diff --git a/scripts/kde/qemu-desktop-image.sh b/scripts/kde/qemu-desktop-image.sh new file mode 100644 index 00000000..d4241441 --- /dev/null +++ b/scripts/kde/qemu-desktop-image.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# qemu-desktop-image.sh — imagen de disco EFI KDE para QEMU (virtio-gpu + software GL), auto-lanza Plasma. +# +# Igual que metal-desktop-image.sh pero para una VM: parchea swrast (mesa-swrast softpipe, sin LLVM) al +# rootfs runtime-completo, instala plasma-start-qemu.sh (software GL sobre el DRM de virtio) y lo AUTO- +# LANZA desde /etc/profile del console-getty. Así la ventana QEMU bootea → arje-zero → Plasma pinta solo. +# +# work/metal-rootfs base: arje-zero PID1 + busybox + kernel(EFI-stub) + firmware +# work/kde-metal-rootfs KDE runtime-completo (206 pkgs) — ya trae fuentes/iconos/kactivitymanagerd/ +# KDEPlasmaPlatformTheme/módulo QML kwindowsystem +# + store/*-mesa-swrast swrast_dri/kms_swrast (software GL, softpipe) +# → work/qemu-desktop-rootfs (hardlinks) → work/hammer-kde-qemu.img +# +# Uso: scripts/kde/qemu-desktop-image.sh # arma la imagen +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" + +BASE="${BASE:-work/metal-rootfs}" +KDE="${KDE:-work/kde-metal-rootfs}" +SWRAST="${SWRAST:-$(ls -dt store/*-mesa-swrast 2>/dev/null | head -1)}" +MERGED="${MERGED:-work/qemu-desktop-rootfs}" +IMG="${IMG:-work/hammer-kde-qemu.img}" + +[ -d "$BASE" ] || { echo "falta $BASE" >&2; exit 1; } +[ -d "$KDE" ] || { echo "falta $KDE" >&2; exit 1; } +[ -n "$SWRAST" ] && [ -d "$SWRAST" ] || { echo "falta artefacto mesa-swrast en store/" >&2; exit 1; } + +echo "==> fundiendo rootfs por hardlinks (base + KDE)" +rm -rf "$MERGED" +cp -al "$BASE" "$MERGED" +cp -al --remove-destination "$KDE"/. "$MERGED"/ + +echo "==> parcheando swrast (software GL) desde $SWRAST" +# el artefacto trae usr/lib/{dri/*swrast*,libEGL,libgbm,libglapi,libGLESv2}; copiamos SIN --remove para +# no pisar sonames del metal salvo lo que falte, pero swrast_dri debe entrar sí o sí. +cp -a "$SWRAST"/usr/lib/dri/. "$MERGED"/usr/lib/dri/ 2>/dev/null || true +for so in libglapi libgbm libEGL libGLESv2; do + cp -a "$SWRAST"/usr/lib/$so* "$MERGED"/usr/lib/ 2>/dev/null || true +done +ls "$MERGED"/usr/lib/dri/*swrast* >/dev/null 2>&1 && echo " ✓ swrast_dri instalado" || { echo " ✗ swrast no entró" >&2; exit 1; } + +echo "==> inyectando musl (loader + libc) — los binarios KDE son dinámicos" +# La base metal es 100% ESTÁTICA (arje-zero+busybox) y el KDE-rootfs no trae libc ⇒ el merge no tiene +# loader musl. Los binarios KDE piden interp /lib/ld-musl-x86_64.so.1 + NEEDED libc.so (única lib base +# que falta; el resto del closure Qt/KF6 está). Copiamos el musl soberano del host (mismo que corre la +# mirada del laptop ⇒ ejecuta binarios hammer-musl dinámicos). En musl el loader ES libc (mismo fichero). +MUSL="${MUSL:-/usr/lib/musl/lib/libc.so}" +[ -r "$MUSL" ] || { echo "no encuentro musl libc ($MUSL) — set 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" # intérprete +ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.so" # NEEDED soname en el search path +echo " ✓ musl inyectado ($(du -h "$MERGED/usr/lib/musl/lib/libc.so" | cut -f1))" + +echo "==> instalando /usr/bin/plasma-start (variante QEMU software-GL)" +install -Dm755 scripts/kde/plasma-start-qemu.sh "$MERGED/usr/bin/plasma-start" + +echo "==> auto-lanzar Plasma: console-getty ejecuta plasma-start (no /bin/sh)" +# El console-getty es un getty de SERIAL (115200 console=ttyS0) que corría /bin/sh — pero /bin/sh así NO +# es login shell, no lee /etc/profile. En vez de eso, hacemos que getty ejecute plasma-start DIRECTO +# (-l /usr/bin/plasma-start). kwin presenta al DRM de virtio-gpu (ventana gráfica), independiente de que +# la consola de texto viva en el serial. Si Plasma falla, plasma-start hace exec /bin/sh ⇒ shell serie. +python3 - "$MERGED/ente/seed.card.json" <<'PY' +import json, sys, os +p = sys.argv[1] +c = json.load(open(p)) +for g in c.get("genesis", []): + if g.get("label") == "console-getty": + argv = g["payload"]["Native"]["argv"] + argv[:] = [("/usr/bin/plasma-start" if a == "/bin/sh" else a) for a in argv] + print(" console-getty argv →", argv) +# escribir a temp y reemplazar la ENTRADA de directorio: rompe el hardlink (el seed en MERGED es un +# hardlink read-only a work/metal-rootfs) sin tocar el inode fuente ni chocar con los permisos. +tmp = p + ".new" +with open(tmp, "w") as f: + json.dump(c, f, indent=2) +os.chmod(tmp, 0o644) +os.replace(tmp, p) +PY + +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" + +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