irs_ist_baser_write() has code that fills in a GICv5ISTConfig based on various register fields, including sanitizing uses of reserved values, enforcing minimum and maximum values, and pre-calculating how many bits index the L2 table.
We will want exactly the same logic for setting up GICv5ISTConfig structs for a VM's LPI and SPI IST structures based on the fields in the L2 VMTE. Factor out the "fill in the GICv5ISTConfig" code to a separate function that we can call. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 181 ++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 81 deletions(-) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index f03b790cf41..8cf7e363f29 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -976,6 +976,96 @@ void gicv5_deactivate(GICv5Common *cs, uint32_t id, GICv5Domain domain, irs_recalc_hppi(s, domain, iaffid); } +static void initialize_ist_config(GICv5Common *cs, GICv5Domain domain, + GICv5ISTConfig *cfg, + hwaddr base, + uint8_t id_bits, uint8_t istsz, uint8_t l2sz, + bool structure) +{ + uint8_t istbits, l2bits, l2_idx_bits; + int tableszbits; + + switch (istsz) { + case 0: + case 3: /* reserved: acts like the minimum required size */ + istbits = 2; + break; + case 1: + istbits = 3; + break; + case 2: + istbits = 4; + break; + default: + g_assert_not_reached(); + } + switch (l2sz) { + case 0: + case 3: /* reserved; CONSTRAINED UNPREDICTABLE */ + l2bits = 12; /* 4K: 12 bits */ + break; + case 1: + l2bits = 14; /* 16K: 14 bits */ + break; + case 2: + l2bits = 16; /* 64K: 16 bits */ + break; + default: + g_assert_not_reached(); + } + /* + * Calculate how many bits of an ID index the L2 table + * (e.g. if we need 14 bits to index each byte in a 16K L2 table, + * but each entry is 4 bytes wide then we need 14 - 2 = 12 bits + * to index an entry in the table). + */ + l2_idx_bits = l2bits - istbits; + cfg->base = base; + cfg->txattrs = irs_txattrs(cs, domain); + cfg->id_bits = id_bits; + cfg->istsz = 1 << istbits; + cfg->l2_idx_bits = l2_idx_bits; + cfg->l2bits = l2bits; + cfg->structure = structure; + + /* + * Bits [N:0] of the base addr are ignored, to enforce that in a + * 1-level IST it is aligned to the size of the ISTE array, + * and in a 2-level IST it is aligned to the size of the L1 table. + * The spec defines N in terms of the raw L2SZ, ISTSZ and LPI_ID_BITS + * fields, but we have already sanitized these to + * istbits = ISTSZ + 2 + * l2bits = (L2SZ * 2) + 12 + * id_bits = LPI_ID_BITS + * We have also already enforced the "bottom 6 bits are 0" via + * the fixed field mask, so can skip the Max() operation. + * We want tableszbits == the number of bits to zero, which is N + 1. + */ + if (cfg->structure) { + /* + * L1 table is indexed by the (id_bits - l2_idx_bits) bits in + * the ID, so has 2^(id_bits - l2_idx_bits) entries, and each + * entry is 8 bytes == 2^3. + */ + tableszbits = id_bits - l2_idx_bits + 3; + } else { + /* table has 2^id_bits entries of 2^istbits size each */ + tableszbits = id_bits + istbits; + } + cfg->base &= ~MAKE_64BIT_MASK(0, tableszbits); + + if (!cfg->lpi_cache) { + /* + * Keys are GINT_TO_POINTER(intid), so we want the g_direct_hash + * and g_direct_equal hash and equality functions. We don't + * want to free the keys, but we do want to free the values + * (which are pointer-to-uint32_t). + */ + cfg->lpi_cache = g_hash_table_new_full(NULL, NULL, NULL, g_free); + } + cfg->valid = true; +} + static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value) { GICv5Common *cs = ARM_GICV5_COMMON(s); @@ -1086,92 +1176,21 @@ static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value) * sanitize the reserved values, and expand fields out into byte counts. */ GICv5ISTConfig *cfg = &s->phys_lpi_config[domain]; - uint8_t istbits, l2bits, l2_idx_bits; - int tableszbits; + hwaddr base = cs->irs_ist_baser[domain] & R_IRS_IST_BASER_ADDR_MASK; uint8_t id_bits = FIELD_EX64(cs->irs_ist_cfgr[domain], IRS_IST_CFGR, LPI_ID_BITS); - id_bits = MIN(MAX(id_bits, QEMU_GICV5_MIN_LPI_ID_BITS), QEMU_GICV5_ID_BITS); - - switch (FIELD_EX64(cs->irs_ist_cfgr[domain], IRS_IST_CFGR, ISTSZ)) { - case 0: - case 3: /* reserved: acts like the minimum required size */ - istbits = 2; - break; - case 1: - istbits = 3; - break; - case 2: - istbits = 4; - break; - default: - g_assert_not_reached(); - } - switch (FIELD_EX64(cs->irs_ist_cfgr[domain], IRS_IST_CFGR, L2SZ)) { - case 0: - case 3: /* reserved; CONSTRAINED UNPREDICTABLE */ - l2bits = 12; /* 4K: 12 bits */ - break; - case 1: - l2bits = 14; /* 16K: 14 bits */ - break; - case 2: - l2bits = 16; /* 64K: 16 bits */ - break; - default: - g_assert_not_reached(); - } - /* - * Calculate how many bits of an ID index the L2 table - * (e.g. if we need 14 bits to index each byte in a 16K L2 table, - * but each entry is 4 bytes wide then we need 14 - 2 = 12 bits - * to index an entry in the table). - */ - l2_idx_bits = l2bits - istbits; - cfg->base = cs->irs_ist_baser[domain] & R_IRS_IST_BASER_ADDR_MASK; - cfg->txattrs = irs_txattrs(cs, domain), - 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], + uint8_t istsz = FIELD_EX64(cs->irs_ist_cfgr[domain], + IRS_IST_CFGR, ISTSZ); + uint8_t l2sz = FIELD_EX64(cs->irs_ist_cfgr[domain], + IRS_IST_CFGR, L2SZ); + bool structure = FIELD_EX64(cs->irs_ist_cfgr[domain], IRS_IST_CFGR, STRUCTURE); - /* - * Bits [N:0] of the base addr are ignored, to enforce that in a - * 1-level IST it is aligned to the size of the ISTE array, - * and in a 2-level IST it is aligned to the size of the L1 table. - * The spec defines N in terms of the raw L2SZ, ISTSZ and LPI_ID_BITS - * fields, but we have already sanitized these to - * istbits = ISTSZ + 2 - * l2bits = (L2SZ * 2) + 12 - * id_bits = LPI_ID_BITS - * We have also already enforced the "bottom 6 bits are 0" via - * R_IRS_IST_BASER_ADDR_MASK, so can skip the Max() operation. - * We want tableszbits == the number of bits to zero, which is N + 1. - */ - if (cfg->structure) { - /* - * L1 table is indexed by the (id_bits - l2_idx_bits) bits in - * the ID, so has 2^(id_bits - l2_idx_bits) entries, and each - * entry is 8 bytes == 2^3. - */ - tableszbits = id_bits - l2_idx_bits + 3; - } else { - /* table has 2^id_bits entries of 2^istbits size each */ - tableszbits = id_bits + istbits; - } - cfg->base &= ~MAKE_64BIT_MASK(0, tableszbits); + id_bits = MIN(MAX(id_bits, QEMU_GICV5_MIN_LPI_ID_BITS), QEMU_GICV5_ID_BITS); + + initialize_ist_config(cs, domain, cfg, base, id_bits, + istsz, l2sz, structure); - if (!cfg->lpi_cache) { - /* - * Keys are GINT_TO_POINTER(intid), so we want the g_direct_hash - * and g_direct_equal hash and equality functions. We don't - * want to free the keys, but we do want to free the values - * (which are pointer-to-uint32_t). - */ - cfg->lpi_cache = g_hash_table_new_full(NULL, NULL, NULL, g_free); - } - cfg->valid = true; trace_gicv5_ist_valid(domain_name[domain], cfg->base, cfg->id_bits, cfg->l2_idx_bits, cfg->istsz, cfg->structure); irs_recalc_hppi_all_cpus(s, domain); -- 2.43.0
