The IRS_VMAP_L2_VISTR allows the guest to make an L2 entry in the
VM's VLPI or VSPI IST valid; it is the equivalent of what
IRS_MAP_L2_ISTR does for the physical LPI IST.

Signed-off-by: Peter Maydell <[email protected]>
---
 hw/intc/arm_gicv5.c                | 76 ++++++++++++++++++++++++++++++
 hw/intc/arm_gicv5_common.c         |  1 +
 include/hw/intc/arm_gicv5_common.h |  1 +
 3 files changed, 78 insertions(+)

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 3fac52012b1..4f74236c62b 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -1792,6 +1792,46 @@ txfail:
                   vmid, vmte->vmte_addr);
 }
 
+static void irs_vmap_l2_vistr_write(GICv5 *s, GICv5Domain domain,
+                                    uint64_t value)
+{
+    GICv5Common *cs = ARM_GICV5_COMMON(s);
+    GICv5VMTConfig *cfg = &s->vmt_config[domain];
+    uint32_t vmid = FIELD_EX64(value, IRS_VMAP_L2_VISTR, VM_ID);
+    bool m = FIELD_EX64(value,  IRS_VMAP_L2_VISTR, M);
+    uint32_t intid = FIELD_EX64(value,  IRS_VMAP_L2_VISTR, ID);
+    GICv5IntType type = FIELD_EX64(value, IRS_VMAP_VISTR, TYPE);
+    VMTE *vmte;
+    GICv5ISTConfig *vist;
+
+    if (!gicv5_domain_has_virt(cs, domain) || !cfg->valid) {
+        /* Whole register RAZ/WI if no virt or no VM table */
+        return;
+    }
+
+    /* M bit is WO/UNKNOWN; write the other fields */
+    cs->irs_vmap_l2_vistr[domain] = value & ~R_IRS_VMAP_L2_VISTR_M_MASK;
+
+    /*
+     * M = 0 and bad VMID must be ignored; invalid TYPE is
+     * UNPREDICTABLE, and we choose to ignore
+     */
+    if (!m || vmid >= (1 << cfg->vm_id_bits) ||
+        (type != GICV5_LPI && type != GICV5_SPI)) {
+        return;
+    }
+
+    vmte = g_hash_table_lookup(cfg->vm_cache, GINT_TO_POINTER(vmid));
+    if (!vmte) {
+        /* VM is not valid */
+        return;
+    }
+
+    vist = type == GICV5_LPI ? &vmte->lpi_ist : &vmte->spi_ist;
+
+    map_l2_istr(cs, vist, intid);
+}
+
 static void spi_sample(GICv5SPIState *spi)
 {
     /*
@@ -1979,6 +2019,22 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
             *data = 0;
         }
         return true;
+    case A_IRS_VMAP_L2_VISTR:
+        if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) {
+            *data = extract64(cs->irs_vmap_l2_vistr[domain], 0, 32);
+        } else {
+            /* RAZ/WI if no virt or no VM table */
+            *data = 0;
+        }
+        return true;
+    case A_IRS_VMAP_L2_VISTR + 4:
+        if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) {
+            *data = extract64(cs->irs_vmap_l2_vistr[domain], 32, 32);
+        } else {
+            /* RAZ/WI if no virt or no VM table */
+            *data = 0;
+        }
+        return true;
     case A_IRS_SPI_STATUSR:
         /*
          * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect
@@ -2128,6 +2184,15 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
                              deposit64(cs->irs_vmap_vistr[domain],
                                        32, 32, data));
         return true;
+    case A_IRS_VMAP_L2_VISTR:
+        irs_vmap_l2_vistr_write(s, domain,
+                                deposit64(cs->irs_vmap_vistr[domain], 0, 32, 
data));
+        return true;
+    case A_IRS_VMAP_L2_VISTR + 4:
+        irs_vmap_l2_vistr_write(s, domain,
+                                deposit64(cs->irs_vmap_vistr[domain],
+                                          32, 32, data));
+        return true;
     case A_IRS_SPI_SELR:
         cs->irs_spi_selr[domain] = data;
         return true;
@@ -2244,6 +2309,14 @@ static bool config_readll(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
             *data = 0;
         }
         return true;
+    case A_IRS_VMAP_L2_VISTR:
+        if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) {
+            *data = cs->irs_vmap_l2_vistr[domain];
+        } else {
+            /* RAZ/WI if no virt or no VM table */
+            *data = 0;
+        }
+        return true;
     }
 
     return false;
@@ -2268,6 +2341,9 @@ static bool config_writell(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_VMAP_VISTR:
         irs_vmap_vistr_write(s, domain, data);
         return true;
+    case A_IRS_VMAP_L2_VISTR:
+        irs_vmap_l2_vistr_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 181171e000b..b52dba3d3b4 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -111,6 +111,7 @@ static void gicv5_common_reset_hold(Object *obj, ResetType 
type)
         memset(cs->irs_vmap_l2_vmtr, 0, sizeof(cs->irs_vmap_l2_vmtr));
         memset(cs->irs_vmap_vmr, 0, sizeof(cs->irs_vmap_vmr));
         memset(cs->irs_vmap_vistr, 0, sizeof(cs->irs_vmap_vistr));
+        memset(cs->irs_vmap_l2_vistr, 0, sizeof(cs->irs_vmap_l2_vistr));
     }
 }
 
diff --git a/include/hw/intc/arm_gicv5_common.h 
b/include/hw/intc/arm_gicv5_common.h
index 19e13693de9..8103f14ba44 100644
--- a/include/hw/intc/arm_gicv5_common.h
+++ b/include/hw/intc/arm_gicv5_common.h
@@ -94,6 +94,7 @@ struct GICv5Common {
     uint64_t irs_vmap_l2_vmtr[NUM_GICV5_DOMAINS];
     uint64_t irs_vmap_vmr[NUM_GICV5_DOMAINS];
     uint64_t irs_vmap_vistr[NUM_GICV5_DOMAINS];
+    uint64_t irs_vmap_l2_vistr[NUM_GICV5_DOMAINS];
 
     /*
      * Pointer to an array of state information for the SPIs.  Array
-- 
2.43.0


Reply via email to