ATS translations should not fail when the write permission is not set.
Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@eviden.com>
---
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 9753f4bb75..e89f31da02 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1980,7 +1980,7 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
uint64_t iova, bool is_write,
uint64_t *flptep, uint32_t *flpte_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;
@@ -2021,7 +2021,8 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
*reads = true;
*writes = (*writes) && (flpte & VTD_FL_RW);
- if (is_write && !(flpte & VTD_FL_RW)) {
+ /* ATS should not fail when the write permission is not set */
+ if (is_write && !(flpte & VTD_FL_RW) && iommu_idx != VTD_IDX_ATS) {
return -VTD_FR_SM_WRITE;
}
if (vtd_flpte_nonzero_rsvd(flpte, *flpte_level)) {
@@ -2080,7 +2081,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;
@@ -2202,7 +2203,8 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
if (s->flts && s->root_scalable) {
ret_fr = vtd_iova_to_flpte(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_FLT;
} else {
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
@@ -3827,7 +3829,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*/
@@ -4923,7 +4925,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 3a1f7a1d99..10a452c0dd 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -664,7 +664,8 @@ typedef struct VTDRootEntry VTDRootEntry;
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;
#endif
--
2.51.0