[PATCH v3 10/36] KVM: arm64: gic-v5: Detect implemented PPIs on boot
Sascha Bischoff
Sascha.Bischoff at arm.com
Fri Jan 9 09:04:42 PST 2026
As part of booting the system and initialising KVM, create and
populate a mask of the implemented PPIs. This mask allows future PPI
operations (such as save/restore or state, or syncing back into the
shadow state) to only consider PPIs that are actually implemented on
the host.
The set of implemented virtual PPIs matches the set of implemented
physical PPIs for a GICv5 host. Therefore, this mask represents all
PPIs that could ever by used by a GICv5-based guest on a specific
host.
Only architected PPIs are currently supported in KVM with
GICv5. Moreover, as KVM only supports a subset of all possible PPIS
(Timers, PMU, GICv5 SW_PPI) the PPI mask only includes these PPIs, if
present. The timers are always assumed to be present; if we have KVM
we have EL2, which means that we have the EL1 & EL2 Timer PPIs. If we
have a PMU (v3), then the PMUIRQ is present. The GICv5 SW_PPI is
always assumed to be present.
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
arch/arm64/kvm/vgic/vgic-init.c | 4 ++++
arch/arm64/kvm/vgic/vgic-v5.c | 36 ++++++++++++++++++++++++++++++
arch/arm64/kvm/vgic/vgic.h | 1 +
include/kvm/arm_vgic.h | 5 +++++
include/linux/irqchip/arm-gic-v5.h | 10 +++++++++
5 files changed, 56 insertions(+)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 86c149537493f..653364299154e 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -750,5 +750,9 @@ int kvm_vgic_hyp_init(void)
}
kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq);
+
+ /* Always safe to call */
+ vgic_v5_get_implemented_ppis();
+
return 0;
}
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 23d0a495d855e..85f9ee5b0ccad 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -8,6 +8,8 @@
#include "vgic.h"
+static struct vgic_v5_ppi_caps *ppi_caps;
+
/*
* Probe for a vGICv5 compatible interrupt controller, returning 0 on success.
* Currently only supports GICv3-based VMs on a GICv5 host, and hence only
@@ -53,3 +55,37 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
return 0;
}
+
+/*
+ * Not all PPIs are guaranteed to be implemented for GICv5. Deterermine which
+ * ones are, and generate a mask.
+ */
+void vgic_v5_get_implemented_ppis(void)
+{
+ if (!cpus_have_final_cap(ARM64_HAS_GICV5_CPUIF))
+ return;
+
+ /* Never freed again */
+ ppi_caps = kzalloc(sizeof(*ppi_caps), GFP_KERNEL);
+ if (!ppi_caps)
+ return;
+
+ ppi_caps->impl_ppi_mask[0] = 0;
+ ppi_caps->impl_ppi_mask[1] = 0;
+
+ /*
+ * If we have KVM, we have EL2, which means that we have support for the
+ * EL1 and EL2 P & V timers.
+ */
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_CNTHP);
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_CNTV);
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_CNTHV);
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_CNTP);
+
+ /* The SW_PPI should be available */
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_SW_PPI);
+
+ /* The PMUIRQ is available if we have the PMU */
+ if (system_supports_pmuv3())
+ ppi_caps->impl_ppi_mask[0] |= BIT_ULL(GICV5_ARCH_PPI_PMUIRQ);
+}
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5f0fc96b4dc29..15f6afe6b75e1 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -362,6 +362,7 @@ void vgic_debug_init(struct kvm *kvm);
void vgic_debug_destroy(struct kvm *kvm);
int vgic_v5_probe(const struct gic_kvm_info *info);
+void vgic_v5_get_implemented_ppis(void);
static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
{
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 67dac9bcc7b01..8529fcbbfd49b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -414,6 +414,11 @@ struct vgic_v3_cpu_if {
unsigned int used_lrs;
};
+/* What PPI capabilities does a GICv5 host have */
+struct vgic_v5_ppi_caps {
+ u64 impl_ppi_mask[2];
+};
+
struct vgic_cpu {
/* CPU vif control registers for world switch */
union {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index 68ddcdb1cec5a..d0103046ceb5e 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -24,6 +24,16 @@
#define GICV5_HWIRQ_TYPE_LPI UL(0x2)
#define GICV5_HWIRQ_TYPE_SPI UL(0x3)
+/*
+ * Architected PPIs
+ */
+#define GICV5_ARCH_PPI_SW_PPI 0x3
+#define GICV5_ARCH_PPI_PMUIRQ 0x17
+#define GICV5_ARCH_PPI_CNTHP 0x1a
+#define GICV5_ARCH_PPI_CNTV 0x1b
+#define GICV5_ARCH_PPI_CNTHV 0x1c
+#define GICV5_ARCH_PPI_CNTP 0x1e
+
/*
* Tables attributes
*/
--
2.34.1
More information about the linux-arm-kernel
mailing list