bool map = cmd & PCI_COMMAND_MEMORY;
unsigned int i;
+ /*
+ * Make sure there are no mappings in the MSIX MMIO areas, so that accesses
+ * can be trapped (and emulated) by Xen when the memory decoding bit is
+ * enabled.
+ *
+ * FIXME: punching holes after the p2m has been set up might be racy for
+ * DomU usage, needs to be revisited.
+ */
+ if ( map && !rom_only && vpci_make_msix_hole(pdev) )
+ return;
+
for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
{
if ( !MAPPABLE_BAR(&header->bars[i]) )
#include <xen/vpci.h>
#include <asm/msi.h>
+#include <asm/p2m.h>
#define VMSIX_SIZE(num) offsetof(struct vpci_msix, entries[num])
.write = msix_write,
};
+int vpci_make_msix_hole(const struct pci_dev *pdev)
+{
+ struct domain *d = pdev->domain;
+ unsigned int i;
+
+ if ( !pdev->vpci->msix )
+ return 0;
+
+ /* Make sure there's a hole for the MSIX table/PBA in the p2m. */
+ for ( i = 0; i < ARRAY_SIZE(pdev->vpci->msix->tables); i++ )
+ {
+ unsigned long start = PFN_DOWN(vmsix_table_addr(pdev->vpci, i));
+ unsigned long end = PFN_DOWN(vmsix_table_addr(pdev->vpci, i) +
+ vmsix_table_size(pdev->vpci, i) - 1);
+
+ for ( ; start <= end; start++ )
+ {
+ p2m_type_t t;
+ mfn_t mfn = get_gfn_query(d, start, &t);
+
+ switch ( t )
+ {
+ case p2m_mmio_dm:
+ case p2m_invalid:
+ break;
+ case p2m_mmio_direct:
+ if ( mfn_x(mfn) == start )
+ {
+ clear_identity_p2m_entry(d, start);
+ break;
+ }
+ /* fallthrough. */
+ default:
+ put_gfn(d, start);
+ gprintk(XENLOG_WARNING,
+ "%04x:%02x:%02x.%u: existing mapping (mfn: %" PRI_mfn
+ "type: %d) at %#lx clobbers MSIX MMIO area\n",
+ pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn), mfn_x(mfn), t, start);
+ return -EEXIST;
+ }
+ put_gfn(d, start);
+ }
+ }
+
+ return 0;
+}
+
static int init_msix(struct pci_dev *pdev)
{
struct domain *d = pdev->domain;
#ifdef __XEN__
void vpci_dump_msi(void);
+/* Make sure there's a hole in the p2m for the MSIX mmio areas. */
+int vpci_make_msix_hole(const struct pci_dev *pdev);
+
/* Arch-specific vPCI MSI helpers. */
void vpci_msi_arch_mask(struct vpci_msi *msi, const struct pci_dev *pdev,
unsigned int entry, bool mask);