| .. | .. |
|---|
| 28 | 28 | * OTHER DEALINGS IN THE SOFTWARE. |
|---|
| 29 | 29 | */ |
|---|
| 30 | 30 | |
|---|
| 31 | | -#include <linux/vmalloc.h> |
|---|
| 32 | | -#include <linux/slab.h> |
|---|
| 33 | | -#include <linux/log2.h> |
|---|
| 34 | 31 | #include <linux/export.h> |
|---|
| 32 | +#include <linux/log2.h> |
|---|
| 33 | +#include <linux/mm.h> |
|---|
| 34 | +#include <linux/mman.h> |
|---|
| 35 | +#include <linux/nospec.h> |
|---|
| 36 | +#include <linux/pci.h> |
|---|
| 37 | +#include <linux/slab.h> |
|---|
| 38 | +#include <linux/uaccess.h> |
|---|
| 39 | +#include <linux/vmalloc.h> |
|---|
| 40 | + |
|---|
| 35 | 41 | #include <asm/shmparam.h> |
|---|
| 36 | | -#include <drm/drmP.h> |
|---|
| 42 | + |
|---|
| 43 | +#include <drm/drm_agpsupport.h> |
|---|
| 44 | +#include <drm/drm_device.h> |
|---|
| 45 | +#include <drm/drm_drv.h> |
|---|
| 46 | +#include <drm/drm_file.h> |
|---|
| 47 | +#include <drm/drm_print.h> |
|---|
| 48 | + |
|---|
| 37 | 49 | #include "drm_legacy.h" |
|---|
| 38 | 50 | |
|---|
| 39 | | -#include <linux/nospec.h> |
|---|
| 40 | 51 | |
|---|
| 41 | 52 | static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, |
|---|
| 42 | 53 | struct drm_local_map *map) |
|---|
| 43 | 54 | { |
|---|
| 44 | 55 | struct drm_map_list *entry; |
|---|
| 56 | + |
|---|
| 45 | 57 | list_for_each_entry(entry, &dev->maplist, head) { |
|---|
| 46 | 58 | /* |
|---|
| 47 | 59 | * Because the kernel-userspace ABI is fixed at a 32-bit offset |
|---|
| .. | .. |
|---|
| 91 | 103 | |
|---|
| 92 | 104 | if (!use_hashed_handle) { |
|---|
| 93 | 105 | int ret; |
|---|
| 106 | + |
|---|
| 94 | 107 | hash->key = user_token >> PAGE_SHIFT; |
|---|
| 95 | 108 | ret = drm_ht_insert_item(&dev->map_hash, hash); |
|---|
| 96 | 109 | if (ret != -EINVAL) |
|---|
| .. | .. |
|---|
| 123 | 136 | shift, add); |
|---|
| 124 | 137 | } |
|---|
| 125 | 138 | |
|---|
| 126 | | -/** |
|---|
| 139 | +/* |
|---|
| 127 | 140 | * Core function to create a range of memory available for mapping by a |
|---|
| 128 | 141 | * non-root process. |
|---|
| 129 | 142 | * |
|---|
| .. | .. |
|---|
| 138 | 151 | { |
|---|
| 139 | 152 | struct drm_local_map *map; |
|---|
| 140 | 153 | struct drm_map_list *list; |
|---|
| 141 | | - drm_dma_handle_t *dmah; |
|---|
| 142 | 154 | unsigned long user_token; |
|---|
| 143 | 155 | int ret; |
|---|
| 144 | 156 | |
|---|
| .. | .. |
|---|
| 313 | 325 | * As we're limiting the address to 2^32-1 (or less), |
|---|
| 314 | 326 | * casting it down to 32 bits is no problem, but we |
|---|
| 315 | 327 | * need to point to a 64bit variable first. */ |
|---|
| 316 | | - dmah = drm_pci_alloc(dev, map->size, map->size); |
|---|
| 317 | | - if (!dmah) { |
|---|
| 328 | + map->handle = dma_alloc_coherent(&dev->pdev->dev, |
|---|
| 329 | + map->size, |
|---|
| 330 | + &map->offset, |
|---|
| 331 | + GFP_KERNEL); |
|---|
| 332 | + if (!map->handle) { |
|---|
| 318 | 333 | kfree(map); |
|---|
| 319 | 334 | return -ENOMEM; |
|---|
| 320 | 335 | } |
|---|
| 321 | | - map->handle = dmah->vaddr; |
|---|
| 322 | | - map->offset = (unsigned long)dmah->busaddr; |
|---|
| 323 | | - kfree(dmah); |
|---|
| 324 | 336 | break; |
|---|
| 325 | 337 | default: |
|---|
| 326 | 338 | kfree(map); |
|---|
| .. | .. |
|---|
| 377 | 389 | } |
|---|
| 378 | 390 | EXPORT_SYMBOL(drm_legacy_addmap); |
|---|
| 379 | 391 | |
|---|
| 380 | | -/** |
|---|
| 392 | +struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, |
|---|
| 393 | + unsigned int token) |
|---|
| 394 | +{ |
|---|
| 395 | + struct drm_map_list *_entry; |
|---|
| 396 | + |
|---|
| 397 | + list_for_each_entry(_entry, &dev->maplist, head) |
|---|
| 398 | + if (_entry->user_token == token) |
|---|
| 399 | + return _entry->map; |
|---|
| 400 | + return NULL; |
|---|
| 401 | +} |
|---|
| 402 | +EXPORT_SYMBOL(drm_legacy_findmap); |
|---|
| 403 | + |
|---|
| 404 | +/* |
|---|
| 381 | 405 | * Ioctl to specify a range of memory that is available for mapping by a |
|---|
| 382 | 406 | * non-root process. |
|---|
| 383 | 407 | * |
|---|
| .. | .. |
|---|
| 400 | 424 | |
|---|
| 401 | 425 | if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && |
|---|
| 402 | 426 | !drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 403 | | - return -EINVAL; |
|---|
| 427 | + return -EOPNOTSUPP; |
|---|
| 404 | 428 | |
|---|
| 405 | 429 | err = drm_addmap_core(dev, map->offset, map->size, map->type, |
|---|
| 406 | 430 | map->flags, &maplist); |
|---|
| .. | .. |
|---|
| 446 | 470 | |
|---|
| 447 | 471 | if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && |
|---|
| 448 | 472 | !drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 449 | | - return -EINVAL; |
|---|
| 473 | + return -EOPNOTSUPP; |
|---|
| 450 | 474 | |
|---|
| 451 | 475 | idx = map->offset; |
|---|
| 452 | 476 | if (idx < 0) |
|---|
| .. | .. |
|---|
| 478 | 502 | return 0; |
|---|
| 479 | 503 | } |
|---|
| 480 | 504 | |
|---|
| 481 | | -/** |
|---|
| 505 | +/* |
|---|
| 482 | 506 | * Remove a map private from list and deallocate resources if the mapping |
|---|
| 483 | 507 | * isn't in use. |
|---|
| 484 | 508 | * |
|---|
| 485 | 509 | * Searches the map on drm_device::maplist, removes it from the list, see if |
|---|
| 486 | | - * its being used, and free any associate resource (such as MTRR's) if it's not |
|---|
| 510 | + * it's being used, and free any associated resource (such as MTRR's) if it's not |
|---|
| 487 | 511 | * being on use. |
|---|
| 488 | 512 | * |
|---|
| 489 | 513 | * \sa drm_legacy_addmap |
|---|
| .. | .. |
|---|
| 491 | 515 | int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) |
|---|
| 492 | 516 | { |
|---|
| 493 | 517 | struct drm_map_list *r_list = NULL, *list_t; |
|---|
| 494 | | - drm_dma_handle_t dmah; |
|---|
| 495 | 518 | int found = 0; |
|---|
| 496 | 519 | struct drm_master *master; |
|---|
| 497 | 520 | |
|---|
| .. | .. |
|---|
| 514 | 537 | switch (map->type) { |
|---|
| 515 | 538 | case _DRM_REGISTERS: |
|---|
| 516 | 539 | iounmap(map->handle); |
|---|
| 517 | | - /* FALLTHROUGH */ |
|---|
| 540 | + fallthrough; |
|---|
| 518 | 541 | case _DRM_FRAME_BUFFER: |
|---|
| 519 | 542 | arch_phys_wc_del(map->mtrr); |
|---|
| 520 | 543 | break; |
|---|
| .. | .. |
|---|
| 532 | 555 | case _DRM_SCATTER_GATHER: |
|---|
| 533 | 556 | break; |
|---|
| 534 | 557 | case _DRM_CONSISTENT: |
|---|
| 535 | | - dmah.vaddr = map->handle; |
|---|
| 536 | | - dmah.busaddr = map->offset; |
|---|
| 537 | | - dmah.size = map->size; |
|---|
| 538 | | - __drm_legacy_pci_free(dev, &dmah); |
|---|
| 558 | + dma_free_coherent(&dev->pdev->dev, |
|---|
| 559 | + map->size, |
|---|
| 560 | + map->handle, |
|---|
| 561 | + map->offset); |
|---|
| 539 | 562 | break; |
|---|
| 540 | 563 | } |
|---|
| 541 | 564 | kfree(map); |
|---|
| .. | .. |
|---|
| 573 | 596 | mutex_unlock(&dev->struct_mutex); |
|---|
| 574 | 597 | } |
|---|
| 575 | 598 | |
|---|
| 599 | +void drm_legacy_rmmaps(struct drm_device *dev) |
|---|
| 600 | +{ |
|---|
| 601 | + struct drm_map_list *r_list, *list_temp; |
|---|
| 602 | + |
|---|
| 603 | + list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) |
|---|
| 604 | + drm_legacy_rmmap(dev, r_list->map); |
|---|
| 605 | +} |
|---|
| 606 | + |
|---|
| 576 | 607 | /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on |
|---|
| 577 | 608 | * the last close of the device, and this is necessary for cleanup when things |
|---|
| 578 | 609 | * exit uncleanly. Therefore, having userland manually remove mappings seems |
|---|
| .. | .. |
|---|
| 598 | 629 | |
|---|
| 599 | 630 | if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && |
|---|
| 600 | 631 | !drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 601 | | - return -EINVAL; |
|---|
| 632 | + return -EOPNOTSUPP; |
|---|
| 602 | 633 | |
|---|
| 603 | 634 | mutex_lock(&dev->struct_mutex); |
|---|
| 604 | 635 | list_for_each_entry(r_list, &dev->maplist, head) { |
|---|
| .. | .. |
|---|
| 610 | 641 | } |
|---|
| 611 | 642 | } |
|---|
| 612 | 643 | |
|---|
| 613 | | - /* List has wrapped around to the head pointer, or its empty we didn't |
|---|
| 644 | + /* List has wrapped around to the head pointer, or it's empty we didn't |
|---|
| 614 | 645 | * find anything. |
|---|
| 615 | 646 | */ |
|---|
| 616 | 647 | if (list_empty(&dev->maplist) || !map) { |
|---|
| .. | .. |
|---|
| 631 | 662 | return ret; |
|---|
| 632 | 663 | } |
|---|
| 633 | 664 | |
|---|
| 634 | | -/** |
|---|
| 665 | +/* |
|---|
| 635 | 666 | * Cleanup after an error on one of the addbufs() functions. |
|---|
| 636 | 667 | * |
|---|
| 637 | 668 | * \param dev DRM device. |
|---|
| .. | .. |
|---|
| 666 | 697 | } |
|---|
| 667 | 698 | |
|---|
| 668 | 699 | #if IS_ENABLED(CONFIG_AGP) |
|---|
| 669 | | -/** |
|---|
| 700 | +/* |
|---|
| 670 | 701 | * Add AGP buffers for DMA transfers. |
|---|
| 671 | 702 | * |
|---|
| 672 | 703 | * \param dev struct drm_device to which the buffers are to be added. |
|---|
| .. | .. |
|---|
| 862 | 893 | struct drm_buf **temp_buflist; |
|---|
| 863 | 894 | |
|---|
| 864 | 895 | if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) |
|---|
| 865 | | - return -EINVAL; |
|---|
| 896 | + return -EOPNOTSUPP; |
|---|
| 866 | 897 | |
|---|
| 867 | 898 | if (!dma) |
|---|
| 868 | 899 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1066 | 1097 | struct drm_buf **temp_buflist; |
|---|
| 1067 | 1098 | |
|---|
| 1068 | 1099 | if (!drm_core_check_feature(dev, DRIVER_SG)) |
|---|
| 1069 | | - return -EINVAL; |
|---|
| 1100 | + return -EOPNOTSUPP; |
|---|
| 1070 | 1101 | |
|---|
| 1071 | 1102 | if (!dma) |
|---|
| 1072 | 1103 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1202 | 1233 | return 0; |
|---|
| 1203 | 1234 | } |
|---|
| 1204 | 1235 | |
|---|
| 1205 | | -/** |
|---|
| 1236 | +/* |
|---|
| 1206 | 1237 | * Add buffers for DMA transfers (ioctl). |
|---|
| 1207 | 1238 | * |
|---|
| 1208 | 1239 | * \param inode device inode. |
|---|
| .. | .. |
|---|
| 1223 | 1254 | int ret; |
|---|
| 1224 | 1255 | |
|---|
| 1225 | 1256 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1226 | | - return -EINVAL; |
|---|
| 1257 | + return -EOPNOTSUPP; |
|---|
| 1227 | 1258 | |
|---|
| 1228 | 1259 | if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
|---|
| 1229 | | - return -EINVAL; |
|---|
| 1260 | + return -EOPNOTSUPP; |
|---|
| 1230 | 1261 | |
|---|
| 1231 | 1262 | #if IS_ENABLED(CONFIG_AGP) |
|---|
| 1232 | 1263 | if (request->flags & _DRM_AGP_BUFFER) |
|---|
| .. | .. |
|---|
| 1243 | 1274 | return ret; |
|---|
| 1244 | 1275 | } |
|---|
| 1245 | 1276 | |
|---|
| 1246 | | -/** |
|---|
| 1277 | +/* |
|---|
| 1247 | 1278 | * Get information about the buffer mappings. |
|---|
| 1248 | 1279 | * |
|---|
| 1249 | 1280 | * This was originally mean for debugging purposes, or by a sophisticated |
|---|
| .. | .. |
|---|
| 1269 | 1300 | int count; |
|---|
| 1270 | 1301 | |
|---|
| 1271 | 1302 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1272 | | - return -EINVAL; |
|---|
| 1303 | + return -EOPNOTSUPP; |
|---|
| 1273 | 1304 | |
|---|
| 1274 | 1305 | if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
|---|
| 1275 | | - return -EINVAL; |
|---|
| 1306 | + return -EOPNOTSUPP; |
|---|
| 1276 | 1307 | |
|---|
| 1277 | 1308 | if (!dma) |
|---|
| 1278 | 1309 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1295 | 1326 | if (*p >= count) { |
|---|
| 1296 | 1327 | for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { |
|---|
| 1297 | 1328 | struct drm_buf_entry *from = &dma->bufs[i]; |
|---|
| 1329 | + |
|---|
| 1298 | 1330 | if (from->buf_count) { |
|---|
| 1299 | 1331 | if (f(data, count, from) < 0) |
|---|
| 1300 | 1332 | return -EFAULT; |
|---|
| .. | .. |
|---|
| 1331 | 1363 | struct drm_file *file_priv) |
|---|
| 1332 | 1364 | { |
|---|
| 1333 | 1365 | struct drm_buf_info *request = data; |
|---|
| 1366 | + |
|---|
| 1334 | 1367 | return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf); |
|---|
| 1335 | 1368 | } |
|---|
| 1336 | 1369 | |
|---|
| 1337 | | -/** |
|---|
| 1370 | +/* |
|---|
| 1338 | 1371 | * Specifies a low and high water mark for buffer allocation |
|---|
| 1339 | 1372 | * |
|---|
| 1340 | 1373 | * \param inode device inode. |
|---|
| .. | .. |
|---|
| 1357 | 1390 | struct drm_buf_entry *entry; |
|---|
| 1358 | 1391 | |
|---|
| 1359 | 1392 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1360 | | - return -EINVAL; |
|---|
| 1393 | + return -EOPNOTSUPP; |
|---|
| 1361 | 1394 | |
|---|
| 1362 | 1395 | if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
|---|
| 1363 | | - return -EINVAL; |
|---|
| 1396 | + return -EOPNOTSUPP; |
|---|
| 1364 | 1397 | |
|---|
| 1365 | 1398 | if (!dma) |
|---|
| 1366 | 1399 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1383 | 1416 | return 0; |
|---|
| 1384 | 1417 | } |
|---|
| 1385 | 1418 | |
|---|
| 1386 | | -/** |
|---|
| 1419 | +/* |
|---|
| 1387 | 1420 | * Unreserve the buffers in list, previously reserved using drmDMA. |
|---|
| 1388 | 1421 | * |
|---|
| 1389 | 1422 | * \param inode device inode. |
|---|
| .. | .. |
|---|
| 1405 | 1438 | struct drm_buf *buf; |
|---|
| 1406 | 1439 | |
|---|
| 1407 | 1440 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1408 | | - return -EINVAL; |
|---|
| 1441 | + return -EOPNOTSUPP; |
|---|
| 1409 | 1442 | |
|---|
| 1410 | 1443 | if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
|---|
| 1411 | | - return -EINVAL; |
|---|
| 1444 | + return -EOPNOTSUPP; |
|---|
| 1412 | 1445 | |
|---|
| 1413 | 1446 | if (!dma) |
|---|
| 1414 | 1447 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1435 | 1468 | return 0; |
|---|
| 1436 | 1469 | } |
|---|
| 1437 | 1470 | |
|---|
| 1438 | | -/** |
|---|
| 1471 | +/* |
|---|
| 1439 | 1472 | * Maps all of the DMA buffers into client-virtual space (ioctl). |
|---|
| 1440 | 1473 | * |
|---|
| 1441 | 1474 | * \param inode device inode. |
|---|
| .. | .. |
|---|
| 1461 | 1494 | int i; |
|---|
| 1462 | 1495 | |
|---|
| 1463 | 1496 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1464 | | - return -EINVAL; |
|---|
| 1497 | + return -EOPNOTSUPP; |
|---|
| 1465 | 1498 | |
|---|
| 1466 | 1499 | if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) |
|---|
| 1467 | | - return -EINVAL; |
|---|
| 1500 | + return -EOPNOTSUPP; |
|---|
| 1468 | 1501 | |
|---|
| 1469 | 1502 | if (!dma) |
|---|
| 1470 | 1503 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1542 | 1575 | struct drm_file *file_priv) |
|---|
| 1543 | 1576 | { |
|---|
| 1544 | 1577 | struct drm_buf_map *request = data; |
|---|
| 1578 | + |
|---|
| 1545 | 1579 | return __drm_legacy_mapbufs(dev, data, &request->count, |
|---|
| 1546 | 1580 | &request->virtual, map_one_buf, |
|---|
| 1547 | 1581 | file_priv); |
|---|
| .. | .. |
|---|
| 1551 | 1585 | struct drm_file *file_priv) |
|---|
| 1552 | 1586 | { |
|---|
| 1553 | 1587 | if (!drm_core_check_feature(dev, DRIVER_LEGACY)) |
|---|
| 1554 | | - return -EINVAL; |
|---|
| 1588 | + return -EOPNOTSUPP; |
|---|
| 1555 | 1589 | |
|---|
| 1556 | 1590 | if (dev->driver->dma_ioctl) |
|---|
| 1557 | 1591 | return dev->driver->dma_ioctl(dev, data, file_priv); |
|---|