| 1 | |
| 2 | * Created: Fri Jan 8 09:01:26 1999 by [email protected]
|
| 3 | *
|
| 4 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
| 5 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
| 6 | * All Rights Reserved.
|
| 7 | *
|
| 8 | * Author Rickard E. (Rik) Faith <[email protected]>
|
| 9 | * Author Gareth Hughes <[email protected]>
|
| 10 | *
|
| 11 | * Permission is hereby granted, free of charge, to any person obtaining a
|
| 12 | * copy of this software and associated documentation files (the "Software"),
|
| 13 | * to deal in the Software without restriction, including without limitation
|
| 14 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 15 | * and/or sell copies of the Software, and to permit persons to whom the
|
| 16 | * Software is furnished to do so, subject to the following conditions:
|
| 17 | *
|
| 18 | * The above copyright notice and this permission notice (including the next
|
| 19 | * paragraph) shall be included in all copies or substantial portions of the
|
| 20 | * Software.
|
| 21 | *
|
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 25 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 26 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 27 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 28 | * OTHER DEALINGS IN THE SOFTWARE.
|
| 29 |
|
| 30 |
|
| 31 | #include <linux/export.h>
|
| 32 | #include <linux/nospec.h>
|
| 33 | #include <linux/pci.h>
|
| 34 | #include <linux/uaccess.h>
|
| 35 |
|
| 36 | #include <drm/drm_auth.h>
|
| 37 | #include <drm/drm_crtc.h>
|
| 38 | #include <drm/drm_drv.h>
|
| 39 | #include <drm/drm_file.h>
|
| 40 | #include <drm/drm_ioctl.h>
|
| 41 | #include <drm/drm_print.h>
|
| 42 |
|
| 43 | #include "drm_crtc_internal.h"
|
| 44 | #include "drm_internal.h"
|
| 45 |
|
| 46 | |
| 47 | * DOC: getunique and setversion story
|
| 48 | *
|
| 49 | * BEWARE THE DRAGONS! MIND THE TRAPDOORS!
|
| 50 | *
|
| 51 | * In an attempt to warn anyone else who's trying to figure out what's going
|
| 52 | * on here, I'll try to summarize the story. First things first, let's clear up
|
| 53 | * the names, because the kernel internals, libdrm and the ioctls are all named
|
| 54 | * differently:
|
| 55 | *
|
| 56 | * - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm
|
| 57 | * through the drmGetBusid function.
|
| 58 | * - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All
|
| 59 | * that code is nerved in the kernel with drm_invalid_op().
|
| 60 | * - The internal set_busid kernel functions and driver callbacks are
|
| 61 | * exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is
|
| 62 | * nerved) allowed userspace to set the busid through the above ioctl.
|
| 63 | * - Other ioctls and functions involved are named consistently.
|
| 64 | *
|
| 65 | * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly
|
| 66 | * handling pci domains in the busid on ppc. Doing this correctly was only
|
| 67 | * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's
|
| 68 | * special with drm 1.2 and 1.3.
|
| 69 | *
|
| 70 | * Now the actual horror story of how device lookup in drm works. At large,
|
| 71 | * there's 2 different ways, either by busid, or by device driver name.
|
| 72 | *
|
| 73 | * Opening by busid is fairly simple:
|
| 74 | *
|
| 75 | * 1. First call SET_VERSION to make sure pci domains are handled properly. As a
|
| 76 | * side-effect this fills out the unique name in the master structure.
|
| 77 | * 2. Call GET_UNIQUE to read out the unique name from the master structure,
|
| 78 | * which matches the busid thanks to step 1. If it doesn't, proceed to try
|
| 79 | * the next device node.
|
| 80 | *
|
| 81 | * Opening by name is slightly different:
|
| 82 | *
|
| 83 | * 1. Directly call VERSION to get the version and to match against the driver
|
| 84 | * name returned by that ioctl. Note that SET_VERSION is not called, which
|
| 85 | * means the unique name for the master node just opening is _not_ filled
|
| 86 | * out. This despite that with current drm device nodes are always bound to
|
| 87 | * one device, and can't be runtime assigned like with drm 1.0.
|
| 88 | * 2. Match driver name. If it mismatches, proceed to the next device node.
|
| 89 | * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by
|
| 90 | * checking that the first byte in the string is 0). If that's not the case
|
| 91 | * libdrm skips and proceeds to the next device node. Probably this is just
|
| 92 | * copypasta from drm 1.0 times where a set unique name meant that the driver
|
| 93 | * was in use already, but that's just conjecture.
|
| 94 | *
|
| 95 | * Long story short: To keep the open by name logic working, GET_UNIQUE must
|
| 96 | * _not_ return a unique string when SET_VERSION hasn't been called yet,
|
| 97 | * otherwise libdrm breaks. Even when that unique string can't ever change, and
|
| 98 | * is totally irrelevant for actually opening the device because runtime
|
| 99 | * assignable device instances were only support in drm 1.0, which is long dead.
|
| 100 | * But the libdrm code in drmOpenByName somehow survived, hence this can't be
|
| 101 | * broken.
|
| 102 |
|
| 103 |
|
| 104 | |
| 105 | * Get the bus id.
|
| 106 | *
|
| 107 | * \param inode device inode.
|
| 108 | * \param file_priv DRM file private.
|
| 109 | * \param cmd command.
|
| 110 | * \param arg user argument, pointing to a drm_unique structure.
|
| 111 | * \return zero on success or a negative number on failure.
|
| 112 | *
|
| 113 | * Copies the bus id from drm_device::unique into user space.
|
| 114 |
|
| 115 | int drm_getunique(struct drm_device *dev, void *data,
|
| 116 | struct drm_file *file_priv)
|
| 117 | {
|
| 118 | struct drm_unique *u = data;
|
| 119 | struct drm_master *master;
|
| 120 |
|
| 121 | mutex_lock(&dev->master_mutex);
|
| 122 | master = file_priv->master;
|
| 123 | if (u->unique_len >= master->unique_len) {
|
| 124 | if (copy_to_user(u->unique, master->unique, master->unique_len)) {
|
| 125 | mutex_unlock(&dev->master_mutex);
|
| 126 | return -EFAULT;
|
| 127 | }
|
| 128 | }
|
| 129 | u->unique_len = master->unique_len;
|
| 130 | mutex_unlock(&dev->master_mutex);
|
| 131 |
|
| 132 | return 0;
|
| 133 | }
|
| 134 |
|
| 135 | static void
|
| 136 | drm_unset_busid(struct drm_device *dev,
|
| 137 | struct drm_master *master)
|
| 138 | {
|
| 139 | kfree(master->unique);
|
| 140 | master->unique = NULL;
|
| 141 | master->unique_len = 0;
|
| 142 | }
|
| 143 |
|
| 144 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
|
| 145 | {
|
| 146 | struct drm_master *master = file_priv->master;
|
| 147 | int ret;
|
| 148 |
|
| 149 | if (master->unique != NULL)
|
| 150 | drm_unset_busid(dev, master);
|
| 151 |
|
| 152 | if (dev->dev && dev_is_pci(dev->dev)) {
|
| 153 | ret = drm_pci_set_busid(dev, master);
|
| 154 | if (ret) {
|
| 155 | drm_unset_busid(dev, master);
|
| 156 | return ret;
|
| 157 | }
|
| 158 | } else {
|
| 159 | WARN_ON(!dev->unique);
|
| 160 | master->unique = kstrdup(dev->unique, GFP_KERNEL);
|
| 161 | if (master->unique)
|
| 162 | master->unique_len = strlen(dev->unique);
|
| 163 | }
|
| 164 |
|
| 165 | return 0;
|
| 166 | }
|
| 167 |
|
| 168 | |
| 169 | * Get client information.
|
| 170 | *
|
| 171 | * \param inode device inode.
|
| 172 | * \param file_priv DRM file private.
|
| 173 | * \param cmd command.
|
| 174 | * \param arg user argument, pointing to a drm_client structure.
|
| 175 | *
|
| 176 | * \return zero on success or a negative number on failure.
|
| 177 | *
|
| 178 | * Searches for the client with the specified index and copies its information
|
| 179 | * into userspace
|
| 180 |
|
| 181 | int drm_getclient(struct drm_device *dev, void *data,
|
| 182 | struct drm_file *file_priv)
|
| 183 | {
|
| 184 | struct drm_client *client = data;
|
| 185 |
|
| 186 | |
| 187 | * Hollowed-out getclient ioctl to keep some dead old drm tests/tools
|
| 188 | * not breaking completely. Userspace tools stop enumerating one they
|
| 189 | * get -EINVAL, hence this is the return value we need to hand back for
|
| 190 | * no clients tracked.
|
| 191 | *
|
| 192 | * Unfortunately some clients (*cough* libva *cough*) use this in a fun
|
| 193 | * attempt to figure out whether they're authenticated or not. Since
|
| 194 | * that's the only thing they care about, give it to the directly
|
| 195 | * instead of walking one giant list.
|
| 196 |
|
| 197 | if (client->idx == 0) {
|
| 198 | client->auth = file_priv->authenticated;
|
| 199 | client->pid = task_pid_vnr(current);
|
| 200 | client->uid = overflowuid;
|
| 201 | client->magic = 0;
|
| 202 | client->iocs = 0;
|
| 203 |
|
| 204 | return 0;
|
| 205 | } else {
|
| 206 | return -EINVAL;
|
| 207 | }
|
| 208 | }
|
| 209 |
|
| 210 | |
| 211 | * Get statistics information.
|
| 212 | *
|
| 213 | * \param inode device inode.
|
| 214 | * \param file_priv DRM file private.
|
| 215 | * \param cmd command.
|
| 216 | * \param arg user argument, pointing to a drm_stats structure.
|
| 217 | *
|
| 218 | * \return zero on success or a negative number on failure.
|
| 219 |
|
| 220 | static int drm_getstats(struct drm_device *dev, void *data,
|
| 221 | struct drm_file *file_priv)
|
| 222 | {
|
| 223 | struct drm_stats *stats = data;
|
| 224 |
|
| 225 |
|
| 226 | memset(stats, 0, sizeof(*stats));
|
| 227 |
|
| 228 | return 0;
|
| 229 | }
|
| 230 |
|
| 231 | |
| 232 | * Get device/driver capabilities
|
| 233 |
|
| 234 | static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
| 235 | {
|
| 236 | struct drm_get_cap *req = data;
|
| 237 | struct drm_crtc *crtc;
|
| 238 |
|
| 239 | req->value = 0;
|
| 240 |
|
| 241 |
|
| 242 | switch (req->capability) {
|
| 243 | case DRM_CAP_TIMESTAMP_MONOTONIC:
|
| 244 | req->value = 1;
|
| 245 | return 0;
|
| 246 | case DRM_CAP_PRIME:
|
| 247 | req->value = DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT;
|
| 248 | return 0;
|
| 249 | case DRM_CAP_SYNCOBJ:
|
| 250 | req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ);
|
| 251 | return 0;
|
| 252 | case DRM_CAP_SYNCOBJ_TIMELINE:
|
| 253 | req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE);
|
| 254 | return 0;
|
| 255 | }
|
| 256 |
|
| 257 |
|
| 258 | if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
| 259 | return -EOPNOTSUPP;
|
| 260 |
|
| 261 | switch (req->capability) {
|
| 262 | case DRM_CAP_DUMB_BUFFER:
|
| 263 | if (dev->driver->dumb_create)
|
| 264 | req->value = 1;
|
| 265 | break;
|
| 266 | case DRM_CAP_VBLANK_HIGH_CRTC:
|
| 267 | req->value = 1;
|
| 268 | break;
|
| 269 | case DRM_CAP_DUMB_PREFERRED_DEPTH:
|
| 270 | req->value = dev->mode_config.preferred_depth;
|
| 271 | break;
|
| 272 | case DRM_CAP_DUMB_PREFER_SHADOW:
|
| 273 | req->value = dev->mode_config.prefer_shadow;
|
| 274 | break;
|
| 275 | case DRM_CAP_ASYNC_PAGE_FLIP:
|
| 276 | req->value = dev->mode_config.async_page_flip;
|
| 277 | break;
|
| 278 | case DRM_CAP_PAGE_FLIP_TARGET:
|
| 279 | req->value = 1;
|
| 280 | drm_for_each_crtc(crtc, dev) {
|
| 281 | if (!crtc->funcs->page_flip_target)
|
| 282 | req->value = 0;
|
| 283 | }
|
| 284 | break;
|
| 285 | case DRM_CAP_CURSOR_WIDTH:
|
| 286 | if (dev->mode_config.cursor_width)
|
| 287 | req->value = dev->mode_config.cursor_width;
|
| 288 | else
|
| 289 | req->value = 64;
|
| 290 | break;
|
| 291 | case DRM_CAP_CURSOR_HEIGHT:
|
| 292 | if (dev->mode_config.cursor_height)
|
| 293 | req->value = dev->mode_config.cursor_height;
|
| 294 | else
|
| 295 | req->value = 64;
|
| 296 | break;
|
| 297 | case DRM_CAP_ADDFB2_MODIFIERS:
|
| 298 | req->value = !dev->mode_config.fb_modifiers_not_supported;
|
| 299 | break;
|
| 300 | case DRM_CAP_CRTC_IN_VBLANK_EVENT:
|
| 301 | req->value = 1;
|
| 302 | break;
|
| 303 | case DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP:
|
| 304 | req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) &&
|
| 305 | dev->mode_config.async_page_flip;
|
| 306 | break;
|
| 307 | default:
|
| 308 | return -EINVAL;
|
| 309 | }
|
| 310 | return 0;
|
| 311 | }
|
| 312 |
|
| 313 | |
| 314 | * Set device/driver capabilities
|
| 315 |
|
| 316 | static int
|
| 317 | drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
| 318 | {
|
| 319 | struct drm_set_client_cap *req = data;
|
| 320 |
|
| 321 |
|
| 322 |
|
| 323 |
|
| 324 | if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
| 325 | return -EOPNOTSUPP;
|
| 326 |
|
| 327 | switch (req->capability) {
|
| 328 | case DRM_CLIENT_CAP_STEREO_3D:
|
| 329 | if (req->value > 1)
|
| 330 | return -EINVAL;
|
| 331 | file_priv->stereo_allowed = req->value;
|
| 332 | break;
|
| 333 | case DRM_CLIENT_CAP_UNIVERSAL_PLANES:
|
| 334 | if (req->value > 1)
|
| 335 | return -EINVAL;
|
| 336 | file_priv->universal_planes = req->value;
|
| 337 | break;
|
| 338 | case DRM_CLIENT_CAP_ATOMIC:
|
| 339 | if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
|
| 340 | return -EOPNOTSUPP;
|
| 341 |
|
| 342 | if (current->comm[0] == 'X' && req->value == 1) {
|
| 343 | pr_info("broken atomic modeset userspace detected, disabling atomic\n");
|
| 344 | return -EOPNOTSUPP;
|
| 345 | }
|
| 346 | if (req->value > 2)
|
| 347 | return -EINVAL;
|
| 348 | file_priv->atomic = req->value;
|
| 349 | file_priv->universal_planes = req->value;
|
| 350 | |
| 351 | * No atomic user-space blows up on aspect ratio mode bits.
|
| 352 |
|
| 353 | file_priv->aspect_ratio_allowed = req->value;
|
| 354 | break;
|
| 355 | case DRM_CLIENT_CAP_ASPECT_RATIO:
|
| 356 | if (req->value > 1)
|
| 357 | return -EINVAL;
|
| 358 | file_priv->aspect_ratio_allowed = req->value;
|
| 359 | break;
|
| 360 | case DRM_CLIENT_CAP_WRITEBACK_CONNECTORS:
|
| 361 | if (!file_priv->atomic)
|
| 362 | return -EINVAL;
|
| 363 | if (req->value > 1)
|
| 364 | return -EINVAL;
|
| 365 | file_priv->writeback_connectors = req->value;
|
| 366 | break;
|
| 367 | case DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT:
|
| 368 | if (!drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT))
|
| 369 | return -EOPNOTSUPP;
|
| 370 | if (!file_priv->atomic)
|
| 371 | return -EINVAL;
|
| 372 | if (req->value > 1)
|
| 373 | return -EINVAL;
|
| 374 | file_priv->supports_virtualized_cursor_plane = req->value;
|
| 375 | break;
|
| 376 | case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE: {
|
| 377 | struct drm_plane *plane;
|
| 378 | bool has_plane_with_color_pipeline = false;
|
| 379 |
|
| 380 | if (!file_priv->atomic)
|
| 381 | return -EINVAL;
|
| 382 | if (req->value > 1)
|
| 383 | return -EINVAL;
|
| 384 | drm_for_each_plane(plane, dev) {
|
| 385 | if (plane->color_pipeline_property) {
|
| 386 | has_plane_with_color_pipeline = true;
|
| 387 | break;
|
| 388 | }
|
| 389 | }
|
| 390 | if (!has_plane_with_color_pipeline)
|
| 391 | return -EOPNOTSUPP;
|
| 392 | file_priv->plane_color_pipeline = req->value;
|
| 393 | break;
|
| 394 | }
|
| 395 | default:
|
| 396 | return -EINVAL;
|
| 397 | }
|
| 398 |
|
| 399 | return 0;
|
| 400 | }
|
| 401 |
|
| 402 | |
| 403 | * Setversion ioctl.
|
| 404 | *
|
| 405 | * \param inode device inode.
|
| 406 | * \param file_priv DRM file private.
|
| 407 | * \param cmd command.
|
| 408 | * \param arg user argument, pointing to a drm_lock structure.
|
| 409 | * \return zero on success or negative number on failure.
|
| 410 | *
|
| 411 | * Sets the requested interface version
|
| 412 |
|
| 413 | static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
| 414 | {
|
| 415 | struct drm_set_version *sv = data;
|
| 416 | int if_version, retcode = 0;
|
| 417 |
|
| 418 | mutex_lock(&dev->master_mutex);
|
| 419 | if (sv->drm_di_major != -1) {
|
| 420 | if (sv->drm_di_major != DRM_IF_MAJOR ||
|
| 421 | sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
|
| 422 | retcode = -EINVAL;
|
| 423 | goto done;
|
| 424 | }
|
| 425 | if_version = DRM_IF_VERSION(sv->drm_di_major,
|
| 426 | sv->drm_di_minor);
|
| 427 | dev->if_version = max(if_version, dev->if_version);
|
| 428 | if (sv->drm_di_minor >= 1) {
|
| 429 | |
| 430 | * Version 1.1 includes tying of DRM to specific device
|
| 431 | * Version 1.4 has proper PCI domain support
|
| 432 |
|
| 433 | retcode = drm_set_busid(dev, file_priv);
|
| 434 | if (retcode)
|
| 435 | goto done;
|
| 436 | }
|
| 437 | }
|
| 438 |
|
| 439 | if (sv->drm_dd_major != -1) {
|
| 440 | if (sv->drm_dd_major != dev->driver->major ||
|
| 441 | sv->drm_dd_minor < 0 || sv->drm_dd_minor >
|
| 442 | dev->driver->minor) {
|
| 443 | retcode = -EINVAL;
|
| 444 | goto done;
|
| 445 | }
|
| 446 | }
|
| 447 |
|
| 448 | done:
|
| 449 | sv->drm_di_major = DRM_IF_MAJOR;
|
| 450 | sv->drm_di_minor = DRM_IF_MINOR;
|
| 451 | sv->drm_dd_major = dev->driver->major;
|
| 452 | sv->drm_dd_minor = dev->driver->minor;
|
| 453 | mutex_unlock(&dev->master_mutex);
|
| 454 |
|
| 455 | return retcode;
|
| 456 | }
|
| 457 |
|
| 458 | |
| 459 | * drm_noop - DRM no-op ioctl implementation
|
| 460 | * @dev: DRM device for the ioctl
|
| 461 | * @data: data pointer for the ioctl
|
| 462 | * @file_priv: DRM file for the ioctl call
|
| 463 | *
|
| 464 | * This no-op implementation for drm ioctls is useful for deprecated
|
| 465 | * functionality where we can't return a failure code because existing userspace
|
| 466 | * checks the result of the ioctl, but doesn't care about the action.
|
| 467 | *
|
| 468 | * Always returns successfully with 0.
|
| 469 |
|
| 470 | int drm_noop(struct drm_device *dev, void *data,
|
| 471 | struct drm_file *file_priv)
|
| 472 | {
|
| 473 | drm_dbg_core(dev, "\n");
|
| 474 | return 0;
|
| 475 | }
|
| 476 | EXPORT_SYMBOL(drm_noop);
|
| 477 |
|
| 478 | |
| 479 | * drm_invalid_op - DRM invalid ioctl implementation
|
| 480 | * @dev: DRM device for the ioctl
|
| 481 | * @data: data pointer for the ioctl
|
| 482 | * @file_priv: DRM file for the ioctl call
|
| 483 | *
|
| 484 | * This no-op implementation for drm ioctls is useful for deprecated
|
| 485 | * functionality where we really don't want to allow userspace to call the ioctl
|
| 486 | * any more. This is the case for old ums interfaces for drivers that
|
| 487 | * transitioned to kms gradually and so kept the old legacy tables around. This
|
| 488 | * only applies to radeon and i915 kms drivers, other drivers shouldn't need to
|
| 489 | * use this function.
|
| 490 | *
|
| 491 | * Always fails with a return value of -EINVAL.
|
| 492 |
|
| 493 | int drm_invalid_op(struct drm_device *dev, void *data,
|
| 494 | struct drm_file *file_priv)
|
| 495 | {
|
| 496 | return -EINVAL;
|
| 497 | }
|
| 498 | EXPORT_SYMBOL(drm_invalid_op);
|
| 499 |
|
| 500 | |
| 501 | * Copy and IOCTL return string to user space
|
| 502 |
|
| 503 | static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value)
|
| 504 | {
|
| 505 | size_t len;
|
| 506 |
|
| 507 |
|
| 508 | if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) {
|
| 509 | *buf_len = 0;
|
| 510 | return 0;
|
| 511 | }
|
| 512 |
|
| 513 |
|
| 514 | len = strlen(value);
|
| 515 | if (len > *buf_len)
|
| 516 | len = *buf_len;
|
| 517 |
|
| 518 | |
| 519 | * larger than the userspace-supplied buffer)
|
| 520 | *buf_len = strlen(value);
|
| 521 |
|
| 522 |
|
| 523 | if (len && buf)
|
| 524 | if (copy_to_user(buf, value, len))
|
| 525 | return -EFAULT;
|
| 526 | return 0;
|
| 527 | }
|
| 528 |
|
| 529 | |
| 530 | * Get version information
|
| 531 | *
|
| 532 | * \param inode device inode.
|
| 533 | * \param filp file pointer.
|
| 534 | * \param cmd command.
|
| 535 | * \param arg user argument, pointing to a drm_version structure.
|
| 536 | * \return zero on success or negative number on failure.
|
| 537 | *
|
| 538 | * Fills in the version information in \p arg.
|
| 539 |
|
| 540 | int drm_version(struct drm_device *dev, void *data,
|
| 541 | struct drm_file *file_priv)
|
| 542 | {
|
| 543 | struct drm_version *version = data;
|
| 544 | int err;
|
| 545 |
|
| 546 | version->version_major = dev->driver->major;
|
| 547 | version->version_minor = dev->driver->minor;
|
| 548 | version->version_patchlevel = dev->driver->patchlevel;
|
| 549 | err = drm_copy_field(version->name, &version->name_len,
|
| 550 | dev->driver->name);
|
| 551 |
|
| 552 |
|
| 553 | if (!err)
|
| 554 | err = drm_copy_field(version->date, &version->date_len, "0");
|
| 555 | if (!err)
|
| 556 | err = drm_copy_field(version->desc, &version->desc_len,
|
| 557 | dev->driver->desc);
|
| 558 |
|
| 559 | return err;
|
| 560 | }
|
| 561 |
|
| 562 | |
| 563 | * Check if the passed string contains control char or spaces or
|
| 564 | * anything that would mess up a formatted output.
|
| 565 |
|
| 566 | static int drm_validate_value_string(const char *value, size_t len)
|
| 567 | {
|
| 568 | int i;
|
| 569 |
|
| 570 | for (i = 0; i < len; i++) {
|
| 571 | if (!isascii(value[i]) || !isgraph(value[i]))
|
| 572 | return -EINVAL;
|
| 573 | }
|
| 574 | return 0;
|
| 575 | }
|
| 576 |
|
| 577 | static int drm_set_client_name(struct drm_device *dev, void *data,
|
| 578 | struct drm_file *file_priv)
|
| 579 | {
|
| 580 | struct drm_set_client_name *name = data;
|
| 581 | size_t len = name->name_len;
|
| 582 | void __user *user_ptr;
|
| 583 | char *new_name;
|
| 584 |
|
| 585 | if (len > DRM_CLIENT_NAME_MAX_LEN) {
|
| 586 | return -EINVAL;
|
| 587 | } else if (len) {
|
| 588 | user_ptr = u64_to_user_ptr(name->name);
|
| 589 |
|
| 590 | new_name = memdup_user_nul(user_ptr, len);
|
| 591 | if (IS_ERR(new_name))
|
| 592 | return PTR_ERR(new_name);
|
| 593 |
|
| 594 | if (strlen(new_name) != len ||
|
| 595 | drm_validate_value_string(new_name, len) < 0) {
|
| 596 | kfree(new_name);
|
| 597 | return -EINVAL;
|
| 598 | }
|
| 599 | } else {
|
| 600 | new_name = NULL;
|
| 601 | }
|
| 602 |
|
| 603 | mutex_lock(&file_priv->client_name_lock);
|
| 604 | kfree(file_priv->client_name);
|
| 605 | file_priv->client_name = new_name;
|
| 606 | mutex_unlock(&file_priv->client_name_lock);
|
| 607 |
|
| 608 | return 0;
|
| 609 | }
|
| 610 |
|
| 611 | static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
|
| 612 | {
|
| 613 |
|
| 614 | if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)))
|
| 615 | return -EACCES;
|
| 616 |
|
| 617 |
|
| 618 | if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) &&
|
| 619 | !file_priv->authenticated))
|
| 620 | return -EACCES;
|
| 621 |
|
| 622 |
|
| 623 | if (unlikely((flags & DRM_MASTER) &&
|
| 624 | !drm_is_current_master(file_priv)))
|
| 625 | return -EACCES;
|
| 626 |
|
| 627 |
|
| 628 | if (unlikely(!(flags & DRM_RENDER_ALLOW) &&
|
| 629 | drm_is_render_client(file_priv)))
|
| 630 | return -EACCES;
|
| 631 |
|
| 632 | return 0;
|
| 633 | }
|
| 634 |
|
| 635 | #define DRM_IOCTL_DEF(ioctl, _func, _flags) \
|
| 636 | [DRM_IOCTL_NR(ioctl)] = { \
|
| 637 | .cmd = ioctl, \
|
| 638 | .func = _func, \
|
| 639 | .flags = _flags, \
|
| 640 | .name = #ioctl \
|
| 641 | }
|
| 642 |
|
| 643 |
|
| 644 | static const struct drm_ioctl_desc drm_ioctls[] = {
|
| 645 | DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_RENDER_ALLOW),
|
| 646 | DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
|
| 647 | DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
|
| 648 |
|
| 649 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
|
| 650 | DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
|
| 651 | DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_RENDER_ALLOW),
|
| 652 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0),
|
| 653 | DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
|
| 654 |
|
| 655 | DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 656 | DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 657 | DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 658 | DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER),
|
| 659 |
|
| 660 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0),
|
| 661 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0),
|
| 662 |
|
| 663 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 664 | DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 665 |
|
| 666 | DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
|
| 667 |
|
| 668 | DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, 0),
|
| 669 |
|
| 670 | DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
| 671 |
|
| 672 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW),
|
| 673 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
|
| 674 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
|
| 675 |
|
| 676 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_invalid_op, DRM_RENDER_ALLOW),
|
| 677 |
|
| 678 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0),
|
| 679 |
|
| 680 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_RENDER_ALLOW),
|
| 681 | DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_RENDER_ALLOW),
|
| 682 |
|
| 683 | DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_NAME, drm_set_client_name, DRM_RENDER_ALLOW),
|
| 684 |
|
| 685 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, 0),
|
| 686 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, 0),
|
| 687 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER),
|
| 688 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, 0),
|
| 689 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER),
|
| 690 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER),
|
| 691 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, 0),
|
| 692 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER),
|
| 693 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, 0),
|
| 694 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0),
|
| 695 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER),
|
| 696 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER),
|
| 697 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, 0),
|
| 698 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER),
|
| 699 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, 0),
|
| 700 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, 0),
|
| 701 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB2, drm_mode_getfb2_ioctl, 0),
|
| 702 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0),
|
| 703 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0),
|
| 704 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0),
|
| 705 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CLOSEFB, drm_mode_closefb_ioctl, 0),
|
| 706 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER),
|
| 707 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER),
|
| 708 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0),
|
| 709 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),
|
| 710 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, 0),
|
| 711 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, 0),
|
| 712 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER),
|
| 713 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER),
|
| 714 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER),
|
| 715 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATEPROPBLOB, drm_mode_createblob_ioctl, 0),
|
| 716 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROYPROPBLOB, drm_mode_destroyblob_ioctl, 0),
|
| 717 |
|
| 718 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_CREATE, drm_syncobj_create_ioctl,
|
| 719 | DRM_RENDER_ALLOW),
|
| 720 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_DESTROY, drm_syncobj_destroy_ioctl,
|
| 721 | DRM_RENDER_ALLOW),
|
| 722 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, drm_syncobj_handle_to_fd_ioctl,
|
| 723 | DRM_RENDER_ALLOW),
|
| 724 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, drm_syncobj_fd_to_handle_ioctl,
|
| 725 | DRM_RENDER_ALLOW),
|
| 726 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TRANSFER, drm_syncobj_transfer_ioctl,
|
| 727 | DRM_RENDER_ALLOW),
|
| 728 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl,
|
| 729 | DRM_RENDER_ALLOW),
|
| 730 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, drm_syncobj_timeline_wait_ioctl,
|
| 731 | DRM_RENDER_ALLOW),
|
| 732 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_EVENTFD, drm_syncobj_eventfd_ioctl,
|
| 733 | DRM_RENDER_ALLOW),
|
| 734 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_RESET, drm_syncobj_reset_ioctl,
|
| 735 | DRM_RENDER_ALLOW),
|
| 736 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl,
|
| 737 | DRM_RENDER_ALLOW),
|
| 738 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, drm_syncobj_timeline_signal_ioctl,
|
| 739 | DRM_RENDER_ALLOW),
|
| 740 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl,
|
| 741 | DRM_RENDER_ALLOW),
|
| 742 | DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, 0),
|
| 743 | DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, 0),
|
| 744 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER),
|
| 745 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER),
|
| 746 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER),
|
| 747 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER),
|
| 748 | };
|
| 749 |
|
| 750 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE(drm_ioctls)
|
| 751 |
|
| 752 | |
| 753 | * DOC: driver specific ioctls
|
| 754 | *
|
| 755 | * First things first, driver private IOCTLs should only be needed for drivers
|
| 756 | * supporting rendering. Kernel modesetting is all standardized, and extended
|
| 757 | * through properties. There are a few exceptions in some existing drivers,
|
| 758 | * which define IOCTL for use by the display DRM master, but they all predate
|
| 759 | * properties.
|
| 760 | *
|
| 761 | * Now if you do have a render driver you always have to support it through
|
| 762 | * driver private properties. There's a few steps needed to wire all the things
|
| 763 | * up.
|
| 764 | *
|
| 765 | * First you need to define the structure for your IOCTL in your driver private
|
| 766 | * UAPI header in ``include/uapi/drm/my_driver_drm.h``::
|
| 767 | *
|
| 768 | * struct my_driver_operation {
|
| 769 | * u32 some_thing;
|
| 770 | * u32 another_thing;
|
| 771 | * };
|
| 772 | *
|
| 773 | * Please make sure that you follow all the best practices from
|
| 774 | * ``Documentation/process/botching-up-ioctls.rst``. Note that drm_ioctl()
|
| 775 | * automatically zero-extends structures, hence make sure you can add more stuff
|
| 776 | * at the end, i.e. don't put a variable sized array there.
|
| 777 | *
|
| 778 | * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(),
|
| 779 | * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix::
|
| 780 | *
|
| 781 | * ##define DRM_IOCTL_MY_DRIVER_OPERATION \
|
| 782 | * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation)
|
| 783 | *
|
| 784 | * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to
|
| 785 | * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire
|
| 786 | * up the handlers and set the access rights::
|
| 787 | *
|
| 788 | * static const struct drm_ioctl_desc my_driver_ioctls[] = {
|
| 789 | * DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation,
|
| 790 | * DRM_AUTH|DRM_RENDER_ALLOW),
|
| 791 | * };
|
| 792 | *
|
| 793 | * And then assign this to the &drm_driver.ioctls field in your driver
|
| 794 | * structure.
|
| 795 | *
|
| 796 | * See the separate chapter on :ref:`file operations<drm_driver_fops>` for how
|
| 797 | * the driver-specific IOCTLs are wired up.
|
| 798 |
|
| 799 |
|
| 800 | long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata,
|
| 801 | u32 flags)
|
| 802 | {
|
| 803 | struct drm_file *file_priv = file->private_data;
|
| 804 | struct drm_device *dev = file_priv->minor->dev;
|
| 805 | int ret;
|
| 806 |
|
| 807 |
|
| 808 | drm_file_update_pid(file_priv);
|
| 809 |
|
| 810 | if (drm_dev_is_unplugged(dev))
|
| 811 | return -ENODEV;
|
| 812 |
|
| 813 | ret = drm_ioctl_permit(flags, file_priv);
|
| 814 | if (unlikely(ret))
|
| 815 | return ret;
|
| 816 |
|
| 817 | return func(dev, kdata, file_priv);
|
| 818 | }
|
| 819 | EXPORT_SYMBOL(drm_ioctl_kernel);
|
| 820 |
|
| 821 | |
| 822 | * drm_ioctl - ioctl callback implementation for DRM drivers
|
| 823 | * @filp: file this ioctl is called on
|
| 824 | * @cmd: ioctl cmd number
|
| 825 | * @arg: user argument
|
| 826 | *
|
| 827 | * Looks up the ioctl function in the DRM core and the driver dispatch table,
|
| 828 | * stored in &drm_driver.ioctls. It checks for necessary permission by calling
|
| 829 | * drm_ioctl_permit(), and dispatches to the respective function.
|
| 830 | *
|
| 831 | * Returns:
|
| 832 | * Zero on success, negative error code on failure.
|
| 833 |
|
| 834 | long drm_ioctl(struct file *filp,
|
| 835 | unsigned int cmd, unsigned long arg)
|
| 836 | {
|
| 837 | struct drm_file *file_priv = filp->private_data;
|
| 838 | struct drm_device *dev;
|
| 839 | const struct drm_ioctl_desc *ioctl = NULL;
|
| 840 | drm_ioctl_t *func;
|
| 841 | unsigned int nr = DRM_IOCTL_NR(cmd);
|
| 842 | int retcode = -EINVAL;
|
| 843 | char stack_kdata[128];
|
| 844 | char *kdata = NULL;
|
| 845 | unsigned int in_size, out_size, drv_size, ksize;
|
| 846 | bool is_driver_ioctl;
|
| 847 |
|
| 848 | dev = file_priv->minor->dev;
|
| 849 |
|
| 850 | if (drm_dev_is_unplugged(dev))
|
| 851 | return -ENODEV;
|
| 852 |
|
| 853 | if (DRM_IOCTL_TYPE(cmd) != DRM_IOCTL_BASE)
|
| 854 | return -ENOTTY;
|
| 855 |
|
| 856 | is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END;
|
| 857 |
|
| 858 | if (is_driver_ioctl) {
|
| 859 |
|
| 860 | unsigned int index = nr - DRM_COMMAND_BASE;
|
| 861 |
|
| 862 | if (index >= dev->driver->num_ioctls)
|
| 863 | goto err_i1;
|
| 864 | index = array_index_nospec(index, dev->driver->num_ioctls);
|
| 865 | ioctl = &dev->driver->ioctls[index];
|
| 866 | } else {
|
| 867 |
|
| 868 | if (nr >= DRM_CORE_IOCTL_COUNT)
|
| 869 | goto err_i1;
|
| 870 | nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
|
| 871 | ioctl = &drm_ioctls[nr];
|
| 872 | }
|
| 873 |
|
| 874 | drv_size = _IOC_SIZE(ioctl->cmd);
|
| 875 | out_size = in_size = _IOC_SIZE(cmd);
|
| 876 | if ((cmd & ioctl->cmd & IOC_IN) == 0)
|
| 877 | in_size = 0;
|
| 878 | if ((cmd & ioctl->cmd & IOC_OUT) == 0)
|
| 879 | out_size = 0;
|
| 880 | ksize = max(max(in_size, out_size), drv_size);
|
| 881 |
|
| 882 | drm_dbg_core(dev, "comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n",
|
| 883 | current->comm, task_pid_nr(current),
|
| 884 | (long)old_encode_dev(file_priv->minor->kdev->devt),
|
| 885 | file_priv->authenticated, ioctl->name);
|
| 886 |
|
| 887 |
|
| 888 | func = ioctl->func;
|
| 889 |
|
| 890 | if (unlikely(!func)) {
|
| 891 | drm_dbg_core(dev, "no function\n");
|
| 892 | retcode = -EINVAL;
|
| 893 | goto err_i1;
|
| 894 | }
|
| 895 |
|
| 896 | if (ksize <= sizeof(stack_kdata)) {
|
| 897 | kdata = stack_kdata;
|
| 898 | } else {
|
| 899 | kdata = kmalloc(ksize, GFP_KERNEL);
|
| 900 | if (!kdata) {
|
| 901 | retcode = -ENOMEM;
|
| 902 | goto err_i1;
|
| 903 | }
|
| 904 | }
|
| 905 |
|
| 906 | if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) {
|
| 907 | retcode = -EFAULT;
|
| 908 | goto err_i1;
|
| 909 | }
|
| 910 |
|
| 911 | if (ksize > in_size)
|
| 912 | memset(kdata + in_size, 0, ksize - in_size);
|
| 913 |
|
| 914 | retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags);
|
| 915 | if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
|
| 916 | retcode = -EFAULT;
|
| 917 |
|
| 918 | err_i1:
|
| 919 | if (!ioctl)
|
| 920 | drm_dbg_core(dev,
|
| 921 | "invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
|
| 922 | current->comm, task_pid_nr(current),
|
| 923 | (long)old_encode_dev(file_priv->minor->kdev->devt),
|
| 924 | file_priv->authenticated, cmd, nr);
|
| 925 |
|
| 926 | if (kdata != stack_kdata)
|
| 927 | kfree(kdata);
|
| 928 | if (retcode)
|
| 929 | drm_dbg_core(dev, "comm=\"%s\", pid=%d, ret=%d\n",
|
| 930 | current->comm, task_pid_nr(current), retcode);
|
| 931 | return retcode;
|
| 932 | }
|
| 933 | EXPORT_SYMBOL(drm_ioctl);
|
| 934 |
|
| 935 | |
| 936 | * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
|
| 937 | * @nr: ioctl number
|
| 938 | * @flags: where to return the ioctl permission flags
|
| 939 | *
|
| 940 | * This ioctl is only used by the vmwgfx driver to augment the access checks
|
| 941 | * done by the drm core and insofar a pretty decent layering violation. This
|
| 942 | * shouldn't be used by any drivers.
|
| 943 | *
|
| 944 | * Returns:
|
| 945 | * True if the @nr corresponds to a DRM core ioctl number, false otherwise.
|
| 946 |
|
| 947 | bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
|
| 948 | {
|
| 949 | if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END)
|
| 950 | return false;
|
| 951 |
|
| 952 | if (nr >= DRM_CORE_IOCTL_COUNT)
|
| 953 | return false;
|
| 954 | nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT);
|
| 955 |
|
| 956 | *flags = drm_ioctls[nr].flags;
|
| 957 | return true;
|
| 958 | }
|
| 959 | EXPORT_SYMBOL(drm_ioctl_flags);
|