Implement the gicv5_request_config() function, which corresponds to the RequestConfig command and its RequestConfigAck reply.
We provide read_l2_iste() as a separate function to keep the "access the in-guest-memory data structure" layer separate from the "operate on the L2_ISTE values" layer. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 92 ++++++++++++++++++++++++++++++ hw/intc/trace-events | 1 + include/hw/intc/arm_gicv5_stream.h | 24 ++++++++ 3 files changed, 117 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 4d99200122..51b25775c4 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -297,6 +297,19 @@ FIELD(L2_ISTE, HWU, 9, 2) FIELD(L2_ISTE, PRIORITY, 11, 5) FIELD(L2_ISTE, IAFFID, 16, 16) +/* + * Format used for gicv5_request_config() return value, which matches + * the ICC_ICSR_EL1 bit layout. + */ +FIELD(ICSR, F, 0, 1) +FIELD(ICSR, ENABLED, 1, 1) +FIELD(ICSR, PENDING, 2, 1) +FIELD(ICSR, IRM, 3, 1) +FIELD(ICSR, ACTIVE, 4, 1) +FIELD(ICSR, HM, 5, 1) +FIELD(ICSR, PRIORITY, 11, 5) +FIELD(ICSR, IAFFID, 32, 16) + static MemTxAttrs irs_txattrs(GICv5Common *cs, GICv5Domain domain) { /* @@ -684,6 +697,85 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid, put_l2_iste(cs, cfg, &h); } +static uint64_t l2_iste_to_icsr(GICv5Common *cs, const GICv5ISTConfig *cfg, + uint32_t id) +{ + uint64_t icsr = 0; + const uint32_t *l2_iste_p; + L2_ISTE_Handle h; + + l2_iste_p = get_l2_iste(cs, cfg, id, &h); + if (!l2_iste_p) { + return R_ICSR_F_MASK; + } + + /* + * The field locations in the L2 ISTE do not line up with the + * corresponding fields in the ICC_ICSR_EL1 register, so we need to + * extract and deposit them individually. + */ + icsr = FIELD_DP64(icsr, ICSR, F, 0); + icsr = FIELD_DP64(icsr, ICSR, ENABLED, FIELD_EX32(*l2_iste_p, L2_ISTE, ENABLE)); + icsr = FIELD_DP64(icsr, ICSR, PENDING, FIELD_EX32(*l2_iste_p, L2_ISTE, PENDING)); + icsr = FIELD_DP64(icsr, ICSR, IRM, FIELD_EX32(*l2_iste_p, L2_ISTE, IRM)); + icsr = FIELD_DP64(icsr, ICSR, ACTIVE, FIELD_EX32(*l2_iste_p, L2_ISTE, ACTIVE)); + icsr = FIELD_DP64(icsr, ICSR, HM, FIELD_EX32(*l2_iste_p, L2_ISTE, HM)); + icsr = FIELD_DP64(icsr, ICSR, PRIORITY, FIELD_EX32(*l2_iste_p, L2_ISTE, PRIORITY)); + icsr = FIELD_DP64(icsr, ICSR, IAFFID, FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID)); + + return icsr; +} + +static uint64_t spi_state_to_icsr(GICv5SPIState *spi) +{ + uint64_t icsr = 0; + + icsr = FIELD_DP64(icsr, ICSR, F, 0); + icsr = FIELD_DP64(icsr, ICSR, ENABLED, spi->enabled); + icsr = FIELD_DP64(icsr, ICSR, PENDING, spi->pending); + icsr = FIELD_DP64(icsr, ICSR, IRM, spi->irm); + icsr = FIELD_DP64(icsr, ICSR, ACTIVE, spi->active); + icsr = FIELD_DP64(icsr, ICSR, HM, spi->hm); + icsr = FIELD_DP64(icsr, ICSR, PRIORITY, spi->priority); + icsr = FIELD_DP64(icsr, ICSR, IAFFID, spi->iaffid); + + return icsr; +} + +uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain, + GICv5IntType type, bool virtual) +{ + const GICv5ISTConfig *cfg; + GICv5 *s = ARM_GICV5(cs); + uint64_t icsr; + + if (virtual) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_request_config: tried to " + "read config of a virtual interrupt\n"); + return R_ICSR_F_MASK; + } + if (type == GICV5_SPI) { + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain); + + if (!spi) { + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_request_config: tried to " + "read config of unreachable SPI %d\n", id); + return R_ICSR_F_MASK; + } + + icsr = spi_state_to_icsr(spi); + trace_gicv5_request_config(domain_name[domain], inttype_name(type), + virtual, id, icsr); + return icsr; + } + cfg = &s->phys_lpi_config[domain]; + + icsr = l2_iste_to_icsr(cs, cfg, id); + trace_gicv5_request_config(domain_name[domain], inttype_name(type), + virtual, id, icsr); + return icsr; +} + static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value) { GICv5Common *cs = ARM_GICV5_COMMON(s); diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 37ca6e8e12..409935e15a 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -240,6 +240,7 @@ gicv5_set_enabled(const char *domain, const char *type, bool virtual, uint32_t i gicv5_set_pending(const char *domain, const char *type, bool virtual, uint32_t id, bool pending) "GICv5 IRS SetPending %s %s virtual:%d ID %u pending %d" gicv5_set_handling(const char *domain, const char *type, bool virtual, uint32_t id, int handling) "GICv5 IRS SetHandling %s %s virtual:%d ID %u handling %d" gicv5_set_target(const char *domain, const char *type, bool virtual, uint32_t id, uint32_t iaffid, int irm) "GICv5 IRS SetTarget %s %s virtual:%d ID %u IAFFID %u routingmode %d" +gicv5_request_config(const char *domain, const char *type, bool virtual, uint32_t id, uint64_t icsr) "GICv5 IRS RequestConfig %s %s virtual:%d ID %u ICSR 0x%" PRIx64 # arm_gicv5_common.c gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u" diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h index db0e3e01c6..1f00e8ffff 100644 --- a/include/hw/intc/arm_gicv5_stream.h +++ b/include/hw/intc/arm_gicv5_stream.h @@ -126,4 +126,28 @@ void gicv5_set_handling(GICv5Common *cs, uint32_t id, void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid, GICv5RoutingMode irm, GICv5Domain domain, GICv5IntType type, bool virtual); + +/** + * gicv5_request_config + * @cs: GIC IRS to send command to + * @id: interrupt ID + * @domain: interrupt domain to act on + * @type: interrupt type (LPI or SPI) + * @virtual: true if this is a virtual interrupt + * + * Query the current configuration of an interrupt; matches stream + * interface RequestConfig command from CPUIF to IRS and the RequestConfigAck + * reply to it. + * + * In the real stream protocol, the RequestConfigAck packet has the same + * information as the register but in a different order; we use the register + * order, not the packet order, so we don't need to unpack and repack in + * the cpuif. + * + * Returns: the config of the interrupt, in the format used by + * ICC_ICSR_EL1. + */ +uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain, + GICv5IntType type, bool virtual); + #endif -- 2.43.0
