@samitouri / QOSamiQemu / commits / 19fd9cd10b

hw/intc/arm_gicv5: Implement IRS_SPI_{SELR, STATUSR, CFGR, DOMAINR}

Implement the IRS registers IRS_SPI_{SELR,STATUSR,CFGR,DOMAINR} which form the config access for setting the trigger mode and domain of an SPI. The way these work is that the guest writes the ID of the interrupt it wants to configure to IRS_SPI_SELR, and then it can read and write the trigger mode of that SPI via IRS_SPI_CFGR and the domain via IRS_SPI_DOMAINR. IRS_SPI_STATUSR has a bit to indicate whether the SPI is valid, and the usual IDLE bit to allow for non-instantaneous updates (which QEMU doesn't do). Since the only domain which can configure the domain of an SPI is EL3 and our initial implementation is NS-only, technically the DOMAINR handling is unused code. However it is straightforward, being almost the same as the CFGR handling, and we'll need it later on. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-28-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC 19fd9cd10b5bc41387424e7ca18cce608ae83103
3 files changed +78
hw/intc/arm_gicv5.c
+68
@@ -310,6 +310,22 @@ FIELD(ICSR, HM, 5, 1)
310 FIELD(ICSR, PRIORITY, 11, 5)
311 FIELD(ICSR, IAFFID, 32, 16)
312
313 +static GICv5SPIState *spi_for_selr(GICv5Common *cs, GICv5Domain domain)
314 +{
315 + /*
316 + * If the IRS_SPI_SELR value specifies an SPI that can be managed in
317 + * this domain, return a pointer to its GICv5SPIState; otherwise
318 + * return NULL.
319 + */
320 + uint32_t id = FIELD_EX32(cs->irs_spi_selr[domain], IRS_SPI_SELR, ID);
321 + GICv5SPIState *spi = gicv5_raw_spi_state(cs, id);
322 +
323 + if (spi && (domain == GICV5_ID_EL3 || domain == spi->domain)) {
324 + return spi;
325 + }
326 + return NULL;
327 +}
328 +
329 static MemTxAttrs irs_txattrs(GICv5Common *cs, GICv5Domain domain)
330 {
331 /*
@@ -1010,6 +1026,38 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
1026 case A_IRS_IST_CFGR:
1027 *data = cs->irs_ist_cfgr[domain];
1028 return true;
1029 +
1030 + case A_IRS_SPI_STATUSR:
1031 + /*
1032 + * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect
1033 + * instantaneously, so the guest can never see the IDLE bit as 0.
1034 + */
1035 + v = FIELD_DP32(v, IRS_SPI_STATUSR, V,
1036 + spi_for_selr(cs, domain) != NULL);
1037 + v = FIELD_DP32(v, IRS_SPI_STATUSR, IDLE, 1);
1038 + *data = v;
1039 + return true;
1040 +
1041 + case A_IRS_SPI_CFGR:
1042 + {
1043 + GICv5SPIState *spi = spi_for_selr(cs, domain);
1044 +
1045 + if (spi) {
1046 + v = FIELD_DP32(v, IRS_SPI_CFGR, TM, spi->tm);
1047 + }
1048 + *data = v;
1049 + return true;
1050 + }
1051 + case A_IRS_SPI_DOMAINR:
1052 + if (domain == GICV5_ID_EL3) {
1053 + /* This is RAZ/WI except for the EL3 domain */
1054 + GICv5SPIState *spi = spi_for_selr(cs, domain);
1055 + if (spi) {
1056 + v = FIELD_DP32(v, IRS_SPI_DOMAINR, DOMAIN, spi->domain);
1057 + }
1058 + }
1059 + *data = v;
1060 + return true;
1061 }
1062
1063 return false;
@@ -1041,6 +1089,26 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
1089 case A_IRS_MAP_L2_ISTR:
1090 irs_map_l2_istr_write(s, domain, data);
1091 return true;
1092 + case A_IRS_SPI_SELR:
1093 + cs->irs_spi_selr[domain] = data;
1094 + return true;
1095 + case A_IRS_SPI_CFGR:
1096 + {
1097 + GICv5SPIState *spi = spi_for_selr(cs, domain);
1098 + if (spi) {
1099 + spi->tm = FIELD_EX32(data, IRS_SPI_CFGR, TM);
1100 + }
1101 + return true;
1102 + }
1103 + case A_IRS_SPI_DOMAINR:
1104 + if (domain == GICV5_ID_EL3) {
1105 + /* this is RAZ/WI except for the EL3 domain */
1106 + GICv5SPIState *spi = spi_for_selr(cs, domain);
1107 + if (spi) {
1108 + spi->domain = FIELD_EX32(data, IRS_SPI_DOMAINR, DOMAIN);
1109 + }
1110 + }
1111 + return true;
1112 }
1113
1114 return false;
hw/intc/arm_gicv5_common.c
+9
@@ -92,6 +92,15 @@ static void gicv5_common_reset_hold(Object *obj, ResetType type)
92 cs->spi[i].domain = mp_domain;
93 }
94 }
95 +
96 + for (int i = 0; i < NUM_GICV5_DOMAINS; i++) {
97 + /*
98 + * We reset irs_spi_selr to an invalid value so that our reset
99 + * value for IRS_SPI_STATUSR.V is correctly 0. The guest can
100 + * never read IRS_SPI_SELR directly.
101 + */
102 + cs->irs_spi_selr[i] = cs->spi_base + cs->spi_irs_range;
103 + }
104 }
105
106 static void gicv5_common_init(Object *obj)
include/hw/intc/arm_gicv5_common.h
+1
@@ -85,6 +85,7 @@ struct GICv5Common {
85
86 uint64_t irs_ist_baser[NUM_GICV5_DOMAINS];
87 uint32_t irs_ist_cfgr[NUM_GICV5_DOMAINS];
88 + uint32_t irs_spi_selr[NUM_GICV5_DOMAINS];
89
90 /*
91 * Pointer to an array of state information for the SPIs. Array