]> xenbits.xensource.com Git - xen.git/commitdiff
vpci/msix: restore PBA access length and alignment restrictions
authorRoger Pau Monné <roger.pau@citrix.com>
Wed, 29 Mar 2023 12:56:33 +0000 (14:56 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 29 Mar 2023 12:56:33 +0000 (14:56 +0200)
Accesses to the PBA array have the same length and alignment
limitations as accesses to the MSI-X table:

"For all accesses to MSI-X Table and MSI-X PBA fields, software must
use aligned full DWORD or aligned full QWORD transactions; otherwise,
the result is undefined."

Introduce such length and alignment checks into the handling of PBA
accesses for vPCI.  This was a mistake of mine for not reading the
specification correctly.

Note that accesses must now be aligned, and hence there's no longer a
need to check that the end of the access falls into the PBA region as
both the access and the region addresses must be aligned.

Fixes: b177892d2d ('vpci/msix: handle accesses adjacent to the MSI-X table')
Reported-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/drivers/vpci/msix.c

index 99dd249c159e97ebe67b2e5d30d0a2f7f6b37acb..25bde77586a47fdf747148409b7f193241e9e881 100644 (file)
@@ -278,6 +278,11 @@ static int adjacent_read(const struct domain *d, const struct vpci_msix *msix,
     if ( !adjacent_handle(msix, addr + len - 1) )
         return X86EMUL_OKAY;
 
+    if ( VMSIX_ADDR_IN_RANGE(addr, vpci, VPCI_MSIX_PBA) &&
+         !access_allowed(msix->pdev, addr, len) )
+        /* PBA accesses must be aligned and 4 or 8 bytes in size. */
+        return X86EMUL_OKAY;
+
     slot = get_slot(vpci, addr);
     if ( slot >= ARRAY_SIZE(msix->table) )
         return X86EMUL_OKAY;
@@ -419,9 +424,8 @@ static int adjacent_write(const struct domain *d, const struct vpci_msix *msix,
      * assumed to be equal or bigger (8 bytes) than the length of any access
      * handled here.
      */
-    if ( (VMSIX_ADDR_IN_RANGE(addr, vpci, VPCI_MSIX_PBA) ||
-          VMSIX_ADDR_IN_RANGE(addr + len - 1, vpci, VPCI_MSIX_PBA)) &&
-         !is_hardware_domain(d) )
+    if ( VMSIX_ADDR_IN_RANGE(addr, vpci, VPCI_MSIX_PBA) &&
+         (!access_allowed(msix->pdev, addr, len) || !is_hardware_domain(d)) )
         /* Ignore writes to PBA for DomUs, it's undefined behavior. */
         return X86EMUL_OKAY;