diff --git a/patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch b/patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch new file mode 100644 index 0000000..f21bf0d --- /dev/null +++ b/patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch @@ -0,0 +1,195 @@ +From 292dcb5eb9ceedeb981eb926be566af8c99cbb26 Mon Sep 17 00:00:00 2001 +From: HW42 +Date: Tue, 12 Sep 2017 00:49:02 +0200 +Subject: [PATCH] xen-pciback: add attribute to allow MSI enable flag writes + +QEMU running in a stubdom needs to be able to set the MSI enable flag in +the PCI config space. This adds an attribute 'allow_msi_enable' which +when set for a PCI device allows writes to this flag. The toolstack will +need to set this for stubdoms. + +This should not introduce any new security issues since a malicious +guest (or stubdom) can already generate MSIs through other ways, see +[1] page 8. + +[1]: https://invisiblethingslab.com/resources/2011/Software%20Attacks%20on%20Intel%20VT-d.pdf +--- + drivers/xen/xen-pciback/conf_space_capability.c | 39 +++++++++++++++ + drivers/xen/xen-pciback/pci_stub.c | 65 +++++++++++++++++++++++++ + drivers/xen/xen-pciback/pciback.h | 1 + + 3 files changed, 105 insertions(+) + +diff --git a/drivers/xen/xen-pciback/conf_space_capability.c b/drivers/xen/xen-pciback/conf_space_capability.c +index 7f83e9083e9d..793635238267 100644 +--- a/drivers/xen/xen-pciback/conf_space_capability.c ++++ b/drivers/xen/xen-pciback/conf_space_capability.c +@@ -189,6 +189,40 @@ static const struct config_field caplist_pm[] = { + {} + }; + ++#define MSI_OK_BITS (PCI_MSI_FLAGS_ENABLE) ++ ++static int msi_flags_write(struct pci_dev *dev, int offset, u16 new_value, ++ void *data) ++{ ++ int err; ++ u16 old_value; ++ struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev); ++ ++ if (xen_pcibk_permissive || dev_data->permissive) ++ goto write; ++ ++ err = pci_read_config_word(dev, offset, &old_value); ++ if (err) ++ return err; ++ ++ if (!dev_data->allow_msi_enable ++ || (new_value ^ old_value) & ~MSI_OK_BITS) ++ return PCIBIOS_SET_FAILED; ++ ++write: ++ return pci_write_config_word(dev, offset, new_value); ++} ++ ++static const struct config_field caplist_msi[] = { ++ { ++ .offset = PCI_MSI_FLAGS, ++ .size = 2, ++ .u.w.read = xen_pcibk_read_config_word, ++ .u.w.write = msi_flags_write, ++ }, ++ {} ++}; ++ + static struct xen_pcibk_config_capability xen_pcibk_config_capability_pm = { + .capability = PCI_CAP_ID_PM, + .fields = caplist_pm, +@@ -197,11 +231,16 @@ static struct xen_pcibk_config_capability xen_pcibk_config_capability_vpd = { + .capability = PCI_CAP_ID_VPD, + .fields = caplist_vpd, + }; ++static struct xen_pcibk_config_capability xen_pcibk_config_capability_msi = { ++ .capability = PCI_CAP_ID_MSI, ++ .fields = caplist_msi, ++}; + + int xen_pcibk_config_capability_init(void) + { + register_capability(&xen_pcibk_config_capability_vpd); + register_capability(&xen_pcibk_config_capability_pm); ++ register_capability(&xen_pcibk_config_capability_msi); + + return 0; + } +diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c +index 6331a95691a4..953866285ac1 100644 +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -303,6 +303,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev) + xen_pcibk_config_reset_dev(dev); + xen_pcibk_config_free_dyn_fields(dev); + ++ dev_data->allow_msi_enable = 0; ++ + xen_unregister_device_domain_owner(dev); + + spin_lock_irqsave(&found_psdev->lock, flags); +@@ -1434,6 +1436,64 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf) + static DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, + permissive_add); + ++static ssize_t allow_msi_enable_add(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int domain, bus, slot, func; ++ int err; ++ struct pcistub_device *psdev; ++ struct xen_pcibk_dev_data *dev_data; ++ ++ err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ if (err) ++ goto out; ++ ++ psdev = pcistub_device_find(domain, bus, slot, func); ++ if (!psdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ dev_data = pci_get_drvdata(psdev->dev); ++ /* the driver data for a device should never be null at this point */ ++ if (!dev_data) { ++ err = -ENXIO; ++ goto release; ++ } ++ dev_data->allow_msi_enable = 1; ++release: ++ pcistub_device_put(psdev); ++out: ++ if (!err) ++ err = count; ++ return err; ++} ++ ++static ssize_t allow_msi_enable_show(struct device_driver *drv, char *buf) ++{ ++ struct pcistub_device *psdev; ++ struct xen_pcibk_dev_data *dev_data; ++ size_t count = 0; ++ unsigned long flags; ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (count >= PAGE_SIZE) ++ break; ++ if (!psdev->dev) ++ continue; ++ dev_data = pci_get_drvdata(psdev->dev); ++ if (!dev_data || !dev_data->allow_msi_enable) ++ continue; ++ count += ++ scnprintf(buf + count, PAGE_SIZE - count, "%s\n", ++ pci_name(psdev->dev)); ++ } ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ return count; ++} ++static DRIVER_ATTR(allow_msi_enable, S_IRUSR | S_IWUSR, allow_msi_enable_show, ++ allow_msi_enable_add); ++ + static void pcistub_exit(void) + { + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_new_slot); +@@ -1443,6 +1503,8 @@ static void pcistub_exit(void) + driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_quirks); + driver_remove_file(&xen_pcibk_pci_driver.driver, + &driver_attr_permissive); ++ driver_remove_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_allow_msi_enable); + driver_remove_file(&xen_pcibk_pci_driver.driver, + &driver_attr_irq_handlers); + driver_remove_file(&xen_pcibk_pci_driver.driver, +@@ -1533,6 +1595,9 @@ static int __init pcistub_init(void) + if (!err) + err = driver_create_file(&xen_pcibk_pci_driver.driver, + &driver_attr_permissive); ++ if (!err) ++ err = driver_create_file(&xen_pcibk_pci_driver.driver, ++ &driver_attr_allow_msi_enable); + + if (!err) + err = driver_create_file(&xen_pcibk_pci_driver.driver, +diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h +index 7af369b6aaa2..32006bb4dad1 100644 +--- a/drivers/xen/xen-pciback/pciback.h ++++ b/drivers/xen/xen-pciback/pciback.h +@@ -44,6 +44,7 @@ struct xen_pcibk_dev_data { + struct list_head config_fields; + struct pci_saved_state *pci_saved_state; + unsigned int permissive:1; ++ unsigned int allow_msi_enable:1; + unsigned int warned_on_write:1; + unsigned int enable_intx:1; + unsigned int isr_on:1; /* Whether the IRQ handler is installed. */ +-- +2.14.1 + diff --git a/series.conf b/series.conf index 4ec122f..aac20d0 100644 --- a/series.conf +++ b/series.conf @@ -23,3 +23,6 @@ patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-p patches.xen/pci_op-cleanup.patch patches.xen/5266b8e4445c-xen-fix-booting-ballooned-down-hvm-guest.patch + +# Fix for MSI support with stubdoms +patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch