When has_virt is true, report virtualization support in the IRS ID
registers.  This includes reporting various specifics of our
implementation.  We choose to implement the maximum possible sizes
for VM and VPE IDs.  We don't need to store any implementation state
in the IMPDEF guest memory VM descriptor and VPE descriptor
structures, so we indicate that we have no VM descriptors and that
the VPE descriptor is the smallest size the spec allows.

Signed-off-by: Peter Maydell <[email protected]>
---
 hw/intc/arm_gicv5.c                | 40 +++++++++++++++++++++++-------
 include/hw/intc/arm_gicv5_common.h | 25 +++++++++++++++++++
 2 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 289a3afaeae..63e4a165eea 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -75,6 +75,16 @@ static uint32_t gicv5_idreg(int regoffset)
     return gic_ids[regoffset];
 }
 
+static bool gicv5_domain_has_virt(GICv5Common *cs, GICv5Domain domain)
+{
+    /*
+     * Return true if this domain implements virtualization.
+     * EL3 never does; if any CPU connected to the IRS has EL2
+     * then all other domains must implement virtualization (R_KDSPG)
+     */
+    return cs->has_virt && domain != GICV5_ID_EL3;
+}
+
 static GICv5SPIState *spi_for_selr(GICv5Common *cs, GICv5Domain domain)
 {
     /*
@@ -1208,8 +1218,8 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
             /* MEC field RES0 except for the Realm domain */
             v &= ~R_IRS_IDR0_MEC_MASK;
         }
-        if (domain == GICV5_ID_EL3) {
-            /* VIRT is RES0 for EL3 domain */
+        if (!gicv5_domain_has_virt(cs, domain)) {
+            /* VIRT is RES0 for this domain */
             v &= ~R_IRS_IDR0_VIRT_MASK;
             /* ...which means VIRT_ONE_N is also RES0 */
             v &= ~R_IRS_IDR0_VIRT_ONE_N_MASK;
@@ -1223,12 +1233,12 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, 
hwaddr offset,
         *data = cs->irs_idr2;
         return true;
     case A_IRS_IDR3:
-        /* In EL3 IDR0.VIRT is 0 so this is RES0 */
-        *data = domain == GICV5_ID_EL3 ? 0 : cs->irs_idr3;
+        /* All fields are RES0 if domain doesn't have virt */
+        *data = gicv5_domain_has_virt(cs, domain) ? cs->irs_idr3 : 0;
         return true;
     case A_IRS_IDR4:
-        /* In EL3 IDR0.VIRT is 0 so this is RES0 */
-        *data = domain == GICV5_ID_EL3 ? 0 : cs->irs_idr4;
+        /* All fields are RES0 if domain doesn't have virt */
+        *data = gicv5_domain_has_virt(cs, domain) ? cs->irs_idr4 : 0;
         return true;
     case A_IRS_IDR5:
         *data = cs->irs_idr5;
@@ -1636,6 +1646,7 @@ static void gicv5_set_idregs(GICv5Common *cs)
      * for 56 bits of physical address space.
      */
     v = FIELD_DP32(v, IRS_IDR0, PA_RANGE, 7);
+    v = FIELD_DP32(v, IRS_IDR0, VIRT, cs->has_virt);
     v = FIELD_DP32(v, IRS_IDR0, IRSID, cs->irsid);
     cs->irs_idr0 = v;
 
@@ -1655,9 +1666,20 @@ static void gicv5_set_idregs(GICv5Common *cs)
     /* Our impl does not need IST metadata, so ISTMD and ISTMD_SZ are 0 */
     cs->irs_idr2 = v;
 
-    /* We don't implement virtualization yet, so these are zero */
-    cs->irs_idr3 = 0;
-    cs->irs_idr4 = 0;
+    v = 0;
+    if (cs->has_virt) {
+        /* Our impl doesn't need a VM descriptor, so VMD and VMD_SZ are zero. 
*/
+        v = FIELD_DP32(v, IRS_IDR3, VM_ID_BITS, QEMU_GICV5_VM_ID_BITS);
+        v = FIELD_DP32(v, IRS_IDR3, VMT_LEVELS, 1);
+    }
+    cs->irs_idr3 = v;
+
+    v = 0;
+    if (cs->has_virt) {
+        v = FIELD_DP32(v, IRS_IDR4, VPED_SZ, QEMU_GICV5_VPED_SZ);
+        v = FIELD_DP32(v, IRS_IDR4, VPE_ID_BITS, QEMU_GICV5_VPE_ID_BITS - 1);
+    }
+    cs->irs_idr4 = v;
 
     /* These three have just one field each */
     cs->irs_idr5 = FIELD_DP32(0, IRS_IDR5, SPI_RANGE, cs->spi_range);
diff --git a/include/hw/intc/arm_gicv5_common.h 
b/include/hw/intc/arm_gicv5_common.h
index d8f6f5d5db9..7b24cad211b 100644
--- a/include/hw/intc/arm_gicv5_common.h
+++ b/include/hw/intc/arm_gicv5_common.h
@@ -153,6 +153,31 @@ struct GICv5CommonClass {
 #define QEMU_GICV5_IAFFID_BITS 16
 /* Number of priority bits supported in the IRS */
 #define QEMU_GICV5_PRI_BITS 5
+/* Number of VM ID bits */
+#define QEMU_GICV5_VM_ID_BITS 16
+/* Number of VPE ID bits */
+#define QEMU_GICV5_VPE_ID_BITS 16
+
+/*
+ * The VPE descriptor is IMPDEF in size and contents; it stores
+ *  - the VPE's residency status and location
+ *  - VPE doorbell settings
+ *  - metadata tracking pending interrupts for the VPE
+ * In a real hardware implementation, the IRS will keep its per-VPE data
+ * in guest memory with a cache so it isn't actually doing full memory
+ * accesses all the time. For QEMU we will keep the per-VPE data in
+ * host-side data structures, which don't have any size limitations.
+ * The specification doesn't define any situations where the IRS
+ * must write its state back out to guest memory, except for the
+ * entirely IMPDEF and optional power-management suspend/resume.
+ * QEMU's IRS doesn't implement power-management, so we will never
+ * write out anything to the VPE descriptors in guest memory.
+ * We therefore define them to the smallest size the spec permits,
+ * which is 8 bytes.
+ * (We similarly do not use VM descriptors, but for those the spec
+ * permits an implementation to tell software it does not use them.)
+ */
+#define QEMU_GICV5_VPED_SZ 3
 
 /*
  * There are no TRMs currently published for hardware implementations
-- 
2.43.0


Reply via email to