Commit 59f2b19e5e for qemu.org
commit 59f2b19e5e79562c213a1cee3ce01489543a9f93
Author: Peter Maydell <peter.maydell@linaro.org>
Date: Tue Oct 13 09:38:10 2026 +0100
hw/intc/arm_gicv5: Ignore low bits in L1_ISTE.L2_ADDR
The GICv5 spec defines that an L2 IST is always aligned to its size,
by stating that bits [N:0] of the address are 0 where
N = 11 + (2 * L2SZ)
We were missing this check, and only aligning by applying
R_L1_ISTE_L2_ADDR_MASK, so we would only enforce 4K alignment even if
the L2 IST was 16K or 64K.
Add the missing masking of low bits. We already needed to calculate
the number of bits needed to index each byte in the L2 table, so add
it to the GICv5ISTConfig to save having to re-calculate it later.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index 3c50238634..2b08f8feec 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -595,6 +595,11 @@ static bool get_l2_iste_addr(GICv5Common *cs, const GICv5ISTConfig *cfg,
return false;
}
l2_base = l1_iste & R_L1_ISTE_L2_ADDR_MASK;
+ /*
+ * The effective base address of the L2 table is always
+ * aligned to the size of the L2 table.
+ */
+ l2_base &= ~MAKE_64BIT_MASK(0, cfg->l2bits);
id = extract32(id, 0, cfg->l2_idx_bits);
} else {
/* 1-level table */
@@ -1358,6 +1363,7 @@ static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value)
cfg->id_bits = id_bits;
cfg->istsz = 1 << istbits;
cfg->l2_idx_bits = l2_idx_bits;
+ cfg->l2bits = l2bits;
cfg->structure = FIELD_EX64(cs->irs_ist_cfgr[domain],
IRS_IST_CFGR, STRUCTURE);
diff --git a/include/hw/intc/arm_gicv5.h b/include/hw/intc/arm_gicv5.h
index b8baf003ad..d763a7939c 100644
--- a/include/hw/intc/arm_gicv5.h
+++ b/include/hw/intc/arm_gicv5.h
@@ -23,6 +23,7 @@ typedef struct GICv5ISTConfig {
uint8_t id_bits; /* number of bits in an ID for this table */
uint8_t l2_idx_bits; /* number of ID bits that index into L2 table */
uint8_t istsz; /* L2 ISTE size in bytes */
+ uint8_t l2bits; /* bits needed to index L2 table in bytes */
bool structure; /* true if using 2-level table */
bool valid; /* true if this table is valid and usable */
/* This caches IST information about pending LPIs */