Add patch for stubdom MSI support
This commit is contained in:
parent
52da881318
commit
96b956b38c
@ -0,0 +1,195 @@
|
||||
From 292dcb5eb9ceedeb981eb926be566af8c99cbb26 Mon Sep 17 00:00:00 2001
|
||||
From: HW42 <hw42@ipsumj.de>
|
||||
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
|
||||
|
@ -22,3 +22,6 @@ patches.xen/xsa155-linux44-0013-xen-blkfront-prepare-request-locally-only-then-p
|
||||
|
||||
# MSI-X enabled device passthrough fix (#1734)
|
||||
patches.xen/pci_op-cleanup.patch
|
||||
|
||||
# Fix for MSI support with stubdoms
|
||||
patches.xen/xen-pciback-add-attribute-to-allow-MSI-enable-flag-w.patch
|
||||
|
Loading…
Reference in New Issue
Block a user