In this commit we update the logic for writes to the virtual PPI
pending state by the guest using the PPI_CPEND or PPI_SPEND registers
to honour the DVI registers, so that the pending state of the
underlying physical PPI is updated.

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

diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index cdde759bf41..5a2927faf75 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -816,16 +816,61 @@ static uint64_t gic_ppi_pend_read(CPUARMState *env, const 
ARMCPRegInfo *ri)
     }
 }
 
+static uint64_t gic_ppi_vpend_to_ppend(CPUARMState *env,
+                                       uint64_t value, int reg)
+{
+    /*
+     * Given a mask of bits which are virtual PPI pending bits being
+     * changed, output the mask of bits which are to be changed in the
+     * physical PPI pending state, by adjusting them for the the timer
+     * PPI redirection.  We require that the input value has already
+     * had the bits masked out for vPPIs that are not direct-injected.
+     */
+    if (reg == 0 && (arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV) {
+        if (arm_is_secure_below_el3(env)) {
+            /* vPPI 20 is pPPI 30; vPPI 19 is pPPI 27 */
+            if (value & (1 << 20)) {
+                value |= 1 << 30;
+            }
+            if (value & (1 << 19)) {
+                value |= 1 << 27;
+            }
+        } else {
+            /* vPPI 26 is pPPI 30; vPPI 28 is pPPI 27 */
+            if (value & (1 << 26)) {
+                value |= 1 << 30;
+            }
+            if (value & (1 << 28)) {
+                value |= 1 << 27;
+            }
+        }
+        value &= ~((1 << 26) | (1 << 28));
+    }
+    return value;
+}
+
 static void gic_ppi_cpend_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                 uint64_t value)
 {
+    int reg = ri->opc2 & 1;
     /* If ICC_PPI_HMR_EL1[n].HM is 1, PEND bits are RO */
-    uint64_t hm = env->gicv5_cpuif.ppi_hm[ri->opc2 & 1];
+    uint64_t hm = env->gicv5_cpuif.ppi_hm[reg];
     value &= ~hm;
 
     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;
+        uint64_t dvi_mask = gic_virt_dvi_mask(env, reg);
+
+        value &= ~env->gicv5_cpuif.ich_ppi_hvi[reg];
+
+        /* Update state for non-injected virtual PPIs */
+        env->gicv5_cpuif.ich_ppi_pend[reg] &= ~(value & ~dvi_mask);
+        /* Update state for injected PPIs */
+        value &= dvi_mask;
+        value = gic_ppi_vpend_to_ppend(env, value, reg);
+        if (value) {
+            env->gicv5_cpuif.ppi_pend[reg] &= ~value;
+            gic_recalc_ppi_hppi(env);
+        }
         gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
@@ -837,13 +882,25 @@ static void gic_ppi_cpend_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 static void gic_ppi_spend_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                 uint64_t value)
 {
+    int reg = ri->opc2 & 1;
     /* If ICC_PPI_HMR_EL1[n].HM is 1, PEND bits are RO */
-    uint64_t hm = env->gicv5_cpuif.ppi_hm[ri->opc2 & 1];
+    uint64_t hm = env->gicv5_cpuif.ppi_hm[reg];
     value &= ~hm;
 
     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;
+        uint64_t dvi_mask = gic_virt_dvi_mask(env, reg);
+
+        value &= ~env->gicv5_cpuif.ich_ppi_hvi[reg];
+
+        /* Update state for non-injected virtual PPIs */
+        env->gicv5_cpuif.ich_ppi_pend[reg] |= (value & ~dvi_mask);
+        /* Update state for injected PPIs */
+        value &= dvi_mask;
+        value = gic_ppi_vpend_to_ppend(env, value, reg);
+        if (value) {
+            env->gicv5_cpuif.ppi_pend[reg] |= value;
+            gic_recalc_ppi_hppi(env);
+        }
         gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
-- 
2.43.0


Reply via email to