Re: [PATCH 23/30] KVM: arm64: Add hvc handler at EL2 for hypercalls from protected VMs

Vincent Donnefort
2026-01-06T15:52:54Z

On Mon, Jan 05, 2026 at 03:49:31PM +0000, Will Deacon wrote:
> Add a hypercall handler at EL2 for hypercalls originating from protected
> VMs. For now, this implements only the FEATURES and MEMINFO calls, but
> subsequent patches will implement the SHARE and UNSHARE functions
> necessary for virtio.
>
> Unhandled hypercalls (including PSCI) are passed back to the host.
>
> Signed-off-by: Will Deacon <will@kernel.org>

Reviewed-by: Vincent Donnefort <vdonnefort@google.com>

> ---
> arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 1 +
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 37 ++++++++++++++++++++++++++
> arch/arm64/kvm/hyp/nvhe/switch.c | 1 +
> 3 files changed, 39 insertions(+)
>
> diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
> index a5a7bb453f3e..c904647d2f76 100644
> --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
> +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
> @@ -88,6 +88,7 @@ struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle);
> struct pkvm_hyp_vm *get_np_pkvm_hyp_vm(pkvm_handle_t handle);
> void put_pkvm_hyp_vm(struct pkvm_hyp_vm *hyp_vm);
>
> +bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code);
> bool kvm_handle_pvm_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code);
> bool kvm_handle_pvm_restricted(struct kvm_vcpu *vcpu, u64 *exit_code);
> void kvm_init_pvm_id_regs(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index df340de59eed..5cdec49e989b 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -4,6 +4,8 @@
> * Author: Fuad Tabba <tabba@google.com>
> */
>
> +#include <kvm/arm_hypercalls.h>
> +
> #include <linux/kvm_host.h>
> #include <linux/mm.h>
>
> @@ -934,3 +936,38 @@ int __pkvm_finalize_teardown_vm(pkvm_handle_t handle)
> hyp_spin_unlock(&vm_table_lock);
> return err;
> }
> +/*
> + * Handler for protected VM HVC calls.
> + *
> + * Returns true if the hypervisor has handled the exit (and control
> + * should return to the guest) or false if it hasn't (and the handling
> + * should be performed by the host).
> + */
> +bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
> +{
> + u64 val[4] = { SMCCC_RET_INVALID_PARAMETER };
> + bool handled = true;
> +
> + switch (smccc_get_function(vcpu)) {
> + case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> + val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> + val[0] |= BIT(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO);
> + break;
> + case ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID:
> + if (smccc_get_arg1(vcpu) ||
> + smccc_get_arg2(vcpu) ||
> + smccc_get_arg3(vcpu)) {
> + break;
> + }
> +
> + val[0] = PAGE_SIZE;
> + break;
> + default:
> + /* Punt everything else back to the host, for now. */
> + handled = false;
> + }
> +
> + if (handled)
> + smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
> + return handled;
> +}
> diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
> index d3b9ec8a7c28..b62e25e8bb7e 100644
> --- a/arch/arm64/kvm/hyp/nvhe/switch.c
> +++ b/arch/arm64/kvm/hyp/nvhe/switch.c
> @@ -190,6 +190,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
>
> static const exit_handler_fn pvm_exit_handlers[] = {
> [0 ... ESR_ELx_EC_MAX] = NULL,
> + [ESR_ELx_EC_HVC64] = kvm_handle_pvm_hvc64,
> [ESR_ELx_EC_SYS64] = kvm_handle_pvm_sys64,
> [ESR_ELx_EC_SVE] = kvm_handle_pvm_restricted,
> [ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd,
> --
> 2.52.0.351.gbe84eed79e-goog
>