[PATCH 45/65] target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1

Peter Maydell posted 65 patches 1 month, 2 weeks ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Eduardo Habkost <eduardo@habkost.net>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
There is a newer version of this series
[PATCH 45/65] target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1
Posted by Peter Maydell 1 month, 2 weeks ago
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 <peter.maydell@linaro.org>
---
 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
Re: [PATCH 45/65] target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1
Posted by Jonathan Cameron via qemu development 1 month ago
On Mon, 23 Feb 2026 17:01:52 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:

> 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 <peter.maydell@linaro.org>

Few formatting things...

Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

> ---
>  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);
> +

Why the blank line?

> +    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/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

>  /*
>   * 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

rewrap

> +     * 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;

Maybe just one line?

> +
> +    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;
> +}