Re: [PATCH v2 09/11] KVM: arm64: Type-check hypercall arguments at the caller
From: Fuad Tabba <fuad.tabba@linux.dev>
Date: 2026-08-03 18:34:32
Also in:
kvmarm, linux-arm-kernel, lkml
On Mon, 3 Aug 2026 at 18:59, Marc Zyngier [off-list ref] wrote: ...
quoted
+/* + * 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, ...) \ + static __always_inline \ + ret nvhe_hvc_##name(__KVM_HCALL_MAP(__KVM_HCALL_DECL, __VA_ARGS__)) \ + { \ + return (ret)__kvm_call_hyp_nvhe(name, \ + __KVM_HCALL_MAP(__KVM_HCALL_ARGS, __VA_ARGS__));\ + } + +#define DECLARE_KVM_HOST_HCALL_VOID(name, ...) \ + static __always_inline \ + void nvhe_hvc_##name(__KVM_HCALL_MAP(__KVM_HCALL_DECL, __VA_ARGS__)) \ + { \ + __kvm_call_hyp_nvhe(name, \ + __KVM_HCALL_MAP(__KVM_HCALL_ARGS, __VA_ARGS__));\ + }I'll bite! ;-) void is a type, not the absence of a type. And returning void is perfectly valid. So with this in mind, I got rid of the *_VOID() helpers altogether, see below.
This looks better. I've built and boot tested it, and the generated code is identical. I noticed is that gcc and clang complain about "return (void)expr" under -Wpedantic, since ISO C only allows it from C23. We never build with that, right? So it doesn't bite ;) Cheers, /fuad
quoted hunk ↗ jump to hunk
Thanks, M.diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h index 3958396a83345..0b1b10d4212da 100644 --- a/arch/arm64/include/asm/kvm_hcall.h +++ b/arch/arm64/include/asm/kvm_hcall.h@@ -88,26 +88,12 @@ struct vgic_v5_cpu_if; __KVM_HCALL_MAP(__KVM_HCALL_ARGS, __VA_ARGS__));\ } -#define DECLARE_KVM_HOST_HCALL_VOID(name, ...) \ - static __always_inline \ - void nvhe_hvc_##name(__KVM_HCALL_MAP(__KVM_HCALL_DECL, __VA_ARGS__)) \ - { \ - __kvm_call_hyp_nvhe(name, \ - __KVM_HCALL_MAP(__KVM_HCALL_ARGS, __VA_ARGS__));\ - } - #define DECLARE_KVM_HOST_HCALL0(ret, name) \ static __always_inline ret nvhe_hvc_##name(void) \ { \ return (ret)__kvm_call_hyp_nvhe(name); \ } -#define DECLARE_KVM_HOST_HCALL0_VOID(name) \ - static __always_inline void nvhe_hvc_##name(void) \ - { \ - __kvm_call_hyp_nvhe(name); \ - } - #define kvm_call_hyp_nvhe(f, ...) nvhe_hvc_##f(__VA_ARGS__) /*@@ -148,12 +134,8 @@ struct vgic_v5_cpu_if; */ #define DECLARE_KVM_HOST_HCALL(ret, name, ...) \ typedef ret kvm_host_hcall_sig_##name(__KVM_HCALL_MAP(__KVM_HCALL_DECL, __VA_ARGS__)); -#define DECLARE_KVM_HOST_HCALL_VOID(name, ...) \ - typedef void kvm_host_hcall_sig_##name(__KVM_HCALL_MAP(__KVM_HCALL_DECL, __VA_ARGS__)); #define DECLARE_KVM_HOST_HCALL0(ret, name) \ typedef ret kvm_host_hcall_sig_##name(void); -#define DECLARE_KVM_HOST_HCALL0_VOID(name) \ - typedef void kvm_host_hcall_sig_##name(void); #endif /* __KVM_NVHE_HYPERVISOR__ */ /* Hypercalls that are unavailable once pKVM has finalised. */@@ -164,52 +146,52 @@ DECLARE_KVM_HOST_HCALL(unsigned long, __pkvm_create_private_mapping, phys_addr_t, phys, size_t, size, u64, prot) DECLARE_KVM_HOST_HCALL(int, __pkvm_cpu_set_vector, enum arm64_hyp_spectre_vector, slot) -DECLARE_KVM_HOST_HCALL0_VOID(__kvm_enable_ssbs) -DECLARE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs) +DECLARE_KVM_HOST_HCALL0(void, __kvm_enable_ssbs) +DECLARE_KVM_HOST_HCALL0(void, __vgic_v3_init_lrs) DECLARE_KVM_HOST_HCALL0(u64, __vgic_v3_get_gic_config) DECLARE_KVM_HOST_HCALL0(int, __pkvm_prot_finalize) /* Hypercalls that are always available and common to [nh]VHE/pKVM. */ -DECLARE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, +DECLARE_KVM_HOST_HCALL(void, __kvm_adjust_pc, struct kvm_vcpu __kern *, vcpu) DECLARE_KVM_HOST_HCALL(int, __kvm_vcpu_run, struct kvm_vcpu __kern *, vcpu) -DECLARE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, +DECLARE_KVM_HOST_HCALL0(void, __kvm_flush_vm_context) +DECLARE_KVM_HOST_HCALL(void, __kvm_tlb_flush_vmid_ipa, struct kvm_s2_mmu __kern *, mmu, phys_addr_t, ipa, int, level) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, +DECLARE_KVM_HOST_HCALL(void, __kvm_tlb_flush_vmid_ipa_nsh, struct kvm_s2_mmu __kern *, mmu, phys_addr_t, ipa, int, level) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, +DECLARE_KVM_HOST_HCALL(void, __kvm_tlb_flush_vmid, struct kvm_s2_mmu __kern *, mmu) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, +DECLARE_KVM_HOST_HCALL(void, __kvm_tlb_flush_vmid_range, struct kvm_s2_mmu __kern *, mmu, phys_addr_t, start, unsigned long, pages) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, +DECLARE_KVM_HOST_HCALL(void, __kvm_flush_cpu_context, struct kvm_s2_mmu __kern *, mmu) -DECLARE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, +DECLARE_KVM_HOST_HCALL(void, __kvm_timer_set_cntvoff, u64, cntvoff) DECLARE_KVM_HOST_HCALL(int, __tracing_load, void __kern *, desc_hva, size_t, desc_size) -DECLARE_KVM_HOST_HCALL0_VOID(__tracing_unload) +DECLARE_KVM_HOST_HCALL0(void, __tracing_unload) DECLARE_KVM_HOST_HCALL(int, __tracing_enable, bool, enable) DECLARE_KVM_HOST_HCALL(int, __tracing_swap_reader, unsigned int, cpu) -DECLARE_KVM_HOST_HCALL_VOID(__tracing_update_clock, +DECLARE_KVM_HOST_HCALL(void, __tracing_update_clock, u32, mult, u32, shift, u64, epoch_ns, u64, epoch_cyc) DECLARE_KVM_HOST_HCALL(int, __tracing_reset, unsigned int, cpu) DECLARE_KVM_HOST_HCALL(int, __tracing_enable_event, unsigned short, id, bool, enable) -DECLARE_KVM_HOST_HCALL_VOID(__tracing_write_event, +DECLARE_KVM_HOST_HCALL(void, __tracing_write_event, u64, id) -DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, +DECLARE_KVM_HOST_HCALL(void, __vgic_v3_save_aprs, struct vgic_v3_cpu_if __kern *, cpu_if) -DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, +DECLARE_KVM_HOST_HCALL(void, __vgic_v3_restore_vmcr_aprs, struct vgic_v3_cpu_if __kern *, cpu_if) -DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, +DECLARE_KVM_HOST_HCALL(void, __vgic_v5_save_apr, struct vgic_v5_cpu_if __kern *, cpu_if) -DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, +DECLARE_KVM_HOST_HCALL(void, __vgic_v5_restore_vmcr_apr, struct vgic_v5_cpu_if __kern *, cpu_if) /* Hypercalls that are available only when pKVM has finalised. */@@ -232,7 +214,7 @@ DECLARE_KVM_HOST_HCALL(int, __pkvm_host_test_clear_young_guest, DECLARE_KVM_HOST_HCALL(int, __pkvm_host_mkyoung_guest, u64, gfn) DECLARE_KVM_HOST_HCALL0(int, __pkvm_reserve_vm) -DECLARE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, +DECLARE_KVM_HOST_HCALL(void, __pkvm_unreserve_vm, pkvm_handle_t, handle) DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vm, struct kvm __kern *, host_kvm, void __kern *, vm_hva,@@ -249,10 +231,10 @@ DECLARE_KVM_HOST_HCALL(int, __pkvm_start_teardown_vm, pkvm_handle_t, handle) DECLARE_KVM_HOST_HCALL(int, __pkvm_finalize_teardown_vm, pkvm_handle_t, handle) -DECLARE_KVM_HOST_HCALL_VOID(__pkvm_vcpu_load, +DECLARE_KVM_HOST_HCALL(void, __pkvm_vcpu_load, pkvm_handle_t, handle, unsigned int, vcpu_idx, u64, hcr_el2) -DECLARE_KVM_HOST_HCALL0_VOID(__pkvm_vcpu_put) -DECLARE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, +DECLARE_KVM_HOST_HCALL0(void, __pkvm_vcpu_put) +DECLARE_KVM_HOST_HCALL(void, __pkvm_tlb_flush_vmid, pkvm_handle_t, handle) #endif /* __ARM64_KVM_HCALL_H__ */ --Without deviation from the norm, progress is not possible.