[PATCH] KVM: arm64: pkvm: Adopt MARKER() to define host hypercall ranges

Fuad Tabba tabba at google.com
Wed Apr 15 02:56:17 PDT 2026


Hi Marc,

On Tue, 14 Apr 2026 at 17:05, Marc Zyngier <maz at kernel.org> wrote:
>
> The EL2 code defines ranges of host hypercalls that are either
> enabled at boot-time only, used by [nh]VHE KVM, or reserved to pKVM.
>
> The way these ranges are delineated is error prone, as the enum symbols
> defining the limits are expressed in terms of actual function symbols.
> This means that should a new function be added, special care must be
> taken to also update the limit symbol.
>
> Improve this by reusing the mechanism introduced for the vcpu_sysreg
> enum, which uses a MARKER() macro and some extra trickery to make
> the limit symbol standalone. Crucially, the limit symbol has the
> same value as the *following* symbol.
>
> The handle_host_hcall() function is then updated to make use of
> the new limit definitions and get rid of the brittle default
> upper limit. This allows for some more strict checks at build
> time, and the removal of an comparison at run time.

This is pretty neat. There is still the issue of a hole, i.e., adding
an enum in the middle but forgetting to add a function, but that is
caught in handle_host_hcall(). I can't think of an easy way to catch
that though (xarray that initializes both?)
>
> Signed-off-by: Marc Zyngier <maz at kernel.org>

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

Cheers,
/fuad


> ---
>  arch/arm64/include/asm/kvm_asm.h   | 12 ++++++++++--
>  arch/arm64/include/asm/kvm_host.h  |  3 ---
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 10 +++++-----
>  3 files changed, 15 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index 37414440cee7f..fa033be6141ad 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -50,6 +50,9 @@
>
>  #include <linux/mm.h>
>
> +#define MARKER(m)                              \
> +       m, __after_##m = m - 1
> +
>  enum __kvm_host_smccc_func {
>         /* Hypercalls that are unavailable once pKVM has finalised. */
>         /* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */
> @@ -59,8 +62,10 @@ enum __kvm_host_smccc_func {
>         __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
>         __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
>         __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
> +
> +       MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
> +
>         __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
> -       __KVM_HOST_SMCCC_FUNC_MIN_PKVM = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
>
>         /* Hypercalls that are always available and common to [nh]VHE/pKVM. */
>         __KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
> @@ -76,7 +81,8 @@ enum __kvm_host_smccc_func {
>         __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
>         __KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
>         __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
> -       __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM = __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
> +
> +       MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
>
>         /* Hypercalls that are available only when pKVM has finalised. */
>         __KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
> @@ -108,6 +114,8 @@ enum __kvm_host_smccc_func {
>         __KVM_HOST_SMCCC_FUNC___tracing_reset,
>         __KVM_HOST_SMCCC_FUNC___tracing_enable_event,
>         __KVM_HOST_SMCCC_FUNC___tracing_write_event,
> +
> +       MARKER(__KVM_HOST_SMCCC_FUNC_MAX)
>  };
>
>  #define DECLARE_KVM_VHE_SYM(sym)       extern char sym[]
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 851f6171751c0..44211e86f5ebd 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -450,9 +450,6 @@ struct kvm_vcpu_fault_info {
>         r = __VNCR_START__ + ((VNCR_ ## r) / 8),        \
>         __after_##r = __MAX__(__before_##r - 1, r)
>
> -#define MARKER(m)                              \
> -       m, __after_##m = m - 1
> -
>  enum vcpu_sysreg {
>         __INVALID_SYSREG__,   /* 0 is reserved as an invalid value */
>         MPIDR_EL1,      /* MultiProcessor Affinity Register */
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 73f2e0221e703..9e44c05cf780e 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -748,9 +748,11 @@ 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, hcall_max = -1;
> +       unsigned long hcall_min = 0, hcall_max = __KVM_HOST_SMCCC_FUNC_MAX;
>         hcall_t hfn;
>
> +       BUILD_BUG_ON(ARRAY_SIZE(host_hcall) != __KVM_HOST_SMCCC_FUNC_MAX);
> +
>         /*
>          * If pKVM has been initialised then reject any calls to the
>          * early "privileged" hypercalls. Note that we cannot reject
> @@ -763,16 +765,14 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
>         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;
> +               hcall_max = __KVM_HOST_SMCCC_FUNC_PKVM_ONLY;
>         }
>
>         id &= ~ARM_SMCCC_CALL_HINTS;
>         id -= KVM_HOST_SMCCC_ID(0);
>
> -       if (unlikely(id < hcall_min || id > hcall_max ||
> -                    id >= ARRAY_SIZE(host_hcall))) {
> +       if (unlikely(id < hcall_min || id >= hcall_max))
>                 goto inval;
> -       }
>
>         hfn = host_hcall[id];
>         if (unlikely(!hfn))
> --
> 2.47.3
>



More information about the linux-arm-kernel mailing list