OpenBSD exposes this by raising CTPR while handling interrupts. If an edge remains pending when EOI lowers the servicing priority, QEMU reasserts INT without checking CTPR; IACK then returns the spurious vector and consumes the masked edge before CTPR permits delivery.
Signed-off-by: Kirill A. Korinsky <[email protected]> --- hw/intc/openpic.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 99d2a1e65e..6f9a562163 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -1033,8 +1033,9 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, n_IRQ = IRQ_get_next(opp, &dst->raised); if (n_IRQ != -1) { src = &opp->src[n_IRQ]; - if (s_IRQ == -1 || - IVPR_PRIORITY(src->ivpr) > dst->servicing.priority) { + if (IVPR_PRIORITY(src->ivpr) > dst->ctpr && + (s_IRQ == -1 || + IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d", idx, n_IRQ); qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); @@ -1070,12 +1071,13 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) } src = &opp->src[irq]; - if (!(src->ivpr & IVPR_ACTIVITY_MASK) || - !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { + if (!(src->ivpr & IVPR_ACTIVITY_MASK)) { error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x", __func__, irq, dst->ctpr, src->ivpr); openpic_update_irq(opp, irq); retval = opp->spve; + } else if (IVPR_PRIORITY(src->ivpr) <= dst->ctpr) { + return opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, irq); -- 2.55.0
