Implement ICC_HPPIR_EL1, which the guest can use to read the current highest priority pending interrupt. Like APR, PCR and CR0, this is banked, with the _EL1 register reading the answer for the current logical interrupt domain, and the _EL3 register reading the answer for the EL3 interrupt domain.
Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 11 ++++++ include/hw/intc/arm_gicv5_stream.h | 14 +++++++ target/arm/tcg/gicv5-cpuif.c | 62 ++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 070d414d67..6cb81123e5 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -527,6 +527,17 @@ static void irs_recall_hppis(GICv5 *s, GICv5Domain domain) } } +GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain, + uint32_t iaffid) +{ + GICv5 *s = ARM_GICV5(cs); + + int cpuidx = irs_cpuidx_from_iaffid(cs, iaffid); + + assert(cpuidx >= 0); + return s->hppi[domain][cpuidx]; +} + static hwaddr l1_iste_addr(GICv5Common *cs, const GICv5ISTConfig *cfg, uint32_t id) { diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h index 13b343504d..6850f03b74 100644 --- a/include/hw/intc/arm_gicv5_stream.h +++ b/include/hw/intc/arm_gicv5_stream.h @@ -175,4 +175,18 @@ uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain, */ void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain); +/** + * gicv5_get_hppi + * @cs: GIC IRS to query + * @domain: interrupt domain to act on + * @iaffid: IAFFID of this CPU interface + * + * Ask the IRS for the highest priority pending interrupt + * that it has for this CPU. This returns the equivalent of what in the + * stream protocol is the outstanding interrupt sent with + * a Forward packet. + */ +GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain, + uint32_t iaffid); + #endif diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index 45ef80ca87..adb4d2018f 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -51,6 +51,10 @@ FIELD(ICC_CR0, PID, 38, 1) FIELD(ICC_PCR, PRIORITY, 0, 5) +FIELD(ICC_HPPIR_EL1, ID, 0, 24) +FIELD(ICC_HPPIR_EL1, TYPE, 29, 3) +FIELD(ICC_HPPIR_EL1, HPPIV, 32, 1) + /* * We implement 24 bits of interrupt ID, the mandated 5 bits of priority, * and no legacy GICv3.3 vcpu interface (yet) @@ -114,6 +118,52 @@ static uint64_t gic_running_prio(CPUARMState *env, GICv5Domain domain) return hap < 32 ? hap : PRIO_IDLE; } +static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain) +{ + /* + * Return the current highest priority pending + * interrupt for the specified domain, if it has sufficient + * priority to preempt. The intid field of the return value + * will be in the format of the ICC_HPPIR register (and will + * be zero if and only if there is no interrupt that can preempt). + */ + + GICv5Common *gic = gicv5_get_gic(env); + GICv5PendingIrq best; + GICv5PendingIrq irs_hppi; + + if (!(env->gicv5_cpuif.icc_cr0[domain] & R_ICC_CR0_EN_MASK)) { + /* If cpuif is disabled there is no HPPI */ + return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE }; + } + + irs_hppi = gicv5_get_hppi(gic, domain, env->gicv5_iaffid); + + /* + * If the best PPI and the best interrupt from the IRS have the + * same priority, it's IMPDEF which we pick (R_VVBPS). We choose + * the PPI. + */ + if (env->gicv5_cpuif.ppi_hppi[domain].prio <= irs_hppi.prio) { + best = env->gicv5_cpuif.ppi_hppi[domain]; + } else { + best = irs_hppi; + } + + /* + * D_MSQKF: an interrupt has sufficient priority if its priority + * is higher than the current running priority and equal to or + * higher than the priority mask. + */ + if (best.prio == PRIO_IDLE || + best.prio > env->gicv5_cpuif.icc_pcr[domain] || + best.prio >= gic_running_prio(env, domain)) { + return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE }; + } + best.intid |= R_ICC_HPPIR_EL1_HPPIV_MASK; + return best; +} + static void gic_recalc_ppi_hppi(CPUARMState *env) { /* @@ -407,6 +457,13 @@ static void gic_icc_pcr_el1_reset(CPUARMState *env, const ARMCPRegInfo *ri) } } +static uint64_t gic_icc_hppir_el1_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + GICv5Domain domain = gicv5_logical_domain(env); + GICv5PendingIrq hppi = gic_hppi(env, domain); + return hppi.intid; +} + static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { /* * Barrier: wait until the effects of a cpuif system register @@ -522,6 +579,11 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { .fieldoffset = offsetof(CPUARMState, gicv5_cpuif.ppi_hm[1]), .resetvalue = PPI_HMR1_RESET, }, + { .name = "ICC_HPPIR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_IO | ARM_CP_NO_RAW, + .readfn = gic_icc_hppir_el1_read, + }, { .name = "ICC_PPI_ENABLER0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 6, .access = PL1_RW, .type = ARM_CP_IO | ARM_CP_NO_RAW, -- 2.43.0
