|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen staging] vpci/msix: improve handling of bogus MSI-X capabilities
commit 53859596c0d34dbca776ec1e47bac8dd90552530
Author: Roger Pau Monne <roger.pau@xxxxxxxxxx>
AuthorDate: Fri Sep 26 17:39:29 2025 +0200
Commit: Roger Pau Monne <roger.pau@xxxxxxxxxx>
CommitDate: Fri Oct 10 11:02:39 2025 +0200
vpci/msix: improve handling of bogus MSI-X capabilities
I've had the luck to come across a PCI card that exposes a MSI-X capability
where the BIR of the vector and PBA tables points at a BAR that has 0 size.
This doesn't play nice with the code in vpci_make_msix_hole(), as it would
still use the address of such empty BAR (0) and attempt to carve a hole in
the p2m. This leads to errors like the one below being reported by Xen:
d0v0 0000:22:00.0: existing mapping (mfn: 181c4300 type: 0) at 0 clobbers
MSIX MMIO area
And the device left unable to enable memory decoding due to the failure
reported by vpci_make_msix_hole().
Introduce checking in init_msix() to ensure the BARs containing the MSI-X
tables are usable. This requires checking that the BIR points to a
non-empty BAR, and the offset and size of the MSI-X tables can fit in the
target BAR.
This fixes booting PVH dom0 on Supermicro AS -2126HS-TN servers with AMD
EPYC 9965 processors. The broken device is:
22:00.0 SATA controller: Advanced Micro Devices, Inc. [AMD] FCH SATA
Controller [AHCI mode] (rev 93)
There are multiple of those integrated controllers in the system, all
broken in the same way.
Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
Released-Acked-By: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
Reviewed-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx>
---
xen/drivers/vpci/msix.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-----
xen/include/xen/lib.h | 3 +++
2 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/xen/drivers/vpci/msix.c b/xen/drivers/vpci/msix.c
index 54a5070733..032e471bb1 100644
--- a/xen/drivers/vpci/msix.c
+++ b/xen/drivers/vpci/msix.c
@@ -18,6 +18,7 @@
*/
#include <xen/io.h>
+#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/vpci.h>
@@ -675,6 +676,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 )
@@ -686,11 +732,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 c434dd5f16..c4ac482392 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -60,6 +60,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)
--
generated by git-patchbot for /home/xen/git/xen.git#staging
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |