linux/drivers/gpu/drm/drm_ioctl.c

/*
 * Created: Fri Jan  8 09:01:26 1999 by [email protected]
 *
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * Author Rickard E. (Rik) Faith <[email protected]>
 * Author Gareth Hughes <[email protected]>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <linux/export.h>
#include <linux/nospec.h>
#include <linux/pci.h>
#include <linux/uaccess.h>

#include <drm/drm_auth.h>
#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>

#include "drm_crtc_internal.h"
#include "drm_internal.h"

/**
 * DOC: getunique and setversion story
 *
 * BEWARE THE DRAGONS! MIND THE TRAPDOORS!
 *
 * In an attempt to warn anyone else who's trying to figure out what's going
 * on here, I'll try to summarize the story. First things first, let's clear up
 * the names, because the kernel internals, libdrm and the ioctls are all named
 * differently:
 *
 *  - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm
 *    through the drmGetBusid function.
 *  - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All
 *    that code is nerved in the kernel with drm_invalid_op().
 *  - The internal set_busid kernel functions and driver callbacks are
 *    exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is
 *    nerved) allowed userspace to set the busid through the above ioctl.
 *  - Other ioctls and functions involved are named consistently.
 *
 * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly
 * handling pci domains in the busid on ppc. Doing this correctly was only
 * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's
 * special with drm 1.2 and 1.3.
 *
 * Now the actual horror story of how device lookup in drm works. At large,
 * there's 2 different ways, either by busid, or by device driver name.
 *
 * Opening by busid is fairly simple:
 *
 * 1. First call SET_VERSION to make sure pci domains are handled properly. As a
 *    side-effect this fills out the unique name in the master structure.
 * 2. Call GET_UNIQUE to read out the unique name from the master structure,
 *    which matches the busid thanks to step 1. If it doesn't, proceed to try
 *    the next device node.
 *
 * Opening by name is slightly different:
 *
 * 1. Directly call VERSION to get the version and to match against the driver
 *    name returned by that ioctl. Note that SET_VERSION is not called, which
 *    means the unique name for the master node just opening is _not_ filled
 *    out. This despite that with current drm device nodes are always bound to
 *    one device, and can't be runtime assigned like with drm 1.0.
 * 2. Match driver name. If it mismatches, proceed to the next device node.
 * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by
 *    checking that the first byte in the string is 0). If that's not the case
 *    libdrm skips and proceeds to the next device node. Probably this is just
 *    copypasta from drm 1.0 times where a set unique name meant that the driver
 *    was in use already, but that's just conjecture.
 *
 * Long story short: To keep the open by name logic working, GET_UNIQUE must
 * _not_ return a unique string when SET_VERSION hasn't been called yet,
 * otherwise libdrm breaks. Even when that unique string can't ever change, and
 * is totally irrelevant for actually opening the device because runtime
 * assignable device instances were only support in drm 1.0, which is long dead.
 * But the libdrm code in drmOpenByName somehow survived, hence this can't be
 * broken.
 */

/*
 * Get the bus id.
 *
 * \param inode device inode.
 * \param file_priv DRM file private.
 * \param cmd command.
 * \param arg user argument, pointing to a drm_unique structure.
 * \return zero on success or a negative number on failure.
 *
 * Copies the bus id from drm_device::unique into user space.
 */
int drm_getunique(struct drm_device *dev, void *data,
		  struct drm_file *file_priv)
{}

static void
drm_unset_busid(struct drm_device *dev,
		struct drm_master *master)
{}

static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{}

/*
 * Get client information.
 *
 * \param inode device inode.
 * \param file_priv DRM file private.
 * \param cmd command.
 * \param arg user argument, pointing to a drm_client structure.
 *
 * \return zero on success or a negative number on failure.
 *
 * Searches for the client with the specified index and copies its information
 * into userspace
 */
int drm_getclient(struct drm_device *dev, void *data,
		  struct drm_file *file_priv)
{}

/*
 * Get statistics information.
 *
 * \param inode device inode.
 * \param file_priv DRM file private.
 * \param cmd command.
 * \param arg user argument, pointing to a drm_stats structure.
 *
 * \return zero on success or a negative number on failure.
 */
static int drm_getstats(struct drm_device *dev, void *data,
		 struct drm_file *file_priv)
{}

/*
 * Get device/driver capabilities
 */
static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{}

/*
 * Set device/driver capabilities
 */
static int
drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{}

/*
 * Setversion ioctl.
 *
 * \param inode device inode.
 * \param file_priv DRM file private.
 * \param cmd command.
 * \param arg user argument, pointing to a drm_lock structure.
 * \return zero on success or negative number on failure.
 *
 * Sets the requested interface version
 */
