From: CLEMENT MATHIEU--DRIF <[email protected]> ATS translations should not fail when the write permission is not set.
Signed-off-by: Clement Mathieu--Drif <[email protected]> Reviewed-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Message-Id: <[email protected]> --- hw/i386/intel_iommu.c | 14 ++++++++------ hw/i386/intel_iommu_internal.h | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 7e7c31cb55..6ba1c1676b 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1998,7 +1998,7 @@ static int vtd_iova_to_fspte(IntelIOMMUState *s, VTDContextEntry *ce, uint64_t iova, bool is_write, uint64_t *fsptep, uint32_t *fspte_level, bool *reads, bool *writes, uint8_t aw_bits, - uint32_t pasid) + uint32_t pasid, int iommu_idx) { dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid); uint32_t offset; @@ -2039,7 +2039,8 @@ static int vtd_iova_to_fspte(IntelIOMMUState *s, VTDContextEntry *ce, *reads = true; *writes = (*writes) && (fspte & VTD_FS_RW); - if (is_write && !(fspte & VTD_FS_RW)) { + /* ATS should not fail when the write permission is not set */ + if (is_write && !(fspte & VTD_FS_RW) && iommu_idx != VTD_IDX_ATS) { return -VTD_FR_SM_WRITE; } if (vtd_fspte_nonzero_rsvd(fspte, *fspte_level)) { @@ -2098,7 +2099,7 @@ static void vtd_report_fault(IntelIOMMUState *s, */ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, uint8_t devfn, hwaddr addr, bool is_write, - IOMMUTLBEntry *entry) + IOMMUTLBEntry *entry, int iommu_idx) { IntelIOMMUState *s = vtd_as->iommu_state; VTDContextEntry ce; @@ -2204,7 +2205,8 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, if (s->fsts && s->root_scalable) { ret_fr = vtd_iova_to_fspte(s, &ce, addr, is_write, &pte, &level, - &reads, &writes, s->aw_bits, pasid); + &reads, &writes, s->aw_bits, pasid, + iommu_idx); pgtt = VTD_SM_PASID_ENTRY_FST; } else { ret_fr = vtd_iova_to_sspte(s, &ce, addr, is_write, &pte, &level, @@ -4033,7 +4035,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr, } } else { success = vtd_do_iommu_translate(vtd_as, vtd_as->bus, vtd_as->devfn, - addr, is_write, &iotlb); + addr, is_write, &iotlb, iommu_idx); } } else { /* DMAR disabled, passthrough, use 4k-page*/ @@ -5196,7 +5198,7 @@ static IOMMUTLBEntry vtd_iommu_ats_do_translate(IOMMUMemoryRegion *iommu, vtd_prepare_error_entry(&entry); entry.target_as = &address_space_memory; } else { - entry = vtd_iommu_translate(iommu, addr, flags, VTD_IDX_UNTRANSLATED); + entry = vtd_iommu_translate(iommu, addr, flags, VTD_IDX_ATS); } return entry; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index be757c290d..18d50191d2 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -692,7 +692,8 @@ typedef struct VTDPIOTLBInvInfo { typedef enum VTDIOMMUIndex { VTD_IDX_UNTRANSLATED = 0, /* Default */ VTD_IDX_TRANSLATED = 1, - VTD_IDX_COUNT = 2, /* Number of supported indexes */ + VTD_IDX_ATS = 2, + VTD_IDX_COUNT = 3, /* Number of supported indexes */ } VTDIOMMUIndex; typedef struct VTDHostIOMMUDevice { -- MST
