diff --git a/xen/drivers/vpci/rebar.c b/xen/drivers/vpci/rebar.c index 63510c337a..4d22f08af3 100644 --- a/xen/drivers/vpci/rebar.c +++ b/xen/drivers/vpci/rebar.c @@ -49,6 +49,58 @@ static void cf_check rebar_ctrl_write(const struct pci_dev *pdev, bar->guest_addr = bar->addr; } +static int cf_check cleanup_rebar(const struct pci_dev *pdev, bool hide) +{ + int rc; + uint32_t ctrl; + unsigned int nbars; + unsigned int rebar_offset = pci_find_ext_capability(pdev, + PCI_EXT_CAP_ID_REBAR); + + if ( !hide ) + return 0; + + ctrl = pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CTRL(0)); + nbars = MASK_EXTR(ctrl, PCI_REBAR_CTRL_NBAR_MASK); + + rc = vpci_remove_registers(pdev->vpci, rebar_offset + PCI_REBAR_CAP(0), + PCI_REBAR_CTRL(nbars - 1)); + if ( rc ) + { + printk(XENLOG_ERR "%pd %pp: fail to remove Rebar handlers rc=%d\n", + pdev->domain, &pdev->sbdf, rc); + ASSERT_UNREACHABLE(); + return rc; + } + + /* + * Unprivileged domains have a deny by default register access policy, no + * need to add any further handlers for them. + */ + if ( !is_hardware_domain(pdev->domain) ) + return 0; + + /* + * The driver may not traverse the capability list and think device + * supports Rebar by default. So here let the control register of Rebar + * be Read-Only is to ensure Rebar disabled. + */ + for ( unsigned int i = 0; i < nbars; i++ ) + { + rc = vpci_add_register(pdev->vpci, vpci_hw_read32, NULL, + rebar_offset + PCI_REBAR_CTRL(i), 4, NULL); + if ( rc ) + { + printk(XENLOG_ERR + "%pd %pp: fail to add Rebar ctrl handler rc=%d\n", + pdev->domain, &pdev->sbdf, rc); + return rc; + } + } + + return 0; +} + static int cf_check init_rebar(struct pci_dev *pdev) { uint32_t ctrl; @@ -97,14 +149,7 @@ static int cf_check init_rebar(struct pci_dev *pdev) { printk(XENLOG_ERR "%pd %pp: BAR%u fail to add reg of REBAR_CTRL rc=%d\n", pdev->domain, &pdev->sbdf, index, rc); - /* - * Ideally we would hide the ReBar capability on error, but code - * for doing so still needs to be written. Use continue instead - * to keep any already setup register hooks, as returning an - * error will cause the hardware domain to get unmediated access - * to all device registers. - */ - continue; + return rc; } bar->resizable_sizes = @@ -118,7 +163,7 @@ static int cf_check init_rebar(struct pci_dev *pdev) return 0; } -REGISTER_VPCI_EXTCAP(REBAR, init_rebar, NULL); +REGISTER_VPCI_EXTCAP(REBAR, init_rebar, cleanup_rebar); /* * Local variables: