kde/metal: andamiaje escritorio dual-GPU (Intel i915 + NVIDIA nouveau) por software
Objetivo: USB "live" que arranca el escritorio KDE en metal y aguanta ambas máquinas (TigerLake/iris y Pascal/nouveau), render por software (mesa-llvmpipe soberano) sobre el KMS del kernel — uniforme en cualquier GPU, reusa los fixes validados en QEMU. - recipes/linux-metal-dual.toml: = linux-generic (dual-GPU i915+nouveau+radeon) + el CMDLINE de pivote de linux-metal (initrd=/initramfs.cpio.gz rdinit=/init) para bootear por EFI-stub directo desde el ESP (root en disco, no RAM). Ni linux-generic (sin pivote) ni linux-metal (nouveau OFF) servían solos. - scripts/kde/metal-desktop-image-dual.sh: arma la imagen — base metal + KDE + inyección mesa-llvmpipe/libLLVM/musl + firmware nvidia gp106 (nouveau modeset Pascal) + kernel linux-metal-dual. - scripts/kde/plasma-start-metal-sw.sh: launcher software-GL para metal, detección de GPU real (i915/nouveau/amd), lanzamiento MANUAL (bringup seguro), con los fixes de la sesión QEMU (GBM_ALWAYS_SOFTWARE, USE_MODIFIERS=0, KWIN_COMPOSE=Q, FORCE_SW_CURSOR, cursor/iconos breeze, D-Bus sesión+sistema). Pendiente: build del kernel (~60min, en curso) → rebuild imagen → validar OVMF → quemar USB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# metal-desktop-image-dual.sh — imagen de disco EFI KDE para METAL que aguanta DOS GPUs (Intel i915 y
|
||||
# NVIDIA Pascal/nouveau) con render por SOFTWARE (mesa-llvmpipe soberano). USB "live" que se adapta a la
|
||||
# máquina donde se bootee. Ver [[kde-metal-qemu-desktop]] y el runbook docs/runbooks/kde-qemu-desktop.md.
|
||||
#
|
||||
# Por qué software y no iris/nouveau HW: el mesa hammer-built es swrast/llvmpipe; una mesa HW con nouveau
|
||||
# hoy sólo existe como binario Alpine (rompe soberanía). llvmpipe sobre el KMS del kernel (i915 O nouveau)
|
||||
# funciona idéntico en ambas máquinas y reusa los fixes ya validados. HW-accel = iteración siguiente.
|
||||
#
|
||||
# work/metal-rootfs base: arje-zero PID1 + busybox + firmware i915 (static ⇒ hay que inyectar musl)
|
||||
# work/kde-metal-rootfs KDE runtime-completo (Qt/KF6/Plasma/apps)
|
||||
# + store/*-mesa-llvmpipe swrast/llvmpipe (software GL) + libLLVM.18
|
||||
# + firmware nvidia/gp106 de work/mirada-rootfs (nouveau necesita el blob firmado para modeset en Pascal)
|
||||
# + kernel linux-generic (i915 + nouveau + radeon builtin) ← NO linux-metal (ese apaga nouveau)
|
||||
# → work/hammer-kde-metal-dual.img
|
||||
#
|
||||
# Uso: scripts/kde/metal-desktop-image-dual.sh
|
||||
# BOOT=1 scripts/kde/metal-desktop-image-dual.sh # + arranca en OVMF para validar el boot chain
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
|
||||
BASE="${BASE:-work/metal-rootfs}"
|
||||
KDE="${KDE:-work/kde-metal-rootfs}"
|
||||
MESA="${MESA:-$(ls -dt store/*-mesa-llvmpipe 2>/dev/null | head -1)}"
|
||||
LLVM="${LLVM:-$(ls -dt store/*-llvm18 2>/dev/null | head -1)}"
|
||||
KERNEL="${KERNEL:-$(ls -dt store/*-linux-generic/boot/bzImage 2>/dev/null | head -1)}"
|
||||
NVFW_SRC="${NVFW_SRC:-work/mirada-rootfs/lib/firmware/nvidia}"
|
||||
MERGED="${MERGED:-work/metal-desktop-dual-rootfs}"
|
||||
IMG="${IMG:-work/hammer-kde-metal-dual.img}"
|
||||
|
||||
for x in "$BASE" "$KDE"; do [ -d "$x" ] || { echo "falta $x" >&2; exit 1; }; done
|
||||
[ -n "$MESA" ] && [ -d "$MESA" ] || { echo "falta mesa-llvmpipe en store/" >&2; exit 1; }
|
||||
[ -n "$LLVM" ] && [ -d "$LLVM" ] || { echo "falta llvm18 en store/" >&2; exit 1; }
|
||||
[ -n "$KERNEL" ] && [ -r "$KERNEL" ] || { echo "falta kernel linux-generic (build recipes/linux-generic.toml)" >&2; exit 1; }
|
||||
|
||||
echo "==> fundiendo rootfs por hardlinks (base metal + KDE)"
|
||||
rm -rf "$MERGED"
|
||||
cp -al "$BASE" "$MERGED"
|
||||
cp -al --remove-destination "$KDE"/. "$MERGED"/
|
||||
|
||||
echo "==> inyectando mesa-llvmpipe (software GL) desde $MESA"
|
||||
cp -a "$MESA"/usr/lib/dri/. "$MERGED"/usr/lib/dri/ 2>/dev/null || true
|
||||
for so in libglapi libgbm libEGL libGLESv2 libgallium; do
|
||||
cp -a "$MESA"/usr/lib/$so* "$MERGED"/usr/lib/ 2>/dev/null || true
|
||||
done
|
||||
ls "$MERGED"/usr/lib/dri/*swrast* >/dev/null 2>&1 || { echo " ✗ swrast no entró" >&2; exit 1; }
|
||||
|
||||
echo "==> inyectando libLLVM.18 + libgcc_s + libstdc++ (llvmpipe JIT los NEEDea)"
|
||||
cp -a "$LLVM"/usr/lib/libLLVM.so.18.1 "$MERGED"/usr/lib/
|
||||
ln -sf libLLVM.so.18.1 "$MERGED"/usr/lib/libLLVM.so.18
|
||||
ln -sf libLLVM.so.18.1 "$MERGED"/usr/lib/libLLVM.so
|
||||
GCCS="${GCCS:-.dev-fs/alpine/usr/lib/libgcc_s.so.1}"; [ -r "$GCCS" ] && cp -a "$GCCS" "$MERGED"/usr/lib/ || echo " ⚠ sin libgcc_s"
|
||||
STDCXX="${STDCXX:-.dev-fs/alpine/usr/lib/libstdc++.so.6}"; [ -r "$STDCXX" ] && cp -a "$STDCXX"* "$MERGED"/usr/lib/ 2>/dev/null || echo " ⚠ sin libstdc++"
|
||||
|
||||
echo "==> inyectando musl (loader + libc) — los binarios KDE son dinámicos, la base metal es estática"
|
||||
MUSL="${MUSL:-/usr/lib/musl/lib/libc.so}"
|
||||
[ -r "$MUSL" ] || { echo "no encuentro musl libc ($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"
|
||||
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.so"
|
||||
|
||||
echo "==> inyectando firmware NVIDIA gp106 (nouveau lo exige para modeset en Pascal; i915 ya está en la base)"
|
||||
if [ -d "$NVFW_SRC" ]; then
|
||||
mkdir -p "$MERGED/lib/firmware/nvidia"
|
||||
cp -a "$NVFW_SRC"/. "$MERGED/lib/firmware/nvidia/"
|
||||
echo " ✓ nvidia fw: $(ls "$MERGED/lib/firmware/nvidia" | tr '\n' ' ')"
|
||||
else
|
||||
echo " ⚠ sin $NVFW_SRC — la rama NVIDIA no hará modeset (Intel sí)"
|
||||
fi
|
||||
|
||||
echo "==> instalando /usr/bin/plasma-start (metal software-GL, lanzamiento manual)"
|
||||
install -Dm755 scripts/kde/plasma-start-metal-sw.sh "$MERGED/usr/bin/plasma-start"
|
||||
|
||||
cat > "$MERGED/etc/motd" <<'MOTD'
|
||||
|
||||
#-- hammer :: escritorio KDE Plasma 6 (metal, dual-GPU software) ------------
|
||||
Render por software (llvmpipe soberano) sobre i915 (Intel) o nouveau (NVIDIA).
|
||||
|
||||
Arrancar el escritorio: plasma-start
|
||||
Logs si algo falla: /tmp/kwin.log /tmp/plasmashell.log
|
||||
Ver GPU detectada: ls /dev/dri ; dmesg | grep -iE 'i915|nouveau|drm'
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
MOTD
|
||||
|
||||
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 · kernel: $(basename "$(dirname "$(dirname "$KERNEL")")")"
|
||||
|
||||
export ROOTFS="$MERGED" IMG ROOT_SIZE KERNEL
|
||||
export ESP_MB="${ESP_MB:-160}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-768}"
|
||||
exec ./scripts/install-image-efi.sh
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/bin/sh
|
||||
# plasma-start-metal-sw.sh — arranca Plasma en METAL con render por SOFTWARE (llvmpipe/kms_swrast) sobre
|
||||
# el DRM real de la máquina (i915 en Intel, nouveau en NVIDIA Pascal). Instalado como /usr/bin/plasma-start.
|
||||
#
|
||||
# Camino "aguanta ambas": el kernel linux-generic da KMS por i915 Y nouveau; encima corre el mesa-llvmpipe
|
||||
# soberano (mismo software GL que validamos en QEMU) ⇒ funciona idéntico en cualquier GPU sin drivers HW.
|
||||
# Trae los mismos fixes que la sesión QEMU (ver [[kde-metal-qemu-desktop]]): GBM_ALWAYS_SOFTWARE (init),
|
||||
# KWIN_DRM_USE_MODIFIERS=0 (FB), KWIN_COMPOSE=Q (rasterizador), KWIN_FORCE_SW_CURSOR (cursor), + cursor/iconos
|
||||
# breeze, D-Bus sesión+sistema, fontdir.
|
||||
#
|
||||
# NO se autoarranca: en un bringup de hardware nuevo, si Plasma falla querés el shell de la consola para
|
||||
# leer los logs, no una pantalla negra. Se corre a mano: `plasma-start`. Logs: /tmp/{kwin,plasmashell,kamd}.log
|
||||
set -u
|
||||
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
say() { echo "== plasma-metal :: $*" | tee -a /dev/console 2>/dev/null; }
|
||||
dump() { echo "---- $1 ----"; cat "$1" 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 el DRM real (i915 o nouveau, según la máquina) ---
|
||||
export LIBGL_ALWAYS_SOFTWARE=1
|
||||
export GALLIUM_DRIVER=llvmpipe
|
||||
export GBM_ALWAYS_SOFTWARE=1 # fuerza gbm->software (si no, trata la GPU real como HW y no hay driver HW)
|
||||
export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast
|
||||
export LIBGL_DRIVERS_PATH=/usr/lib/dri
|
||||
export QT_QUICK_BACKEND=software
|
||||
export LP_NUM_THREADS=1
|
||||
export KWIN_COMPOSE=Q # QPainter: esquiva el segfault del rasterizador llvmpipe
|
||||
export KWIN_DRM_USE_MODIFIERS=0 # varios KMS rechazan AddFB2WithModifiers con render software
|
||||
export KWIN_FORCE_SW_CURSOR=1 # cursor por software (el plano HW no se presenta con sw render)
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
export QT_QPA_PLATFORMTHEME=kde
|
||||
export QT_QPA_FONTDIR=/usr/share/fonts/dejavu
|
||||
export XCURSOR_THEME=breeze_cursors
|
||||
export XCURSOR_PATH=/usr/share/icons:/usr/share/pixmaps
|
||||
export XCURSOR_SIZE=24
|
||||
|
||||
mkdir -p "$XDG_RUNTIME_DIR" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /run/dbus /var/lib/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
|
||||
cp -f /etc/machine-id /var/lib/dbus/machine-id 2>/dev/null || true
|
||||
|
||||
cat > "$XDG_CONFIG_HOME/kdeglobals" <<EOF
|
||||
[Icons]
|
||||
Theme=breeze
|
||||
|
||||
[General]
|
||||
ColorScheme=BreezeLight
|
||||
widgetStyle=Breeze
|
||||
|
||||
[KDE]
|
||||
widgetStyle=Breeze
|
||||
EOF
|
||||
cat > "$XDG_CONFIG_HOME/kcminputrc" <<EOF
|
||||
[Mouse]
|
||||
cursorTheme=breeze_cursors
|
||||
cursorSize=24
|
||||
EOF
|
||||
|
||||
# --- detectar la GPU real y decirle a kwin que use SÓLO ese card (ignora efifb/simpledrm) ---
|
||||
say "GPUs DRM: $(ls /dev/dri/ 2>/dev/null | tr '\n' ' ')"
|
||||
REAL_CARD=
|
||||
for c in /dev/dri/card*; do
|
||||
[ -e "$c" ] || continue
|
||||
n=$(basename "$c")
|
||||
drv=$(readlink -f "/sys/class/drm/$n/device/driver" 2>/dev/null)
|
||||
case "$drv" in
|
||||
*i915*|*nouveau*|*amdgpu*|*radeon*|*xe*) REAL_CARD="$c"; say "GPU real: $n ($(basename "$drv"))"; break;;
|
||||
esac
|
||||
done
|
||||
[ -n "$REAL_CARD" ] && export KWIN_DRM_DEVICES="$REAL_CARD" || say "!! no hallé GPU real (i915/nouveau/amd) — kwin verá todos los DRM"
|
||||
|
||||
# --- D-Bus de sistema (udisks/solid/powerdevil) y de sesión ---
|
||||
if [ ! -S /run/dbus/system_bus_socket ]; then
|
||||
dbus-daemon --system --fork 2>/dev/null && say "system bus ON" || say "system bus NO arrancó"
|
||||
fi
|
||||
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 sesión: ${DBUS_SESSION_BUS_ADDRESS:-NO ARRANCÓ}"
|
||||
|
||||
# --- compositor sobre el DRM real ---
|
||||
say "lanzando kwin_wayland (DRM real, 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 murió:"; dump /tmp/kwin.log; exec /bin/sh; }
|
||||
i=$((i+1)); sleep 0.5
|
||||
done
|
||||
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] || { say "!! kwin no expuso wayland-0:"; dump /tmp/kwin.log; exec /bin/sh; }
|
||||
say "compositor OK (wayland-0)"
|
||||
export WAYLAND_DISPLAY=wayland-0
|
||||
|
||||
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. Ctrl-C termina la sesión. Logs: /tmp/{kwin,plasmashell,kamd}.log"
|
||||
wait $KWIN
|
||||
say "kwin salió (código $?)"; dump /tmp/kwin.log
|
||||
exec /bin/sh
|
||||
Reference in New Issue
Block a user