diff --git a/xen/drivers/vpci/msix.c b/xen/drivers/vpci/msix.c index 6bd8c55bb4..faa7c1cd49 100644 --- a/xen/drivers/vpci/msix.c +++ b/xen/drivers/vpci/msix.c @@ -17,6 +17,7 @@ * License along with this program; If not, see . */ +#include #include #include @@ -723,6 +724,51 @@ static int cf_check init_msix(struct pci_dev *pdev) if ( !msix ) return -ENOMEM; + msix->tables[VPCI_MSIX_TABLE] = + pci_conf_read32(pdev->sbdf, msix_table_offset_reg(msix_offset)); + msix->tables[VPCI_MSIX_PBA] = + pci_conf_read32(pdev->sbdf, msix_pba_offset_reg(msix_offset)); + + /* Check that the referenced BAR(s) regions are valid. */ + for ( i = 0; i < ARRAY_SIZE(msix->tables); i++ ) + { + const char *name = (i == VPCI_MSIX_TABLE) ? "vector" : "PBA"; + const struct vpci_bar *bars = pdev->vpci->header.bars; + unsigned int bir = msix->tables[i] & PCI_MSIX_BIRMASK; + unsigned int type; + unsigned int offset = msix->tables[i] & ~PCI_MSIX_BIRMASK; + unsigned int size = + (i == VPCI_MSIX_TABLE) ? max_entries * PCI_MSIX_ENTRY_SIZE + : ROUNDUP(DIV_ROUND_UP(max_entries, 8), 8); + + if ( bir >= ARRAY_SIZE(pdev->vpci->header.bars) ) + { + printk(XENLOG_ERR DEV_BUG_PREFIX + "%pp: MSI-X %s table with out of range BIR %u\n", + &pdev->sbdf, name, bir); + invalid: + xfree(msix); + return -ENODEV; + } + + type = bars[bir].type; + if ( type != VPCI_BAR_MEM32 && type != VPCI_BAR_MEM64_LO ) + { + printk(XENLOG_ERR DEV_BUG_PREFIX + "%pp: MSI-X %s table at invalid BAR%u with type %u\n", + &pdev->sbdf, name, bir, type); + goto invalid; + } + + if ( (uint64_t)offset + size > bars[bir].size ) + { + printk(XENLOG_ERR DEV_BUG_PREFIX + "%pp: MSI-X %s table offset %#x size %#x outside of BAR%u size %#lx\n", + &pdev->sbdf, name, offset, size, bir, bars[bir].size); + goto invalid; + } + } + rc = vpci_add_register(pdev->vpci, control_read, control_write, msix_control_reg(msix_offset), 2, msix); if ( rc ) @@ -734,11 +780,6 @@ static int cf_check init_msix(struct pci_dev *pdev) msix->max_entries = max_entries; msix->pdev = pdev; - msix->tables[VPCI_MSIX_TABLE] = - pci_conf_read32(pdev->sbdf, msix_table_offset_reg(msix_offset)); - msix->tables[VPCI_MSIX_PBA] = - pci_conf_read32(pdev->sbdf, msix_pba_offset_reg(msix_offset)); - for ( i = 0; i < max_entries; i++) { msix->entries[i].masked = true; diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index 130f96791f..1a09f8ada9 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -58,6 +58,9 @@ static inline void debugtrace_printk(const char *fmt, ...) {} #endif +/* Common log prefixes for platform related issues. */ +#define DEV_BUG_PREFIX "DEVICE BUG: " + extern void printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2), cold)); void vprintk(const char *fmt, va_list args)