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并检查返回值:

  1. 进程A打开设备,调用DRM_IOCTL_SET_MASTER,应返回0(成功获取master)。
  2. 进程B打开设备,调用DRM_IOCTL_DROP_MASTER,应返回-EACCES(非master无权释放)。
  3. 进程B调用DRM_IOCTL_AUTH_MAGIC并传入进程A的magic值(通过进程A的fd获取),应返回0(认证通过)。
  4. 进程B传入错误magic值,应返回-EACCES(认证失败)。
  5. 进程A调用DRM_IOCTL_DROP_MASTER,应返回0(成功释放)。
  6. 进程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)判断。
  • 认证通过后驱动未执行具体特权操作,仅验证了授权流程;实际使用时应在认证成功后允许客户端调用模式设置等特权接口。