kde: pipeline escritorio QEMU (qemu-desktop-image + plasma-start-qemu)
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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" <<EOF
|
||||
[Icons]
|
||||
Theme=breeze
|
||||
|
||||
[General]
|
||||
ColorScheme=BreezeLight
|
||||
widgetStyle=Breeze
|
||||
|
||||
[KDE]
|
||||
widgetStyle=Breeze
|
||||
EOF
|
||||
|
||||
say "GPU DRM: $(ls /dev/dri/ 2>/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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user