Implement the redirection of ICC_HPPIR_EL1 to the virtual
ICV_HPPIR_EL1 register.  This requires us to calculate the highest
priority pending interrupt for the virtual interrupt domain, using a
gic_virt_hppi() function that works in a similar way to the existing
gic_hppi() for the physical interrupt domains.

As we have not yet implemented IRS_CONTEXTR_EL2, we leave a
placeholder "IRS does not have a virtual HPPI candidate"; we will
fill this in later by calling gicv5_get_hppi() when the IRICHPPIDS
bit in that register tells us we should.

Signed-off-by: Peter Maydell <[email protected]>
---
 target/arm/tcg/gicv5-cpuif.c | 73 +++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 5d0d599ddd5..d2454011b40 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -70,6 +70,9 @@ FIELD(ICC_HPPIR_EL1, HPPIV, 32, 1)
 FIELD(ICH_VMCR_EL2, EN, 0, 1)
 FIELD(ICH_VMCR_EL2, VMPR, 27, 5)
 
+FIELD(ICH_VCTLR_EL2, EN, 0, 1)
+FIELD(ICH_VCTLR_EL2, V3, 1, 1)
+
 /*
  * We implement 24 bits of interrupt ID, the mandated 5 bits of priority,
  * and no legacy GICv3.3 vcpu interface (yet)
@@ -153,6 +156,13 @@ static uint64_t gic_running_prio(CPUARMState *env, 
GICv5Domain domain)
     return hap < 32 ? hap : PRIO_IDLE;
 }
 
+static uint64_t gic_virt_running_prio(CPUARMState *env)
+{
+    /* Return the current virtual running priority */
+    uint64_t hap = ctz64(env->gicv5_cpuif.ich_apr_el2);
+    return hap < 32 ? hap : PRIO_IDLE;
+}
+
 static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
 {
     /*
@@ -196,6 +206,59 @@ static GICv5PendingIrq gic_hppi(CPUARMState *env, 
GICv5Domain domain)
     return best;
 }
 
+static GICv5PendingIrq gic_virt_hppi(CPUARMState *env)
+{
+    /*
+     * Return the current highest priority pending interrupt for the
+     * virtual interrupt domain, if it has sufficient priority to
+     * preempt.  If there is no interrupt that can preempt we signal
+     * this by returning a struct with prio == PRIO_IDLE.
+     */
+    GICv5PendingIrq best, irs_hppi;
+
+    /*
+     * R_ZKPVN: No virtual HPPI if EL2 is not implemented and enabled
+     * in the Security state identified by SCR_EL3.{NSE,NS}, or if the
+     * enable bits in ICV_CR0_EL1 (stored in VMCR_EL2) or
+     * ICH_VCTLR_EL2 are 0.
+     */
+    if (!arm_is_el2_enabled(env) ||
+        !(env->gicv5_cpuif.ich_vctlr_el2 & R_ICH_VCTLR_EL2_EN_MASK) ||
+        !(env->gicv5_cpuif.ich_vmcr_el2 & R_ICH_VMCR_EL2_EN_MASK)) {
+        return GICV5_PENDING_IRQ_NONE;
+    }
+
+    /*
+     * TODO: When we implement ICH_CONTEXTR_EL2, we need to check
+     * IRICHPPIDS and if it is 0 get the IRS candidate HPPI.  For now,
+     * set irs_hppi to "no candidate".
+     */
+    irs_hppi = GICV5_PENDING_IRQ_NONE;
+
+    /*
+     * 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.virt_ppi_hppi.prio <= irs_hppi.prio) {
+        best = env->gicv5_cpuif.virt_ppi_hppi;
+    } 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 > FIELD_EX64(env->gicv5_cpuif.ich_vmcr_el2, ICH_VMCR_EL2, 
VMPR) ||
+        best.prio >= gic_virt_running_prio(env)) {
+        return GICV5_PENDING_IRQ_NONE;
+    }
+    return best;
+}
+
 static void gicv5_update_irq_fiq(CPUARMState *env)
 {
     /*
@@ -844,8 +907,14 @@ 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);
+    GICv5PendingIrq hppi;
+
+    if (gicv5_icv_access(env)) {
+        hppi = gic_virt_hppi(env);
+    } else {
+        GICv5Domain domain = gicv5_logical_domain(env);
+        hppi = gic_hppi(env, domain);
+    }
 
     if (hppi.prio == PRIO_IDLE) {
         /* No valid interrupt */
-- 
2.43.0


Reply via email to