diff options
author | Christian König <christian.koenig@amd.com> | 2015-06-11 14:56:18 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-06-29 11:21:46 -0400 |
commit | f1689ec1b0b1256d0e69653cd4aaeee44aafdf5c (patch) | |
tree | f3e7492dc2576a4d8a17042a6e403807684e5362 | |
parent | 68fdd3df79ee4bff4d63dab920b01d9ed5731115 (diff) |
drm/amdgpu: check VCE relocation buffer range
port of radeon commit 2fc5703abda201f138faf63bdca743d04dbf4b1a.
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Leo Liu <leo.liu@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h | 1 |
3 files changed, 92 insertions, 29 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 22866d1c3d69..963c4ba5dcba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -1622,6 +1622,7 @@ struct amdgpu_vce { | |||
1622 | unsigned fb_version; | 1622 | unsigned fb_version; |
1623 | atomic_t handles[AMDGPU_MAX_VCE_HANDLES]; | 1623 | atomic_t handles[AMDGPU_MAX_VCE_HANDLES]; |
1624 | struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES]; | 1624 | struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES]; |
1625 | uint32_t img_size[AMDGPU_MAX_VCE_HANDLES]; | ||
1625 | struct delayed_work idle_work; | 1626 | struct delayed_work idle_work; |
1626 | const struct firmware *fw; /* VCE firmware */ | 1627 | const struct firmware *fw; /* VCE firmware */ |
1627 | struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS]; | 1628 | struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS]; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1127a504f118..cb1bff742550 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | |||
@@ -464,10 +464,12 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, | |||
464 | * @p: parser context | 464 | * @p: parser context |
465 | * @lo: address of lower dword | 465 | * @lo: address of lower dword |
466 | * @hi: address of higher dword | 466 | * @hi: address of higher dword |
467 | * @size: minimum size | ||
467 | * | 468 | * |
468 | * Patch relocation inside command stream with real buffer address | 469 | * Patch relocation inside command stream with real buffer address |
469 | */ | 470 | */ |
470 | int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi) | 471 | static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, |
472 | int lo, int hi, unsigned size) | ||
471 | { | 473 | { |
472 | struct amdgpu_bo_va_mapping *mapping; | 474 | struct amdgpu_bo_va_mapping *mapping; |
473 | struct amdgpu_ib *ib = &p->ibs[ib_idx]; | 475 | struct amdgpu_ib *ib = &p->ibs[ib_idx]; |
@@ -484,6 +486,13 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int | |||
484 | return -EINVAL; | 486 | return -EINVAL; |
485 | } | 487 | } |
486 | 488 | ||
489 | if ((addr + (uint64_t)size) > | ||
490 | ((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) { | ||
491 | DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n", | ||
492 | addr, lo, hi); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
487 | addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE; | 496 | addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE; |
488 | addr += amdgpu_bo_gpu_offset(bo); | 497 | addr += amdgpu_bo_gpu_offset(bo); |
489 | 498 | ||
@@ -494,6 +503,39 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int | |||
494 | } | 503 | } |
495 | 504 | ||
496 | /** | 505 | /** |
506 | * amdgpu_vce_validate_handle - validate stream handle | ||
507 | * | ||
508 | * @p: parser context | ||
509 | * @handle: handle to validate | ||
510 | * | ||
511 | * Validates the handle and return the found session index or -EINVAL | ||
512 | * we we don't have another free session index. | ||
513 | */ | ||
514 | static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, | ||
515 | uint32_t handle) | ||
516 | { | ||
517 | unsigned i; | ||
518 | |||
519 | /* validate the handle */ | ||
520 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | ||
521 | if (atomic_read(&p->adev->vce.handles[i]) == handle) | ||
522 | return i; | ||
523 | } | ||
524 | |||
525 | /* handle not found try to alloc a new one */ | ||
526 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | ||
527 | if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { | ||
528 | p->adev->vce.filp[i] = p->filp; | ||
529 | p->adev->vce.img_size[i] = 0; | ||
530 | return i; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | DRM_ERROR("No more free VCE handles!\n"); | ||
535 | return -EINVAL; | ||
536 | } | ||
537 | |||
538 | /** | ||
497 | * amdgpu_vce_cs_parse - parse and validate the command stream | 539 | * amdgpu_vce_cs_parse - parse and validate the command stream |
498 | * | 540 | * |
499 | * @p: parser context | 541 | * @p: parser context |
@@ -501,10 +543,12 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int | |||
501 | */ | 543 | */ |
502 | int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) | 544 | int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) |
503 | { | 545 | { |
504 | uint32_t handle = 0; | ||
505 | bool destroy = false; | ||
506 | int i, r, idx = 0; | ||
507 | struct amdgpu_ib *ib = &p->ibs[ib_idx]; | 546 | struct amdgpu_ib *ib = &p->ibs[ib_idx]; |
547 | int session_idx = -1; | ||
548 | bool destroyed = false; | ||
549 | uint32_t tmp, handle = 0; | ||
550 | uint32_t *size = &tmp; | ||
551 | int i, r, idx = 0; | ||
508 | 552 | ||
509 | amdgpu_vce_note_usage(p->adev); | 553 | amdgpu_vce_note_usage(p->adev); |
510 | 554 | ||
@@ -517,13 +561,29 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) | |||
517 | return -EINVAL; | 561 | return -EINVAL; |
518 | } | 562 | } |
519 | 563 | ||
564 | if (destroyed) { | ||
565 | DRM_ERROR("No other command allowed after destroy!\n"); | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | |||
520 | switch (cmd) { | 569 | switch (cmd) { |
521 | case 0x00000001: // session | 570 | case 0x00000001: // session |
522 | handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); | 571 | handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); |
572 | session_idx = amdgpu_vce_validate_handle(p, handle); | ||
573 | if (session_idx < 0) | ||
574 | return session_idx; | ||
575 | size = &p->adev->vce.img_size[session_idx]; | ||
523 | break; | 576 | break; |
524 | 577 | ||
525 | case 0x00000002: // task info | 578 | case 0x00000002: // task info |
579 | break; | ||
580 | |||
526 | case 0x01000001: // create | 581 | case 0x01000001: // create |
582 | *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) * | ||
583 | amdgpu_get_ib_value(p, ib_idx, idx + 10) * | ||
584 | 8 * 3 / 2; | ||
585 | break; | ||
586 | |||
527 | case 0x04000001: // config extension | 587 | case 0x04000001: // config extension |
528 | case 0x04000002: // pic control | 588 | case 0x04000002: // pic control |
529 | case 0x04000005: // rate control | 589 | case 0x04000005: // rate control |
@@ -534,23 +594,39 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) | |||
534 | break; | 594 | break; |
535 | 595 | ||
536 | case 0x03000001: // encode | 596 | case 0x03000001: // encode |
537 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9); | 597 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, |
598 | *size); | ||
538 | if (r) | 599 | if (r) |
539 | return r; | 600 | return r; |
540 | 601 | ||
541 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11); | 602 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, |
603 | *size / 3); | ||
542 | if (r) | 604 | if (r) |
543 | return r; | 605 | return r; |
544 | break; | 606 | break; |
545 | 607 | ||
546 | case 0x02000001: // destroy | 608 | case 0x02000001: // destroy |
547 | destroy = true; | 609 | destroyed = true; |
548 | break; | 610 | break; |
549 | 611 | ||
550 | case 0x05000001: // context buffer | 612 | case 0x05000001: // context buffer |
613 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, | ||
614 | *size * 2); | ||
615 | if (r) | ||
616 | return r; | ||
617 | break; | ||
618 | |||
551 | case 0x05000004: // video bitstream buffer | 619 | case 0x05000004: // video bitstream buffer |
620 | tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); | ||
621 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, | ||
622 | tmp); | ||
623 | if (r) | ||
624 | return r; | ||
625 | break; | ||
626 | |||
552 | case 0x05000005: // feedback buffer | 627 | case 0x05000005: // feedback buffer |
553 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2); | 628 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, |
629 | 4096); | ||
554 | if (r) | 630 | if (r) |
555 | return r; | 631 | return r; |
556 | break; | 632 | break; |
@@ -560,34 +636,21 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) | |||
560 | return -EINVAL; | 636 | return -EINVAL; |
561 | } | 637 | } |
562 | 638 | ||
639 | if (session_idx == -1) { | ||
640 | DRM_ERROR("no session command at start of IB\n"); | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
563 | idx += len / 4; | 644 | idx += len / 4; |
564 | } | 645 | } |
565 | 646 | ||
566 | if (destroy) { | 647 | if (destroyed) { |
567 | /* IB contains a destroy msg, free the handle */ | 648 | /* IB contains a destroy msg, free the handle */ |
568 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) | 649 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) |
569 | atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); | 650 | atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); |
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | /* create or encode, validate the handle */ | ||
575 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | ||
576 | if (atomic_read(&p->adev->vce.handles[i]) == handle) | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | /* handle not found try to alloc a new one */ | ||
581 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | ||
582 | if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { | ||
583 | p->adev->vce.filp[i] = p->filp; | ||
584 | return 0; | ||
585 | } | ||
586 | } | 651 | } |
587 | 652 | ||
588 | DRM_ERROR("No more free VCE handles!\n"); | 653 | return 0; |
589 | |||
590 | return -EINVAL; | ||
591 | } | 654 | } |
592 | 655 | ||
593 | /** | 656 | /** |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h index b6a9d0956c60..7ccdb5927da5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h | |||
@@ -33,7 +33,6 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, | |||
33 | int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, | 33 | int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, |
34 | struct amdgpu_fence **fence); | 34 | struct amdgpu_fence **fence); |
35 | void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp); | 35 | void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp); |
36 | int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi); | ||
37 | int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx); | 36 | int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx); |
38 | bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring, | 37 | bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring, |
39 | struct amdgpu_semaphore *semaphore, | 38 | struct amdgpu_semaphore *semaphore, |