Re: [PATCH v1 09/11] KVM: arm64: Type-check hypercall arguments at the caller

Marc Zyngier <[email protected]> Thu, 30 Jul 2026 13:37:49 +0100
Newsgroups org.kernel.vger.linux-trace-kernel,dev.linux.lists.kvmarm,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On Mon, 20 Jul 2026 17:13:41 +0100,
Fuad Tabba <[email protected]> wrote:
> 
> kvm_call_hyp_nvhe() reduces its target to an SMCCC function number, so
> the compiler never sees a callable: arguments that are wrong in number,
> type or order are silently marshalled into registers. The kvm_call_hyp()
> wrappers only catch this on the VHE branch, and the pKVM-only hypercalls
> have no such branch.
> 
> Declare each hypercall's signature once in kvm_hcall.h and generate a
> typed stub from it, in the mold of the syscall wrappers. Make
> kvm_call_hyp_nvhe() resolve to the stub so every caller is checked
> against the declared signature; a stale or mistyped call now fails to
> compile. The stubs inline to the same SMCCC call the untyped macro used
> to make: the compiled callers are unchanged, apart from hypercall
> returns now being tested at their declared width.
> 
> The stage-2 protection arguments are declared u64 rather than
> enum kvm_pgtable_prot, as kvm_pgtable.h includes linux/kvm_host.h and
> the enum cannot be completed here.
> 
> Assisted-by: Antigravity:gemini-3.1-pro
> Signed-off-by: Fuad Tabba <[email protected]>
> ---
>  arch/arm64/include/asm/kvm_hcall.h | 165 ++++++++++++++++++++++++++++-
>  arch/arm64/kvm/hyp_trace.c         |   2 +-
>  2 files changed, 165 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
> index d925b2c28a3d8..51bfd14748464 100644
> --- a/arch/arm64/include/asm/kvm_hcall.h
> +++ b/arch/arm64/include/asm/kvm_hcall.h
> @@ -16,12 +16,35 @@
>  
>  #include <asm/barrier.h>
>  #include <asm/kvm_asm.h>
> +#include <asm/spectre.h>
>  #include <asm/virt.h>
>  
>  typedef u16 pkvm_handle_t;
>  
> +struct kvm;
> +struct kvm_s2_mmu;
> +struct kvm_vcpu;
> +struct vgic_v3_cpu_if;
> +struct vgic_v5_cpu_if;
> +
> +/*
> + * Hypercall signatures are declared as (type, name) argument pairs.
> + * __KVM_HCALL_MAP() applies a macro to each pair, in the mold of __MAP()
> + * in <linux/syscalls.h>.
> + */
> +#define __KVM_HCALL_MAP1(m, t, a, ...) m(t, a)
> +#define __KVM_HCALL_MAP2(m, t, a, ...) m(t, a), __KVM_HCALL_MAP1(m, __VA_ARGS__)
> +#define __KVM_HCALL_MAP3(m, t, a, ...) m(t, a), __KVM_HCALL_MAP2(m, __VA_ARGS__)
> +#define __KVM_HCALL_MAP4(m, t, a, ...) m(t, a), __KVM_HCALL_MAP3(m, __VA_ARGS__)
> +#define __KVM_HCALL_MAP5(m, t, a, ...) m(t, a), __KVM_HCALL_MAP4(m, __VA_ARGS__)
> +#define __KVM_HCALL_MAP6(m, t, a, ...) m(t, a), __KVM_HCALL_MAP5(m, __VA_ARGS__)
> +#define __KVM_HCALL_MAP(n, ...) __KVM_HCALL_MAP##n(__VA_ARGS__)
> +
> +#define __KVM_HCALL_DECL(t, a)	t a
> +#define __KVM_HCALL_ARGS(t, a)	a
> +
>  #ifndef __KVM_NVHE_HYPERVISOR__
> -#define kvm_call_hyp_nvhe(f, ...)					\
> +#define __kvm_call_hyp_nvhe(f, ...)					\
>  	({								\
>  		struct arm_smccc_res res;				\
>  									\
> @@ -33,6 +56,43 @@ typedef u16 pkvm_handle_t;
>  		res.a1;							\
>  	})
>  
> +/*
> + * Generate a typed stub for each declared hypercall. kvm_call_hyp_nvhe()
> + * resolves to the stub, so a call with the wrong argument count or types
> + * fails to compile instead of being silently truncated to an SMCCC function
> + * number and a pile of registers. The stub inlines to the same SMCCC call
> + * the untyped macro used to make.
> + */
> +#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...)			\
> +	static __always_inline						\
> +	ret nvhe_hvc_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__)) \
> +	{								\
> +		return (ret)__kvm_call_hyp_nvhe(name,			\
> +			__KVM_HCALL_MAP(x, __KVM_HCALL_ARGS, __VA_ARGS__)); \
> +	}

One thing I find absolutely horrible is to have to specify the number
of parameters here. It is already bad to have to comma-separate
everything, but having to count them is too hard for me ;-).

We already have facilities to count the number of parameters to a
macro (see the COUNT_ARGS macro). You could make use of it all over
the place.

Thanks,

	M.

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