aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-04-08 15:15:17 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-04-22 09:23:12 +0100
commit9de53de60cb8638e9c2e02b25ec4445791672aeb (patch)
tree67d263353553b97ede6b66a624dee4949cbf7b40 /hw/intc
parent50d84584d3c77e3a9104826a53a691318aeaf038 (diff)
downloadqemu-9de53de60cb8638e9c2e02b25ec4445791672aeb.zip
qemu-9de53de60cb8638e9c2e02b25ec4445791672aeb.tar.gz
qemu-9de53de60cb8638e9c2e02b25ec4445791672aeb.tar.bz2
hw/intc/arm_gicv3_its: Implement VMAPI and VMAPTI
Implement the GICv4 VMAPI and VMAPTI commands. These write an interrupt translation table entry that maps (DeviceID,EventID) to (vPEID,vINTID,doorbell). The only difference between VMAPI and VMAPTI is that VMAPI assumes vINTID == EventID rather than both being specified in the command packet. (This code won't be reachable until we allow the GIC version to be set to 4. Support for reading this new virtual-interrupt DTE and handling it correctly will be implemented in a later commit.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220408141550.1271295-9-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/arm_gicv3_its.c91
-rw-r--r--hw/intc/gicv3_internal.h9
-rw-r--r--hw/intc/trace-events2
3 files changed, 102 insertions, 0 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index f9704c0..8aed57e 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -91,6 +91,12 @@ static inline bool intid_in_lpi_range(uint32_t id)
id < (1 << (GICD_TYPER_IDBITS + 1));
}
+static inline bool valid_doorbell(uint32_t id)
+{
+ /* Doorbell fields may be an LPI, or 1023 to mean "no doorbell" */
+ return id == INTID_SPURIOUS || intid_in_lpi_range(id);
+}
+
static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
{
uint64_t result = 0;
@@ -486,6 +492,85 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL;
}
+static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
+ bool ignore_vintid)
+{
+ uint32_t devid, eventid, vintid, doorbell, vpeid;
+ uint32_t num_eventids;
+ DTEntry dte;
+ ITEntry ite;
+
+ if (!its_feature_virtual(s)) {
+ return CMD_CONTINUE;
+ }
+
+ devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
+ eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
+ vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
+ doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
+ if (ignore_vintid) {
+ vintid = eventid;
+ trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
+ } else {
+ vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
+ trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
+ }
+
+ if (devid >= s->dt.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
+ __func__, devid, s->dt.num_entries);
+ return CMD_CONTINUE;
+ }
+
+ if (get_dte(s, devid, &dte) != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ if (!dte.valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: no entry in device table for DeviceID 0x%x\n",
+ __func__, devid);
+ return CMD_CONTINUE;
+ }
+
+ num_eventids = 1ULL << (dte.size + 1);
+
+ if (eventid >= num_eventids) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: EventID 0x%x too large for DeviceID 0x%x "
+ "(must be less than 0x%x)\n",
+ __func__, eventid, devid, num_eventids);
+ return CMD_CONTINUE;
+ }
+ if (!intid_in_lpi_range(vintid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: VIntID 0x%x not a valid LPI\n",
+ __func__, vintid);
+ return CMD_CONTINUE;
+ }
+ if (!valid_doorbell(doorbell)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Doorbell %d not 1023 and not a valid LPI\n",
+ __func__, doorbell);
+ return CMD_CONTINUE;
+ }
+ if (vpeid >= s->vpet.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
+ __func__, vpeid, s->vpet.num_entries);
+ return CMD_CONTINUE;
+ }
+ /* add ite entry to interrupt translation table */
+ ite.valid = true;
+ ite.inttype = ITE_INTTYPE_VIRTUAL;
+ ite.intid = vintid;
+ ite.icid = 0;
+ ite.doorbell = doorbell;
+ ite.vpeid = vpeid;
+ return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL;
+}
+
/*
* Update the Collection Table entry for @icid to @cte. Returns true
* on success, false if there was a memory access error.
@@ -872,6 +957,12 @@ static void process_cmdq(GICv3ITSState *s)
case GITS_CMD_MOVALL:
result = process_movall(s, cmdpkt);
break;
+ case GITS_CMD_VMAPTI:
+ result = process_vmapti(s, cmdpkt, false);
+ break;
+ case GITS_CMD_VMAPI:
+ result = process_vmapti(s, cmdpkt, true);
+ break;
default:
trace_gicv3_its_cmd_unknown(cmd);
break;
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 4613b9e..d3670a8 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -329,6 +329,8 @@ FIELD(GITS_TYPER, CIL, 36, 1)
#define GITS_CMD_INVALL 0x0D
#define GITS_CMD_MOVALL 0x0E
#define GITS_CMD_DISCARD 0x0F
+#define GITS_CMD_VMAPTI 0x2A
+#define GITS_CMD_VMAPI 0x2B
/* MAPC command fields */
#define ICID_LENGTH 16
@@ -368,6 +370,13 @@ FIELD(MOVI_0, DEVICEID, 32, 32)
FIELD(MOVI_1, EVENTID, 0, 32)
FIELD(MOVI_2, ICID, 0, 16)
+/* VMAPI, VMAPTI command fields */
+FIELD(VMAPTI_0, DEVICEID, 32, 32)
+FIELD(VMAPTI_1, EVENTID, 0, 32)
+FIELD(VMAPTI_1, VPEID, 32, 16)
+FIELD(VMAPTI_2, VINTID, 0, 32) /* VMAPTI only */
+FIELD(VMAPTI_2, DOORBELL, 32, 32)
+
/*
* 12 bytes Interrupt translation Table Entry size
* as per Table 5.3 in GICv3 spec
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 53414aa..c6b2b9a 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -187,6 +187,8 @@ gicv3_its_cmd_mapti(uint32_t devid, uint32_t eventid, uint32_t icid, uint32_t in
gicv3_its_cmd_inv(void) "GICv3 ITS: command INV or INVALL"
gicv3_its_cmd_movall(uint64_t rd1, uint64_t rd2) "GICv3 ITS: command MOVALL RDbase1 0x%" PRIx64 " RDbase2 0x%" PRIx64
gicv3_its_cmd_movi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MOVI DeviceID 0x%x EventID 0x%x ICID 0x%x"
+gicv3_its_cmd_vmapi(uint32_t devid, uint32_t eventid, uint32_t vpeid, uint32_t doorbell) "GICv3 ITS: command VMAPI DeviceID 0x%x EventID 0x%x vPEID 0x%x Dbell_pINTID 0x%x"
+gicv3_its_cmd_vmapti(uint32_t devid, uint32_t eventid, uint32_t vpeid, uint32_t vintid, uint32_t doorbell) "GICv3 ITS: command VMAPI DeviceID 0x%x EventID 0x%x vPEID 0x%x vINTID 0x%x Dbell_pINTID 0x%x"
gicv3_its_cmd_unknown(unsigned cmd) "GICv3 ITS: unknown command 0x%x"
gicv3_its_cte_read(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table read for ICID 0x%x: valid %d RDBase 0x%x"
gicv3_its_cte_write(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table write for ICID 0x%x: valid %d RDBase 0x%x"