97a0425e04
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
399 lines
14 KiB
Diff
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,
|