[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] hw/pci-host/pnv_phb4: Fix LSI irq source calculation overrun
From: |
Nicholas Piggin |
Subject: |
[PATCH] hw/pci-host/pnv_phb4: Fix LSI irq source calculation overrun |
Date: |
Tue, 3 Dec 2024 16:07:14 +1000 |
PHB5 has big and small PHBs, that have 4k and 2k interrupt sources
respective. The LSI interrupt sources are set with a 9-bit register
field, that selects the aligned block of 8 irqs, giving a 4k range.
This is initialized by hardware to 0x1ff in order to select the
last 8 irq sources.
The small PHB is meant to ignore the MSB of the source ID, so the
LSI default would select the last 8 of 2k irqs. The PHB model does
not mask this bit consistently, which can cause the irq to be
miscalculated and the source irq array to be overrun.
Move the lsi_base calculation into a helper function that does the
masking and some extra checking.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
hw/pci-host/pnv_phb4.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index fb129f3266..5486ef44ea 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -458,6 +458,27 @@ static void pnv_phb4_update_all_msi_regions(PnvPHB4 *phb)
}
}
+static int pnv_phb4_get_lsi_base(PnvPHB4 *phb)
+{
+ int lsi_base, nr_irqs;
+
+ lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
+ if (!phb->big_phb) {
+ /* Small PHBs ignore the top bit of the source ID */
+ lsi_base &= ~0x100;
+ }
+ lsi_base <<= 3;
+
+ if (phb->big_phb) {
+ nr_irqs = PNV_PHB4_MAX_INTs;
+ } else {
+ nr_irqs = PNV_PHB4_MAX_INTs >> 1;
+ }
+ g_assert(lsi_base + 8 <= nr_irqs);
+
+ return lsi_base;
+}
+
static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
{
int shift, flags, i, lsi_base;
@@ -487,9 +508,7 @@ static void pnv_phb4_update_xsrc(PnvPHB4 *phb)
phb->xsrc.esb_shift = shift;
phb->xsrc.esb_flags = flags;
- lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
- lsi_base <<= 3;
- lsi_base &= (xsrc->nr_irqs - 1);
+ lsi_base = pnv_phb4_get_lsi_base(phb);
/* TODO: need a xive_source_irq_reset_lsi() */
bitmap_zero(xsrc->lsi_map, xsrc->nr_irqs);
@@ -1597,8 +1616,7 @@ static void pnv_phb4_set_irq(void *opaque, int irq_num,
int level)
if (irq_num > 3) {
phb_error(phb, "IRQ %x is not an LSI", irq_num);
}
- lsi_base = GETFIELD(PHB_LSI_SRC_ID, phb->regs[PHB_LSI_SOURCE_ID >> 3]);
- lsi_base <<= 3;
+ lsi_base = pnv_phb4_get_lsi_base(phb);
qemu_set_irq(phb->qirqs[lsi_base + irq_num], level);
}
--
2.45.2
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] hw/pci-host/pnv_phb4: Fix LSI irq source calculation overrun,
Nicholas Piggin <=