From b74d7c0e50ac4bde85c0ff629bfc23cdf378e62c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 26 Nov 2021 16:39:14 +0000 Subject: hw/intc/arm_gicv3: Add new gicv3_intid_is_special() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GICv3/v4 pseudocode has a function IsSpecial() which returns true if passed a "special" interrupt ID number (anything between 1020 and 1023 inclusive). We open-code this condition in a couple of places, so abstract it out into a new function gicv3_intid_is_special(). Signed-off-by: Peter Maydell Reviewed-by: Marc Zyngier Reviewed-by: Alex Bennée --- hw/intc/arm_gicv3_cpuif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw/intc/arm_gicv3_cpuif.c') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 3fe5de8ad7..7fbc36ff41 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -997,7 +997,7 @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri) intid = icc_hppir0_value(cs, env); } - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { + if (!gicv3_intid_is_special(intid)) { icc_activate_irq(cs, intid); } @@ -1020,7 +1020,7 @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) intid = icc_hppir1_value(cs, env); } - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { + if (!gicv3_intid_is_special(intid)) { icc_activate_irq(cs, intid); } -- cgit 1.4.1 From 90feffad2aafe856ed2af75313b2c1669ba671e9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 26 Nov 2021 16:39:15 +0000 Subject: hw/intc/arm_gicv3: fix handling of LPIs in list registers It is valid for an OS to put virtual interrupt ID values into the list registers ICH_LR which are greater than 1023. This corresponds to (for example) KVM using the in-kernel emulated ITS to give a (nested) guest an ITS. LPIs are delivered by the L1 kernel to the L2 guest via the list registers in the same way as non-LPI interrupts. QEMU's code for handling writes to ICV_IARn (which happen when the L2 guest acknowledges an interrupt) and to ICV_EOIRn (which happen at the end of the interrupt) did not consider LPIs, so it would incorrectly treat interrupt IDs above 1023 as invalid. Fix this by using the correct condition, which is gicv3_intid_is_special(). Note that the condition in icv_dir_write() is correct -- LPIs are not valid there and so we want to ignore both "special" ID values and LPIs. (In the pseudocode this logic is in: - VirtualReadIAR0(), VirtualReadIAR1(), which call IsSpecial() - VirtualWriteEOIR0(), VirtualWriteEOIR1(), which call VirtualIdentifierValid(data, TRUE) meaning "LPIs OK" - VirtualWriteDIR(), which calls VirtualIdentifierValid(data, FALSE) meaning "LPIs not OK") This bug doesn't seem to have any visible effect on Linux L2 guests most of the time, because the two bugs cancel each other out: we neither mark the interrupt active nor deactivate it. However it does mean that the L2 vCPU priority while the LPI handler is running will not be correct, so the interrupt handler could be unexpectedly interrupted by a different interrupt. (NB: this has nothing to do with using QEMU's emulated ITS.) Signed-off-by: Peter Maydell Reviewed-by: Marc Zyngier --- hw/intc/arm_gicv3_cpuif.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'hw/intc/arm_gicv3_cpuif.c') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 7fbc36ff41..7fba931450 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -653,7 +653,7 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) { intid = ich_lr_vintid(lr); - if (intid < INTID_SECURE) { + if (!gicv3_intid_is_special(intid)) { icv_activate_irq(cs, idx, grp); } else { /* Interrupt goes from Pending to Invalid */ @@ -1265,8 +1265,7 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1, gicv3_redist_affid(cs), value); - if (irq >= GICV3_MAXIRQ) { - /* Also catches special interrupt numbers and LPIs */ + if (gicv3_intid_is_special(irq)) { return; } -- cgit 1.4.1