DRM full analysis - MAP_DUMB (1)

In the author's previous libdrm full analysis series, I talked about drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map) and its package function drmModeMapDumbBuffer. The corresponding article link is:

Full analysis of libdrm Thirty-Three - Full analysis of source code (30)

Full analysis of libdrm thirty-four - full analysis of source code (31)

It is mentioned in the article that the drmIoctl function actually calls the ioctl system call. The relevant code is in xf86drm.c, and the code is as follows:

/**
 * Call ioctl, restarting if it is interrupted
 */
drm_public int
drmIoctl(int fd, unsigned long request, void *arg)
{
    int ret;
 
    do {
        ret = ioctl(fd, request, arg);
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    return ret;
}

It can be seen that the incoming request value is DRM_IOCTL_MODE_MAP_DUMB.

As we all know, the ioctl system call will enter the kernel space from the user space to perform related operations and processing, and then return the result to the user space. Therefore, use DRM_IOCTL_MODE_MAP_DUMB as a clue (keyword) to enter the Linux Kernel source code, and look at the DRM-related code corresponding to this item in libdrm.

The author's kernel version is 6.1. Search for "DRM_IOCTL_MODE_MAP_DUMB" in the kernel source code. Although there are several places, what we want is this line of code in drivers/gpu/drm/drm_ioctl.c:

DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),

DRM_IOCTL_MODE_MAP_DUMB is a macro, which was mentioned in libdrm before. This definition exists not only in the libdrm source code, but also in the Linux Kernel code, because libdrm and DRM have to correspond up and down. The corresponding file in the DRM kernel source code is include/uapi/drm/drm.h, and the code is as follows:

#define DRM_IOCTL_MODE_MAP_DUMB    DRM_IOWR(0xB3, struct drm_mode_map_dumb)

The final expanded definition of the macro is:

#define DRM_IOCTL_MODE_MAP_DUMB        ( ((3)  << 30) | (('d') << 8) | ((0xB3)   << 0) | ((sizeof(struct drm_mode_map_dumb)) << 16) )

DRM_IOCTL_DEF is a macro, defined in the same file, as follows:

#define DRM_IOCTL_DEF(ioctl, _func, _flags)	\
	[DRM_IOCTL_NR(ioctl)] = {		\
		.cmd = ioctl,			\
		.func = _func,			\
		.flags = _flags,		\
		.name = #ioctl			\
	}

DRM_IOCTL_NR is also a macro, defined in include/drm/drm_ioctl.h, as follows:

#define DRM_IOCTL_NR(n)                _IOC_NR(n)

_IOC_NR is defined in include/uapi/asm-generic/ioctl.h, as follows:

/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)

_IOC_NRSHIFT, _IOC_NRMASK and other macro definitions are on the top, as follows:

#define _IOC_NRBITS	8
#define _IOC_TYPEBITS	8
 
/*
 * Let any architecture override either of the following before
 * including this file.
 */
 
#ifndef _IOC_SIZEBITS
# define _IOC_SIZEBITS	14
#endif
 
#ifndef _IOC_DIRBITS
# define _IOC_DIRBITS	2
#endif
 
#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)
 
#define _IOC_NRSHIFT	0
#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)

Readers who have read the libdrm full analysis series of articles will have the impression that the author has talked about the macro definition related to _IOC in detail. At that time, it was in /usr/include/asm-generic/ioctl. path, not a relative kernel source path):

#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

The _IOC_NR here is actually the "anti-macro" of the _IO, _IOR, _IOW, and _IOWR macros. The macros IO, _IOR, _IOW, and _IOWR combine the functions of four parts into a whole, while the macros _IOC_DIR, _IOC_TYPE, _IOC_NR, and _IOC_SIZE split the four parts of the whole one by one.

In summary, the DRM_IOCTL_DEF macro definition is expanded layer by layer as follows:

​#define DRM_IOCTL_DEF(ioctl, _func, _flags)	\
	[_IOC_NR(ioctl)] = {		\
		.cmd = ioctl,			\
		.func = _func,			\
		.flags = _flags,		\
		.name = #ioctl			\
	}

--->

​#define DRM_IOCTL_DEF(ioctl, _func, _flags)	\
	[(((ioctl) >> _IOC_NRSHIFT) & _IOC_NRMASK)] = {		\
		.cmd = ioctl,			\
		.func = _func,			\
		.flags = _flags,		\
		.name = #ioctl			\
	}

--->

​#define DRM_IOCTL_DEF(ioctl, _func, _flags)	\
	[(((ioctl) >> 0) & 0xFF)] = {		\
		.cmd = ioctl,			\
		.func = _func,			\
		.flags = _flags,		\
		.name = #ioctl			\
	}

Substitute the following actual values:

DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),

and end up with:

​#define DRM_IOCTL_DEF(ioctl, _func, _flags)	\
	[0xB3] = {		\
		.cmd = DRM_IOCTL_MODE_MAP_DUMB,			\
		.func = drm_mode_mmap_dumb_ioctl,			\
		.flags = 0,		\
		.name = "DRM_IOCTL_MODE_MAP_DUMB"
	}

Regarding the DRM_IOCTL_MODE_MAP_DUMB in the kernel and the corresponding function drm_mode_mmap_dumb_ioctl, the rest will be explained in subsequent articles.

Guess you like

Origin blog.csdn.net/phmatthaus/article/details/132702292