gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 815Rust 56Shell 37Markdown 291229 Definitions

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>

746d2dedd17905b67f8977018d27615e38c70ded · by sergio · (3 months ago) · parent a1ceaf6ff · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

3 files · +303 −0

diff --git a/recipes/linux-metal-dual.toml b/recipes/linux-metal-dual.toml
new file mode 100644
index 00000000..869ac911
--- /dev/null
+++ b/recipes/linux-metal-dual.toml
@@ -0,0 +1,91 @@
+# Linux kernel 7.1.2 — VARIANTE "METAL-DUAL": = linux-generic (dual-GPU i915+nouveau+radeon) PERO con el
+# CMDLINE de pivote horneado (initrd=/initramfs.cpio.gz rdinit=/init) para bootear por EFI-stub DIRECTO
+# desde el ESP como hace scripts/install-image-efi.sh (root en disco, no RAM). linux-generic no lo trae
+# (era para el path systemd-boot de mirada) y linux-metal lo trae pero APAGA nouveau. Este los une:
+# escritorio KDE en metal que aguanta Intel Y NVIDIA Pascal. Ver scripts/kde/metal-desktop-image-dual.sh.
+# Único cambio real vs linux-generic: la línea CMDLINE (+ efi=novamap para robustez de firmware UEFI).
+#
+# --- doc original de linux-generic (config idéntica) ---
+# Linux kernel 7.1.2 — VARIANTE "GENÉRICA": un solo bzImage que bootea en hardware VARIADO de testers
+# (Intel / AMD / NVIDIA), no clavado a un laptop. Hermana de:
+#   - recipes/linux.toml         (6.16.12, QEMU-tuned, of_tree LOAD-BEARING del selfhost-verify — INTOCADO)
+#   - recipes/linux-metal.toml   (6.16.12, clavado al TigerLake/Iris-Xe/AX201 del otro agente)
+# SUSTRATO kikin/harkaq (PLAN-KIKIN §4.bis + HANDOFF-KIKIN-DESDE-HAMMER, 2026-07-16): SECURITY_LANDLOCK
+# +AUDIT (la jaula del anfitrión kikin J4b / harkaq), IO_URING (kikin J4 se diseña sobre él) y
+# BPF_SYSCALL (horizonte observabilidad) van EXPLÍCITOS: «al azar del defconfig» no es un contrato.
+# GPU built-in: i915 (Intel) + radeon (AMD viejo) + NOUVEAU (NVIDIA) para que mirada tenga un DRM
+# device. amdgpu (AMD moderno) DROPEADO en v1: es el driver más grande/lento y no hace falta para el
+# tester NVIDIA; se agrega en v2 cuando la base esté validada. Monolítico (MODULES off): arje-zero PID1 sin udev/
+# modprobe ⇒ todo lo de boot/ver/teclear debe ser =y. Build ~60min (config ANCHA, GPU pesadas).
+#
+# ⚠️ NVIDIA / mirada — alcance del KERNEL: esta receta da KMS (modesetting) por nouveau, que es
+# NECESARIO pero NO suficiente para mirada en NVIDIA:
+#   (1) FIRMWARE: nouveau carga blobs de /lib/firmware/nouveau/ (ctxsw, pre-Turing) y
+#       /lib/firmware/nvidia/<chip>/gsp/*.bin (GSP-RM, Turing+ / RTX). Los inyecta la IMAGEN
+#       (linux-firmware) — NO van en el kernel. Sin GSP, nouveau no hace modeset en GPUs Turing+.
+#   (2) USERLAND GPU: mirada (wgpu→Vulkan / GL) necesita MESA con nouveau (gallium "nouveau"/zink) o
+#       NVK (Vulkan). La mesa del otro agente es IRIS-ONLY ⇒ hay que construir una mesa con nouveau/NVK
+#       para que mirada renderice en NVIDIA. Eso es del frente del otro agente. El kernel sólo aporta
+#       el /dev/dri/cardN con KMS.
+# Compilador: CC=gcc/HOSTCC=gcc — gueto-GCC (zig cc choca con el kbuild x86), igual que linux.toml/metal.
+
+name    = "linux-metal-dual"
+version = "7.1.2"
+
+[source]
+tarball = "https://mirrors.edge.kernel.org/pub/linux/kernel/v7.x/linux-7.1.2.tar.gz"
+sha256  = "b43e0a2db2a89fc5a88f54417ea13a3f05fbb17fdaf53015ce16525750a2db83"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+
+[deps]
+build = ["flex", "bison", "m4", "openssl", "elfutils", "make"]
+
+[build.phases]
+configure = """
+make ARCH=x86_64 defconfig && \
+scripts/config -d MODULE_SIG -d MODULE_SIG_ALL -d DEBUG_INFO_BTF -d DEBUG_INFO -d MODULES \
+  -d UNWINDER_ORC -e UNWINDER_FRAME_POINTER \
+  -e BLK_DEV_INITRD -e DEVTMPFS -e DEVTMPFS_MOUNT -e TMPFS \
+  -e OVERLAY_FS -e USER_NS -e NAMESPACES \
+  -e FANOTIFY -e FANOTIFY_ACCESS_PERMISSIONS \
+  -e OVERLAY_FS_REDIRECT_DIR -e OVERLAY_FS_INDEX -e OVERLAY_FS_XINO_AUTO -e OVERLAY_FS_METACOPY \
+  -e SECURITY -e SECURITY_LANDLOCK -e AUDIT -e IO_URING -e BPF_SYSCALL \
+  -e VIRTIO -e VIRTIO_PCI -e VIRTIO_BLK -e VIRTIO_NET -e DRM_VIRTIO_GPU \
+  -e PCI -e PCIEPORTBUS -e ACPI -e FW_LOADER \
+  -e EXT4_FS -e SQUASHFS -e SQUASHFS_XZ -e SQUASHFS_ZSTD -e SQUASHFS_LZ4 \
+  -e SATA_AHCI -e ATA -e ATA_PIIX -e SCSI -e BLK_DEV_SD -e BLK_DEV_SR -e BLK_DEV_LOOP \
+  -e NVME_CORE -e BLK_DEV_NVME \
+  -e MMC -e MMC_BLOCK -e MMC_SDHCI -e MMC_SDHCI_PCI -e MMC_SDHCI_ACPI \
+  -e USB_SUPPORT -e USB -e USB_PCI -e USB_XHCI_HCD -e USB_XHCI_PCI \
+  -e USB_EHCI_HCD -e USB_EHCI_PCI -e USB_OHCI_HCD -e USB_UHCI_HCD -e USB_STORAGE \
+  -e HID -e HID_GENERIC -e USB_HID -e HID_MULTITOUCH -e INPUT_EVDEV \
+  -e INPUT_KEYBOARD -e KEYBOARD_ATKBD -e INPUT_MOUSE -e MOUSE_PS2 -e INPUT_TOUCHPAD \
+  -e SERIO -e SERIO_I8042 -e VT -e VT_CONSOLE \
+  -e DRM -e DRM_SIMPLEDRM -e SYSFB_SIMPLEFB -e FB -e FB_EFI -e FB_VESA \
+  -e DRM_I915 -e DRM_RADEON -e DRM_NOUVEAU -d DRM_AMDGPU -d DRM_AMD_DC -d HSA_AMD \
+  -e DRM_FBDEV_EMULATION -e FRAMEBUFFER_CONSOLE -e FRAMEBUFFER_CONSOLE_DETECT_PRIMARY \
+  -e EFI -e EFI_STUB -e EFI_PARTITION -e EFIVAR_FS -e CMDLINE_BOOL \
+  -e VFAT_FS -e FAT_FS -e MSDOS_FS -e NLS_CODEPAGE_437 -e NLS_ISO8859_1 -e NLS_UTF8 \
+  -e ISO9660_FS -e JOLIET -e DEVTMPFS \
+  -e WLAN -e WIRELESS -e CFG80211 -e MAC80211 -e RFKILL \
+  -e WLAN_VENDOR_INTEL -e IWLWIFI -e IWLMVM -e IWLDVM \
+  -e ETHERNET -e NET_VENDOR_INTEL -e E1000 -e E1000E -e IGB -e IGC \
+  -e NET_VENDOR_REALTEK -e R8169 -e NET_VENDOR_BROADCOM -e TG3 \
+  -e USB_NET_DRIVERS -e USB_USBNET -e USB_NET_CDCETHER -e USB_NET_CDC_NCM -e USB_NET_RNDIS_HOST \
+  -d SOUND -d SND -d MEDIA_SUPPORT -d INFINIBAND -d BT -d NFC -d CAN \
+  -d WATCHDOG -d THUNDERBOLT -d FIREWIRE -d DEBUG_WX \
+  -d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS && \
+scripts/config --set-str CMDLINE "console=tty0 console=ttyS0,115200 ignore_loglevel efi=novamap initrd=/initramfs.cpio.gz rdinit=/init" && \
+make ARCH=x86_64 olddefconfig
+"""
+# amdgpu (AMD moderno) NO compila en 7.1 con el gcc del gueto (ICE sin mensaje en amdgpu_userq_fence.c)
+# y syncconfig lo re-activaba pese a -d en kconfig (default-y de DRM_AMD_DC + un select que no aparece).
+# SLEDGEHAMMER GARANTIZADO: borro las líneas `obj-$(CONFIG_DRM_AMDGPU)+= amd/...` del Makefile del drm
+# ⇒ amd/{amdgpu,amdxcp,display} nunca se descienden, sin importar kconfig. amdgpu es self-contained
+# (nada del core lo referencia) ⇒ excluirlo es seguro. radeon (AMD viejo) + i915 + nouveau quedan.
+compile = "sed -i '/CONFIG_DRM_AMDGPU)+= amd/d' drivers/gpu/drm/Makefile && make ARCH=x86_64 CC=gcc HOSTCC=gcc -j\"$(nproc)\" bzImage"
+install = "mkdir -p /out/boot && cp arch/x86/boot/bzImage /out/boot/bzImage && cp .config /out/boot/config-7.1.2-metal-dual"
diff --git a/scripts/kde/metal-desktop-image-dual.sh b/scripts/kde/metal-desktop-image-dual.sh
new file mode 100755
index 00000000..5bfd9e4e
--- /dev/null
+++ b/scripts/kde/metal-desktop-image-dual.sh
@@ -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
diff --git a/scripts/kde/plasma-start-metal-sw.sh b/scripts/kde/plasma-start-metal-sw.sh
new file mode 100755
index 00000000..31c2eeac
--- /dev/null
+++ b/scripts/kde/plasma-start-metal-sw.sh
@@ -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