4. DRM 内存管理器初始化与清理
任务目标
在DRM子系统中,master是拥有特权操作权限的客户端(如模式设置、提交framebuffer等),而auth机制用于管理客户端与master之间的认证关系。本案例实现一个最小可运行的DRM master获取/释放与客户端认证流程,确保只有通过认证的master客户端才能执行特权操作。
核心实现
以下代码实现了一个字符设备驱动,通过ioctl暴露DRM_IOCTL_SET_MASTER、DRM_IOCTL_DROP_MASTER和DRM_IOCTL_AUTH_MAGIC三个命令。驱动内部维护当前master的进程PID和magic值,仅当调用者与master PID匹配时才允许drop操作;仅当magic匹配时才允许auth操作。
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#define DRM_IOCTL_BASE 'd'
#define DRM_IOCTL_SET_MASTER _IO(DRM_IOCTL_BASE, 0x01)
#define DRM_IOCTL_DROP_MASTER _IO(DRM_IOCTL_BASE, 0x02)
#define DRM_IOCTL_AUTH_MAGIC _IOW(DRM_IOCTL_BASE, 0x03, unsigned int)
static DEFINE_MUTEX(drm_lock);
static pid_t master_pid = -1;
static unsigned int master_magic = 0;
static unsigned int next_magic = 0xA5A50001;
static int drm_open(struct inode *inode, struct file *filp)
{
filp->private_data = (void *)next_magic++;
return 0;
}
static long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
unsigned int magic = (unsigned int)filp->private_data;
pid_t caller_pid = task_tgid_vnr(current);
mutex_lock(&drm_lock);
switch (cmd) {
case DRM_IOCTL_SET_MASTER:
if (master_pid != -1) {
ret = -EBUSY;
break;
}
master_pid = caller_pid;
master_magic = magic;
break;
case DRM_IOCTL_DROP_MASTER:
if (master_pid != caller_pid) {
ret = -EACCES;
break;
}
master_pid = -1;
master_magic = 0;
break;
case DRM_IOCTL_AUTH_MAGIC: {
unsigned int auth_magic;
if (copy_from_user(&auth_magic, (void __user *)arg, sizeof(auth_magic))) {
ret = -EFAULT;
break;
}
if (master_pid == -1) {
ret = -EINVAL;
break;
}
if (auth_magic != master_magic) {
ret = -EACCES;
break;
}
/* 认证通过:允许执行特权操作(此处仅记录状态) */
break;
}
default:
ret = -ENOTTY;
break;
}
mutex_unlock(&drm_lock);
return ret;
}
static const struct file_operations drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.unlocked_ioctl = drm_ioctl,
};
static struct miscdevice drm_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "drm_master_auth",
.fops = &drm_fops,
};
static int __init drm_auth_init(void)
{
return misc_register(&drm_misc);
}
static void __exit drm_auth_exit(void)
{
misc_deregister(&drm_misc);
}
module_init(drm_auth_init);
module_exit(drm_auth_exit);
MODULE_LICENSE("GPL");
编译与加载
# 编译
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
# 加载
sudo insmod drm_master_auth.ko
# 查看设备节点(应生成 /dev/drm_master_auth)
ls -l /dev/drm_master_auth
验证方法
编写用户态测试程序,按以下顺序调用ioctl并检查返回值:
- 进程A打开设备,调用
DRM_IOCTL_SET_MASTER,应返回0(成功获取master)。 - 进程B打开设备,调用
DRM_IOCTL_DROP_MASTER,应返回-EACCES(非master无权释放)。 - 进程B调用
DRM_IOCTL_AUTH_MAGIC并传入进程A的magic值(通过进程A的fd获取),应返回0(认证通过)。 - 进程B传入错误magic值,应返回
-EACCES(认证失败)。 - 进程A调用
DRM_IOCTL_DROP_MASTER,应返回0(成功释放)。 - 进程A再次调用
DRM_IOCTL_DROP_MASTER,应返回-EACCES(已不是master)。
通过条件:上述6个步骤的返回值与预期完全一致,且dmesg无错误输出,即证明master获取/释放与auth认证机制工作正常。
关键说明
- 本实现使用进程PID作为master身份标识,magic值在
open时分配并保存在file私有数据中,模拟真实DRM中客户端唯一标识。 - 真实DRM子系统中,
SET_MASTER仅允许具备CAP_SYS_ADMIN权限的进程调用,本案例为聚焦机制省略了权限检查,实际集成时应在SET_MASTER分支中增加capable(CAP_SYS_ADMIN)判断。 - 认证通过后驱动未执行具体特权操作,仅验证了授权流程;实际使用时应在认证成功后允许客户端调用模式设置等特权接口。