When a physical PPI changes its pending state we usually don't need to update the virtual PPI state. However, if the PPI is direct-injected to the VM then we do need to do that update. Make this check and call gic_recalc_virt_ppi_hppi() where we update physical PPI pending state.
Signed-off-by: Peter Maydell <[email protected]> --- target/arm/tcg/gicv5-cpuif.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index e7e3dc214d6..406c980af5e 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -602,6 +602,28 @@ void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain, bool virtual) } } +static void gic_recalc_virt_ppi_hppi_for_dvi(CPUARMState *env, int reg, + uint64_t mask) +{ + /* + * Called after the physical PPI pending state has changed for the + * PPIs indicated by the mask and reg arguments. If any of these + * PPIs are direct-injected, we need to recalculate the virtual + * HPPI. + * + * It is possible that even if the DVI bit is set we might not + * actually be direct-injecting the PPI (e.g. if HVI is set, or if + * timer-PPI redirection means we're ignoring this DVI bit), but + * if so the recalculation will just do nothing. These cases are + * "the guest did something valid but odd" in that it set a DVI + * bit it knew wasn't going to have any effect, so not worth + * trying to catch early. + */ + if (env->gicv5_cpuif.ich_ppi_dvi[reg] & mask) { + gic_recalc_virt_ppi_hppi(env); + } +} + void gicv5_update_ppi_state(CPUARMState *env, int ppi, bool level) { /* @@ -627,6 +649,7 @@ void gicv5_update_ppi_state(CPUARMState *env, int ppi, bool level) env->gicv5_cpuif.ppi_pend[0] = deposit64(env->gicv5_cpuif.ppi_pend[0], ppi, 1, level); gic_recalc_ppi_hppi(env); + gic_recalc_virt_ppi_hppi_for_dvi(env, 0, 1ULL << ppi); } } @@ -894,6 +917,7 @@ static void gic_ppi_cpend_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t old = raw_read(env, ri); raw_write(env, ri, old & ~value); gic_recalc_ppi_hppi(env); + gic_recalc_virt_ppi_hppi_for_dvi(env, reg, value); } } @@ -924,6 +948,7 @@ static void gic_ppi_spend_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t old = raw_read(env, ri); raw_write(env, ri, old | value); gic_recalc_ppi_hppi(env); + gic_recalc_virt_ppi_hppi_for_dvi(env, reg, value); } } @@ -1428,6 +1453,7 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const ARMCPRegInfo *ri) if (hm_edge) { /* handling mode is Edge: clear pending */ env->gicv5_cpuif.ppi_pend[ppireg] &= ~ppibit; + gic_recalc_virt_ppi_hppi_for_dvi(env, ppireg, ppibit); } gic_recalc_ppi_hppi(env); } -- 2.43.0
