3. DRM核心数据结构:drm_device、drm_driver、drm_file、drm_minor等核心对象关系
DRM(Direct Rendering Manager)子系统的核心架构围绕几个关键数据结构展开。理解 drm_device、drm_driver、drm_file 和 drm_minor 之间的关系,是掌握整个显示子系统的基础。这些对象共同构成了用户空间与内核空间交互的桥梁,并管理着从硬件抽象到文件操作的全生命周期。
3.1 核心对象全景图
下图展示了 DRM 核心对象之间的静态层次关系与动态交互路径。每个 drm_device 对应一个物理或虚拟显示控制器,通过 drm_driver 绑定具体硬件操作,通过 drm_minor 暴露给用户空间,而 drm_file 则代表一次打开的文件描述符会话。
drm_driver 定义能力,drm_device 管理状态,drm_minor 提供访问入口,drm_file 隔离会话。用户空间的每次 open() 调用都会在内核中创建一个 drm_file 实例,并通过 drm_minor 找到对应的 drm_device。
3.2 drm_device:核心设备对象
drm_device 是 DRM 子系统中最高层级的抽象,代表一个完整的显示控制器。它聚合了所有子组件,包括模式设置、帧缓冲、CRTC、编码器、连接器以及内存管理(GEM/TTM)等。
| 字段 | 类型 | 说明 |
|---|---|---|
driver |
struct drm_driver * |
指向驱动操作函数表的指针 |
dev |
struct device * |
内核通用设备结构,用于电源管理和设备模型 |
primary |
struct drm_minor * |
主设备节点(/dev/dri/card0) |
render |
struct drm_minor * |
渲染节点(/dev/dri/renderD128) |
filelist |
struct list_head |
所有打开文件句柄的链表头 |
mode_config |
struct drm_mode_config |
模式配置管理结构,包含所有 CRTC/Encoder/Connector |
vblank |
struct drm_vblank_crtc * |
垂直消隐中断管理数组 |
drm_device 的初始化通常发生在驱动探测阶段,调用 drm_dev_alloc() 分配内存,然后通过 drm_dev_register() 注册到系统。其生命周期与硬件设备绑定,当设备拔出或驱动卸载时,调用 drm_dev_unregister() 和 drm_dev_put() 释放。
3.3 drm_driver:驱动操作函数表
drm_driver 是 DRM 框架与具体硬件驱动之间的契约。它定义了一组回调函数,驱动开发者必须实现这些函数来提供硬件特定的功能。它同时携带驱动元数据,如名称、版本、支持的芯片组等。
- 设备生命周期:
load()、unload()、open()、postclose()、lastclose() - 内存管理:
gem_create_object()、gem_prime_import()、dumb_create()、dumb_map_offset() - 文件操作:
fops字段指向struct file_operations,包含open、release、ioctl、mmap等 - 调试支持:
debugfs_init()、show_fdinfo()
一个典型的 drm_driver 实例定义如下:
static const struct drm_driver my_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.name = "my_gpu",
.desc = "My GPU DRM Driver",
.date = "20250101",
.major = 1,
.minor = 0,
.fops = &my_drm_fops,
.gem_create_object = my_gem_create_object,
.dumb_create = my_dumb_create,
.dumb_map_offset = my_dumb_map_offset,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
};
driver_features 标志位决定了驱动支持的功能集。例如,DRIVER_MODESET 表示支持模式设置,DRIVER_ATOMIC 表示支持原子提交,DRIVER_RENDER 表示支持渲染节点。这些标志必须在驱动初始化时正确设置,否则相关功能不可用。
3.4 drm_minor:设备节点抽象
drm_minor 是 DRM 设备在用户空间的访问入口。每个 drm_device 可以拥有多个 drm_minor,分别对应不同的设备节点类型。Linux 内核通过次设备号来区分不同的 minor 实例。
| 类型 | 设备节点路径 | 次设备号范围 | 用途 |
|---|---|---|---|
DRM_MINOR_PRIMARY |
/dev/dri/card0 |
0-63 | 主设备节点,支持模式设置和渲染 |
DRM_MINOR_CONTROL |
/dev/dri/controlD64 |
64-127 | 控制节点,用于权限管理(已废弃) |
DRM_MINOR_RENDER |
/dev/dri/renderD128 |
128-191 | 渲染节点,仅用于 GPU 计算,无模式设置能力 |
drm_minor 结构体包含以下关键字段:
struct drm_minor {
int index; /* 次设备号索引 */
int type; /* 类型:PRIMARY / CONTROL / RENDER */
struct device *kdev; /* 内核设备结构 */
struct drm_device *dev; /* 指向所属的 drm_device */
struct drm_mode_group mode_group; /* 模式设置组 */
};
当用户空间打开 /dev/dri/card0 时,VFS 层根据次设备号找到对应的 drm_minor,然后通过 drm_minor->dev 找到 drm_device,最终调用 drm_driver->fops->open() 完成初始化。
3.5 drm_file:文件句柄私有数据
drm_file 是每个用户空间打开操作(open)在内核中的私有数据。它隔离了不同进程之间的状态,确保并发访问的安全性。每个 drm_file 实例都包含该会话特有的上下文信息。
| 字段 | 说明 |
|---|---|
authenticated |
是否通过权限认证(仅主节点需要) |
master |
指向主控节点(master)的指针,用于权限管理 |
pid |
打开该文件描述符的进程 PID |
lhead |
链表节点,用于挂入 drm_device->filelist |
object_idr |
IDR 树,管理该会话创建的 GEM 对象句柄 |
event_list |
待发送的 DRM 事件链表(如 VBLANK 事件) |
prime |
PRIME 缓冲区共享相关数据 |
drm_file 的生命周期与文件描述符绑定:
- open():内核分配
drm_file,初始化 IDR 树和事件链表,挂入filelist,调用驱动open()回调。 - ioctl():通过
drm_file查找句柄对应的 GEM 对象,执行具体操作。 - mmap():通过
drm_file中的地址空间信息完成内存映射。 - release():清理所有 GEM 对象句柄,释放事件,从
filelist移除,调用驱动postclose()回调。
3.6 对象关系总结
下表总结了四个核心对象之间的主要关系:
| 关系 | 方向 | 实现方式 | 说明 |
|---|---|---|---|
| drm_device → drm_driver | 1:1 | 指针引用 | 每个设备绑定一个驱动,驱动可被多个设备共享 |
| drm_device → drm_minor | 1:N | 数组(primary/render) | 一个设备可暴露多个设备节点 |
| drm_device → drm_file | 1:N | 链表(filelist) | 多个进程可同时打开同一个设备 |
| drm_minor → drm_device | N:1 | 指针引用 | 所有 minor 指向同一个设备 |
| drm_file → drm_device | N:1 | 指针引用 | 通过 minor 间接关联 |
| drm_file → drm_minor | N:1 | 指针引用 | 每个文件句柄对应一个 minor |
/sys/kernel/debug/dri/ 下的 debugfs 接口查看这些对象的实时状态。例如,cat /sys/kernel/debug/dri/0/name 可以查看 drm_device 的名称,cat /sys/kernel/debug/dri/0/clients 可以查看所有 drm_file 列表。