- Timestamp:
- Jan 20, 2021 4:56:18 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r87315 r87326 42 42 /** The IOMMU device instance magic. */ 43 43 #define IOMMU_MAGIC 0x10acce55 44 /** The maximum number of IOTLB entries in our cache implementation. */45 #define IOMMU_IOTLBE_MAX 6446 44 /** Enable the IOTLBE cache. */ 47 45 #define IOMMU_WITH_IOTLBE_CACHE 46 48 47 #ifdef IOMMU_WITH_IOTLBE_CACHE 48 # define IOMMU_IOTLBE_PAGE_SIZE_MAX _4M 49 /** The maximum number of IOTLB entries in our cache implementation. */ 50 # define IOMMU_IOTLBE_MAX (IOMMU_IOTLBE_PAGE_SIZE_MAX / _4K) 49 51 /** The mask of bits for the domain ID of the IOTLBE key. */ 50 52 # define IOMMU_IOTLB_DOMAIN_ID_MASK UINT64_C(0xffffff0000000000) … … 133 135 uint8_t fIoPerm; 134 136 /** Padding. */ 135 uint 8_tabPadding[2];137 uint16_t abPadding[2]; 136 138 } IOWALKRESULT; 137 139 /** Pointer to an I/O walk result struct. */ … … 148 150 /** The domain ID assigned by software. */ 149 151 uint16_t uDomainId; 150 /** Whether the d omain ID is valid (since all bits of domain ID are usable). */152 /** Whether the device ID is valid (if not, lookups must re-read DTE). */ 151 153 bool fValid; 152 154 bool afAlignment[1]; … … 544 546 #ifdef IOMMU_WITH_IOTLBE_CACHE 545 547 /** 548 * @callback_method_impl{AVLU64CALLBACK} 549 */ 550 static DECLCALLBACK(int) iommuAmdR3DestroyIotlbe(PAVLU64NODECORE pCore, void *pvUser) 551 { 552 RT_NOREF2(pCore, pvUser); 553 /* Nothing to do as we will destroy IOTLB entries wholesale later. */ 554 return VINF_SUCCESS; 555 } 556 557 558 /** 546 559 * Constructs the key for an IOTLB entry suitable for using as part of the IOTLB 547 560 * cache. … … 607 620 static void iommuAmdIotlbAdd(PIOMMU pThis, PCIOWALKRESULT pWalkResult) 608 621 { 622 /** @todo Make sure somewhere we don't cache translations whose permissions are 623 * IOMMU_IO_PERM_NONE. */ 609 624 /* 610 625 * If the cache is full, evict the last recently used entry. … … 618 633 RTAvlU64Remove(&pThis->TreeIotlbe, pIotlbe->Core.Key); 619 634 --pThis->cCachedIotlbes; 620 /* Zero out IOTLB entry before reuse. */621 RT_BZERO(pIotlbe, sizeof(IOTLBE));622 635 } 623 636 else … … 628 641 } 629 642 643 /* Zero out IOTLB entry before reuse. */ 644 Assert(pIotlbe); 645 RT_ZERO(*pIotlbe); 646 630 647 /* Update the entry with the results of the page walk. */ 631 Assert(pIotlbe);632 648 pIotlbe->WalkResult = *pWalkResult; 633 649 … … 640 656 */ 641 657 RTListAppend(&pThis->LstLruIotlbe, &pIotlbe->NdLru); 658 } 659 660 661 /** 662 * Removes the IOTLB entry corresponding to the given domain ID and I/O virtual 663 * address. 664 * 665 * @param pThis The IOMMU device state. 666 * @param uDomainId The domain ID. 667 * @param uIova The I/O virtual address. 668 */ 669 static void iommuAmdIotlbRemove(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova) 670 { 671 uint64_t const uKey = iommuAmdIotlbConstructKey(uDomainId, uIova); 672 PIOTLBE pIotlbe = (PIOTLBE)RTAvlU64Remove(&pThis->TreeIotlbe, uKey); 673 if (pIotlbe) 674 { 675 RTListNodeRemove(&pIotlbe->NdLru); 676 --pThis->cCachedIotlbes; 677 RT_BZERO(pIotlbe, sizeof(IOTLBE)); 678 } 679 } 680 681 682 /** 683 * Removes all IOTLB entries from the cache. 684 * 685 * @param pThis The IOMMU device state. 686 */ 687 static void iommuAmdIotlbRemoveAll(PIOMMU pThis) 688 { 689 RTAvlU64Destroy(&pThis->TreeIotlbe, iommuAmdR3DestroyIotlbe, NULL /* pvParam */); 690 RTListInit(&pThis->LstLruIotlbe); 691 pThis->cCachedIotlbes = 0; 692 } 693 694 695 /** 696 * Removes a set of IOTLB entries from the cache given the domain ID, I/O virtual 697 * address and size. 698 * 699 * @param pThis The IOMMU device state. 700 * @param uDomainId The domain ID. 701 * @param uIova The I/O virtual address. 702 * @param cShift The number of bits to shift to get the size of the range 703 * being removed. 704 */ 705 static void iommuAmdIotlbRemoveRange(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, uint8_t cShift) 706 { 707 /* 708 * Our cache is currently based on 4K pages. Pages larger than this are split into 4K pages 709 * before storing in the cache. So an 8K page will have 2 IOTLB entries, 16K will have 4 etc. 710 * However, our cache capacity is limited (see IOMMU_IOTLBE_MAX). Thus, if the guest uses pages 711 * larger than what our cache can split and hold, we will simply flush the entire cache when 712 * requested to flush a partial range since it exceeds the capacity anyway. 713 */ 714 bool fFitsInCache; 715 /** @todo Find a more efficient way of checking split sizes? */ 716 if ( cShift == 12 /* 4K */ 717 || cShift == 13 /* 8K */ 718 || cShift == 14 /* 16K */ 719 || cShift == 20 /* 1M */) 720 fFitsInCache = true; 721 else 722 fFitsInCache = false; 723 724 if (fFitsInCache) 725 { 726 /* Mask off 4K page offset from the address. */ 727 uIova &= X86_PAGE_4K_OFFSET_MASK; 728 729 /* Remove pages in the given range. */ 730 uint16_t const cPages = (1 << cShift) / X86_PAGE_4K_SHIFT; 731 Assert(cPages <= IOMMU_IOTLBE_MAX); 732 for (uint32_t i = 0; i < cPages; i++) 733 { 734 iommuAmdIotlbRemove(pThis, uDomainId, uIova); 735 uIova += _4K; 736 } 737 } 738 else 739 iommuAmdIotlbRemoveAll(pThis); 642 740 } 643 741 #endif /* IOMMU_WITH_IOTLBE_CACHE */ … … 4570 4668 return VERR_NOT_IMPLEMENTED; 4571 4669 } 4572 4573 4574 #ifdef IOMMU_WITH_IOTLBE_CACHE4575 /**4576 * @callback_method_impl{AVLU64CALLBACK}4577 */4578 static DECLCALLBACK(int) iommuAmdR3DestroyIotlbe(PAVLU64NODECORE pCore, void *pvUser)4579 {4580 RT_NOREF2(pCore, pvUser);4581 /* Nothing to do as we will destroy IOTLB entries wholesale later. */4582 return VINF_SUCCESS;4583 }4584 #endif4585 4670 4586 4671
Note:
See TracChangeset
for help on using the changeset viewer.