@samitouri / QOSamiQemu / commits / ce71478e81

hw/intc/arm_gicv5: Implement IRS_PE_{CR0, SELR, STATUSR}

The IRS_PE_CR0, IRS_PE_SELR, IRS_PE_STATUSR registers allow software to set and query per-CPU config. Software writes the AFFID of a CPU to IRS_PE_SELR, and can then read and write the 1ofN config for that CPU to IRS_PE_CR0, and read the CPU's online status from IRS_PE_STATUSR. For QEMU, we do not implement 1-of-N interrupt routing, so IRS_PE_CR0 can be RAZ/WI. Our CPUs are always online and selecting a new one via SELR is instantaneous, so IRS_PE_STATUSR will return either ONLINE | V | IDLE if a valid AFFID was written to SELR, or just IDLE if an invalid AFFID was written. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-32-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC ce71478e811342502eeacfc7cc518f8496ba15db
3 files changed +41
hw/intc/arm_gicv5.c
+39
@@ -968,6 +968,21 @@ static void spi_sample(GICv5SPIState *spi)
968 }
969 }
970
971 +static bool irs_pe_selr_valid(GICv5Common *cs, GICv5Domain domain)
972 +{
973 + /*
974 + * Return true if IRS_PE_SELR has a valid AFFID in it. We don't
975 + * expect the guest to do this except perhaps once at startup, so
976 + * do a simple linear scan through the cpu_iaffids array.
977 + */
978 + for (int i = 0; i < cs->num_cpu_iaffids; i++) {
979 + if (cs->irs_pe_selr[domain] == cs->cpu_iaffids[i]) {
980 + return true;
981 + }
982 + }
983 + return false;
984 +}
985 +
986 static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
987 uint64_t *data, MemTxAttrs attrs)
988 {
@@ -1091,6 +1106,24 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
1106 /* Sync is a no-op for QEMU: we are always IDLE */
1107 *data = R_IRS_SYNC_STATUSR_IDLE_MASK;
1108 return true;
1109 + case A_IRS_PE_SELR:
1110 + *data = cs->irs_pe_selr[domain];
1111 + return true;
1112 + case A_IRS_PE_CR0:
1113 + /* We don't implement 1ofN, so this is RAZ/WI for us */
1114 + *data = 0;
1115 + return true;
1116 + case A_IRS_PE_STATUSR:
1117 + /*
1118 + * Our CPUs are always online, so we're really just reporting
1119 + * whether the guest wrote a valid AFFID to IRS_PE_SELR
1120 + */
1121 + v = R_IRS_PE_STATUSR_IDLE_MASK;
1122 + if (irs_pe_selr_valid(cs, domain)) {
1123 + v |= R_IRS_PE_STATUSR_V_MASK | R_IRS_PE_STATUSR_ONLINE_MASK;
1124 + }
1125 + *data = v;
1126 + return true;
1127 }
1128
1129 return false;
@@ -1179,6 +1212,12 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
1212 case A_IRS_SYNCR:
1213 /* Sync is a no-op for QEMU: ignore write */
1214 return true;
1215 + case A_IRS_PE_SELR:
1216 + cs->irs_pe_selr[domain] = data;
1217 + return true;
1218 + case A_IRS_PE_CR0:
1219 + /* We don't implement 1ofN, so this is RAZ/WI for us */
1220 + return true;
1221 }
1222
1223 return false;
hw/intc/arm_gicv5_common.c
+1
@@ -66,6 +66,7 @@ static void gicv5_common_reset_hold(Object *obj, ResetType type)
66 memset(cs->irs_ist_cfgr, 0, sizeof(cs->irs_ist_cfgr));
67 memset(cs->irs_cr0, 0, sizeof(cs->irs_cr0));
68 memset(cs->irs_cr1, 0, sizeof(cs->irs_cr1));
69 + memset(cs->irs_pe_selr, 0, sizeof(cs->irs_pe_selr));
70
71 if (cs->spi) {
72 GICv5Domain mp_domain;
include/hw/intc/arm_gicv5_common.h
+1
@@ -88,6 +88,7 @@ struct GICv5Common {
88 uint32_t irs_spi_selr[NUM_GICV5_DOMAINS];
89 uint32_t irs_cr0[NUM_GICV5_DOMAINS];
90 uint32_t irs_cr1[NUM_GICV5_DOMAINS];
91 + uint32_t irs_pe_selr[NUM_GICV5_DOMAINS];
92
93 /*
94 * Pointer to an array of state information for the SPIs. Array