[PATCH v2 21/36] KVM: arm64: gic-v5: Finalize GICv5 PPIs and generate mask
Sascha Bischoff
Sascha.Bischoff at arm.com
Fri Dec 19 07:52:43 PST 2025
We only want to expose a subset of the PPIs to a guest. If a PPI does
not have an owner, it is not being actively driven by a device. The
SW_PPI is a special case, as it is likely for userspace to wish to
inject that.
Therefore, just prior to running the guest for the first time, we need
to finalize the PPIs. A mask is generated which, when combined with
trapping a guest's PPI accesses, allows for the guest's view of the
PPI to be filtered.
Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
arch/arm64/kvm/arm.c | 4 +++
arch/arm64/kvm/vgic/vgic-v5.c | 60 +++++++++++++++++++++++++++++++++++
include/kvm/arm_vgic.h | 9 ++++++
3 files changed, 73 insertions(+)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index b7cf9d86aabb7..94f8d13ab3b58 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -888,6 +888,10 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
return ret;
}
+ ret = vgic_v5_finalize_ppi_state(kvm);
+ if (ret)
+ return ret;
+
if (is_protected_kvm_enabled()) {
ret = pkvm_create_hyp_vm(kvm);
if (ret)
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index c7ecc4f40b1e5..f1fa63e67c1f6 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -81,6 +81,66 @@ static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
return priority_mask;
}
+static int vgic_v5_finalize_state(struct kvm_vcpu *vcpu)
+{
+ if (!ppi_caps)
+ return -ENXIO;
+
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[0] = 0;
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[1] = 0;
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[0] = 0;
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[1] = 0;
+ for (int i = 0; i < VGIC_V5_NR_PRIVATE_IRQS; ++i) {
+ int reg = i / 64;
+ u64 bit = BIT_ULL(i % 64);
+ struct vgic_irq *irq = &vcpu->arch.vgic_cpu.private_irqs[i];
+
+ raw_spin_lock(&irq->irq_lock);
+
+ /*
+ * We only expose PPIs with an owner or thw SW_PPI to
+ * the guest.
+ */
+ if (!irq->owner && irq->intid == GICV5_SW_PPI)
+ goto unlock;
+
+ /*
+ * If the PPI isn't implemented, we can't pass it
+ * through to a guest anyhow.
+ */
+ if (!(ppi_caps->impl_ppi_mask[reg] & bit))
+ goto unlock;
+
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_mask[reg] |= bit;
+
+ if (irq->config == VGIC_CONFIG_LEVEL)
+ vcpu->arch.vgic_cpu.vgic_v5.vgic_ppi_hmr[reg] |= bit;
+
+unlock:
+ raw_spin_unlock(&irq->irq_lock);
+ }
+
+ return 0;
+}
+
+int vgic_v5_finalize_ppi_state(struct kvm *kvm)
+{
+ struct kvm_vcpu *vcpu;
+ unsigned long c;
+ int ret;
+
+ if (!vgic_is_v5(kvm))
+ return 0;
+
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ ret = vgic_v5_finalize_state(vcpu);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
struct vgic_irq *irq)
{
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index b5180edbd1165..dc7bac0226b3c 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -455,6 +455,13 @@ struct vgic_v5_cpu_if {
u64 vgic_ich_ppi_enabler_exit[2];
u64 vgic_ppi_pendr_exit[2];
+ /*
+ * We only expose a subset of PPIs to the guest. This subset
+ * is a combination of the PPIs that are actually implemented
+ * and what we actually choose to expose.
+ */
+ u64 vgic_ppi_mask[2];
+
/*
* The ICSR is re-used across host and guest, and hence it needs to be
* saved/restored. Only one copy is required as the host should block
@@ -592,6 +599,8 @@ int vgic_v4_load(struct kvm_vcpu *vcpu);
void vgic_v4_commit(struct kvm_vcpu *vcpu);
int vgic_v4_put(struct kvm_vcpu *vcpu);
+int vgic_v5_finalize_ppi_state(struct kvm *kvm);
+
bool vgic_state_is_nested(struct kvm_vcpu *vcpu);
/* CPU HP callbacks */
--
2.34.1
More information about the linux-arm-kernel
mailing list