Implement gic_recalc_virt_ppi_hppi(), which calculates the current HPPI PPI for the virtual interrupt domain, using similar logic to gic_recalc_ppi_hppi(). We call this from everywhere where we update the state of the virtual PPIs.
Signed-off-by: Peter Maydell <[email protected]> --- target/arm/cpu.h | 2 ++ target/arm/tcg/gicv5-cpuif.c | 51 ++++++++++++++++++++++++++++++++++++ target/arm/tcg/trace-events | 1 + 3 files changed, 54 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 81fb68facb9..abaee5fc3a0 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -596,6 +596,8 @@ typedef struct CPUArchState { /* Cached highest-priority pending PPI for each domain */ GICv5PendingIrq ppi_hppi[NUM_GICV5_DOMAINS]; + /* And for the virtual interrupt domain */ + GICv5PendingIrq virt_ppi_hppi; uint64_t ich_apr_el2; uint64_t ich_vctlr_el2; diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index 96384c58726..0d38ed7b15b 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -298,6 +298,45 @@ static void gic_recalc_ppi_hppi(CPUARMState *env) gicv5_update_irq_fiq(env); } +static void gic_recalc_virt_ppi_hppi(CPUARMState *env) +{ + /* + * Recalculate the HPPI PPI for the virtual interrupt domain: this is + * the best PPI which is enabled, pending and not active. + */ + env->gicv5_cpuif.virt_ppi_hppi = GICV5_PENDING_IRQ_NONE; + + for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.ich_ppi_active); i++) { + uint64_t en_pend_nact = env->gicv5_cpuif.ich_ppi_enable[i] & + env->gicv5_cpuif.ich_ppi_pend[i] & + ~env->gicv5_cpuif.ich_ppi_active[i]; + + while (en_pend_nact) { + uint8_t prio; + int ppi; + int bit = ctz64(en_pend_nact); + + en_pend_nact &= ~(1ULL << bit); + + ppi = i * 64 + bit; + prio = extract64(env->gicv5_cpuif.ich_ppi_priority[ppi / 8], + (ppi & 7) * 8, 5); + + if (prio < env->gicv5_cpuif.virt_ppi_hppi.prio) { + uint32_t intid = 0; + + intid = FIELD_DP32(intid, INTID, ID, ppi); + intid = FIELD_DP32(intid, INTID, TYPE, GICV5_PPI); + env->gicv5_cpuif.virt_ppi_hppi.intid = intid; + env->gicv5_cpuif.virt_ppi_hppi.prio = prio; + } + } + } + + trace_gicv5_recalc_virt_ppi_hppi(env->gicv5_cpuif.virt_ppi_hppi.intid, + env->gicv5_cpuif.virt_ppi_hppi.prio); +} + void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain) { /* @@ -460,6 +499,7 @@ static void gic_ppi_cactive_write(CPUARMState *env, const ARMCPRegInfo *ri, if (gicv5_icv_access(env)) { value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1]; env->gicv5_cpuif.ich_ppi_active[ri->opc2 & 1] &= ~value; + gic_recalc_virt_ppi_hppi(env); } else { uint64_t old = raw_read(env, ri); raw_write(env, ri, old & ~value); @@ -473,6 +513,7 @@ static void gic_ppi_sactive_write(CPUARMState *env, const ARMCPRegInfo *ri, if (gicv5_icv_access(env)) { value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1]; env->gicv5_cpuif.ich_ppi_active[ri->opc2 & 1] |= value; + gic_recalc_virt_ppi_hppi(env); } else { uint64_t old = raw_read(env, ri); raw_write(env, ri, old | value); @@ -502,6 +543,7 @@ static void gic_ppi_cpend_write(CPUARMState *env, const ARMCPRegInfo *ri, if (gicv5_icv_access(env)) { value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1]; env->gicv5_cpuif.ich_ppi_pend[ri->opc2 & 1] &= ~value; + gic_recalc_virt_ppi_hppi(env); } else { uint64_t old = raw_read(env, ri); raw_write(env, ri, old & ~value); @@ -519,6 +561,7 @@ static void gic_ppi_spend_write(CPUARMState *env, const ARMCPRegInfo *ri, if (gicv5_icv_access(env)) { value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1]; env->gicv5_cpuif.ich_ppi_pend[ri->opc2 & 1] |= value; + gic_recalc_virt_ppi_hppi(env); } else { uint64_t old = raw_read(env, ri); raw_write(env, ri, old | value); @@ -544,6 +587,7 @@ static void gic_ppi_enable_write(CPUARMState *env, const ARMCPRegInfo *ri, if (gicv5_icv_access(env)) { value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1]; env->gicv5_cpuif.ich_ppi_enable[ri->opc2 & 1] = value; + gic_recalc_virt_ppi_hppi(env); } else { raw_write(env, ri, value); gic_recalc_ppi_hppi(env); @@ -610,6 +654,7 @@ static void gic_ppi_priority_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t hvi_mask = gic_ppi_prio_hvi_mask(env, idx); env->gicv5_cpuif.ich_ppi_priority[idx] = value & ~hvi_mask; + gic_recalc_virt_ppi_hppi(env); } else { raw_write(env, ri, value); gic_recalc_ppi_hppi(env); @@ -620,36 +665,42 @@ static void gic_ich_ppi_enable_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_ppi_pend_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_ppi_active_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_ppi_priority_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_ppi_dvi_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_ppi_hvi_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { raw_write(env, ri, value); + gic_recalc_virt_ppi_hppi(env); } static void gic_ich_vctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/tcg/trace-events b/target/arm/tcg/trace-events index bf1803c8722..da25ec994cc 100644 --- a/target/arm/tcg/trace-events +++ b/target/arm/tcg/trace-events @@ -3,6 +3,7 @@ # gicv5-cpuif.c gicv5_recalc_ppi_hppi(int domain, uint32_t id, uint8_t prio) "domain %d new PPI HPPI id 0x%x prio %u" +gicv5_recalc_virt_ppi_hppi(uint32_t id, uint8_t prio) "virtual domain new PPI HPPI id 0x%x prio %u" gicv5_gicr_cdia_fail(int domain, const char *reason) "domain %d CDIA attempt failed: %s" gicv5_gicr_cdia(int domain, uint32_t id) "domain %d CDIA acknowledge of interrupt 0x%x" gicv5_cdeoi(int domain) "domain %d CDEOI performing priority drop" -- 2.43.0
