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