The IRS provides a set of registers to allow software to read and
write the configuration of a VPE.  IRS_VPE_SELR selects the VPE to
operate on, IRS_VPE_STATUSR indicates whether that selection was
successful, and other registers like IRS_VPE_DBR will then provide
access to the config for the selected VPE.

Implement IRS_VPE_SELR and IRS_VPE_STATUSR, for the "select a VPE"
part of this mechanism.

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

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index e762c058a98..455242596bc 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -116,6 +116,24 @@ static void VMTE_free(void *data)
     g_free(vmte);
 }
 
+static VPE *vpe_for_vpeid(VMTE *vmte, uint32_t vpeid)
+{
+    /*
+     * Return the VPE struct for the specified VPEID for this VM, or
+     * NULL if there is no such valid VPE.
+     */
+    VPE *vpe;
+
+    if (!vmte || vpeid >= (1 << vmte->vpe_id_bits)) {
+        return NULL;
+    }
+    vpe = &vmte->vpet[vpeid];
+    if (!vpe->valid) {
+        return NULL;
+    }
+    return vpe;
+}
+
 static bool gicv5_domain_has_virt(GICv5Common *cs, GICv5Domain domain)
 {
     /*
@@ -1949,6 +1967,56 @@ txfail:
                   vmid, vpeid, vpete_addr);
 }
 
+static VPE *vpe_from_selr(GICv5 *s, GICv5Domain domain)
+{
+    /*
+     * Return the VPE for the VM/VPE indicated by the current value of
+     * IRS_VPE_SELR, or NULL if none.
+     */
+    GICv5Common *cs = ARM_GICV5_COMMON(s);
+    GICv5VMTConfig *cfg = &s->vmt_config[domain];
+    uint32_t vmid, vpeid;
+    VMTE *vmte;
+
+    if (FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, S) == 0) {
+        return NULL;
+    }
+
+    vmid = FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, VM_ID);
+    vpeid = FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, VPE_ID);
+
+    if (!cfg->valid || vmid >= (1 << cfg->vm_id_bits)) {
+        return NULL;
+    }
+
+    vmte = g_hash_table_lookup(cfg->vm_cache, GINT_TO_POINTER(vmid));
+    return vpe_for_vpeid(vmte, vpeid);
+}
+
+static void irs_vpe_selr_write(GICv5 *s, GICv5Domain domain, uint64_t value)
+{
+    GICv5Common *cs = ARM_GICV5_COMMON(s);
+    uint32_t status = R_IRS_VPE_STATUSR_IDLE_MASK;
+    VPE *vpe;
+
+    /* RES0 if we don't have virt */
+    if (!gicv5_domain_has_virt(cs, domain)) {
+        return;
+    }
+
+    cs->irs_vpe_selr[domain] = value;
+
+    vpe = vpe_from_selr(s, domain);
+    if (vpe) {
+        /* We successfully selected a valid VPE */
+        status |= R_IRS_VPE_STATUSR_V_MASK;
+    }
+
+    trace_gicv5_irs_vpe_selr_write(domain_name[domain], value, status);
+
+    cs->irs_vpe_statusr[domain] = status;
+}
+
 static void spi_sample(GICv5SPIState *spi)
 {
     /*
@@ -2168,6 +2236,30 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
             *data = 0;
         }
         return true;
+    case A_IRS_VPE_SELR:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = extract64(cs->irs_vpe_selr[domain], 0, 32);
+        } else {
+            /* RAZ/WI if no virt */
+            *data = 0;
+        }
+        return true;
+    case A_IRS_VPE_SELR + 4:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = extract64(cs->irs_vpe_selr[domain], 32, 32);
+        } else {
+            /* RAZ/WI if no virt */
+            *data = 0;
+        }
+        return true;
+    case A_IRS_VPE_STATUSR:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = cs->irs_vpe_statusr[domain];
+        } else {
+            /* RAZ/WI if no virt */
+            *data = 0;
+        }
+        return true;
     case A_IRS_SPI_STATUSR:
         /*
          * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect
@@ -2334,6 +2426,14 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
         irs_vmap_vper_write(s, domain,
                             deposit64(cs->irs_vmap_vper[domain], 32, 32, 
data));
         return true;
+    case A_IRS_VPE_SELR:
+        irs_vpe_selr_write(s, domain,
+                           deposit64(cs->irs_vpe_selr[domain], 0, 32, data));
+        return true;
+    case A_IRS_VPE_SELR + 4:
+        irs_vpe_selr_write(s, domain,
+                           deposit64(cs->irs_vpe_selr[domain], 32, 32, data));
+        return true;
     case A_IRS_SPI_SELR:
         cs->irs_spi_selr[domain] = data;
         return true;
@@ -2466,6 +2566,14 @@ static bool config_readll(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
             *data = 0;
         }
         return true;
+    case A_IRS_VPE_SELR:
+        if (gicv5_domain_has_virt(cs, domain)) {
+            *data = cs->irs_vpe_selr[domain];
+        } else {
+            /* RAZ/WI if no virt */
+            *data = 0;
+        }
+        return true;
     }
 
     return false;
