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 <[email protected]> --- hw/intc/arm_gicv5.c | 71 ++++++++++++++++++++++++++++++ hw/intc/arm_gicv5_common.c | 4 ++ include/hw/intc/arm_gicv5_common.h | 3 ++ 3 files changed, 78 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index f34bb81966..f5933197ea 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -265,6 +265,24 @@ REG64(IRS_SWERR_SYNDROMER0, 0x3c8) REG64(IRS_SWERR_SYNDROMER1, 0x3d0) FIELD(IRS_SWERR_SYNDROMER2, ADDR, 3, 53) +static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value) +{ + GICv5Common *cs = ARM_GICV5_COMMON(s); + + if (FIELD_EX64(cs->irs_ist_baser[domain], IRS_IST_BASER, VALID)) { + /* If VALID is set, ADDR is RO and we can only update VALID */ + bool valid = FIELD_EX64(value, IRS_IST_BASER, VALID); + if (valid) { + /* Ignore 1->1 transition */ + return; + } + cs->irs_ist_baser[domain] = FIELD_DP64(cs->irs_ist_baser[domain], + IRS_IST_BASER, VALID, valid); + return; + } + cs->irs_ist_baser[domain] = value; +} + static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, uint64_t *data, MemTxAttrs attrs) { @@ -323,6 +341,26 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, case A_IRS_AIDR: *data = cs->irs_aidr; return true; + + case A_IRS_IST_BASER: + *data = extract64(cs->irs_ist_baser[domain], 0, 32); + return true; + + case A_IRS_IST_BASER + 4: + *data = extract64(cs->irs_ist_baser[domain], 32, 32); + return true; + + case A_IRS_IST_STATUSR: + /* + * For QEMU writes to IRS_IST_BASER and IRS_MAP_L2_ISTR take effect + * instantaneously, and the guest can never see the IDLE bit as 0. + */ + *data = R_IRS_IST_STATUSR_IDLE_MASK; + return true; + + case A_IRS_IST_CFGR: + *data = cs->irs_ist_cfgr[domain]; + return true; } return false; } @@ -330,18 +368,51 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset, uint64_t data, MemTxAttrs attrs) { + GICv5Common *cs = ARM_GICV5_COMMON(s); + + switch (offset) { + case A_IRS_IST_BASER: + irs_ist_baser_write(s, domain, + deposit64(cs->irs_ist_baser[domain], 0, 32, data)); + return true; + case A_IRS_IST_BASER + 4: + irs_ist_baser_write(s, domain, + deposit64(cs->irs_ist_baser[domain], 32, 32, data)); + return true; + case A_IRS_IST_CFGR: + if (FIELD_EX64(cs->irs_ist_baser[domain], IRS_IST_BASER, VALID)) { + qemu_log_mask(LOG_GUEST_ERROR, + "guest tried to write IRS_IST_CFGR for %s config frame " + "while IST_BASER.VALID set\n", domain_name[domain]); + } else { + cs->irs_ist_cfgr[domain] = data; + } + return true; + } return false; } static bool config_readll(GICv5 *s, GICv5Domain domain, hwaddr offset, uint64_t *data, MemTxAttrs attrs) { + GICv5Common *cs = ARM_GICV5_COMMON(s); + + switch (offset) { + case A_IRS_IST_BASER: + *data = cs->irs_ist_baser[domain]; + return true; + } return false; } static bool config_writell(GICv5 *s, GICv5Domain domain, hwaddr offset, uint64_t data, MemTxAttrs attrs) { + switch (offset) { + case A_IRS_IST_BASER: + irs_ist_baser_write(s, domain, data); + return true; + } return false; } diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c index 046dcdf5a3..751df2001c 100644 --- a/hw/intc/arm_gicv5_common.c +++ b/hw/intc/arm_gicv5_common.c @@ -62,6 +62,10 @@ void gicv5_common_init_irqs_and_mmio(GICv5Common *cs, static void gicv5_common_reset_hold(Object *obj, ResetType type) { + GICv5Common *cs = ARM_GICV5_COMMON(obj); + + memset(cs->irs_ist_baser, 0, sizeof(cs->irs_ist_baser)); + memset(cs->irs_ist_cfgr, 0, sizeof(cs->irs_ist_cfgr)); } static void gicv5_common_init(Object *obj) diff --git a/include/hw/intc/arm_gicv5_common.h b/include/hw/intc/arm_gicv5_common.h index 7db2c87ddc..2a49d58679 100644 --- a/include/hw/intc/arm_gicv5_common.h +++ b/include/hw/intc/arm_gicv5_common.h @@ -62,6 +62,9 @@ struct GICv5Common { MemoryRegion iomem[NUM_GICV5_DOMAINS]; + uint64_t irs_ist_baser[NUM_GICV5_DOMAINS]; + uint32_t irs_ist_cfgr[NUM_GICV5_DOMAINS]; + /* Bits here are set for each physical interrupt domain implemented */ uint8_t implemented_domains; -- 2.43.0
