3 puntos por GN⁺ 2025-08-08 | 1 comentarios | Compartir por WhatsApp
  • Este artículo se centra en el proceso de desarrollo de Tyr, el moderno driver de GPU para kernel Linux desarrollado en Rust, y en el principio de funcionamiento de los controladores GPU
  • En el desarrollo de drivers GPU, se explica la distinción y la interacción entre UMD (controlador en modo usuario) y KMD (controlador en modo kernel) a través del ejemplo VkCube
  • El UMD convierte APIs de alto nivel en comandos de bajo nivel que la GPU puede entender, mientras que el KMD se encarga de funciones críticas como la asignación de memoria, la planificación de trabajos y la inicialización del dispositivo
  • La API que ofrece el driver Tyr es idéntica a la de Panthor y se compone de consultas de dispositivo, gestión de memoria, gestión de grupos, envío de trabajos y administración del heap de Tiler
  • En el siguiente texto se abordará la arquitectura de hardware Arm CSF y sus componentes principales (por ejemplo, el MCU) junto con el proceso de arranque

Introducción: Desarrollo de un driver moderno de kernel GPU basado en Rust

  • Este es el segundo artículo de la serie de desarrollo de Tyr, un driver de GPU en Rust de última generación para Linux que soporta GPUs basadas en Arm Mali CSF
  • Se eligió como ejemplo real VkCube, un programa 3D simple que renderiza un cubo rotando con la API de Vulkan, para explicar cómo funciona internamente un driver de GPU
  • La estructura simple de VkCube lo hace apto para aprender los principios de operación de un driver GPU

Fundamentos del driver GPU: rol y estructura de UMD y KMD

  • Se compone de User Mode Driver (UMD) y Kernel Mode Driver (KMD)
    • UMD: implementa API de aplicaciones normales (como Vulkan, OpenGL), como panvk (el driver de Vulkan de Mesa)
    • KMD: drivers de nivel kernel con privilegios sobre el hardware, como Tyr, que funcionan como parte del kernel de Linux
  • El driver GPU en modo kernel conecta el UMD con la GPU real, mientras que el UMD interpreta instrucciones de la API y las convierte en un conjunto de comandos entendible por la GPU
  • El UMD prepara datos necesarios para componer la escena, como geometría, texturas y shaders, y antes de ejecutar solicita al KMD que los asigne en la memoria de la GPU
  • Los shaders son programas independientes que se ejecutan en la GPU; en VkCube se encargan del posicionamiento del cubo, coloreado y rotación. La ejecución del shader necesita datos externos (geometría, color, matriz de rotación, etc.)
  • El UMD envía al KMD comandos preparados (por ejemplo, VkCommandBuffers) para ejecutarlos; cuando el trabajo termina, recibe una notificación para poder guardar el resultado en memoria

Responsabilidades principales del KMD (Kernel Mode Driver)

  • Asignación y mapeo de memoria de GPU (proporcionando aislamiento por aplicación)
  • Envío de trabajos a la cola de hardware y notificación al usuario al completarse
  • En entornos hardware asíncronos y paralelos, la gestión de dependencias de trabajo es esencial, y para obtener resultados correctos el KMD realiza la programación y validación de dependencias
  • También incluye inicialización del dispositivo, operación de reguladores de reloj/voltaje, ejecución de código de arranque y gestión de rotación de acceso para que múltiples clientes compartan el hardware de forma justa

Dónde está la complejidad: la división de trabajo entre UMD y KMD

  • La complejidad de un driver GPU se concentra principalmente en el UMD
    • UMD: convertir comandos de API de alto nivel en instrucciones de hardware
    • KMD: proveer funciones clave para que el UMD funcione correctamente, como aislamiento de memoria, compartición y acceso justo

Estructura de la interfaz del driver (API) que provee Tyr

  • La API del driver Tyr (igual a la de Panthor) se puede clasificar en 5 grupos grandes
    1. Consulta de información del dispositivo: DEV_QUERY (consulta de información de hardware de la GPU mediante IOCTL, aprovechamiento del área ROM)
    2. Asignación y aislamiento de memoria: VM_CREATE, VM_BIND, VM_DESTROY, VM_GET_STATE, BO_CREATE, BO_MMAP_OFFSET, etc.
    3. Gestión de grupos de scheduling: GROUP_CREATE, GROUP_DESTROY, GROUP_GET_STATE (se explicará con más detalle en el siguiente artículo)
    4. Envío de trabajos: GROUP_SUBMIT (solicita ejecución en la GPU mediante el buffer de comandos del dispositivo)
    5. Gestión de heap de Tiler: TILER_HEAP_CREATE, TILER_HEAP_DESTROY (para cubrir los requisitos de memoria de una GPU de renderizado con tileado)
  • Estas APIs están algo alejadas del trabajo de dibujar directamente en pantalla: el UMD maneja la ejecución real de los comandos y el KMD únicamente expone esta interfaz para permitir el acceso al hardware

