Re: [PATCH v5 16/36] KVM: arm64: gic-v5: Implement direct injection of PPIs

Marc Zyngier
2026-03-04T09:35:33Z

On Thu, 26 Feb 2026 15:59:33 +0000,
Sascha Bischoff <Sascha.Bischoff@arm.com> wrote:
>
> GICv5 is able to directly inject PPI pending state into a guest using
> a mechanism called DVI whereby the pending bit for a paticular PPI is
> driven directly by the physically-connected hardware. This mechanism
> itself doesn't allow for any ID translation, so the host interrupt is
> directly mapped into a guest with the same interrupt ID.
>
> When mapping a virtual interrupt to a physical interrupt via
> kvm_vgic_map_irq for a GICv5 guest, check if the interrupt itself is a
> PPI or not. If it is, and the host's interrupt ID matches that used
> for the guest DVI is enabled, and the interrupt itself is marked as
> directly_injected.
>
> When the interrupt is unmapped again, this process is reversed, and
> DVI is disabled for the interrupt again.
>
> Note: the expectation is that a directly injected PPI is disabled on
> the host while the guest state is loaded. The reason is that although
> DVI is enabled to drive the guest's pending state directly, the host
> pending state also remains driven. In order to avoid the same PPI
> firing on both the host and the guest, the host's interrupt must be
> disabled (masked). This is left up to the code that owns the device
> generating the PPI as this needs to be handled on a per-VM basis. One
> VM might use DVI, while another might not, in which case the physical
> PPI should be enabled for the latter.
>
> Co-authored-by: Timothy Hayes <timothy.hayes@arm.com>
> Signed-off-by: Timothy Hayes <timothy.hayes@arm.com>
> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
> arch/arm64/kvm/vgic/vgic-v5.c | 15 +++++++++++++++
> arch/arm64/kvm/vgic/vgic.c | 10 ++++++++++
> arch/arm64/kvm/vgic/vgic.h | 1 +
> include/kvm/arm_vgic.h | 1 +
> 4 files changed, 27 insertions(+)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index 5b35c756887a9..f5cd9decfc26e 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -86,6 +86,21 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
> return 0;
> }
>
> +/*
> + * Sets/clears the corresponding bit in the ICH_PPI_DVIR register.
> + */
> +int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> + u32 ppi = FIELD_GET(GICV5_HWIRQ_ID, irq);
> + unsigned long *p;
> +
> + p = (unsigned long *)&cpu_if->vgic_ppi_dvir[ppi / 64];
> + __assign_bit(ppi % 64, p, dvi);
> +
> + return 0;
> +}
> +
> void vgic_v5_load(struct kvm_vcpu *vcpu)
> {
> struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 1005ff5f36235..62e58fdf611d3 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -577,12 +577,22 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
> irq->host_irq = host_irq;
> irq->hwintid = data->hwirq;
> irq->ops = ops;
> +
> + if (vgic_is_v5(vcpu->kvm) &&
> + __irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, irq->intid))
> + irq->directly_injected = !vgic_v5_set_ppi_dvi(vcpu, irq->hwintid,
> + true);
> +

Huh. A couple of things here:

- under what conditions would irq->directly_injected not be set to
true for a PPI? That can never happen here AFAICT.

- we have per-IRQ operations, and PPIs do have such ops attached to
them. Why can't this be moved to such a callback?

> return 0;
> }
>
> /* @irq->irq_lock must be held */
> static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
> {
> + if (irq->directly_injected && vgic_is_v5(irq->target_vcpu->kvm))
> + WARN_ON(vgic_v5_set_ppi_dvi(irq->target_vcpu, irq->hwintid, false));
> +
> + irq->directly_injected = false;
> irq->hw = false;
> irq->hwintid = 0;
> irq->ops = NULL;
> diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> index 81d464d26534f..d7fe867a27b64 100644
> --- a/arch/arm64/kvm/vgic/vgic.h
> +++ b/arch/arm64/kvm/vgic/vgic.h
> @@ -364,6 +364,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);
> +int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);

Doing the above would keep these things private to the vgic-v5
implementation.

Thanks,

M.

--
Without deviation from the norm, progress is not possible.