Implement the GICv5 IRS_VMT_BASER register, which holds the base
address of the VM table.  This is very similar to the IRS_IST_BASER
register: it is 64 bits wide but can be accessed as two 32 bit
pieces, it has a valid bit which the guest sets to make the table
valid, and there is an associated IRS_VMT_STATUSR register which has
an IDLE bit which the guest can read to find out when the write to
VALID has completed.

Implement IRS_VMT_BASER and IRS_VMT_STATUSR, using the same pattern
we have for IRS_IST_BASER and IRS_IST_STATUSR.

Signed-off-by: Peter Maydell <[email protected]>
---
 hw/intc/arm_gicv5.c                | 73 ++++++++++++++++++++++++++++++
 hw/intc/arm_gicv5_common.c         |  4 ++
 hw/intc/trace-events               |  2 +
 include/hw/intc/arm_gicv5_common.h |  1 +
 4 files changed, 80 insertions(+)

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 63e4a165eea..05c6b9c57fc 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -1166,6 +1166,36 @@ static void irs_ist_baser_write(GICv5 *s, GICv5Domain 
domain, uint64_t value)
     }
 }
 
+static void irs_vmt_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value)
+{
+    GICv5Common *cs = ARM_GICV5_COMMON(s);
+
+    if (!gicv5_domain_has_virt(cs, domain)) {
+        return;
+    }
+
+    if (FIELD_EX64(cs->irs_vmt_baser[domain], IRS_VMT_BASER, VALID)) {
+        /* If VALID is set, ADDR is RO and we can only update VALID */
+        bool valid = FIELD_EX64(value, IRS_VMT_BASER, VALID);
+
+        if (valid) {
+            /* Ignore 1->1 transition */
+            return;
+        }
+        cs->irs_vmt_baser[domain] = FIELD_DP64(cs->irs_vmt_baser[domain],
+                                               IRS_VMT_BASER, VALID, valid);
+        trace_gicv5_vmt_invalid(domain_name[domain]);
+        return;
+    }
+
+    cs->irs_vmt_baser[domain] = value;
+
+    if (FIELD_EX64(cs->irs_vmt_baser[domain], IRS_VMT_BASER, VALID)) {
+        trace_gicv5_vmt_valid(domain_name[domain],
+                              cs->irs_vmt_baser[domain] & 
R_IRS_VMT_BASER_ADDR_MASK);
+    }
+}
+
 static void spi_sample(GICv5SPIState *spi)
 {
     /*
@@ -1271,6 +1301,31 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_IST_CFGR:
         *data = cs->irs_ist_cfgr[domain];
         return true;
+    case A_IRS_VMT_BASER:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = extract64(cs->irs_vmt_baser[domain], 0, 32);
+        } else {
+            *data = 0;
+        }
+        return true;
+    case A_IRS_VMT_BASER + 4:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = extract64(cs->irs_vmt_baser[domain], 32, 32);
+        } else {
+            *data = 0;
+        }
+        return true;
+    case A_IRS_VMT_STATUSR:
+        /*
+         * QEMU writes to IRS_VMT_BASER and IRS_VMAP_* take effect
+         * instantaneously, so the guest can never see the IDLE bit as 0.
+         */
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = R_IRS_VMT_STATUSR_IDLE_MASK;
+        } else {
+            *data = 0;
+        }
+        return true;
     case A_IRS_SPI_STATUSR:
         /*
          * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect
@@ -1373,6 +1428,14 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_MAP_L2_ISTR:
         irs_map_l2_istr_write(s, domain, data);
         return true;
+    case A_IRS_VMT_BASER:
+        irs_vmt_baser_write(s, domain,
+                            deposit64(cs->irs_vmt_baser[domain], 0, 32, data));
+        return true;
+    case A_IRS_VMT_BASER + 4:
+        irs_vmt_baser_write(s, domain,
+                            deposit64(cs->irs_vmt_baser[domain], 32, 32, 
data));
+        return true;
     case A_IRS_SPI_SELR:
         cs->irs_spi_selr[domain] = data;
         return true;
@@ -1457,6 +1520,13 @@ static bool config_readll(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_IST_BASER:
         *data = cs->irs_ist_baser[domain];
         return true;
+    case A_IRS_VMT_BASER:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = cs->irs_vmt_baser[domain];
+        } else {
+            *data = 0;
+        }
+        return true;
     }
 
     return false;
@@ -1469,6 +1539,9 @@ static bool config_writell(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_IST_BASER:
         irs_ist_baser_write(s, domain, data);
         return true;
+    case A_IRS_VMT_BASER:
+        irs_vmt_baser_write(s, domain, data);
+        return true;
     }
 
     return false;
diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c
index 17fd67b5ccd..89669493b83 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -104,6 +104,10 @@ static void gicv5_common_reset_hold(Object *obj, ResetType 
type)
          */
         cs->irs_spi_selr[i] = cs->spi_base + cs->spi_irs_range;
     }
+
+    if (cs->has_virt) {
+        memset(cs->irs_vmt_baser, 0, sizeof(cs->irs_vmt_baser));
+    }
 }
 
 static void gicv5_common_init(Object *obj)
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 6681e32d1b7..3c7619cf3cd 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -246,6 +246,8 @@ gicv5_deactivate(const char *domain, const char *type, bool 
virtual, uint32_t id
 gicv5_spi_state(uint32_t spi_id, bool level, bool pending, bool active) "GICv5 
IRS SPI ID %u now level %d pending %d active %d"
 gicv5_irs_recalc_hppi_fail(const char *domain, uint32_t iaffid, const char 
*reason) "GICv5 IRS %s IAFFID %u: no HPPI: %s"
 gicv5_irs_recalc_hppi(const char *domain, uint32_t iaffid, uint32_t id, 
uint8_t prio) "GICv5 IRS %s IAFFID %u: new HPPI ID 0x%x prio %u"
+gicv5_vmt_valid(const char *domain, uint64_t base) "GICv5 IRS %s VM table now 
valid: base 0x%" PRIx64
+gicv5_vmt_invalid(const char *domain) "GICv5 IRS %s VM table no longer valid"
 
 # arm_gicv5_common.c
 gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, 
uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u 
CPUs, SPI base %u, SPI IRS range %u, SPI range %u"
diff --git a/include/hw/intc/arm_gicv5_common.h 
b/include/hw/intc/arm_gicv5_common.h
index 7b24cad211b..f134602d66e 100644
--- a/include/hw/intc/arm_gicv5_common.h
+++ b/include/hw/intc/arm_gicv5_common.h
@@ -89,6 +89,7 @@ struct GICv5Common {
     uint32_t irs_cr0[NUM_GICV5_DOMAINS];
     uint32_t irs_cr1[NUM_GICV5_DOMAINS];
     uint32_t irs_pe_selr[NUM_GICV5_DOMAINS];
+    uint64_t irs_vmt_baser[NUM_GICV5_DOMAINS];
 
     /*
      * Pointer to an array of state information for the SPIs.  Array
-- 
2.43.0


Reply via email to