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

[xen stable-4.13] AMD/IOMMU: wait for command slot to be available



commit 0a3eb9bbc2188f36692a570c85816c6d3d0da697
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Tue Jun 8 18:58:05 2021 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Tue Jun 8 18:58:12 2021 +0100

    AMD/IOMMU: wait for command slot to be available
    
    No caller cared about send_iommu_command() indicating unavailability of
    a slot. Hence if a sufficient number prior commands timed out, we did
    blindly assume that the requested command was submitted to the IOMMU
    when really it wasn't. This could mean both a hanging system (waiting
    for a command to complete that was never seen by the IOMMU) or blindly
    propagating success back to callers, making them believe they're fine
    to e.g. free previously unmapped pages.
    
    Fold the three involved functions into one, add spin waiting for an
    available slot along the lines of VT-d's qinval_next_index(), and as a
    consequence drop all error indicator return types/values.
    
    This is part of XSA-373 / CVE-2021-28692.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
    (cherry picked from commit c4e44343579e2c3304d676404d81b2b9bd893c5b)
---
 xen/drivers/passthrough/amd/iommu_cmd.c | 42 ++++++++++++---------------------
 1 file changed, 15 insertions(+), 27 deletions(-)

diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c 
b/xen/drivers/passthrough/amd/iommu_cmd.c
index c9c7d7b290..3e48fc3733 100644
--- a/xen/drivers/passthrough/amd/iommu_cmd.c
+++ b/xen/drivers/passthrough/amd/iommu_cmd.c
@@ -22,48 +22,36 @@
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include "../ats.h"
 
-static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[])
+static void send_iommu_command(struct amd_iommu *iommu,
+                               const uint32_t cmd[4])
 {
-    uint32_t tail, head;
+    uint32_t tail;
 
     tail = iommu->cmd_buffer.tail;
     if ( ++tail == iommu->cmd_buffer.entries )
         tail = 0;
 
-    head = iommu_get_rb_pointer(readl(iommu->mmio_base +
-                                      IOMMU_CMD_BUFFER_HEAD_OFFSET));
-    if ( head != tail )
+    while ( tail == iommu_get_rb_pointer(readl(iommu->mmio_base +
+                                               IOMMU_CMD_BUFFER_HEAD_OFFSET)) )
     {
-        memcpy(iommu->cmd_buffer.buffer +
-               (iommu->cmd_buffer.tail * sizeof(cmd_entry_t)),
-               cmd, sizeof(cmd_entry_t));
-
-        iommu->cmd_buffer.tail = tail;
-        return 1;
+        printk_once(XENLOG_ERR
+                    "AMD IOMMU %04x:%02x:%02x.%u: no cmd slot available\n",
+                    iommu->seg, PCI_BUS(iommu->bdf),
+                    PCI_SLOT(iommu->bdf), PCI_FUNC(iommu->bdf));
+        cpu_relax();
     }
 
-    return 0;
-}
+    memcpy(iommu->cmd_buffer.buffer +
+           (iommu->cmd_buffer.tail * sizeof(cmd_entry_t)),
+           cmd, sizeof(cmd_entry_t));
 
-static void commit_iommu_command_buffer(struct amd_iommu *iommu)
-{
-    u32 tail = 0;
+    iommu->cmd_buffer.tail = tail;
 
+    tail = 0;
     iommu_set_rb_pointer(&tail, iommu->cmd_buffer.tail);
     writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET);
 }
 
-int send_iommu_command(struct amd_iommu *iommu, u32 cmd[])
-{
-    if ( queue_iommu_command(iommu, cmd) )
-    {
-        commit_iommu_command_buffer(iommu);
-        return 1;
-    }
-
-    return 0;
-}
-
 static void flush_command_buffer(struct amd_iommu *iommu)
 {
     u32 cmd[4], status;
--
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®.