[PATCH v3 11/13] KVM: selftests: Add macros to handle simple VMX instructions

From: Sean Christopherson

Date: Wed Aug 26 2026 - 19:46:45 EST


Add macros to build helpers for VMXON, VMPTRLD, and VMCLEAR, i.e. the VMX
instructions that take a VMCS address as input, and don't have outputs.
Getting the params right is annoying, especially when using KVM_ASM_SAFE().

As a bonus, this adds non-asserting double-underscores versions of VMXON
and VMCLEAR for "free".

Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
tools/testing/selftests/kvm/include/x86/vmx.h | 71 +++++++------------
1 file changed, 26 insertions(+), 45 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 5c46ae95c4c3..3def8df902a2 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -313,58 +313,39 @@ struct vmx_msr_entry {
__GUEST_ASSERT(!__r, __stringify(insn) "[0x%lx] hit %s", \
__pa, __r < 0 ? "VM-Fail" : ex_str(__r))

-static inline void vmxon(u64 phys)
-{
- u8 ret;
-
- __asm__ __volatile__ ("vmxon %[pa]; setna %[ret]"
- : [ret]"=rm"(ret)
- : [pa]"m"(phys)
- : "cc", "memory");
-
- __GUEST_ASSERT(!ret, "vmxon [0x%lx] failed", phys);
+#define BUILD_VMCS_ASM_HELPERS(insn) \
+static inline int __##insn(u64 vmcs_pa) \
+{ \
+ u64 error_code; \
+ u8 vector; \
+ u8 failed; \
+ \
+ asm volatile(KVM_ASM_SAFE(__stringify(insn) " %[pa]") \
+ "\n\tsetna %[failed]" \
+ : KVM_ASM_SAFE_OUTPUTS(vector, error_code), \
+ [failed]"=qm"(failed) \
+ : [pa]"m"(vmcs_pa) \
+ : "cc", "memory", KVM_ASM_SAFE_CLOBBERS); \
+ \
+ return vector ? vector : failed ? -EINVAL : 0; \
+} \
+ \
+static inline void insn(u64 vmcs_pa) \
+{ \
+ int ret = __##insn(vmcs_pa); \
+ \
+ GUEST_ASSERT_VMX_INSN_SUCCEEDED(insn, ret, vmcs_pa); \
}

+BUILD_VMCS_ASM_HELPERS(vmxon)
+BUILD_VMCS_ASM_HELPERS(vmptrld)
+BUILD_VMCS_ASM_HELPERS(vmclear)
+
static inline void vmxoff(void)
{
__asm__ __volatile__("vmxoff");
}

-static inline void vmclear(u64 vmcs_pa)
-{
- u8 ret;
-
- __asm__ __volatile__ ("vmclear %[pa]; setna %[ret]"
- : [ret]"=rm"(ret)
- : [pa]"m"(vmcs_pa)
- : "cc", "memory");
-
- __GUEST_ASSERT(!ret, "vmclear [0x%lx] failed\n", vmcs_pa);
-}
-
-static inline int __vmptrld(u64 vmcs_pa)
-{
- u64 error_code;
- u8 vector;
- u8 failed;
-
- asm volatile(KVM_ASM_SAFE("vmptrld %[pa]")
- "\n\tsetna %[failed]"
- : KVM_ASM_SAFE_OUTPUTS(vector, error_code),
- [failed]"=qm"(failed)
- : [pa]"m"(vmcs_pa)
- : "cc", "memory", KVM_ASM_SAFE_CLOBBERS);
-
- return vector ? vector : failed ? -EINVAL : 0;
-}
-
-static inline void vmptrld(u64 vmcs_pa)
-{
- int ret = __vmptrld(vmcs_pa);
-
- GUEST_ASSERT_VMX_INSN_SUCCEEDED(vmptrld, ret, vmcs_pa);
-}
-
static inline u64 vmptrst(void)
{
u64 value = 0;
--
2.55.0.887.g758fc8c411-goog