Current logic of emulating legacy capability list is only for domU. So, expand it to emulate for dom0 too. Then it will be easy to hide a capability whose initialization fails in a function.
And restrict adding PCI_STATUS register only for domU since dom0 has no limitation to access that register. Signed-off-by: Jiqian Chen <jiqian.c...@amd.com> --- cc: "Roger Pau Monné" <roger....@citrix.com> --- v4->v5 changes: * Return early if dom0, so that I didn't need to change the exiting return chunk. v3->v4 changes: * Also pass supported_caps to pci_find_next_cap_ttl() for dom0 since the n is zero when dom0, and add a comment to explain it. * Restrict adding PCI_STATUS register only for domU since dom0 has no limitation to access that register. * For dom0 register handler, set vpci_hw_write8 to it instead of NULL. v2->v3 changes: * Not to add handler of PCI_CAP_LIST_ID when domain is dom0. v1->v2 changes: new patch. Best regards, Jiqian Chen. --- xen/drivers/vpci/header.c | 39 ++++++++++++++++++++++++++------------- xen/drivers/vpci/vpci.c | 6 ++++++ xen/include/xen/vpci.h | 2 ++ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c index 0fb3cfa6a376..d26cbba08ee1 100644 --- a/xen/drivers/vpci/header.c +++ b/xen/drivers/vpci/header.c @@ -758,9 +758,9 @@ static int vpci_init_capability_list(struct pci_dev *pdev) { int rc; bool mask_cap_list = false; + bool is_hwdom = is_hardware_domain(pdev->domain); - if ( !is_hardware_domain(pdev->domain) && - pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST ) + if ( pci_conf_read16(pdev->sbdf, PCI_STATUS) & PCI_STATUS_CAP_LIST ) { /* Only expose capabilities to the guest that vPCI can handle. */ unsigned int next, ttl = 48; @@ -768,12 +768,18 @@ static int vpci_init_capability_list(struct pci_dev *pdev) PCI_CAP_ID_MSI, PCI_CAP_ID_MSIX, }; + /* + * For dom0, we should expose all capabilities instead of a fixed + * capabilities array, so setting n to 0 here is to get the next + * capability position directly in pci_find_next_cap_ttl. + */ + const unsigned int n = is_hwdom ? 0 : ARRAY_SIZE(supported_caps); next = pci_find_next_cap_ttl(pdev->sbdf, PCI_CAPABILITY_LIST, - supported_caps, - ARRAY_SIZE(supported_caps), &ttl); + supported_caps, n, &ttl); - rc = vpci_add_register(pdev->vpci, vpci_read_val, NULL, + rc = vpci_add_register(pdev->vpci, vpci_read_val, + is_hwdom ? vpci_hw_write8 : NULL, PCI_CAPABILITY_LIST, 1, (void *)(uintptr_t)next); if ( rc ) @@ -781,7 +787,7 @@ static int vpci_init_capability_list(struct pci_dev *pdev) next &= ~3; - if ( !next ) + if ( !next && !is_hwdom ) /* * If we don't have any supported capabilities to expose to the * guest, mask the PCI_STATUS_CAP_LIST bit in the status @@ -795,15 +801,18 @@ static int vpci_init_capability_list(struct pci_dev *pdev) next = pci_find_next_cap_ttl(pdev->sbdf, pos + PCI_CAP_LIST_NEXT, - supported_caps, - ARRAY_SIZE(supported_caps), &ttl); + supported_caps, n, &ttl); - rc = vpci_add_register(pdev->vpci, vpci_hw_read8, NULL, - pos + PCI_CAP_LIST_ID, 1, NULL); - if ( rc ) - return rc; + if ( !is_hwdom ) + { + 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, + rc = vpci_add_register(pdev->vpci, vpci_read_val, + is_hwdom ? vpci_hw_write8 : NULL, pos + PCI_CAP_LIST_NEXT, 1, (void *)(uintptr_t)next); if ( rc ) @@ -813,6 +822,10 @@ static int vpci_init_capability_list(struct pci_dev *pdev) } } + /* Return early for the hw domain, no masking of PCI_STATUS. */ + if ( is_hwdom ) + return 0; + /* Utilize rsvdp_mask to hide PCI_STATUS_CAP_LIST from the guest. */ return vpci_add_register_mask(pdev->vpci, vpci_hw_read16, vpci_hw_write16, PCI_STATUS, 2, NULL, diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c index d2f0f97e0a04..09988f04c27c 100644 --- a/xen/drivers/vpci/vpci.c +++ b/xen/drivers/vpci/vpci.c @@ -255,6 +255,12 @@ uint32_t cf_check vpci_hw_read32( return pci_conf_read32(pdev->sbdf, reg); } +void cf_check vpci_hw_write8( + const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data) +{ + pci_conf_write8(pdev->sbdf, reg, val); +} + void cf_check vpci_hw_write16( const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data) { diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index 475981cb8155..fc8d5b470b0b 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -76,6 +76,8 @@ uint32_t cf_check vpci_hw_read16( const struct pci_dev *pdev, unsigned int reg, void *data); uint32_t cf_check vpci_hw_read32( const struct pci_dev *pdev, unsigned int reg, void *data); +void cf_check vpci_hw_write8( + const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data); void cf_check vpci_hw_write16( const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data); -- 2.34.1