static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
{}

/**
 * drm_noop - DRM no-op ioctl implementation
 * @dev: DRM device for the ioctl
 * @data: data pointer for the ioctl
 * @file_priv: DRM file for the ioctl call
 *
 * This no-op implementation for drm ioctls is useful for deprecated
 * functionality where we can't return a failure code because existing userspace
 * checks the result of the ioctl, but doesn't care about the action.
 *
 * Always returns successfully with 0.
 */
int drm_noop(struct drm_device *dev, void *data,
	     struct drm_file *file_priv)
{}
EXPORT_SYMBOL();

/**
 * drm_invalid_op - DRM invalid ioctl implementation
 * @dev: DRM device for the ioctl
 * @data: data pointer for the ioctl
 * @file_priv: DRM file for the ioctl call
 *
 * This no-op implementation for drm ioctls is useful for deprecated
 * functionality where we really don't want to allow userspace to call the ioctl
 * any more. This is the case for old ums interfaces for drivers that
 * transitioned to kms gradually and so kept the old legacy tables around. This
 * only applies to radeon and i915 kms drivers, other drivers shouldn't need to
 * use this function.
 *
 * Always fails with a return value of -EINVAL.
 */
int drm_invalid_op(struct drm_device *dev, void *data,
		   struct drm_file *file_priv)
{}
EXPORT_SYMBOL();

/*
 * Copy and IOCTL return string to user space
 */
static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value)
{}

/*
 * Get version information
 *
 * \param inode device inode.
 * \param filp file pointer.
 * \param cmd command.
 * \param arg user argument, pointing to a drm_version structure.
 * \return zero on success or negative number on failure.
 *
 * Fills in the version information in \p arg.
 */
int drm_version(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
{}

static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
{}

#define DRM_IOCTL_DEF(ioctl, _func, _flags)

/* Ioctl table */
static const struct drm_ioctl_desc drm_ioctls[] =;

#define DRM_CORE_IOCTL_COUNT

/**
 * DOC: driver specific ioctls
 *
 * First things first, driver private IOCTLs should only be needed for drivers
 * supporting rendering. Kernel modesetting is all standardized, and extended
 * through properties. There are a few exceptions in some existing drivers,
 * which define IOCTL for use by the display DRM master, but they all predate
 * properties.
 *
 * Now if you do have a render driver you always have to support it through
 * driver private properties. There's a few steps needed to wire all the things
 * up.
 *
 * First you need to define the structure for your IOCTL in your driver private
 * UAPI header in ``include/uapi/drm/my_driver_drm.h``::
 *
 *     struct my_driver_operation {
 *             u32 some_thing;
 *             u32 another_thing;
 *     };
 *
 * Please make sure that you follow all the best practices from
 * ``Documentation/process/botching-up-ioctls.rst``. Note that drm_ioctl()
 * automatically zero-extends structures, hence make sure you can add more stuff
 * at the end, i.e. don't put a variable sized array there.
 *
 * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(),
 * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix::
 *
 *     ##define DRM_IOCTL_MY_DRIVER_OPERATION \
 *         DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation)
 *
 * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to
 * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire
 * up the handlers and set the access rights::
 *
 *     static const struct drm_ioctl_desc my_driver_ioctls[] = {
 *         DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation,
 *                 DRM_AUTH|DRM_RENDER_ALLOW),
 *     };
 *
 * And then assign this to the &drm_driver.ioctls field in your driver
 * structure.
 *
 * See the separate chapter on :ref:`file operations<drm_driver_fops>` for how
 * the driver-specific IOCTLs are wired up.
 */

long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata,
		      u32 flags)
{}
EXPORT_SYMBOL();

/**
 * drm_ioctl - ioctl callback implementation for DRM drivers
 * @filp: file this ioctl is called on
 * @cmd: ioctl cmd number
 * @arg: user argument
 *
 * Looks up the ioctl function in the DRM core and the driver dispatch table,
 * stored in &drm_driver.ioctls. It checks for necessary permission by calling
 * drm_ioctl_permit(), and dispatches to the respective function.
 *
 * Returns:
 * Zero on success, negative error code on failure.
 */
long drm_ioctl(struct file *filp,
	      unsigned int cmd, unsigned long arg)
{}
EXPORT_SYMBOL();

/**
 * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
 * @nr: ioctl number
 * @flags: where to return the ioctl permission flags
 *
 * This ioctl is only used by the vmwgfx driver to augment the access checks
 * done by the drm core and insofar a pretty decent layering violation. This
 * shouldn't be used by any drivers.
 *
 * Returns:
 * True if the @nr corresponds to a DRM core ioctl number, false otherwise.
 */
bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
{}
EXPORT_SYMBOL();