|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 3/3] xen/vpci: header: filter PCI capabilities
Xen vPCI only supports virtualizing the MSI and MSI-X capabilities, so all other
PCI capabilities should be hidden from a domU for now. We parse the physical PCI
capabilities linked list and add vPCI register handlers for the next elements,
inserting our own next value, thus presenting a modified linked list to the
domU.
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx>
---
If there are no capabilities to be exposed to the guest, a future status
register handler likely would want to mask the PCI_STATUS_CAP_LIST bit. I'm
thinking we could track this in struct vpci_header as follows:
vpci.h:
struct vpci_header {
...
+ bool mask_cap_list : 1;
} header;
header.c:init_bars():
rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
PCI_CAPABILITY_LIST, 1,
(void *)(uintptr_t)next);
if ( rc )
return rc;
+ if ( !next )
+ header->mask_cap_list = true;
+
for ( ttl = 48; ttl > 0; ttl-- )
{
uint8_t pos;
---
xen/drivers/vpci/header.c | 78 +++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index 60f7049e3498..cb1304fa1eed 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -513,6 +513,36 @@ static void cf_check rom_write(
rom->addr = val & PCI_ROM_ADDRESS_MASK;
}
+static uint8_t vpci_find_next_cap(pci_sbdf_t sbdf, uint8_t pos)
+{
+ uint8_t id;
+ int ttl;
+
+ if ( pos < 0x40 )
+ pos = pci_conf_read8(sbdf, PCI_CAPABILITY_LIST);
+ else
+ pos = pci_conf_read8(sbdf, pos + PCI_CAP_LIST_NEXT);
+
+ for ( ttl = 48; ttl > 0; ttl-- )
+ {
+ if ( pos < 0x40 )
+ break;
+
+ pos &= ~3;
+ id = pci_conf_read8(sbdf, pos + PCI_CAP_LIST_ID);
+
+ if ( id == 0xff )
+ break;
+
+ if ( id == PCI_CAP_ID_MSI ||
+ id == PCI_CAP_ID_MSIX )
+ return pos;
+
+ pos = pci_conf_read8(sbdf, pos + PCI_CAP_LIST_NEXT);
+ }
+ return 0;
+}
+
static int cf_check init_bars(struct pci_dev *pdev)
{
uint16_t cmd;
@@ -544,6 +574,54 @@ static int cf_check init_bars(struct pci_dev *pdev)
if ( rc )
return rc;
+ if ( !is_hardware_domain(pdev->domain) )
+ {
+ if ( (pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST)
+ == 0 )
+ {
+ /* RAZ/WI */
+ rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
+ PCI_CAPABILITY_LIST, 1, NULL);
+ if ( rc )
+ return rc;
+ }
+ else
+ {
+ /* Only expose capabilities to the guest that vPCI can handle. */
+ uint8_t next, ttl;
+
+ next = vpci_find_next_cap(pdev->sbdf, PCI_CAPABILITY_LIST);
+
+ rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
+ PCI_CAPABILITY_LIST, 1,
+ (void *)(uintptr_t)next);
+ if ( rc )
+ return rc;
+
+ for ( ttl = 48; ttl > 0; ttl-- )
+ {
+ uint8_t pos;
+
+ if ( !next )
+ break;
+
+ pos = next;
+ next = vpci_find_next_cap(pdev->sbdf, pos);
+
+ rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL,
+ pos + PCI_CAP_LIST_ID, 1, NULL);
+ if ( rc )
+ return rc;
+
+ rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL,
+ pos + PCI_CAP_LIST_NEXT, 1,
+ (void *)(uintptr_t)next);
+ if ( rc )
+ return rc;
+ }
+ }
+ }
+
if ( pdev->ignore_bars )
return 0;
--
2.41.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |