diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 107 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 27 |
3 files changed, 97 insertions, 39 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6d21b9e48b89..ae83fe0ab374 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
| @@ -356,7 +356,7 @@ static int validate_cmd(int cmd) | |||
| 356 | return ret; | 356 | return ret; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords) | 359 | static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) |
| 360 | { | 360 | { |
| 361 | drm_i915_private_t *dev_priv = dev->dev_private; | 361 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 362 | int i; | 362 | int i; |
| @@ -370,8 +370,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor | |||
| 370 | for (i = 0; i < dwords;) { | 370 | for (i = 0; i < dwords;) { |
| 371 | int cmd, sz; | 371 | int cmd, sz; |
| 372 | 372 | ||
| 373 | if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) | 373 | cmd = buffer[i]; |
| 374 | return -EINVAL; | ||
| 375 | 374 | ||
| 376 | if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) | 375 | if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) |
| 377 | return -EINVAL; | 376 | return -EINVAL; |
| @@ -379,11 +378,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor | |||
| 379 | OUT_RING(cmd); | 378 | OUT_RING(cmd); |
| 380 | 379 | ||
| 381 | while (++i, --sz) { | 380 | while (++i, --sz) { |
| 382 | if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], | 381 | OUT_RING(buffer[i]); |
| 383 | sizeof(cmd))) { | ||
| 384 | return -EINVAL; | ||
| 385 | } | ||
| 386 | OUT_RING(cmd); | ||
| 387 | } | 382 | } |
| 388 | } | 383 | } |
| 389 | 384 | ||
| @@ -397,17 +392,13 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor | |||
| 397 | 392 | ||
| 398 | int | 393 | int |
| 399 | i915_emit_box(struct drm_device *dev, | 394 | i915_emit_box(struct drm_device *dev, |
| 400 | struct drm_clip_rect __user *boxes, | 395 | struct drm_clip_rect *boxes, |
| 401 | int i, int DR1, int DR4) | 396 | int i, int DR1, int DR4) |
| 402 | { | 397 | { |
| 403 | drm_i915_private_t *dev_priv = dev->dev_private; | 398 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 404 | struct drm_clip_rect box; | 399 | struct drm_clip_rect box = boxes[i]; |
| 405 | RING_LOCALS; | 400 | RING_LOCALS; |
| 406 | 401 | ||
| 407 | if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { | ||
| 408 | return -EFAULT; | ||
| 409 | } | ||
| 410 | |||
| 411 | if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { | 402 | if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { |
| 412 | DRM_ERROR("Bad box %d,%d..%d,%d\n", | 403 | DRM_ERROR("Bad box %d,%d..%d,%d\n", |
| 413 | box.x1, box.y1, box.x2, box.y2); | 404 | box.x1, box.y1, box.x2, box.y2); |
| @@ -460,7 +451,9 @@ static void i915_emit_breadcrumb(struct drm_device *dev) | |||
| 460 | } | 451 | } |
| 461 | 452 | ||
| 462 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, | 453 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, |
| 463 | drm_i915_cmdbuffer_t * cmd) | 454 | drm_i915_cmdbuffer_t *cmd, |
| 455 | struct drm_clip_rect *cliprects, | ||
| 456 | void *cmdbuf) | ||
| 464 | { | 457 | { |
| 465 | int nbox = cmd->num_cliprects; | 458 | int nbox = cmd->num_cliprects; |
| 466 | int i = 0, count, ret; | 459 | int i = 0, count, ret; |
| @@ -476,13 +469,13 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, | |||
| 476 | 469 | ||
| 477 | for (i = 0; i < count; i++) { | 470 | for (i = 0; i < count; i++) { |
| 478 | if (i < nbox) { | 471 | if (i < nbox) { |
| 479 | ret = i915_emit_box(dev, cmd->cliprects, i, | 472 | ret = i915_emit_box(dev, cliprects, i, |
| 480 | cmd->DR1, cmd->DR4); | 473 | cmd->DR1, cmd->DR4); |
| 481 | if (ret) | 474 | if (ret) |
| 482 | return ret; | 475 | return ret; |
| 483 | } | 476 | } |
| 484 | 477 | ||
| 485 | ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); | 478 | ret = i915_emit_cmds(dev, cmdbuf, cmd->sz / 4); |
| 486 | if (ret) | 479 | if (ret) |
| 487 | return ret; | 480 | return ret; |
| 488 | } | 481 | } |
| @@ -492,10 +485,10 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, | |||
| 492 | } | 485 | } |
| 493 | 486 | ||
| 494 | static int i915_dispatch_batchbuffer(struct drm_device * dev, | 487 | static int i915_dispatch_batchbuffer(struct drm_device * dev, |
| 495 | drm_i915_batchbuffer_t * batch) | 488 | drm_i915_batchbuffer_t * batch, |
| 489 | struct drm_clip_rect *cliprects) | ||
| 496 | { | 490 | { |
| 497 | drm_i915_private_t *dev_priv = dev->dev_private; | 491 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 498 | struct drm_clip_rect __user *boxes = batch->cliprects; | ||
| 499 | int nbox = batch->num_cliprects; | 492 | int nbox = batch->num_cliprects; |
| 500 | int i = 0, count; | 493 | int i = 0, count; |
| 501 | RING_LOCALS; | 494 | RING_LOCALS; |
| @@ -511,7 +504,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, | |||
| 511 | 504 | ||
| 512 | for (i = 0; i < count; i++) { | 505 | for (i = 0; i < count; i++) { |
| 513 | if (i < nbox) { | 506 | if (i < nbox) { |
| 514 | int ret = i915_emit_box(dev, boxes, i, | 507 | int ret = i915_emit_box(dev, cliprects, i, |
| 515 | batch->DR1, batch->DR4); | 508 | batch->DR1, batch->DR4); |
| 516 | if (ret) | 509 | if (ret) |
| 517 | return ret; | 510 | return ret; |
| @@ -626,6 +619,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
| 626 | master_priv->sarea_priv; | 619 | master_priv->sarea_priv; |
| 627 | drm_i915_batchbuffer_t *batch = data; | 620 | drm_i915_batchbuffer_t *batch = data; |
| 628 | int ret; | 621 | int ret; |
| 622 | struct drm_clip_rect *cliprects = NULL; | ||
| 629 | 623 | ||
| 630 | if (!dev_priv->allow_batchbuffer) { | 624 | if (!dev_priv->allow_batchbuffer) { |
| 631 | DRM_ERROR("Batchbuffer ioctl disabled\n"); | 625 | DRM_ERROR("Batchbuffer ioctl disabled\n"); |
| @@ -637,17 +631,35 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
| 637 | 631 | ||
| 638 | RING_LOCK_TEST_WITH_RETURN(dev, file_priv); | 632 | RING_LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 639 | 633 | ||
| 640 | if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, | 634 | if (batch->num_cliprects < 0) |
| 641 | batch->num_cliprects * | 635 | return -EINVAL; |
| 642 | sizeof(struct drm_clip_rect))) | 636 | |
| 643 | return -EFAULT; | 637 | if (batch->num_cliprects) { |
| 638 | cliprects = drm_calloc(batch->num_cliprects, | ||
| 639 | sizeof(struct drm_clip_rect), | ||
| 640 | DRM_MEM_DRIVER); | ||
| 641 | if (cliprects == NULL) | ||
| 642 | return -ENOMEM; | ||
| 643 | |||
| 644 | ret = copy_from_user(cliprects, batch->cliprects, | ||
| 645 | batch->num_cliprects * | ||
| 646 | sizeof(struct drm_clip_rect)); | ||
| 647 | if (ret != 0) | ||
| 648 | goto fail_free; | ||
| 649 | } | ||
| 644 | 650 | ||
| 645 | mutex_lock(&dev->struct_mutex); | 651 | mutex_lock(&dev->struct_mutex); |
| 646 | ret = i915_dispatch_batchbuffer(dev, batch); | 652 | ret = i915_dispatch_batchbuffer(dev, batch, cliprects); |
| 647 | mutex_unlock(&dev->struct_mutex); | 653 | mutex_unlock(&dev->struct_mutex); |
| 648 | 654 | ||
| 649 | if (sarea_priv) | 655 | if (sarea_priv) |
| 650 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 656 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 657 | |||
| 658 | fail_free: | ||
| 659 | drm_free(cliprects, | ||
| 660 | batch->num_cliprects * sizeof(struct drm_clip_rect), | ||
| 661 | DRM_MEM_DRIVER); | ||
| 662 | |||
| 651 | return ret; | 663 | return ret; |
| 652 | } | 664 | } |
| 653 | 665 | ||
| @@ -659,6 +671,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
| 659 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 671 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
| 660 | master_priv->sarea_priv; | 672 | master_priv->sarea_priv; |
| 661 | drm_i915_cmdbuffer_t *cmdbuf = data; | 673 | drm_i915_cmdbuffer_t *cmdbuf = data; |
| 674 | struct drm_clip_rect *cliprects = NULL; | ||
| 675 | void *batch_data; | ||
| 662 | int ret; | 676 | int ret; |
| 663 | 677 | ||
| 664 | DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", | 678 | DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", |
| @@ -666,25 +680,50 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
| 666 | 680 | ||
| 667 | RING_LOCK_TEST_WITH_RETURN(dev, file_priv); | 681 | RING_LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 668 | 682 | ||
| 669 | if (cmdbuf->num_cliprects && | 683 | if (cmdbuf->num_cliprects < 0) |
| 670 | DRM_VERIFYAREA_READ(cmdbuf->cliprects, | 684 | return -EINVAL; |
| 671 | cmdbuf->num_cliprects * | 685 | |
| 672 | sizeof(struct drm_clip_rect))) { | 686 | batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER); |
| 673 | DRM_ERROR("Fault accessing cliprects\n"); | 687 | if (batch_data == NULL) |
| 674 | return -EFAULT; | 688 | return -ENOMEM; |
| 689 | |||
| 690 | ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz); | ||
| 691 | if (ret != 0) | ||
| 692 | goto fail_batch_free; | ||
| 693 | |||
| 694 | if (cmdbuf->num_cliprects) { | ||
| 695 | cliprects = drm_calloc(cmdbuf->num_cliprects, | ||
| 696 | sizeof(struct drm_clip_rect), | ||
| 697 | DRM_MEM_DRIVER); | ||
| 698 | if (cliprects == NULL) | ||
| 699 | goto fail_batch_free; | ||
| 700 | |||
| 701 | ret = copy_from_user(cliprects, cmdbuf->cliprects, | ||
| 702 | cmdbuf->num_cliprects * | ||
| 703 | sizeof(struct drm_clip_rect)); | ||
| 704 | if (ret != 0) | ||
| 705 | goto fail_clip_free; | ||
| 675 | } | 706 | } |
| 676 | 707 | ||
| 677 | mutex_lock(&dev->struct_mutex); | 708 | mutex_lock(&dev->struct_mutex); |
| 678 | ret = i915_dispatch_cmdbuffer(dev, cmdbuf); | 709 | ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data); |
| 679 | mutex_unlock(&dev->struct_mutex); | 710 | mutex_unlock(&dev->struct_mutex); |
| 680 | if (ret) { | 711 | if (ret) { |
| 681 | DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); | 712 | DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); |
| 682 | return ret; | 713 | goto fail_batch_free; |
| 683 | } | 714 | } |
| 684 | 715 | ||
| 685 | if (sarea_priv) | 716 | if (sarea_priv) |
| 686 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 717 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 687 | return 0; | 718 | |
| 719 | fail_batch_free: | ||
| 720 | drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER); | ||
| 721 | fail_clip_free: | ||
| 722 | drm_free(cliprects, | ||
| 723 | cmdbuf->num_cliprects * sizeof(struct drm_clip_rect), | ||
| 724 | DRM_MEM_DRIVER); | ||
| 725 | |||
| 726 | return ret; | ||
| 688 | } | 727 | } |
| 689 | 728 | ||
| 690 | static int i915_flip_bufs(struct drm_device *dev, void *data, | 729 | static int i915_flip_bufs(struct drm_device *dev, void *data, |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 75e33844146b..2c02ce6b2b98 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -520,7 +520,7 @@ extern int i915_driver_device_is_agp(struct drm_device * dev); | |||
| 520 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, | 520 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, |
| 521 | unsigned long arg); | 521 | unsigned long arg); |
| 522 | extern int i915_emit_box(struct drm_device *dev, | 522 | extern int i915_emit_box(struct drm_device *dev, |
| 523 | struct drm_clip_rect __user *boxes, | 523 | struct drm_clip_rect *boxes, |
| 524 | int i, int DR1, int DR4); | 524 | int i, int DR1, int DR4); |
| 525 | 525 | ||
| 526 | /* i915_irq.c */ | 526 | /* i915_irq.c */ |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 010af908bdb6..2bda15197cce 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -2891,11 +2891,10 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, | |||
| 2891 | static int | 2891 | static int |
| 2892 | i915_dispatch_gem_execbuffer(struct drm_device *dev, | 2892 | i915_dispatch_gem_execbuffer(struct drm_device *dev, |
| 2893 | struct drm_i915_gem_execbuffer *exec, | 2893 | struct drm_i915_gem_execbuffer *exec, |
| 2894 | struct drm_clip_rect *cliprects, | ||
| 2894 | uint64_t exec_offset) | 2895 | uint64_t exec_offset) |
| 2895 | { | 2896 | { |
| 2896 | drm_i915_private_t *dev_priv = dev->dev_private; | 2897 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 2897 | struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *) | ||
| 2898 | (uintptr_t) exec->cliprects_ptr; | ||
| 2899 | int nbox = exec->num_cliprects; | 2898 | int nbox = exec->num_cliprects; |
| 2900 | int i = 0, count; | 2899 | int i = 0, count; |
| 2901 | uint32_t exec_start, exec_len; | 2900 | uint32_t exec_start, exec_len; |
| @@ -2916,7 +2915,7 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, | |||
| 2916 | 2915 | ||
| 2917 | for (i = 0; i < count; i++) { | 2916 | for (i = 0; i < count; i++) { |
| 2918 | if (i < nbox) { | 2917 | if (i < nbox) { |
| 2919 | int ret = i915_emit_box(dev, boxes, i, | 2918 | int ret = i915_emit_box(dev, cliprects, i, |
| 2920 | exec->DR1, exec->DR4); | 2919 | exec->DR1, exec->DR4); |
| 2921 | if (ret) | 2920 | if (ret) |
| 2922 | return ret; | 2921 | return ret; |
| @@ -2983,6 +2982,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 2983 | struct drm_gem_object **object_list = NULL; | 2982 | struct drm_gem_object **object_list = NULL; |
| 2984 | struct drm_gem_object *batch_obj; | 2983 | struct drm_gem_object *batch_obj; |
| 2985 | struct drm_i915_gem_object *obj_priv; | 2984 | struct drm_i915_gem_object *obj_priv; |
| 2985 | struct drm_clip_rect *cliprects = NULL; | ||
| 2986 | int ret, i, pinned = 0; | 2986 | int ret, i, pinned = 0; |
| 2987 | uint64_t exec_offset; | 2987 | uint64_t exec_offset; |
| 2988 | uint32_t seqno, flush_domains; | 2988 | uint32_t seqno, flush_domains; |
| @@ -3019,6 +3019,23 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 3019 | goto pre_mutex_err; | 3019 | goto pre_mutex_err; |
| 3020 | } | 3020 | } |
| 3021 | 3021 | ||
| 3022 | if (args->num_cliprects != 0) { | ||
| 3023 | cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects), | ||
| 3024 | DRM_MEM_DRIVER); | ||
| 3025 | if (cliprects == NULL) | ||
| 3026 | goto pre_mutex_err; | ||
| 3027 | |||
| 3028 | ret = copy_from_user(cliprects, | ||
| 3029 | (struct drm_clip_rect __user *) | ||
| 3030 | (uintptr_t) args->cliprects_ptr, | ||
| 3031 | sizeof(*cliprects) * args->num_cliprects); | ||
| 3032 | if (ret != 0) { | ||
| 3033 | DRM_ERROR("copy %d cliprects failed: %d\n", | ||
| 3034 | args->num_cliprects, ret); | ||
| 3035 | goto pre_mutex_err; | ||
| 3036 | } | ||
| 3037 | } | ||
| 3038 | |||
| 3022 | mutex_lock(&dev->struct_mutex); | 3039 | mutex_lock(&dev->struct_mutex); |
| 3023 | 3040 | ||
| 3024 | i915_verify_inactive(dev, __FILE__, __LINE__); | 3041 | i915_verify_inactive(dev, __FILE__, __LINE__); |
| @@ -3155,7 +3172,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 3155 | #endif | 3172 | #endif |
| 3156 | 3173 | ||
| 3157 | /* Exec the batchbuffer */ | 3174 | /* Exec the batchbuffer */ |
| 3158 | ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset); | 3175 | ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset); |
| 3159 | if (ret) { | 3176 | if (ret) { |
| 3160 | DRM_ERROR("dispatch failed %d\n", ret); | 3177 | DRM_ERROR("dispatch failed %d\n", ret); |
| 3161 | goto err; | 3178 | goto err; |
| @@ -3224,6 +3241,8 @@ pre_mutex_err: | |||
| 3224 | DRM_MEM_DRIVER); | 3241 | DRM_MEM_DRIVER); |
| 3225 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, | 3242 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, |
| 3226 | DRM_MEM_DRIVER); | 3243 | DRM_MEM_DRIVER); |
| 3244 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, | ||
| 3245 | DRM_MEM_DRIVER); | ||
| 3227 | 3246 | ||
| 3228 | return ret; | 3247 | return ret; |
| 3229 | } | 3248 | } |
