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

[Xen-devel] [PATCH v3 6/9] xen/vpci: trap access to the list of PCI capabilities



Add traps to each capability PCI_CAP_LIST_NEXT field in order to mask them on
request.

All capabilities from the device are fetched and stored in an internal list,
that's later used in order to return the next capability to the guest. Note
that this only removes the capability from the linked list as seen by the
guest, but the actual capability structure could still be accessed by the
guest, provided that it's position can be found using another mechanism.
Finally the MSI and MSI-X capabilities are masked until Xen knows how to
properly handle accesses to them.

This should allow a PVH Dom0 to boot on some hardware, provided that the
hardware doesn't require MSI/MSI-X and that there are no SR-IOV devices in the
system, so the panic at the end of the PVH Dom0 build is replaced by a
warning.

Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
Changes since v1:
 - Add missing newline between cmd handlers.
 - Switch the handler to use list_for_each_entry_continue instead of a wrong
   open-coded version of it.
---
 xen/arch/x86/hvm/dom0_build.c   |   2 +-
 xen/drivers/vpci/Makefile       |   2 +-
 xen/drivers/vpci/capabilities.c | 159 ++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/vpci.h          |   3 +
 4 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 xen/drivers/vpci/capabilities.c

diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c
index 9efe4e571b..7cf794447f 100644
--- a/xen/arch/x86/hvm/dom0_build.c
+++ b/xen/arch/x86/hvm/dom0_build.c
@@ -1097,7 +1097,7 @@ int __init dom0_construct_pvh(struct domain *d, const 
module_t *image,
         return rc;
     }
 
-    panic("Building a PVHv2 Dom0 is not yet supported.");
+    printk("WARNING: PVH is an experimental mode with limited 
functionality\n");
     return 0;
 }
 
diff --git a/xen/drivers/vpci/Makefile b/xen/drivers/vpci/Makefile
index 241467212f..c3f3085c93 100644
--- a/xen/drivers/vpci/Makefile
+++ b/xen/drivers/vpci/Makefile
@@ -1 +1 @@
-obj-y += vpci.o header.o
+obj-y += vpci.o header.o capabilities.o
diff --git a/xen/drivers/vpci/capabilities.c b/xen/drivers/vpci/capabilities.c
new file mode 100644
index 0000000000..b2a3326aa7
--- /dev/null
+++ b/xen/drivers/vpci/capabilities.c
@@ -0,0 +1,159 @@
+/*
+ * Generic functionality for handling accesses to the PCI capabilities from
+ * the configuration space.
+ *
+ * Copyright (C) 2017 Citrix Systems R&D
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/sched.h>
+#include <xen/vpci.h>
+
+struct vpci_capability {
+    struct list_head next;
+    uint8_t offset;
+    bool masked;
+};
+
+static int vpci_cap_read(struct pci_dev *pdev, unsigned int reg,
+                         union vpci_val *val, void *data)
+{
+    struct vpci_capability *cap = data;
+
+    val->half_word = 0;
+
+    /* Return the position of the next non-masked capability. */
+    list_for_each_entry_continue ( cap, &pdev->vpci->cap_list, next )
+    {
+        if ( !cap->masked )
+        {
+            val->half_word = cap->offset;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int vpci_cap_write(struct pci_dev *pdev, unsigned int reg,
+                          union vpci_val val, void *data)
+{
+    /* Ignored. */
+    return 0;
+}
+
+static int vpci_index_capabilities(struct pci_dev *pdev)
+{
+    uint8_t seg = pdev->seg, bus = pdev->bus;
+    uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn);
+    uint8_t pos = PCI_CAPABILITY_LIST;
+    uint16_t status;
+    unsigned int max_cap = 48;
+    struct vpci_capability *cap;
+    int rc;
+
+    INIT_LIST_HEAD(&pdev->vpci->cap_list);
+
+    /* Check if device has capabilities. */
+    status = pci_conf_read16(seg, bus, slot, func, PCI_STATUS);
+    if ( !(status & PCI_STATUS_CAP_LIST) )
+        return 0;
+
+    /* Add the root capability pointer. */
+    cap = xzalloc(struct vpci_capability);
+    if ( !cap )
+        return -ENOMEM;
+
+    cap->offset = pos;
+    list_add_tail(&cap->next, &pdev->vpci->cap_list);
+    rc = xen_vpci_add_register(pdev, vpci_cap_read, vpci_cap_write, pos,
+                               1, cap);
+    if ( rc )
+        return rc;
+
+    /*
+     * Iterate over the list of capabilities present in the device, and
+     * add a handler for each register pointer to the next item
+     * (PCI_CAP_LIST_NEXT).
+     */
+    while ( max_cap-- )
+    {
+        pos = pci_conf_read8(seg, bus, slot, func, pos);
+        if ( pos < 0x40 )
+            break;
+
+        cap = xzalloc(struct vpci_capability);
+        if ( !cap )
+            return -ENOMEM;
+
+        cap->offset = pos;
+        list_add_tail(&cap->next, &pdev->vpci->cap_list);
+        pos += PCI_CAP_LIST_NEXT;
+        rc = xen_vpci_add_register(pdev, vpci_cap_read, vpci_cap_write, pos,
+                                   1, cap);
+        if ( rc )
+            return rc;
+    }
+
+    return 0;
+}
+
+static void vpci_mask_capability(struct pci_dev *pdev, uint8_t cap_id)
+{
+    struct vpci_capability *cap;
+    uint8_t cap_offset;
+
+    cap_offset = pci_find_cap_offset(pdev->seg, pdev->bus,
+                                     PCI_SLOT(pdev->devfn),
+                                     PCI_FUNC(pdev->devfn), cap_id);
+    if ( !cap_offset )
+        return;
+
+    list_for_each_entry ( cap, &pdev->vpci->cap_list, next )
+    {
+        if ( cap->offset == cap_offset )
+        {
+            cap->masked = true;
+            break;
+        }
+    }
+}
+
+static int vpci_capabilities_init(struct pci_dev *pdev)
+{
+    int rc;
+
+    rc = vpci_index_capabilities(pdev);
+    if ( rc )
+        return rc;
+
+    /* Mask MSI and MSI-X capabilities until Xen handles them. */
+    vpci_mask_capability(pdev, PCI_CAP_ID_MSI);
+    vpci_mask_capability(pdev, PCI_CAP_ID_MSIX);
+
+    return 0;
+}
+
+REGISTER_VPCI_INIT(vpci_capabilities_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index 235b4ebd1f..d41277f39b 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -77,6 +77,9 @@ struct vpci {
             bool unset;
         } bars[6];
     } header;
+
+    /* List of capabilities supported by the device. */
+    struct list_head cap_list;
 #endif
 };
 
-- 
2.11.0 (Apple Git-81)


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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