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等总线与硬件交互。
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对象,并实现对应的回调函数。
2.2.2 KMS关键操作流程
- 模式探测: Connector检测显示器连接状态,读取EDID获取支持的分辨率列表。
- 模式设置: 用户态选择显示模式,调用
drm_mode_set配置CRTC时序、Encoder输出格式、Connector连接参数。 - 页面翻转: 通过
drm_crtc_page_flip切换Framebuffer,实现无撕裂的动画显示。 - 原子提交: 现代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)区域。
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扫描输出。