@@ -2496,6 +2604,9 @@ static bool config_writell(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
     case A_IRS_VMAP_VPER:
         irs_vmap_vper_write(s, domain, data);
         return true;
+    case A_IRS_VPE_SELR:
+        irs_vpe_selr_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 6e0e2295fde..553598e3178 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -9,6 +9,7 @@
 #include "qemu/osdep.h"
 #include "hw/intc/arm_gicv5_common.h"
 #include "hw/intc/arm_gicv5_stream.h"
+#include "hw/intc/arm_gicv5_regs.h"
 #include "hw/core/qdev-properties.h"
 #include "qapi/error.h"
 #include "trace.h"
@@ -113,6 +114,11 @@ static void gicv5_common_reset_hold(Object *obj, ResetType 
type)
         memset(cs->irs_vmap_vistr, 0, sizeof(cs->irs_vmap_vistr));
         memset(cs->irs_vmap_l2_vistr, 0, sizeof(cs->irs_vmap_l2_vistr));
         memset(cs->irs_vmap_vper, 0, sizeof(cs->irs_vmap_vper));
+        memset(cs->irs_vpe_selr, 0, sizeof(cs->irs_vpe_selr));
+
+        for (int i = 0; i < NUM_GICV5_DOMAINS; i++) {
+            cs->irs_vpe_statusr[i] = R_IRS_VPE_STATUSR_IDLE_MASK;
+        }
     }
 }
 
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 79381c109b7..edfbf7d7157 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -253,6 +253,7 @@ gicv5_cache_vmte(const char *domain, uint32_t vmid) "GICv5 
IRS %s VM ID %u valid
 gicv5_irs_vmap_vistr_write(const char *domain, uint32_t vmid, const char 
*type, const char *what) "GICv5 IRS %s VM ID %u %s IST now %s"
 gicv5_initialize_vpet(const char *domain, uint32_t vmid, uint32_t vpeid, bool 
valid) "GICv5 IRS %s VM ID %u VPE %u starts as valid %d"
 gicv5_irs_vmap_vper_write(const char *domain, uint32_t vmid, uint32_t vpeid) 
"GICv5 IRS %s VM ID %u VPE %u now made valid"
+gicv5_irs_vpe_selr_write(const char *domain, uint64_t selr, uint32_t status) 
"GICv5 IRS %s IRS_VPE_SELR written 0x%" PRIx64 " IRS_VPE_STATUSR now 0x%x"
 
 # 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 c8574f66a63..5823a7f78a0 100644
--- a/include/hw/intc/arm_gicv5_common.h
+++ b/include/hw/intc/arm_gicv5_common.h
@@ -96,6 +96,8 @@ struct GICv5Common {
     uint64_t irs_vmap_vistr[NUM_GICV5_DOMAINS];
     uint64_t irs_vmap_l2_vistr[NUM_GICV5_DOMAINS];
     uint64_t irs_vmap_vper[NUM_GICV5_DOMAINS];
+    uint64_t irs_vpe_selr[NUM_GICV5_DOMAINS];
+    uint32_t irs_vpe_statusr[NUM_GICV5_DOMAINS];
 
     /*
      * Pointer to an array of state information for the SPIs.  Array
-- 
2.43.0


Reply via email to