xen/x86-MSI-X-maskall.patch
Charles Arnold 97a0425e04 - Update to Xen Version 4.5.1 FCS (fate#315675)
xen-4.5.1-testing-src.tar.bz2
- Dropped patches now contained in tarball
  556c2cf2-x86-don-t-crash-mapping-a-page-using-EFI-rt-page-tables.patch
  556d9718-efi-fix-allocation-problems-if-ExitBootServices-fails.patch
  556eabf7-x86-apic-Disable-the-LAPIC-later-in-smp_send_stop.patch
  556eac15-x86-crash-don-t-use-set_fixmap-in-the-crash-path.patch
  55780aaa-efi-avoid-calling-boot-services-after-ExitBootServices.patch
  55780aff-x86-EFI-fix-EFI_MEMORY_WP-handling.patch
  55780b43-EFI-early-add-mapbs-to-map-EfiBootServices-Code-Data.patch
  55780b97-EFI-support-default-attributes-to-map-Runtime-service-areas.patch

- Replace 5124efbe-add-qxl-support.patch with the variant that
  finally made it upstream, 554cc211-libxl-add-qxl.patch

- bsc#931627 - VUL-0: CVE-2015-4105: XSA-130: xen: Guest triggerable
  qemu MSI-X pass-through error messages
  qemu-MSI-X-latch-writes.patch
- bsc#907514 - Bus fatal error & sles12 sudden reboot has been observed
- bsc#910258 - SLES12 Xen host crashes with FATAL NMI after shutdown
  of guest with VT-d NIC
- bsc#918984 - Bus fatal error & sles11-SP4 sudden reboot has been
  observed
- bsc#923967 - Partner-L3: Bus fatal error & sles11-SP3 sudden reboot
  has been observed
  x86-MSI-X-teardown.patch
  x86-MSI-X-enable.patch
  x86-MSI-X-guest-mask.patch
  x86-MSI-X-maskall.patch
  qemu-MSI-X-enable-maskall.patch

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=364
2015-06-30 14:23:29 +00:00

399 lines
14 KiB
Diff

References: bsc#907514 bsc#910258 bsc#918984 bsc#923967
x86/MSI-X: provide hypercall interface for mask-all control
Qemu shouldn't be fiddling with this bit directly, as the hypervisor
may (and now does) use it for its own purposes. Provide it with a
replacement interface, allowing the hypervisor to track host and guest
masking intentions independently (clearing the bit only when both want
it clear).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
Whether the permission check should really be an XSM_TARGET one needs
to be determined: That allowing the guest to issue the hypercalls on
itself means permitting it to bypass the device model, and thus render
device model state stale.
--- trunk.orig/tools/libxc/include/xenctrl.h 2015-01-14 18:44:18.000000000 +0100
+++ trunk/tools/libxc/include/xenctrl.h 2015-03-25 13:51:05.000000000 +0100
@@ -1793,6 +1793,17 @@ int xc_physdev_unmap_pirq(xc_interface *
int domid,
int pirq);
+int xc_physdev_msix_enable(xc_interface *xch,
+ int segment,
+ int bus,
+ int devfn,
+ int on);
+int xc_physdev_msix_mask_all(xc_interface *xch,
+ int segment,
+ int bus,
+ int devfn,
+ int mask);
+
int xc_hvm_set_pci_intx_level(
xc_interface *xch, domid_t dom,
uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx,
--- trunk.orig/tools/libxc/xc_physdev.c 2013-07-09 20:57:12.000000000 +0200
+++ trunk/tools/libxc/xc_physdev.c 2015-03-24 15:59:43.000000000 +0100
@@ -108,3 +108,38 @@ int xc_physdev_unmap_pirq(xc_interface *
return rc;
}
+int xc_physdev_msix_enable(xc_interface *xch,
+ int segment,
+ int bus,
+ int devfn,
+ int on)
+{
+ struct physdev_pci_device dev = {
+ .seg = segment,
+ .bus = bus,
+ .devfn = devfn
+ };
+
+ return do_physdev_op(xch,
+ on ? PHYSDEVOP_msix_enable
+ : PHYSDEVOP_msix_disable,
+ &dev, sizeof(dev));
+}
+
+int xc_physdev_msix_mask_all(xc_interface *xch,
+ int segment,
+ int bus,
+ int devfn,
+ int mask)
+{
+ struct physdev_pci_device dev = {
+ .seg = segment,
+ .bus = bus,
+ .devfn = devfn
+ };
+
+ return do_physdev_op(xch,
+ mask ? PHYSDEVOP_msix_mask_all
+ : PHYSDEVOP_msix_unmask_all,
+ &dev, sizeof(dev));
+}
--- trunk.orig/xen/arch/x86/msi.c 2015-05-18 11:44:39.000000000 +0200
+++ trunk/xen/arch/x86/msi.c 2015-06-10 12:53:52.000000000 +0200
@@ -394,7 +394,7 @@ static bool_t msi_set_mask_bit(struct ir
struct pci_dev *pdev;
u16 seg, control;
u8 bus, slot, func;
- bool_t flag = host || guest;
+ bool_t flag = host || guest, maskall;
ASSERT(spin_is_locked(&desc->lock));
BUG_ON(!entry || !entry->dev);
@@ -415,13 +415,17 @@ static bool_t msi_set_mask_bit(struct ir
}
break;
case PCI_CAP_ID_MSIX:
+ maskall = pdev->msix->host_maskall;
control = pci_conf_read16(seg, bus, slot, func,
msix_control_reg(entry->msi_attrib.pos));
if ( unlikely(!(control & PCI_MSIX_FLAGS_ENABLE)) )
+ {
+ pdev->msix->host_maskall = 1;
pci_conf_write16(seg, bus, slot, func,
msix_control_reg(entry->msi_attrib.pos),
control | (PCI_MSIX_FLAGS_ENABLE |
PCI_MSIX_FLAGS_MASKALL));
+ }
if ( likely(memory_decoded(pdev)) )
{
writel(flag, entry->mask_base + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
@@ -434,7 +438,7 @@ static bool_t msi_set_mask_bit(struct ir
{
domid_t domid = pdev->domain->domain_id;
- control |= PCI_MSIX_FLAGS_MASKALL;
+ maskall = 1;
if ( pdev->msix->warned != domid )
{
pdev->msix->warned = domid;
@@ -444,6 +448,9 @@ static bool_t msi_set_mask_bit(struct ir
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
}
}
+ pdev->msix->host_maskall = maskall;
+ if ( maskall || pdev->msix->guest_maskall )
+ control |= PCI_MSIX_FLAGS_MASKALL;
pci_conf_write16(seg, bus, slot, func,
msix_control_reg(entry->msi_attrib.pos), control);
return flag;
@@ -839,6 +846,7 @@ static int msix_capability_init(struct p
u8 bus = dev->bus;
u8 slot = PCI_SLOT(dev->devfn);
u8 func = PCI_FUNC(dev->devfn);
+ bool_t maskall = msix->host_maskall;
ASSERT(spin_is_locked(&pcidevs_lock));
@@ -850,6 +858,7 @@ static int msix_capability_init(struct p
* to mask all the vectors to prevent interrupts coming in before they're
* fully set up.
*/
+ msix->host_maskall = 1;
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
control | (PCI_MSIX_FLAGS_ENABLE |
PCI_MSIX_FLAGS_MASKALL));
@@ -972,6 +981,10 @@ static int msix_capability_init(struct p
if ( !msix->used_entries )
{
+ maskall = 0;
+ msix->guest_maskall = 0;
+ control &= ~PCI_MSIX_FLAGS_MASKALL;
+
if ( rangeset_add_range(mmio_ro_ranges, msix->table.first,
msix->table.last) )
WARN();
@@ -1002,6 +1015,7 @@ static int msix_capability_init(struct p
++msix->used_entries;
/* Restore MSI-X enabled bits */
+ msix->host_maskall = maskall;
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
return 0;
@@ -1142,6 +1156,7 @@ static void __pci_disable_msix(struct ms
int pos;
u16 control, seg;
u8 bus, slot, func;
+ bool_t maskall;
dev = entry->dev;
seg = dev->seg;
@@ -1151,10 +1166,14 @@ static void __pci_disable_msix(struct ms
pos = pci_find_cap_offset(seg, bus, slot, func, PCI_CAP_ID_MSIX);
control = pci_conf_read16(seg, bus, slot, func, msix_control_reg(pos));
+ maskall = dev->msix->host_maskall;
if ( unlikely(!(control & PCI_MSIX_FLAGS_ENABLE)) )
+ {
+ dev->msix->host_maskall = 1;
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
control | (PCI_MSIX_FLAGS_ENABLE |
PCI_MSIX_FLAGS_MASKALL));
+ }
BUG_ON(list_empty(&dev->msi_list));
@@ -1166,8 +1185,11 @@ static void __pci_disable_msix(struct ms
"cannot disable IRQ %d: masking MSI-X on %04x:%02x:%02x.%u\n",
entry->irq, dev->seg, dev->bus,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- control |= PCI_MSIX_FLAGS_MASKALL;
+ maskall = 1;
}
+ dev->msix->host_maskall = maskall;
+ if ( maskall || dev->msix->guest_maskall )
+ control |= PCI_MSIX_FLAGS_MASKALL;
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
_pci_cleanup_msix(dev->msix);
@@ -1211,6 +1233,62 @@ int pci_prepare_msix(u16 seg, u8 bus, u8
return rc;
}
+int pci_msix_enable(u16 seg, u8 bus, u8 devfn, bool_t on)
+{
+ int rc;
+ struct pci_dev *pdev;
+
+ if ( !use_msi )
+ return -EOPNOTSUPP;
+
+ spin_lock(&pcidevs_lock);
+ pdev = pci_get_pdev(seg, bus, devfn);
+ if ( !pdev || !pdev->msix || !pdev->domain )
+ rc = -ENODEV;
+ else if ( !is_hvm_domain(pdev->domain) )
+ rc = -ENXIO;
+ else if ( (rc = xsm_manage_domain_pirq(XSM_TARGET, pdev->domain)) == 0 )
+ msix_set_enable(pdev, on);
+ spin_unlock(&pcidevs_lock);
+
+ return rc;
+}
+
+int pci_msix_maskall(u16 seg, u8 bus, u8 devfn, bool_t mask)
+{
+ int rc;
+ struct pci_dev *pdev;
+ u8 slot = PCI_SLOT(devfn), func = PCI_FUNC(devfn);
+
+ if ( !use_msi )
+ return -EOPNOTSUPP;
+
+ spin_lock(&pcidevs_lock);
+ pdev = pci_get_pdev(seg, bus, devfn);
+ if ( !pdev || !pdev->msix || !pdev->domain )
+ rc = -ENODEV;
+ else if ( !is_hvm_domain(pdev->domain) )
+ rc = -ENXIO;
+ else if ( (rc = xsm_manage_domain_pirq(XSM_TARGET, pdev->domain)) == 0 )
+ {
+ unsigned int pos = pci_find_cap_offset(seg, bus, slot, func,
+ PCI_CAP_ID_MSIX);
+ u16 control = pci_conf_read16(seg, bus, slot, func,
+ msix_control_reg(pos));
+
+ BUG_ON(!pos);
+ pdev->msix->guest_maskall = mask;
+ if ( pdev->msix->host_maskall || mask )
+ control |= PCI_MSIX_FLAGS_MASKALL;
+ else
+ control &= ~PCI_MSIX_FLAGS_MASKALL;
+ pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos), control);
+ }
+ spin_unlock(&pcidevs_lock);
+
+ return rc;
+}
+
/*
* Notice: only construct the msi_desc
* no change to irq_desc here, and the interrupt is masked
--- trunk.orig/xen/arch/x86/physdev.c 2015-01-14 18:44:18.000000000 +0100
+++ trunk/xen/arch/x86/physdev.c 2015-03-25 14:02:24.000000000 +0100
@@ -648,6 +648,30 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
break;
}
+ case PHYSDEVOP_msix_enable:
+ case PHYSDEVOP_msix_disable: {
+ struct physdev_pci_device dev;
+
+ if ( copy_from_guest(&dev, arg, 1) )
+ ret = -EFAULT;
+ else
+ ret = pci_msix_enable(dev.seg, dev.bus, dev.devfn,
+ cmd == PHYSDEVOP_msix_enable);
+ break;
+ }
+
+ case PHYSDEVOP_msix_mask_all:
+ case PHYSDEVOP_msix_unmask_all: {
+ struct physdev_pci_device dev;
+
+ if ( copy_from_guest(&dev, arg, 1) )
+ ret = -EFAULT;
+ else
+ ret = pci_msix_maskall(dev.seg, dev.bus, dev.devfn,
+ cmd == PHYSDEVOP_msix_mask_all);
+ break;
+ }
+
case PHYSDEVOP_pci_mmcfg_reserved: {
struct physdev_pci_mmcfg_reserved info;
--- trunk.orig/xen/include/asm-x86/msi.h 2015-03-09 09:42:49.000000000 +0100
+++ trunk/xen/include/asm-x86/msi.h 2015-03-25 14:01:00.000000000 +0100
@@ -78,6 +78,8 @@ struct msi_desc;
extern int pci_enable_msi(struct msi_info *msi, struct msi_desc **desc);
extern void pci_disable_msi(struct msi_desc *desc);
extern int pci_prepare_msix(u16 seg, u8 bus, u8 devfn, bool_t off);
+extern int pci_msix_enable(u16 seg, u8 bus, u8 devfn, bool_t on);
+extern int pci_msix_maskall(u16 seg, u8 bus, u8 devfn, bool_t mask);
extern void pci_cleanup_msi(struct pci_dev *pdev);
extern int setup_msi_irq(struct irq_desc *, struct msi_desc *);
extern int __setup_msi_irq(struct irq_desc *, struct msi_desc *,
@@ -228,6 +230,7 @@ struct arch_msix {
int table_refcnt[MAX_MSIX_TABLE_PAGES];
int table_idx[MAX_MSIX_TABLE_PAGES];
spinlock_t table_lock;
+ bool_t host_maskall, guest_maskall;
domid_t warned;
};
--- trunk.orig/xen/include/public/physdev.h 2013-12-24 18:25:25.000000000 +0100
+++ trunk/xen/include/public/physdev.h 2015-03-24 15:54:54.000000000 +0100
@@ -310,6 +310,14 @@ DEFINE_XEN_GUEST_HANDLE(physdev_pci_devi
*/
#define PHYSDEVOP_prepare_msix 30
#define PHYSDEVOP_release_msix 31
+/*
+ * The device model domain for a guest should be using these instead of
+ * fiddling with the respective flags in the MSI-X capability structure.
+ */
+#define PHYSDEVOP_msix_enable 32
+#define PHYSDEVOP_msix_disable 33
+#define PHYSDEVOP_msix_mask_all 34
+#define PHYSDEVOP_msix_unmask_all 35
struct physdev_pci_device {
/* IN */
uint16_t seg;
--- trunk.orig/xen/include/xsm/dummy.h 2015-01-14 18:44:18.000000000 +0100
+++ trunk/xen/include/xsm/dummy.h 2015-03-23 11:13:16.000000000 +0100
@@ -439,6 +439,12 @@ static XSM_INLINE int xsm_map_domain_irq
return xsm_default_action(action, current->domain, d);
}
+static XSM_INLINE int xsm_manage_domain_pirq(XSM_DEFAULT_ARG struct domain *d)
+{
+ XSM_ASSERT_ACTION(XSM_TARGET);
+ return xsm_default_action(action, current->domain, d);
+}
+
static XSM_INLINE int xsm_unmap_domain_pirq(XSM_DEFAULT_ARG struct domain *d)
{
XSM_ASSERT_ACTION(XSM_TARGET);
--- trunk.orig/xen/include/xsm/xsm.h 2015-01-14 18:44:18.000000000 +0100
+++ trunk/xen/include/xsm/xsm.h 2015-05-15 10:28:19.000000000 +0200
@@ -105,6 +105,7 @@ struct xsm_operations {
char *(*show_irq_sid) (int irq);
int (*map_domain_pirq) (struct domain *d);
int (*map_domain_irq) (struct domain *d, int irq, void *data);
+ int (*manage_domain_pirq) (struct domain *d);
int (*unmap_domain_pirq) (struct domain *d);
int (*unmap_domain_irq) (struct domain *d, int irq, void *data);
int (*irq_permission) (struct domain *d, int pirq, uint8_t allow);
@@ -409,6 +410,11 @@ static inline int xsm_map_domain_irq (xs
return xsm_ops->map_domain_irq(d, irq, data);
}
+static inline int xsm_manage_domain_pirq(xsm_default_t def, struct domain *d)
+{
+ return xsm_ops->manage_domain_pirq(d);
+}
+
static inline int xsm_unmap_domain_pirq (xsm_default_t def, struct domain *d)
{
return xsm_ops->unmap_domain_pirq(d);
--- trunk.orig/xen/xsm/dummy.c 2015-01-14 18:44:18.000000000 +0100
+++ trunk/xen/xsm/dummy.c 2015-05-15 10:27:35.000000000 +0200
@@ -79,6 +79,7 @@ void xsm_fixup_ops (struct xsm_operation
set_to_dummy_if_null(ops, show_irq_sid);
set_to_dummy_if_null(ops, map_domain_pirq);
set_to_dummy_if_null(ops, map_domain_irq);
+ set_to_dummy_if_null(ops, manage_domain_pirq);
set_to_dummy_if_null(ops, unmap_domain_pirq);
set_to_dummy_if_null(ops, unmap_domain_irq);
set_to_dummy_if_null(ops, irq_permission);
--- trunk.orig/xen/xsm/flask/hooks.c 2015-01-14 18:44:18.000000000 +0100
+++ trunk/xen/xsm/flask/hooks.c 2015-05-15 10:27:50.000000000 +0200
@@ -875,6 +875,11 @@ static int flask_map_domain_irq (struct
return rc;
}
+static int flask_manage_domain_pirq(struct domain *d)
+{
+ return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__USE);
+}
+
static int flask_unmap_domain_pirq (struct domain *d)
{
return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE);
@@ -1556,6 +1561,7 @@ static struct xsm_operations flask_ops =
.map_domain_pirq = flask_map_domain_pirq,
.map_domain_irq = flask_map_domain_irq,
+ .manage_domain_pirq = flask_manage_domain_pirq,
.unmap_domain_pirq = flask_unmap_domain_pirq,
.unmap_domain_irq = flask_unmap_domain_irq,
.irq_permission = flask_irq_permission,