In the GIC system instructions, VDPEND is special: the other "act on
virtual interrupt domain" operations act on the resident VPE/VM, but
this one allows the guest to pass in the VM ID, so that a hypervisor
can pend an interrupt for a VM even if there isn't currently a VPE
for that VM resident on the CPU.

Add the VM argument to gicv5_set_pending(), and fill it in with the
VM argument from the guest for VDPEND, or the current VM (as set in
ICH_CONTEXTR_EL2) for CDPEND and LDPEND. (The IRS will fail all
virtual interrupt operations until we implement its virtualization
support.)

The placing of the VM field moves the PENDING bit from bit 32 to 63,
so we need also to special case the reading of that bit.

Signed-off-by: Peter Maydell <[email protected]>
---
 hw/intc/arm_gicv5.c                |  5 +++--
 hw/intc/trace-events               |  2 +-
 include/hw/intc/arm_gicv5_stream.h |  3 ++-
 target/arm/tcg/gicv5-cpuif.c       | 34 +++++++++++++++++++++++++++++-
 4 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 5ac50acc786..d503d8db426 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -855,13 +855,14 @@ void gicv5_set_enabled(GICv5Common *cs, uint32_t id, bool 
enabled,
 }
 
 void gicv5_set_pending(GICv5Common *cs, uint32_t id, bool pending,
-                       GICv5Domain domain, GICv5IntType type, bool virtual)
+                       GICv5Domain domain, GICv5IntType type, bool virtual,
+                       uint32_t vm)
 {
     GICv5 *s = ARM_GICV5(cs);
     uint32_t iaffid;
 
     trace_gicv5_set_pending(domain_name[domain], inttype_name(type), virtual,
-                            id, pending);
+                            vm, id, pending);
     if (virtual) {
         qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set "
                       "pending state of a virtual interrupt\n");
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 7512c6e6004..6681e32d1b7 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -237,7 +237,7 @@ gicv5_ist_valid(const char *domain, uint64_t base, uint8_t 
id_bits, uint8_t l2_i
 gicv5_ist_invalid(const char *domain) "GICv5 IRS %s IST no longer valid"
 gicv5_set_priority(const char *domain, const char *type, bool virtual, 
uint32_t id, uint8_t priority) "GICv5 IRS SetPriority %s %s virtual:%d ID %u 
prio %u"
 gicv5_set_enabled(const char *domain, const char *type, bool virtual, uint32_t 
id, bool enabled) "GICv5 IRS SetEnabled %s %s virtual:%d ID %u enabled %d"
-gicv5_set_pending(const char *domain, const char *type, bool virtual, uint32_t 
id, bool pending) "GICv5 IRS SetPending %s %s virtual:%d ID %u pending %d"
+gicv5_set_pending(const char *domain, const char *type, bool virtual, uint32_t 
vm, uint32_t id, bool pending) "GICv5 IRS SetPending %s %s virtual:%d VM %u ID 
%u pending %d"
 gicv5_set_handling(const char *domain, const char *type, bool virtual, 
uint32_t id, int handling) "GICv5 IRS SetHandling %s %s virtual:%d ID %u 
handling %d"
 gicv5_set_target(const char *domain, const char *type, bool virtual, uint32_t 
id, uint32_t iaffid, int irm) "GICv5 IRS SetTarget %s %s virtual:%d ID %u 
IAFFID %u routingmode %d"
 gicv5_request_config(const char *domain, const char *type, bool virtual, 
uint32_t id, uint64_t icsr) "GICv5 IRS RequestConfig %s %s virtual:%d ID %u 
ICSR 0x%" PRIx64
diff --git a/include/hw/intc/arm_gicv5_stream.h 
b/include/hw/intc/arm_gicv5_stream.h
index 162d55a8e6b..f6d32c6beca 100644
--- a/include/hw/intc/arm_gicv5_stream.h
+++ b/include/hw/intc/arm_gicv5_stream.h
@@ -86,6 +86,7 @@ void gicv5_set_enabled(GICv5Common *cs, uint32_t id,
  * @domain: interrupt Domain to act on
  * @type: interrupt type (LPI or SPI)
  * @virtual: true if this is a virtual interrupt
+ * @vm: VM ID (for virtual interrupts)
  *
  * Set pending state of an interrupt; matches stream interface
  * SetPending command from CPUIF to IRS. There is no report back of
@@ -93,7 +94,7 @@ void gicv5_set_enabled(GICv5Common *cs, uint32_t id,
  */
 void gicv5_set_pending(GICv5Common *cs, uint32_t id,
                        bool pending, GICv5Domain domain,
-                       GICv5IntType type, bool virtual);
+                       GICv5IntType type, bool virtual, uint32_t vm);
 
 /**
  * gicv5_set_handling
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 4ee548a768b..7f0109e9b12 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -40,6 +40,11 @@ FIELD(GIC_CDPEND, ID, 0, 24)
 FIELD(GIC_CDPEND, TYPE, 29, 3)
 FIELD(GIC_CDPEND, PENDING, 32, 1)
 
+FIELD(GIC_VDPEND, ID, 0, 24)
+FIELD(GIC_VDPEND, TYPE, 29, 3)
+FIELD(GIC_VDPEND, VM, 32, 16)
+FIELD(GIC_VDPEND, PENDING, 63, 1)
+
 FIELD(GIC_CDHM, ID, 0, 24)
 FIELD(GIC_CDHM, TYPE, 29, 3)
 FIELD(GIC_CDHM, HM, 32, 1)
@@ -594,8 +599,35 @@ static void gic_cdpend_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     uint32_t id = FIELD_EX64(value, GIC_CDPEND, ID);
     bool virtual;
     GICv5Domain domain = gicv5_domain_for_insn(env, ri, &virtual);
+    uint32_t vm = 0;
 
-    gicv5_set_pending(gic, id, pending, domain, type, virtual);
+    if (virtual) {
+        if (ri->opc1 == 4) {
+            /*
+             * GIC VDPEND has a VM argument field, and PENDING
+             * is in a different bit location to normal
+             */
+            vm = FIELD_EX64(value, GIC_VDPEND, VM);
+            pending = FIELD_EX64(value, GIC_VDPEND, PENDING);
+        } else {
+            /*
+             * GIC CDPEND for the virtual interrupt domain operates on
+             * the VM for the resident VPE. Our implementation of
+             * ICH_CONTEXTR_EL2 means we can trust that if the V bit
+             * is set the VM field is the right one.
+             */
+            if (FIELD_EX64(env->gicv5_cpuif.ich_contextr_el2,
+                           ICH_CONTEXTR_EL2, V)) {
+                vm = FIELD_EX64(env->gicv5_cpuif.ich_contextr_el2,
+                                ICH_CONTEXTR_EL2, VM);
+            } else {
+                /* no resident VPE: instruction is a NOP */
+                return;
+            }
+        }
+    }
+
+    gicv5_set_pending(gic, id, pending, domain, type, virtual, vm);
 }
 
 static void gic_cdrcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
-- 
2.43.0


Reply via email to