Handle the virtual interrupt domain in our GICR CDIA and
GICR CDNMIA implementation. LPIs and SPIs are handled by
passing through the 'virtual' parameter; PPIs look at the
virtual PPI state.

Signed-off-by: Peter Maydell <[email protected]>
---
 target/arm/tcg/gicv5-cpuif.c | 40 ++++++++++++++++++++++++++----------
 target/arm/tcg/trace-events  |  4 ++--
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index c85d72b05d0..4ee548a768b 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -1143,7 +1143,7 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const 
ARMCPRegInfo *ri)
     GICv5Common *gic = gicv5_get_gic(env);
     bool virtual;
     GICv5Domain domain = gicv5_domain_for_insn(env, ri, &virtual);
-    GICv5PendingIrq hppi = gic_hppi(env, domain);
+    GICv5PendingIrq hppi = virtual ? gic_virt_hppi(env) : gic_hppi(env, 
domain);
     GICv5IntType type = FIELD_EX64(hppi.intid, INTID, TYPE);
     uint32_t id = FIELD_EX64(hppi.intid, INTID, ID);
 
@@ -1151,20 +1151,20 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const 
ARMCPRegInfo *ri)
 
     if (hppi.prio == PRIO_IDLE) {
         /* No interrupt available to acknowledge */
-        trace_gicv5_gicr_cdia_fail(domain,
+        trace_gicv5_gicr_cdia_fail(domain, virtual,
                                    "no available interrupt to acknowledge");
         return 0;
     }
 
     if (gic_hppi_is_nmi(env, hppi, domain) != cdnmia) {
         /* GICR CDIA only acknowledges non-NMI; GICR CDNMIA only NMI */
-        trace_gicv5_gicr_cdia_fail(domain,
+        trace_gicv5_gicr_cdia_fail(domain, virtual,
                                    cdnmia ? "CDNMIA but HPPI is not NMI" :
                                    "CDIA but HPPI is NMI");
         return 0;
     }
 
-    trace_gicv5_gicr_cdia(domain, hppi.intid);
+    trace_gicv5_gicr_cdia(domain, virtual, hppi.intid);
 
     /*
      * The interrupt becomes Active. If the handling mode of the
@@ -1177,23 +1177,41 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const 
ARMCPRegInfo *ri)
      * gicv5_activate() cause a re-evaluation of HPPIs they use the
      * right (new) running priority.
      */
-    env->gicv5_cpuif.icc_apr[domain] |= (1ULL << hppi.prio);
+    if (virtual) {
+        env->gicv5_cpuif.ich_apr_el2 |= (1ULL << hppi.prio);
+    } else {
+        env->gicv5_cpuif.icc_apr[domain] |= (1ULL << hppi.prio);
+    }
+
     switch (type) {
     case GICV5_PPI:
     {
         uint32_t ppireg;
         uint64_t ppibit;
+        bool hm_edge;
 
         assert(id < GICV5_NUM_PPIS);
         ppireg = id / 64;
         ppibit = 1ULL << (id % 64);
 
-        env->gicv5_cpuif.ppi_active[ppireg] |= ppibit;
-        if (!(env->gicv5_cpuif.ppi_hm[ppireg] & ppibit)) {
-            /* handling mode is Edge: clear pending */
-            env->gicv5_cpuif.ppi_pend[ppireg] &= ~ppibit;
+        /* handling mode is constant and doesn't differ for virt vs phys */
+        hm_edge = !(env->gicv5_cpuif.ppi_hm[ppireg] & ppibit);
+
+        if (virtual) {
+            env->gicv5_cpuif.ich_ppi_active[ppireg] |= ppibit;
+            if (hm_edge) {
+                /* handling mode is Edge: clear pending */
+                env->gicv5_cpuif.ich_ppi_pend[ppireg] &= ~ppibit;
+            }
+            gic_recalc_virt_ppi_hppi(env);
+        } else {
+            env->gicv5_cpuif.ppi_active[ppireg] |= ppibit;
+            if (hm_edge) {
+                /* handling mode is Edge: clear pending */
+                env->gicv5_cpuif.ppi_pend[ppireg] &= ~ppibit;
+            }
+            gic_recalc_ppi_hppi(env);
         }
-        gic_recalc_ppi_hppi(env);
         break;
     }
     case GICV5_LPI:
@@ -1203,7 +1221,7 @@ static uint64_t gicr_cdia_read(CPUARMState *env, const 
ARMCPRegInfo *ri)
          * name of the stream command, does both "set Active" and
          * "maybe set not Pending" as a single atomic action.
          */
-        gicv5_activate(gic, id, domain, type, false);
+        gicv5_activate(gic, id, domain, type, virtual);
         break;
     default:
         g_assert_not_reached();
diff --git a/target/arm/tcg/trace-events b/target/arm/tcg/trace-events
index 31c6eafd8ed..856a11b7d1b 100644
--- a/target/arm/tcg/trace-events
+++ b/target/arm/tcg/trace-events
@@ -4,8 +4,8 @@
 # gicv5-cpuif.c
 gicv5_recalc_ppi_hppi(int domain, uint32_t id, uint8_t prio) "domain %d new 
PPI HPPI id 0x%x prio %u"
 gicv5_recalc_virt_ppi_hppi(uint32_t id, uint8_t prio) "virtual domain new PPI 
HPPI id 0x%x prio %u"
-gicv5_gicr_cdia_fail(int domain, const char *reason) "domain %d CDIA attempt 
failed: %s"
-gicv5_gicr_cdia(int domain, uint32_t id) "domain %d CDIA acknowledge of 
interrupt 0x%x"
+gicv5_gicr_cdia_fail(int domain, bool virtual, const char *reason) "domain %d 
virtual %d CDIA attempt failed: %s"
+gicv5_gicr_cdia(int domain, bool virtual, uint32_t id) "domain %d virtual %d 
CDIA acknowledge of interrupt 0x%x"
 gicv5_cdeoi(int domain) "domain %d CDEOI performing priority drop"
 gicv5_vcdeoi(void) "virtual interrupt domain CDEOI performing priority drop"
 gicv5_cddi(int domain, bool virtual, uint32_t id) "domain %d virtual %d CDDI 
deactivating interrupt ID 0x%x"
-- 
2.43.0


Reply via email to