Conclusión y próximos pasos

  • En este texto se revisó la estructura general y el flujo interno de los drivers GPU, así como la API clave que provee Tyr
  • Partiendo de esto, en los próximos artículos de la serie se abordarán elementos centrales como la arquitectura de hardware Arm CSF, el MCU (unidad de control micro) y el proceso de inicialización del driver

1 comentarios

 
GN⁺ 2025-08-08
Comentarios de Hacker News
  • Fue un artículo muy bueno, pero se quedó demasiado corto; apenas empezaba a ponerse interesante y terminó justo cuando acababa de engancharme, así que espero con ansias la siguiente entrega.
    • La próxima semana habrá otro episodio igual de interesante: podremos ver cómo los comandos pendientes en la GPU salen de la cola y se ejecutan. La capa de abstracción que trata aquí se limita al paso de datos en la frontera entre usuario y kernel. Al centrarse principalmente en la gestión de colas y buffers, no hay mucha lógica de cómputo. Lo realmente importante sucede cuando se ejecutan los comandos encolados, y también me intriga la señal de finalización de comandos que regresa desde la GPU en sentido opuesto. La mayor parte de este manejo asíncrono ocurre en el código de usuario, no en el driver; el driver solo transmite la señal de terminación.
  • Yo uso uno de los dispositivos RK3588 como escritorio y utilizo panfrost, pero a veces en Firefox aparece la pantalla negra o se crean áreas transparentes; es un comportamiento extraño.
    • RK3588 en realidad usa el driver panthor, que es justamente el tema del artículo.
  • Me preguntaba si se consideró usar uring_cmd en lugar de ioctls; como este proyecto se está construyendo desde cero, parecía viable, y me intriga por qué se concluyó que su ventaja era casi nula.
    • Como la GPU ya tiene su propia cola de comandos asíncronos, IOCTL ya cumple originalmente una función relativamente barata de escribir en esa cola, así que crear otra cola asíncrona en el lado de CPU para programar esa escritura es una opción de utilidad limitada. Si la propuesta fuera mapear la propia cola de comandos de la GPU como uring para usuariospace, entonces para soportar correctamente la especificación del API de io_uring habría que cambiar bastante el firmware, y puede que por las características del hardware sea imposible.
    • El driver descrito en el artículo sigue exactamente el API que requiere la librería userspace de Mesa.
  • Lo leí con mucho interés y me pregunté si habría una continuación o algo lógicamente conectado.
    • Es el primer artículo publicado hoy, así que espero que haya más actualizaciones.
  • Entiendo que el título “Rust GPU driver” intenta atraer más clics, pero en realidad esto no es un driver de GPU basado en Arm Mali CSF. En lo personal, no me gusta que se ponga el foco en una meta-herramienta para desarrollo; lo que percibo es un objetivo orientado a construir algo en Rust. Aunque el artículo diga que es un “kernel de driver de GPU basado en arm mali”, no lo llama de manera explícita driver de Arm Mali. Creo que hacer un driver es unir la API del sistema operativo con la API del fabricante de hardware, no construir una capa extra de abstracción arriba de eso, como un framework de metacapa; espero que disculpes que sea directo.
    • Lo que hace a Rust relevante aquí es que es uno de los primeros (si no el primero) ejemplos de un driver de GPU con soporte de infraestructura en Rust en Linux.
    • No me disculpas por hablar con crudeza: por tu forma de hablar parece que no tienes idea de lo que es un driver de GPU moderno. Aunque lo usé hace 15 años, al menos sé que desde entonces se ha vuelto mucho más complejo. Si revisas el código fuente del kernel de Linux, los drivers de GPU son precisamente el área con más líneas de código; casi todos los drivers terminan soportando múltiples tarjetas gráficas. Me pregunto si sabes que es irracional crear un driver totalmente independiente para cada tarjeta GPU. El trabajo con drivers de GPU no consiste solo en “conectar dos APIs con líneas”; en realidad es bastante más distinto. Si quieres contradecir eso, muéstrame el driver de GPU que hayas escrito y veamos si de verdad solo conectaste unas cuantas líneas para terminarlo.
    • Rust es importante aquí porque este es uno de los primeros casos (si no el primero) en los que se usó infraestructura de Rust en un driver de GPU.