Re: [PATCH v3 06/36] KVM: arm64: Remove is_protected_kvm_enabled() checks from hypercalls

Fuad Tabba
2026-03-11T10:17:00Z

On Thu, 5 Mar 2026 at 14:44, Will Deacon <will@kernel.org> wrote:
>
> When pKVM is not enabled, the host shouldn't issue pKVM-specific
> hypercalls and so there's no point checking for this in the pKVM
> hypercall handlers.
>
> Remove the redundant is_protected_kvm_enabled() checks from each
> hypercall and instead rejig the hypercall table so that the
> pKVM-specific hypercalls are unreachable when pKVM is not being used.
>
> Reviewed-by: Quentin Perret <qperret@google.com>
> Signed-off-by: Will Deacon <will@kernel.org>

Reviewed-by: Fuad Tabba <tabba@google.com>

Cheers,
/fuad

> ---
> arch/arm64/include/asm/kvm_asm.h | 24 +++++++-----
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 63 ++++++++++--------------------
> 2 files changed, 34 insertions(+), 53 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index a1ad12c72ebf..7b72aac4730d 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -51,7 +51,7 @@
> #include <linux/mm.h>
>
> enum __kvm_host_smccc_func {
> - /* Hypercalls available only prior to pKVM finalisation */
> + /* Hypercalls that are unavailable once pKVM has finalised. */
> /* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */
> __KVM_HOST_SMCCC_FUNC___pkvm_init = __KVM_HOST_SMCCC_FUNC___kvm_hyp_init + 1,
> __KVM_HOST_SMCCC_FUNC___pkvm_create_private_mapping,
> @@ -60,16 +60,9 @@ enum __kvm_host_smccc_func {
> __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
> __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
> __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
> + __KVM_HOST_SMCCC_FUNC_MIN_PKVM = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
>
> - /* Hypercalls available after pKVM finalisation */
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_hyp,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_share_guest,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_guest,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_relax_perms_guest,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_wrprotect_guest,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_test_clear_young_guest,
> - __KVM_HOST_SMCCC_FUNC___pkvm_host_mkyoung_guest,
> + /* Hypercalls that are always available and common to [nh]VHE/pKVM. */
> __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
> __KVM_HOST_SMCCC_FUNC___kvm_vcpu_run,
> __KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
> @@ -81,6 +74,17 @@ 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_MAX_NO_PKVM = __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
> +
> + /* Hypercalls that are available only when pKVM has finalised. */
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_hyp,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_share_guest,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_guest,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_relax_perms_guest,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_wrprotect_guest,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_test_clear_young_guest,
> + __KVM_HOST_SMCCC_FUNC___pkvm_host_mkyoung_guest,
> __KVM_HOST_SMCCC_FUNC___pkvm_reserve_vm,
> __KVM_HOST_SMCCC_FUNC___pkvm_unreserve_vm,
> __KVM_HOST_SMCCC_FUNC___pkvm_init_vm,
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index e7790097db93..127decc2dd2b 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -169,9 +169,6 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
> DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
> struct pkvm_hyp_vcpu *hyp_vcpu;
>
> - if (!is_protected_kvm_enabled())
> - return;
> -
> hyp_vcpu = pkvm_load_hyp_vcpu(handle, vcpu_idx);
> if (!hyp_vcpu)
> return;
> @@ -188,12 +185,8 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
>
> static void handle___pkvm_vcpu_put(struct kvm_cpu_context *host_ctxt)
> {
> - struct pkvm_hyp_vcpu *hyp_vcpu;
> + struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
>
> - if (!is_protected_kvm_enabled())
> - return;
> -
> - hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
> if (hyp_vcpu)
> pkvm_put_hyp_vcpu(hyp_vcpu);
> }
> @@ -257,9 +250,6 @@ static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
> struct pkvm_hyp_vcpu *hyp_vcpu;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
> if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
> goto out;
> @@ -281,9 +271,6 @@ static void handle___pkvm_host_unshare_guest(struct kvm_cpu_context *host_ctxt)
> struct pkvm_hyp_vm *hyp_vm;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vm = get_np_pkvm_hyp_vm(handle);
> if (!hyp_vm)
> goto out;
> @@ -301,9 +288,6 @@ static void handle___pkvm_host_relax_perms_guest(struct kvm_cpu_context *host_ct
> struct pkvm_hyp_vcpu *hyp_vcpu;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
> if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
> goto out;
> @@ -321,9 +305,6 @@ static void handle___pkvm_host_wrprotect_guest(struct kvm_cpu_context *host_ctxt
> struct pkvm_hyp_vm *hyp_vm;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vm = get_np_pkvm_hyp_vm(handle);
> if (!hyp_vm)
> goto out;
> @@ -343,9 +324,6 @@ static void handle___pkvm_host_test_clear_young_guest(struct kvm_cpu_context *ho
> struct pkvm_hyp_vm *hyp_vm;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vm = get_np_pkvm_hyp_vm(handle);
> if (!hyp_vm)
> goto out;
> @@ -362,9 +340,6 @@ static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
> struct pkvm_hyp_vcpu *hyp_vcpu;
> int ret = -EINVAL;
>
> - if (!is_protected_kvm_enabled())
> - goto out;
> -
> hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
> if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
> goto out;
> @@ -424,12 +399,8 @@ static void handle___kvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
> static void handle___pkvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
> {
> DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
> - struct pkvm_hyp_vm *hyp_vm;
> + struct pkvm_hyp_vm *hyp_vm = get_np_pkvm_hyp_vm(handle);
>
> - if (!is_protected_kvm_enabled())
> - return;
> -
> - hyp_vm = get_np_pkvm_hyp_vm(handle);
> if (!hyp_vm)
> return;
>
> @@ -603,14 +574,6 @@ static const hcall_t host_hcall[] = {
> HANDLE_FUNC(__vgic_v3_get_gic_config),
> HANDLE_FUNC(__pkvm_prot_finalize),
>
> - HANDLE_FUNC(__pkvm_host_share_hyp),
> - HANDLE_FUNC(__pkvm_host_unshare_hyp),
> - HANDLE_FUNC(__pkvm_host_share_guest),
> - HANDLE_FUNC(__pkvm_host_unshare_guest),
> - HANDLE_FUNC(__pkvm_host_relax_perms_guest),
> - HANDLE_FUNC(__pkvm_host_wrprotect_guest),
> - HANDLE_FUNC(__pkvm_host_test_clear_young_guest),
> - HANDLE_FUNC(__pkvm_host_mkyoung_guest),
> HANDLE_FUNC(__kvm_adjust_pc),
> HANDLE_FUNC(__kvm_vcpu_run),
> HANDLE_FUNC(__kvm_flush_vm_context),
> @@ -622,6 +585,15 @@ 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(__pkvm_host_share_hyp),
> + HANDLE_FUNC(__pkvm_host_unshare_hyp),
> + HANDLE_FUNC(__pkvm_host_share_guest),
> + HANDLE_FUNC(__pkvm_host_unshare_guest),
> + HANDLE_FUNC(__pkvm_host_relax_perms_guest),
> + HANDLE_FUNC(__pkvm_host_wrprotect_guest),
> + HANDLE_FUNC(__pkvm_host_test_clear_young_guest),
> + HANDLE_FUNC(__pkvm_host_mkyoung_guest),
> HANDLE_FUNC(__pkvm_reserve_vm),
> HANDLE_FUNC(__pkvm_unreserve_vm),
> HANDLE_FUNC(__pkvm_init_vm),
> @@ -635,7 +607,7 @@ static const hcall_t host_hcall[] = {
> static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> {
> DECLARE_REG(unsigned long, id, host_ctxt, 0);
> - unsigned long hcall_min = 0;
> + unsigned long hcall_min = 0, hcall_max = -1;
> hcall_t hfn;
>
> /*
> @@ -647,14 +619,19 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> * basis. This is all fine, however, since __pkvm_prot_finalize
> * returns -EPERM after the first call for a given CPU.
> */
> - if (static_branch_unlikely(&kvm_protected_mode_initialized))
> - hcall_min = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize;
> + if (static_branch_unlikely(&kvm_protected_mode_initialized)) {
> + hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM;
> + } else {
> + hcall_max = __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM;
> + }
>
> id &= ~ARM_SMCCC_CALL_HINTS;
> id -= KVM_HOST_SMCCC_ID(0);
>
> - if (unlikely(id < hcall_min || id >= ARRAY_SIZE(host_hcall)))
> + if (unlikely(id < hcall_min || id > hcall_max ||
> + id >= ARRAY_SIZE(host_hcall))) {
> goto inval;
> + }
>
> hfn = host_hcall[id];
> if (unlikely(!hfn))
> --
> 2.53.0.473.g4a7958ca14-goog
>