Message ID | 20240502152810.187492-5-clement.mathieu--drif@eviden.com |
---|---|
State | New |
Headers | show |
Series | ATS support for VT-d | expand |
>-----Original Message----- >From: CLEMENT MATHIEU--DRIF <clement.mathieu--drif@eviden.com> >Subject: [PATCH ats_vtd v1 04/24] intel_iommu: set accessed and dirty bits >during first stage translation > >Signed-off-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com> >--- > hw/i386/intel_iommu.c | 26 ++++++++++++++++++++++++++ > hw/i386/intel_iommu_internal.h | 3 +++ > 2 files changed, 29 insertions(+) > >diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c >index 240ecb8f72..cad70e0d05 100644 >--- a/hw/i386/intel_iommu.c >+++ b/hw/i386/intel_iommu.c >@@ -1913,6 +1913,7 @@ static const bool vtd_qualified_faults[] = { > [VTD_FR_PASID_TABLE_ENTRY_INV] = true, > [VTD_FR_SM_INTERRUPT_ADDR] = true, > [VTD_FR_FS_NON_CANONICAL] = true, >+ [VTD_FR_FS_BIT_UPDATE_FAILED] = true, > [VTD_FR_MAX] = false, > }; > >@@ -2039,6 +2040,20 @@ static bool >vtd_iova_fl_check_canonical(IntelIOMMUState *s, > ); > } > >+static MemTxResult vtd_set_flag_in_pte(dma_addr_t base_addr, uint32_t >index, >+ uint64_t pte, uint64_t flag) >+{ >+ if (pte & flag) { >+ return MEMTX_OK; >+ } >+ pte |= flag; >+ pte = cpu_to_le64(pte); >+ return dma_memory_write(&address_space_memory, >+ base_addr + index * sizeof(pte), >+ &pte, sizeof(pte), >+ MEMTXATTRS_UNSPECIFIED); >+} >+ > /* > * Given the @iova, get relevant @flptep. @flpte_level will be the last level > * of the translation, can be used for deciding the size of large page. >@@ -2080,11 +2095,22 @@ static int vtd_iova_to_flpte(IntelIOMMUState >*s, VTDContextEntry *ce, > > *reads = true; > *writes = (*writes) && (flpte & VTD_FL_RW_MASK); >+ >+ if (vtd_set_flag_in_pte(addr, offset, flpte, VTD_FL_PTE_A) >+ != MEMTX_OK) { >+ return -VTD_FR_FS_BIT_UPDATE_FAILED; >+ } >+ > if (is_write && !(flpte & VTD_FL_RW_MASK)) { > return -VTD_FR_WRITE; > } May be better to set access bit here? Speculatively setting access bit is allowed but not necessary. Thanks Zhenzhong > > if (vtd_is_last_flpte(flpte, level)) { >+ if (is_write && >+ (vtd_set_flag_in_pte(addr, offset, flpte, VTD_FL_PTE_D) != >+ MEMTX_OK)) { >+ return -VTD_FR_FS_BIT_UPDATE_FAILED; >+ } > *flptep = flpte; > *flpte_level = level; > return 0; >diff --git a/hw/i386/intel_iommu_internal.h >b/hw/i386/intel_iommu_internal.h >index e9448291a4..14879d3a58 100644 >--- a/hw/i386/intel_iommu_internal.h >+++ b/hw/i386/intel_iommu_internal.h >@@ -328,6 +328,7 @@ typedef enum VTDFaultReason { > > /* Output address in the interrupt address range for scalable mode */ > VTD_FR_SM_INTERRUPT_ADDR = 0x87, >+ VTD_FR_FS_BIT_UPDATE_FAILED = 0x91, /* SFS.10 */ > VTD_FR_MAX, /* Guard */ > } VTDFaultReason; > >@@ -649,6 +650,8 @@ typedef struct VTDPIOTLBInvInfo { > /* First Level Paging Structure */ > #define VTD_FL_PT_LEVEL 1 > #define VTD_FL_PT_ENTRY_NR 512 >+#define VTD_FL_PTE_A 0x20 >+#define VTD_FL_PTE_D 0x40 > > /* Masks for First Level Paging Entry */ > #define VTD_FL_RW_MASK (1ULL << 1) >-- >2.44.0
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 240ecb8f72..cad70e0d05 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1913,6 +1913,7 @@ static const bool vtd_qualified_faults[] = { [VTD_FR_PASID_TABLE_ENTRY_INV] = true, [VTD_FR_SM_INTERRUPT_ADDR] = true, [VTD_FR_FS_NON_CANONICAL] = true, + [VTD_FR_FS_BIT_UPDATE_FAILED] = true, [VTD_FR_MAX] = false, }; @@ -2039,6 +2040,20 @@ static bool vtd_iova_fl_check_canonical(IntelIOMMUState *s, ); } +static MemTxResult vtd_set_flag_in_pte(dma_addr_t base_addr, uint32_t index, + uint64_t pte, uint64_t flag) +{ + if (pte & flag) { + return MEMTX_OK; + } + pte |= flag; + pte = cpu_to_le64(pte); + return dma_memory_write(&address_space_memory, + base_addr + index * sizeof(pte), + &pte, sizeof(pte), + MEMTXATTRS_UNSPECIFIED); +} + /* * Given the @iova, get relevant @flptep. @flpte_level will be the last level * of the translation, can be used for deciding the size of large page. @@ -2080,11 +2095,22 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce, *reads = true; *writes = (*writes) && (flpte & VTD_FL_RW_MASK); + + if (vtd_set_flag_in_pte(addr, offset, flpte, VTD_FL_PTE_A) + != MEMTX_OK) { + return -VTD_FR_FS_BIT_UPDATE_FAILED; + } + if (is_write && !(flpte & VTD_FL_RW_MASK)) { return -VTD_FR_WRITE; } if (vtd_is_last_flpte(flpte, level)) { + if (is_write && + (vtd_set_flag_in_pte(addr, offset, flpte, VTD_FL_PTE_D) != + MEMTX_OK)) { + return -VTD_FR_FS_BIT_UPDATE_FAILED; + } *flptep = flpte; *flpte_level = level; return 0; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index e9448291a4..14879d3a58 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -328,6 +328,7 @@ typedef enum VTDFaultReason { /* Output address in the interrupt address range for scalable mode */ VTD_FR_SM_INTERRUPT_ADDR = 0x87, + VTD_FR_FS_BIT_UPDATE_FAILED = 0x91, /* SFS.10 */ VTD_FR_MAX, /* Guard */ } VTDFaultReason; @@ -649,6 +650,8 @@ typedef struct VTDPIOTLBInvInfo { /* First Level Paging Structure */ #define VTD_FL_PT_LEVEL 1 #define VTD_FL_PT_ENTRY_NR 512 +#define VTD_FL_PTE_A 0x20 +#define VTD_FL_PTE_D 0x40 /* Masks for First Level Paging Entry */ #define VTD_FL_RW_MASK (1ULL << 1)
Signed-off-by: Clément Mathieu--Drif <clement.mathieu--drif@eviden.com> --- hw/i386/intel_iommu.c | 26 ++++++++++++++++++++++++++ hw/i386/intel_iommu_internal.h | 3 +++ 2 files changed, 29 insertions(+)