72 cores, 3 dias, y una linea: la batalla por la GPU de una Raspberry Pi 3 en NixOS
Esta es la historia de como tardamos 3 dias en activar una GPU en una Raspberry Pi 3. No porque sea dificil, sino porque NixOS y el firmware de la Pi no se ponen de acuerdo en quien manda sobre el hardware. Y de como la solucion fue comentar una linea.
El problema
La Raspberry Pi 3 tiene una GPU VideoCore IV (vc4). En Raspbian funciona de serie. En NixOS, no. RetroArch iba a 1 fps. Software rendering puro. La GPU estaba ahi pero nadie la usaba.
$ cat /sys/firmware/devicetree/base/soc/gpu/status
disabled
$ cat /sys/class/drm/card0/device/uevent
DRIVER=simple-framebuffer
$ lsmod | grep vc4
vc4 442368 0 <-- cargado pero 0 referencias, no engancha
El modulo del kernel vc4 se cargaba,
pero con cero referencias. No encontraba hardware. El device tree tenia
la GPU en disabled.
Por que pasa esto
El boot de una Raspberry Pi es una cadena:
1. GPU firmware (start.elf) arranca
|
v
2. Lee config.txt
| -> dtoverlay=vc4-fkms-v3d (activa GPU en el device tree)
v
3. Prepara DTB con overlays aplicados
| -> gpu: status = "okay"
v
4. Carga u-boot (bootloader de NixOS)
|
v
5. u-boot lee extlinux.conf
| -> FDTDIR ../nixos/kernel-dtbs/ <-- AHI ESTA EL PROBLEMA
v
6. u-boot SOBREESCRIBE el DTB del firmware con el del kernel
| -> gpu: status = "disabled" (vuelta al principio)
v
7. Linux arranca con GPU desactivada
El firmware de la Pi hace su trabajo correctamente: lee el overlay
vc4-fkms-v3d, lo aplica al device tree, y
le pasa un DTB con la GPU activada a u-boot. Pero u-boot tiene la
directiva FDTDIR en extlinux.conf, que le
dice "ignora ese DTB y carga el del kernel". Y el DTB del kernel tiene
la GPU en disabled porque nadie le aplico
el overlay.
Es un conflicto de autoridad: el firmware dice "GPU ON", u-boot dice "me da igual, uso mi DTB".
Lo que intentamos (y fallo)
Intento 1: Cargar el modulo vc4 por fuerza
boot.kernelModules = [ "vc4" ];Resultado: el modulo se carga pero con 0 referencias. No encuentra
hardware porque el device tree dice disabled. El modulo no es el problema.
Intento 2: DTS overlay via NixOS
hardware.deviceTree = {
enable = true;
filter = "bcm2710-rpi-3-b.dtb";
overlays = [{
name = "enable-vc4";
dtsText = ''
/dts-v1/; /plugin/;
/ { fragment@0 { target-path = "/soc/v3d@7ec00000";
__overlay__ { status = "okay"; }; }; };
'';
}];
};Resultado: rompio el boot. La Pi no arrancaba. El
script de NixOS que aplica overlays al DTB fallo con FDT_ERR_BADOFFSET. Tuvimos que revertir con
extlinux desde el disco conectado a aurin.
Intento 3: Modificar el DTB manualmente
Decompilamos el DTB con dtc, cambiamos
disabled por okay en los nodos v3d, gpu y hdmi, recompilamos,
y lo pusimos en la particion firmware.
Resultado: u-boot ignora el DTB de la particion firmware. Usa el de
FDTDIR.
Lo pusimos en el directorio de FDTDIR
(/boot/nixos/kernel-dtbs/).
Resultado: sigue disabled. NixOS monta
esos ficheros desde el nix store (inmutable). Nuestro DTB modificado fue
ignorado.
Intento 4: Cambiar a armv7l (32 bits)
La GPU vc4 supuestamente no funciona en aarch64 (64 bits) en la Pi 3. Probamos compilar todo el sistema en armv7l.
Resultado: bun y otros paquetes de
home-manager no soportan armv7l. Errors de Unsupported system en cascada. Volvimos a
aarch64.
Intento 5:
simpledrm.disable=1 y video=simplefb:off
Desactivar el simple framebuffer que se apodera de la GPU antes de que vc4 pueda probar.
Resultado: simpledrm esta compilado
como builtin en el kernel (no como modulo). Los parametros de modulo no
afectan a builtins. Sigue cargandose primero.
Intento 6: nixos-raspberrypi (kernel vendor)
El paquete nixos-raspberrypi promete un kernel vendor con firmware y device tree gestionados.
Resultado: 8 horas de compilacion cross-aarch64 via
QEMU. 72 cores de Dual Xeon E5-2699v3 al 100% toda la noche. El
kernel compilo, pero el script de instalacion fallo porque la particion
firmware tenia solo 30MB (necesitaba mas). Y cuando funciono, el FDTDIR en extlinux seguia sobreescribiendo el
DTB.
La solucion: una linea
Despues de 3 dias y 6 intentos fallidos, la solucion fue comentar una
linea en /boot/extlinux/extlinux.conf:
LABEL nixos-default
LINUX ../nixos/kernel-Image
INITRD ../nixos/kernel-initrd
APPEND init=/nix/store/...-nixos-system/init ...
- FDTDIR ../nixos/kernel-dtbs
+# FDTDIR ../nixos/kernel-dtbsSin FDTDIR, u-boot no sobreescribe el
DTB. Usa el que el firmware preparo con el overlay vc4-fkms-v3d aplicado. La GPU se activa.
$ cat /sys/firmware/devicetree/base/soc/gpu/status
okay
$ ls /dev/dri/
by-path card1 renderD128
$ lsmod | grep vc4
vc4 442368 3 <-- 3 referencias, ENGANCHADO
$ cat /sys/class/drm/card*/device/uevent
DRIVER=vc4-drm
Una linea. 3 dias. 8 horas de compilacion. 6 intentos fallidos.
El diagrama: por que tarda 8 horas compilar
Aurin (x86_64) Raspberry Pi 3 (aarch64)
Dual Xeon E5-2699v3 BCM2837 ARM Cortex-A53
72 threads, 128GB RAM 4 cores, 1GB RAM
======================== ========================
nix build .#retropix.sdImage
|
v
QEMU aarch64 emulacion
(cada instruccion ARM se
traduce a x86 por software)
|
+-- gcc cross-compile kernel
| 6.12.47 (millones de lineas C)
| ~4 horas
|
+-- compilar 353 overlays DTB
| ~10 minutos
|
+-- compilar modulos kernel
| ~2 horas
|
+-- compilar firmware vendor
| ~30 minutos
|
+-- generar imagen SD (ext4 + zstd)
| ~1 hora
|
v
resultado: 12GB .img.zst
tiempo total: ~8 horas
Si tuvieramos un Mac Studio M5 Ultra:
- 16 cores nativos ARM a 4.5 GHz
- Sin emulacion QEMU
- Estimacion: ~20 minutos
La emulacion QEMU es el cuello de botella. Cada instruccion ARM que gcc genera para el kernel tiene que ser traducida por QEMU a x86, ejecutada en el Xeon, y el resultado traducido de vuelta. Son capas sobre capas sobre capas.
72 cores ayudan en paralelo (make -j72), pero la IPC emulada es ~10x mas lenta que nativa. Un M5 Ultra con ARM nativo haria esto en minutos.
Lo que queda por hacer
La solucion funciona pero es fragil: cada nixos-rebuild regenera extlinux.conf y restaura
el FDTDIR. Hay que volver a comentarlo
despues de cada deploy.
La solucion definitiva seria:
- Que nixos-raspberrypi genere DTBs con vc4 enabled por defecto
- O que el bootloader NO use
FDTDIRy deje al firmware gestionar el device tree - O parchear el script de generacion de extlinux para omitir
FDTDIRen la Pi
Pero por hoy, la GPU funciona. RetroArch va con aceleracion hardware. Xenogears va a correr como en una PlayStation de verdad. Y hemos aprendido mas sobre el boot de una Raspberry Pi de lo que jamas quisimos saber.
Leccion
A veces la solucion no es anadir codigo, sino quitar una linea. Tres dias buscando que anaddir: modulos, overlays, kernels, builds de 8 horas. Y al final era quitar 40 caracteres.
# FDTDIR ../nixos/kernel-dtbs
Esa linea comentada es el resultado de 72 cores x 3 dias x 6 intentos. Es la linea mas cara que he escrito.
—
Dedicado a todos los que han peleado con device trees a las 3 de la manana. No estais solos.
Comentarios (0)
Sin comentarios todavia. Se el primero!
Deja un comentario