@samitouri / QOSamiQemu / commits / a05e512406

hw/intc/arm_gicv5: Implement gicv5_request_config()

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 <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260327111700.795099-26-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC a05e5124068a36c72db85986b03da500facda40a
3 files changed +127
hw/intc/arm_gicv5.c
+102
@@ -297,6 +297,19 @@ FIELD(L2_ISTE, HWU, 9, 2)
297 FIELD(L2_ISTE, PRIORITY, 11, 5)
298 FIELD(L2_ISTE, IAFFID, 16, 16)
299
300 +/*
301 + * Format used for gicv5_request_config() return value, which matches
302 + * the ICC_ICSR_EL1 bit layout.
303 + */
304 +FIELD(ICSR, F, 0, 1)
305 +FIELD(ICSR, ENABLED, 1, 1)
306 +FIELD(ICSR, PENDING, 2, 1)
307 +FIELD(ICSR, IRM, 3, 1)
308 +FIELD(ICSR, ACTIVE, 4, 1)
309 +FIELD(ICSR, HM, 5, 1)
310 +FIELD(ICSR, PRIORITY, 11, 5)
311 +FIELD(ICSR, IAFFID, 32, 16)
312 +
313 static MemTxAttrs irs_txattrs(GICv5Common *cs, GICv5Domain domain)
314 {
315 /*
@@ -713,6 +726,95 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
726 }
727 }
728
729 +static uint64_t l2_iste_to_icsr(GICv5Common *cs, const GICv5ISTConfig *cfg,
730 + uint32_t id)
731 +{
732 + uint64_t icsr = 0;
733 + const uint32_t *l2_iste_p;
734 + L2_ISTE_Handle h;
735 +
736 + l2_iste_p = get_l2_iste(cs, cfg, id, &h);
737 + if (!l2_iste_p) {
738 + return R_ICSR_F_MASK;
739 + }
740 +
741 + /*
742 + * The field locations in the L2 ISTE do not line up with the
743 + * corresponding fields in the ICC_ICSR_EL1 register, so we need
744 + * to extract and deposit them individually.
745 + */
746 + icsr = FIELD_DP64(icsr, ICSR, F, 0);
747 + icsr = FIELD_DP64(icsr, ICSR, ENABLED, FIELD_EX32(*l2_iste_p, L2_ISTE, ENABLE));
748 + icsr = FIELD_DP64(icsr, ICSR, PENDING, FIELD_EX32(*l2_iste_p, L2_ISTE, PENDING));
749 + icsr = FIELD_DP64(icsr, ICSR, IRM, FIELD_EX32(*l2_iste_p, L2_ISTE, IRM));
750 + icsr = FIELD_DP64(icsr, ICSR, ACTIVE, FIELD_EX32(*l2_iste_p, L2_ISTE, ACTIVE));
751 + icsr = FIELD_DP64(icsr, ICSR, HM, FIELD_EX32(*l2_iste_p, L2_ISTE, HM));
752 + icsr = FIELD_DP64(icsr, ICSR, PRIORITY, FIELD_EX32(*l2_iste_p, L2_ISTE, PRIORITY));
753 + icsr = FIELD_DP64(icsr, ICSR, IAFFID, FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID));
754 +
755 + return icsr;
756 +}
757 +
758 +static uint64_t spi_state_to_icsr(GICv5SPIState *spi)
759 +{
760 + uint64_t icsr = 0;
761 +
762 + icsr = FIELD_DP64(icsr, ICSR, F, 0);
763 + icsr = FIELD_DP64(icsr, ICSR, ENABLED, spi->enabled);
764 + icsr = FIELD_DP64(icsr, ICSR, PENDING, spi->pending);
765 + icsr = FIELD_DP64(icsr, ICSR, IRM, spi->irm);
766 + icsr = FIELD_DP64(icsr, ICSR, ACTIVE, spi->active);
767 + icsr = FIELD_DP64(icsr, ICSR, HM, spi->hm);
768 + icsr = FIELD_DP64(icsr, ICSR, PRIORITY, spi->priority);
769 + icsr = FIELD_DP64(icsr, ICSR, IAFFID, spi->iaffid);
770 +
771 + return icsr;
772 +}
773 +
774 +uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
775 + GICv5IntType type, bool virtual)
776 +{
777 + GICv5 *s = ARM_GICV5(cs);
778 + uint64_t icsr;
779 +
780 + if (virtual) {
781 + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_request_config: tried to "
782 + "read config of a virtual interrupt\n");
783 + return R_ICSR_F_MASK;
784 + }
785 +
786 + switch (type) {
787 + case GICV5_LPI:
788 + {
789 + const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
790 +
791 + icsr = l2_iste_to_icsr(cs, cfg, id);
792 + trace_gicv5_request_config(domain_name[domain], inttype_name(type),
793 + virtual, id, icsr);
794 + return icsr;
795 + }
796 + case GICV5_SPI:
797 + {
798 + GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
799 +
800 + if (!spi) {
801 + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_request_config: tried to "
802 + "read config of unreachable SPI %d\n", id);
803 + return R_ICSR_F_MASK;
804 + }
805 +
806 + icsr = spi_state_to_icsr(spi);
807 + trace_gicv5_request_config(domain_name[domain], inttype_name(type),
808 + virtual, id, icsr);
809 + return icsr;
810 + }
811 + default:
812 + qemu_log_mask(LOG_GUEST_ERROR, "gicv5_request_config: tried to "
813 + "read config of bad interrupt type %d\n", type);
814 + return R_ICSR_F_MASK;
815 + }
816 +}
817 +
818 static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value)
819 {
820 GICv5Common *cs = ARM_GICV5_COMMON(s);
hw/intc/trace-events
+1
@@ -240,6 +240,7 @@ gicv5_set_enabled(const char *domain, const char *type, bool virtual, uint32_t i
240 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"
241 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"
242 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"
243 +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
244
245 # arm_gicv5_common.c
246 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"
include/hw/intc/arm_gicv5_stream.h
+24
@@ -126,4 +126,28 @@ void gicv5_set_handling(GICv5Common *cs, uint32_t id,
126 void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
127 GICv5RoutingMode irm, GICv5Domain domain,
128 GICv5IntType type, bool virtual);
129 +
130 +/**
131 + * gicv5_request_config
132 + * @cs: GIC IRS to send command to
133 + * @id: interrupt ID
134 + * @domain: interrupt domain to act on
135 + * @type: interrupt type (LPI or SPI)
136 + * @virtual: true if this is a virtual interrupt
137 + *
138 + * Query the current configuration of an interrupt; matches stream
139 + * interface RequestConfig command from CPUIF to IRS and the
140 + * RequestConfigAck reply to it.
141 + *
142 + * In the real stream protocol, the RequestConfigAck packet has the
143 + * same information as the register but in a different order; we use
144 + * the register order, not the packet order, so we don't need to
145 + * unpack and repack in the cpuif.
146 + *
147 + * Returns: the config of the interrupt, in the format used by
148 + * ICC_ICSR_EL1.
149 + */
150 +uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
151 + GICv5IntType type, bool virtual);
152 +
153 #endif