[PATCH 03/43] KVM: arm64: gic-v5: Add resident/non-resident hyp calls
Marc Zyngier
maz at kernel.org
Tue Apr 28 07:28:18 PDT 2026
On Mon, 27 Apr 2026 17:07:03 +0100,
Sascha Bischoff <Sascha.Bischoff at arm.com> wrote:
>
> So far the KVM GICv5 support has been limited to PPIs. These only go
> as far out as the CPU interface, and have no interaction with the
> host's IRS. Therefore, PPIs can be directly used for guests without
> host IRS involvement. However, in order to support both SPIs and LPIs
> IRS involvement is required.
Please keep this in the cover letter. It isn't required to understand
this patch.
>
> GICv5 introduces the concept of VPE residency - a VPE can be either
> resident or non-resident. When the VPE is resident, the IRS is allowed
> to select interrupts that target that VPE (or the VM) as the HPPI
> (Highest Priority Pending Interrupt). As the IRS handles both SPIs and
> LPIs, these will only be picked as the IRS's HPPI when a VPE is
> resident.
>
> A GICv5 VPE is made resident by writing to the ICH_CONTEXTR_EL2 with a
> valid VM and VPE ID, and marking it valid in the process. This informs
> the IRS that a specific VPE is running, and that it can begin HPPI
> selection for that VPE. Making a VPE non-resident (by making the
> ICH_CONTEXTR_EL2 invalid) informs the IRS that the VPE is no longer
> running, and it stops HPPI selection for it.
>
> This change introduces two new hyp calls - one to make a VPE resident
> and its counterpart to make a VPE non-resident. As part of making a
> VPE resident, the ICH_CONTEXTR_EL2.F bit is checked in order to catch
> faults, at which point the kernel will WARN. If everything is
> configured correctly, this should not happen.
>
> Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> ---
> arch/arm64/include/asm/kvm_asm.h | 2 ++
> arch/arm64/include/asm/kvm_hyp.h | 2 ++
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 15 +++++++++++++++
> arch/arm64/kvm/hyp/vgic-v5-sr.c | 25 +++++++++++++++++++++++++
> include/kvm/arm_vgic.h | 3 +++
> 5 files changed, 47 insertions(+)
>
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index fa033be6141ad..8c69f1f4de534 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -79,6 +79,8 @@ enum __kvm_host_smccc_func {
> __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff,
> __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
> __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
> + __KVM_HOST_SMCCC_FUNC___vgic_v5_make_resident,
> + __KVM_HOST_SMCCC_FUNC___vgic_v5_make_non_resident,
> __KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
> __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
>
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index 8d06b62e7188c..5f9184276b04e 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -88,6 +88,8 @@ void __vgic_v3_restore_vmcr_aprs(struct vgic_v3_cpu_if *cpu_if);
> int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>
> /* GICv5 */
> +void __vgic_v5_make_resident(struct vgic_v5_cpu_if *cpu_if);
> +void __vgic_v5_make_non_resident(struct vgic_v5_cpu_if *cpu_if);
> void __vgic_v5_save_apr(struct vgic_v5_cpu_if *cpu_if);
> void __vgic_v5_restore_vmcr_apr(struct vgic_v5_cpu_if *cpu_if);
> /* No hypercalls for the following */
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9e44c05cf780e..804a9ffdc8594 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -672,6 +672,19 @@ static void handle___tracing_write_event(struct kvm_cpu_context *host_ctxt)
> trace_selftest(id);
> }
>
> +static void handle___vgic_v5_make_resident(struct kvm_cpu_context *host_ctxt)
> +{
> + DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> + __vgic_v5_make_resident(kern_hyp_va(cpu_if));
> +}
> +static void handle___vgic_v5_make_non_resident(struct kvm_cpu_context *host_ctxt)
> +{
> + DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> +
> + __vgic_v5_make_non_resident(kern_hyp_va(cpu_if));
> +}
> +
> static void handle___vgic_v5_save_apr(struct kvm_cpu_context *host_ctxt)
> {
> DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
> @@ -711,6 +724,8 @@ static const hcall_t host_hcall[] = {
> HANDLE_FUNC(__kvm_timer_set_cntvoff),
> HANDLE_FUNC(__vgic_v3_save_aprs),
> HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
> + HANDLE_FUNC(__vgic_v5_make_resident),
> + HANDLE_FUNC(__vgic_v5_make_non_resident),
> HANDLE_FUNC(__vgic_v5_save_apr),
> HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
>
> diff --git a/arch/arm64/kvm/hyp/vgic-v5-sr.c b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> index 6d69dfe89a96c..04c5846b9abac 100644
> --- a/arch/arm64/kvm/hyp/vgic-v5-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> @@ -7,6 +7,31 @@
>
> #include <asm/kvm_hyp.h>
>
> +void __vgic_v5_make_resident(struct vgic_v5_cpu_if *cpu_if)
> +{
> + write_sysreg_s(cpu_if->vgic_contextr, SYS_ICH_CONTEXTR_EL2);
> + isb();
> +
> + /* Catch any faults */
> + cpu_if->vgic_contextr = read_sysreg_s(SYS_ICH_CONTEXTR_EL2);
> + if (WARN_ON(FIELD_GET(ICH_CONTEXTR_EL2_F, cpu_if->vgic_contextr)))
> + return;
I don't think this is particularly useful here. With non-VHE, this
results in a panic. If there is a problem, you need to fail the vcpu
entry early, and let the caller find out.
> +
> + cpu_if->gicv5_vpe.resident = true;
> +}
> +
> +void __vgic_v5_make_non_resident(struct vgic_v5_cpu_if *cpu_if)
> +{
> + /*
> + * Make as non-resident before actually making non-resident. Avoids race
> + * with doorbell arriving.
> + */
> + cpu_if->gicv5_vpe.resident = false;
Stores and sysreg accesses are not ordered without a DSB ST in between.
> +
> + write_sysreg_s(cpu_if->vgic_contextr, SYS_ICH_CONTEXTR_EL2);
Is this really making anything non-resident? Who clears the V bit?
> + isb();
> +}
> +
> void __vgic_v5_save_apr(struct vgic_v5_cpu_if *cpu_if)
> {
> cpu_if->vgic_apr = read_sysreg_s(SYS_ICH_APR_EL2);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index fe49fb56dc3c9..d14cf4771d606 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -495,6 +495,9 @@ struct vgic_v5_cpu_if {
> */
> u64 vgic_icsr;
>
> + /* The contextr used to make VPEs resident and non-resident */
> + u64 vgic_contextr;
> +
> struct gicv5_vpe gicv5_vpe;
> };
>
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
More information about the linux-arm-kernel
mailing list