[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.13] AMD/IOMMU: update live PTEs atomically



commit 3009e4d6b46c365e553c67499c45459cf1955f51
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Tue Oct 20 14:52:23 2020 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Oct 20 14:52:23 2020 +0200

    AMD/IOMMU: update live PTEs atomically
    
    Updating a live PTE bitfield by bitfield risks the compiler re-ordering
    the individual updates as well as splitting individual updates into
    multiple memory writes. Construct the new entry fully in a local
    variable, do the check to determine the flushing needs on the thus
    established new entry, and then write the new entry by a single insn.
    
    Similarly using memset() to clear a PTE is unsafe, as the order of
    writes the function does is, at least in principle, undefined.
    
    This is part of XSA-347.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
    master commit: 3b055121c5410e2c3105d6d06aa24ca0d58868cd
    master date: 2020-10-20 14:22:52 +0200
---
 xen/drivers/passthrough/amd/iommu_map.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/xen/drivers/passthrough/amd/iommu_map.c 
b/xen/drivers/passthrough/amd/iommu_map.c
index a039038113..7f8971c73c 100644
--- a/xen/drivers/passthrough/amd/iommu_map.c
+++ b/xen/drivers/passthrough/amd/iommu_map.c
@@ -45,7 +45,7 @@ static unsigned int clear_iommu_pte_present(unsigned long 
l1_mfn,
     pte = &table[pfn_to_pde_idx(dfn, 1)];
 
     flush_flags = pte->pr ? IOMMU_FLUSHF_modified : 0;
-    memset(pte, 0, sizeof(*pte));
+    write_atomic(&pte->raw, 0);
 
     unmap_domain_page(table);
 
@@ -57,26 +57,30 @@ static unsigned int set_iommu_pde_present(union 
amd_iommu_pte *pte,
                                           unsigned int next_level, bool iw,
                                           bool ir)
 {
+    union amd_iommu_pte new = {}, old;
     unsigned int flush_flags = IOMMU_FLUSHF_added;
 
-    if ( pte->pr &&
-         (pte->mfn != next_mfn ||
-          pte->iw != iw ||
-          pte->ir != ir ||
-          pte->next_level != next_level) )
-            flush_flags |= IOMMU_FLUSHF_modified;
-
     /*
      * FC bit should be enabled in PTE, this helps to solve potential
      * issues with ATS devices
      */
-    pte->fc = !next_level;
+    new.fc = !next_level;
+
+    new.mfn = next_mfn;
+    new.iw = iw;
+    new.ir = ir;
+    new.next_level = next_level;
+    new.pr = true;
+
+    old.raw = read_atomic(&pte->raw);
+    old.ign0 = 0;
+    old.ign1 = 0;
+    old.ign2 = 0;
+
+    if ( old.pr && old.raw != new.raw )
+        flush_flags |= IOMMU_FLUSHF_modified;
 
-    pte->mfn = next_mfn;
-    pte->iw = iw;
-    pte->ir = ir;
-    pte->next_level = next_level;
-    pte->pr = 1;
+    write_atomic(&pte->raw, new.raw);
 
     return flush_flags;
 }
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.13



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.