When HCR_EL2.{NV,NV1} or SCR_EL3.NS change, this can affect how
direct injection of timer PPIs is handled, which in turn can
potentially affect what the highest priority virtual pending PPI is.
Since the virtual HPPI can be read from EL2 or EL3, we need to
arrange that changes to these bits trigger a GICv5 recalculation.

Signed-off-by: Peter Maydell <[email protected]>
---
 target/arm/gicv5-stubs.c     |  8 ++++++++
 target/arm/helper.c          | 23 ++++++++++++++++++-----
 target/arm/internals.h       |  9 +++++++++
 target/arm/tcg/gicv5-cpuif.c | 18 ++++++++++++++++++
 4 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/target/arm/gicv5-stubs.c b/target/arm/gicv5-stubs.c
index 845626d7c6b..b8c926744cb 100644
--- a/target/arm/gicv5-stubs.c
+++ b/target/arm/gicv5-stubs.c
@@ -15,3 +15,11 @@ void define_gicv5_cpuif_regs(ARMCPU *cpu)
 void gicv5_update_ppi_state(CPUARMState *env, int ppi, bool level)
 {
 }
+
+void gicv5_update_on_hcr_nv_change(CPUARMState *env)
+{
+}
+
+void gicv5_update_on_scr_ns_change(CPUARMState *env)
+{
+}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ff0b766b73d..959f1d83a70 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1012,6 +1012,12 @@ static void scr_write(CPUARMState *env, const 
ARMCPRegInfo *ri, uint64_t value)
                                            ARMMMUIdxBit_E2 |
                                            ARMMMUIdxBit_E2_GCS));
     }
+    /* The GICv5 cpuif needs to know if SCR_EL3.NS changes */
+#ifndef CONFIG_USER_ONLY
+    if (changed & SCR_NS) {
+        gicv5_update_on_scr_ns_change(env);
+    }
+#endif
 }
 
 static void scr_reset(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -3881,7 +3887,7 @@ static const ARMCPRegInfo v8_aa32_el1_reginfo[] = {
 static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
 {
     ARMCPU *cpu = env_archcpu(env);
-    bool hcr_change_timer;
+    uint64_t changed;
 
     if (arm_feature(env, ARM_FEATURE_V8)) {
         valid_mask |= MAKE_64BIT_MASK(0, 34);  /* ARMv8.0 */
@@ -3960,6 +3966,8 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
         }
     }
 
+    changed = env->cp15.hcr_el2 ^ value;
+
     /*
      * These bits change the MMU setup:
      * HCR_VM enables stage 2 translation
@@ -3969,16 +3977,21 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
      * HCR_FWB changes the interpretation of stage2 descriptor bits
      * HCR_NV and HCR_NV1 affect interpretation of descriptor bits
      */
-    if ((env->cp15.hcr_el2 ^ value) &
+    if (changed &
         (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB | HCR_NV | HCR_NV1)) {
         tlb_flush(CPU(cpu));
     }
-    hcr_change_timer = (env->cp15.hcr_el2 ^ value) &
-                       (HCR_E2H | HCR_TGE);
 
     /* update */
     env->cp15.hcr_el2 = value;
 
+    /* If HCR_EL2.{NV,NV1} change we must inform the GICv5 cpuif */
+#ifndef CONFIG_USER_ONLY
+    if (changed & (HCR_NV | HCR_NV1)) {
+        gicv5_update_on_hcr_nv_change(env);
+    }
+#endif
+
     /*
      * Updates to VI and VF require us to update the status of
      * virtual interrupts, which are the logical OR of these bits
@@ -3998,7 +4011,7 @@ static void do_hcr_write(CPUARMState *env, uint64_t 
value, uint64_t valid_mask)
         arm_cpu_update_vinmi(cpu);
         arm_cpu_update_vfnmi(cpu);
     }
-    if (hcr_change_timer) {
+    if (changed & (HCR_E2H | HCR_TGE)) {
 #ifndef CONFIG_USER_ONLY
         gt_recalc_timer(cpu, GTIMER_PHYS);
 #endif
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 9d817961c67..f291aee0bd8 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1909,6 +1909,15 @@ void define_gicv5_cpuif_regs(ARMCPU *cpu);
  */
 void gicv5_update_ppi_state(CPUARMState *env, int ppi, bool level);
 
+/*
+ * Tell the GICv5 when HCR_EL2.{NV,NV1} change. Does nothing if GICv5 not
+ * present.
+ */
+void gicv5_update_on_hcr_nv_change(CPUARMState *env);
+
+/* Tell the GICv5 when SCR_EL3.NS changes. Does nothing if GICv5 not present */
+void gicv5_update_on_scr_ns_change(CPUARMState *env);
+
 /* Effective value of MDCR_EL2 */
 static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
 {
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 1f032e39bf6..e7e3dc214d6 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -630,6 +630,24 @@ void gicv5_update_ppi_state(CPUARMState *env, int ppi, 
bool level)
     }
 }
 
+void gicv5_update_on_hcr_nv_change(CPUARMState *env)
+{
+    /* HCR_EL2.{NV,NV1} changed, which affects DVI timer PPI remapping */
+    if (!cpu_isar_feature(aa64_gcie, env_archcpu(env))) {
+        return;
+    }
+    gic_recalc_virt_ppi_hppi(env);
+}
+
+void gicv5_update_on_scr_ns_change(CPUARMState *env)
+{
+    /* SCR_EL3.NS changed, which affects DVI timer PPI remapping */
+    if (!cpu_isar_feature(aa64_gcie, env_archcpu(env))) {
+        return;
+    }
+    gic_recalc_virt_ppi_hppi(env);
+}
+
 static void gic_cddis_write(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t value)
 {
-- 
2.43.0


Reply via email to