2. DRM子系统基础:DRM核心架构、KMS与GEM简介

在无GPU平台上进行DRM驱动开发,首先需要理解DRM子系统的三大支柱:核心架构、KMS(内核模式设置)和GEM(图形执行管理器)。这三者共同构成了Linux图形栈的基石,为drm_fbdev模拟层提供了运行环境。

2.1 DRM核心架构:从用户态到硬件的桥梁

DRM(Direct Rendering Manager)是Linux内核中负责图形显示和渲染管理的子系统。它通过统一的接口,将用户态应用程序(如Xorg、Wayland compositor)与底层显示硬件(GPU或Framebuffer设备)解耦。

核心设计理念: DRM将显示控制与内存管理分离,KMS负责显示管线的配置,GEM负责图形缓冲区的分配与共享。

DRM核心架构主要包含以下层次:

  • 用户态接口层: 通过/dev/dri/card0等设备节点暴露ioctl接口,供用户态程序调用。
  • DRM核心框架: 提供通用的驱动注册、文件操作、ioctl分发、调试支持等基础设施。
  • 驱动实现层: 具体硬件厂商实现的驱动,包含KMS和GEM的具体操作函数。
  • 硬件抽象层: 通过MMIO、I2C、GPIO等总线与硬件交互。
DRM核心架构分层图 用户态:Xorg / Wayland / 应用程序 系统调用 / ioctl 接口 DRM核心框架(drm_driver / drm_device) 驱动实现层:KMS回调 + GEM回调 + 硬件操作

2.2 KMS(内核模式设置):掌控显示管线

KMS是DRM子系统中负责显示模式设置和显示管线管理的核心组件。它将原本分散在用户态的模式设置逻辑移入内核,提供了原子化、无撕裂的显示配置能力。

2.2.1 KMS核心对象

KMS通过四个核心对象来描述和管理显示硬件:

对象 数据结构 职责描述 无GPU平台对应
CRTC drm_crtc 控制显示时序、扫描输出,驱动显示控制器 SoC内置Display Controller
Encoder drm_encoder 将CRTC输出的像素数据编码为特定接口信号 RGB/LVDS/MIPI DSI发送器
Connector drm_connector 代表物理显示接口,检测连接状态和EDID HDMI/VGA/DSI接口
Plane drm_plane 管理显示图层,支持叠加、缩放、旋转 硬件图层(通常至少1个主平面)
无GPU平台提示: 即使没有GPU,SoC内部的显示控制器通常也包含上述四个对象的硬件实现。驱动开发者的任务就是将这些硬件单元注册为KMS对象,并实现对应的回调函数。
KMS核心对象关系与显示管线 用户态应用程序 Framebuffer (drm_framebuffer) Plane(图层) CRTC(显示控制器) Encoder(编码器) Connector(连接器) 显示管线数据流 Framebuffer → Plane → CRTC → Encoder → Connector → 显示器

2.2.2 KMS关键操作流程

  1. 模式探测: Connector检测显示器连接状态,读取EDID获取支持的分辨率列表。
  2. 模式设置: 用户态选择显示模式,调用drm_mode_set配置CRTC时序、Encoder输出格式、Connector连接参数。
  3. 页面翻转: 通过drm_crtc_page_flip切换Framebuffer,实现无撕裂的动画显示。
  4. 原子提交: 现代KMS驱动支持drm_atomic_commit,将多个对象的配置变更打包为一个原子操作,确保显示状态的一致性。

2.3 GEM(图形执行管理器):内存管理的基石

GEM是DRM子系统中负责图形缓冲区管理的框架。它提供了一套标准化的API,用于分配、释放、共享和映射图形内存。

2.3.1 GEM核心概念

概念 说明 无GPU平台实现要点
GEM对象 内核中表示一块图形缓冲区的抽象,通过句柄(handle)在用户态引用 通常使用dma_alloc_coherent或dma_buf分配连续物理内存
GEM句柄 用户态通过ioctl获取的整数标识符,用于操作GEM对象 每个进程拥有独立的句柄空间,内核维护引用计数
GEM名称 全局唯一的名称(flink),用于跨进程共享缓冲区 通过drm_gem_flink和drm_gem_open实现
DMA-BUF 现代DRM推荐使用dma_buf机制替代flink,支持更灵活的内存共享 通过drm_gem_prime_export和drm_gem_prime_import实现
无GPU平台注意事项: 在没有GPU的情况下,GEM对象的分配不能依赖GPU的显存管理器。驱动开发者需要实现自己的gem_create_object回调,通常使用DMA API分配连续物理内存,或者使用预留的CMA(Contiguous Memory Allocator)区域。
GEM对象生命周期与内存管理流程 ① GEM对象分配 drm_gem_object_init ② 用户态映射 mmap / prime_fd ③ 渲染/显示 CPU填充 / KMS扫描 ④ 释放 drm_gem_object_put 无GPU平台GEM内存分配策略 • CMA区域:使用dma_alloc_from_contiguous分配连续物理内存,适合Framebuffer • 系统RAM:使用kzalloc分配非连续内存,适合小尺寸缓冲区 • 预留内存:在设备树中预留专用内存区域,通过memblock_reserve或reserved-memory节点

2.4 DRM、KMS与GEM的协作关系

在无GPU平台的DRM驱动中,这三个组件协同工作:

  • DRM核心 提供驱动注册框架和用户态接口。
  • KMS 管理显示管线,将GEM分配的Framebuffer扫描输出到显示器。
  • GEM 负责Framebuffer的内存分配和管理,确保KMS可以高效访问像素数据。
关键理解: 对于drm_fbdev模拟层来说,它本质上是KMS的一个特殊用户——它创建一个Framebuffer,注册为一个KMS平面,然后通过GEM管理该Framebuffer的内存。当用户态通过/dev/fb0写入像素数据时,drm_fbdev将这些数据同步到GEM对象中,最终由KMS扫描输出。