@samitouri / QOSamiQemu / commits / bae0d9a50d

hw/intc/arm_gicv5: Implement IRS_IST_{BASER, STATUSR, CFGR}

Implement the three registers that handle configuration of the interrupt status table for physical LPIs: * IRS_IST_BASER holds the base address of the table, and has the VALID bit that tells the IRS to start using the config * IRS_IST_CFGR has all the other config data for the table * IRS_IST_STATUSR has the IDLE bit that tells software when updates to IRS_IST_BASER have taken effect Implement these registers. Note that neither BASER nor CFGR can be written when VALID == 1, except to clear the VALID bit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-17-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC bae0d9a50d9d1e5d6e2bc08050a24ac544232d45
3 files changed +81
hw/intc/arm_gicv5.c
+74
@@ -265,6 +265,24 @@ REG64(IRS_SWERR_SYNDROMER0, 0x3c8)
265 REG64(IRS_SWERR_SYNDROMER1, 0x3d0)
266 FIELD(IRS_SWERR_SYNDROMER2, ADDR, 3, 53)
267
268 +static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value)
269 +{
270 + GICv5Common *cs = ARM_GICV5_COMMON(s);
271 +
272 + if (FIELD_EX64(cs->irs_ist_baser[domain], IRS_IST_BASER, VALID)) {
273 + /* If VALID is set, ADDR is RO and we can only update VALID */
274 + bool valid = FIELD_EX64(value, IRS_IST_BASER, VALID);
275 + if (valid) {
276 + /* Ignore 1->1 transition */
277 + return;
278 + }
279 + cs->irs_ist_baser[domain] = FIELD_DP64(cs->irs_ist_baser[domain],
280 + IRS_IST_BASER, VALID, valid);
281 + return;
282 + }
283 + cs->irs_ist_baser[domain] = value;
284 +}
285 +
286 static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
287 uint64_t *data, MemTxAttrs attrs)
288 {
@@ -325,6 +343,26 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
343 case A_IRS_AIDR:
344 *data = cs->irs_aidr;
345 return true;
346 +
347 + case A_IRS_IST_BASER:
348 + *data = extract64(cs->irs_ist_baser[domain], 0, 32);
349 + return true;
350 +
351 + case A_IRS_IST_BASER + 4:
352 + *data = extract64(cs->irs_ist_baser[domain], 32, 32);
353 + return true;
354 +
355 + case A_IRS_IST_STATUSR:
356 + /*
357 + * For QEMU writes to IRS_IST_BASER and IRS_MAP_L2_ISTR take effect
358 + * instantaneously, and the guest can never see the IDLE bit as 0.
359 + */
360 + *data = R_IRS_IST_STATUSR_IDLE_MASK;
361 + return true;
362 +
363 + case A_IRS_IST_CFGR:
364 + *data = cs->irs_ist_cfgr[domain];
365 + return true;
366 }
367
368 return false;
@@ -333,18 +371,54 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset,
371 static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset,
372 uint64_t data, MemTxAttrs attrs)
373 {
374 + GICv5Common *cs = ARM_GICV5_COMMON(s);
375 +
376 + switch (offset) {
377 + case A_IRS_IST_BASER:
378 + irs_ist_baser_write(s, domain,
379 + deposit64(cs->irs_ist_baser[domain], 0, 32, data));
380 + return true;
381 + case A_IRS_IST_BASER + 4:
382 + irs_ist_baser_write(s, domain,
383 + deposit64(cs->irs_ist_baser[domain], 32, 32, data));
384 + return true;
385 + case A_IRS_IST_CFGR:
386 + if (FIELD_EX64(cs->irs_ist_baser[domain], IRS_IST_BASER, VALID)) {
387 + qemu_log_mask(LOG_GUEST_ERROR,
388 + "guest tried to write IRS_IST_CFGR for %s config frame "
389 + "while IST_BASER.VALID set\n", domain_name[domain]);
390 + } else {
391 + cs->irs_ist_cfgr[domain] = data;
392 + }
393 + return true;
394 + }
395 +
396 return false;
397 }
398
399 static bool config_readll(GICv5 *s, GICv5Domain domain, hwaddr offset,
400 uint64_t *data, MemTxAttrs attrs)
401 {
402 + GICv5Common *cs = ARM_GICV5_COMMON(s);
403 +
404 + switch (offset) {
405 + case A_IRS_IST_BASER:
406 + *data = cs->irs_ist_baser[domain];
407 + return true;
408 + }
409 +
410 return false;
411 }
412
413 static bool config_writell(GICv5 *s, GICv5Domain domain, hwaddr offset,
414 uint64_t data, MemTxAttrs attrs)
415 {
416 + switch (offset) {
417 + case A_IRS_IST_BASER:
418 + irs_ist_baser_write(s, domain, data);
419 + return true;
420 + }
421 +
422 return false;
423 }
424
hw/intc/arm_gicv5_common.c
+4
@@ -60,6 +60,10 @@ void gicv5_common_init_irqs_and_mmio(GICv5Common *cs,
60
61 static void gicv5_common_reset_hold(Object *obj, ResetType type)
62 {
63 + GICv5Common *cs = ARM_GICV5_COMMON(obj);
64 +
65 + memset(cs->irs_ist_baser, 0, sizeof(cs->irs_ist_baser));
66 + memset(cs->irs_ist_cfgr, 0, sizeof(cs->irs_ist_cfgr));
67 }
68
69 static void gicv5_common_init(Object *obj)
include/hw/intc/arm_gicv5_common.h
+3
@@ -64,6 +64,9 @@ struct GICv5Common {
64
65 MemoryRegion iomem[NUM_GICV5_DOMAINS];
66
67 + uint64_t irs_ist_baser[NUM_GICV5_DOMAINS];
68 + uint32_t irs_ist_cfgr[NUM_GICV5_DOMAINS];
69 +
70 /* Bits here are set for each physical interrupt domain implemented */
71 uint8_t implemented_domains;
72