189b0c9f5SSean Christopherson /* SPDX-License-Identifier: GPL-2.0 */ 289b0c9f5SSean Christopherson #ifndef __KVM_X86_VMX_INSN_H 389b0c9f5SSean Christopherson #define __KVM_X86_VMX_INSN_H 489b0c9f5SSean Christopherson 589b0c9f5SSean Christopherson #include <linux/nospec.h> 689b0c9f5SSean Christopherson 789b0c9f5SSean Christopherson #include <asm/kvm_host.h> 889b0c9f5SSean Christopherson #include <asm/vmx.h> 989b0c9f5SSean Christopherson 1089b0c9f5SSean Christopherson #include "evmcs.h" 1189b0c9f5SSean Christopherson #include "vmcs.h" 1289b0c9f5SSean Christopherson 1389b0c9f5SSean Christopherson #define __ex(x) __kvm_handle_fault_on_reboot(x) 1489b0c9f5SSean Christopherson 15514ccc19SQian Cai asmlinkage void vmread_error(unsigned long field, bool fault); 16842f4be9SSean Christopherson __attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field, 17842f4be9SSean Christopherson bool fault); 1852a9fcbcSSean Christopherson void vmwrite_error(unsigned long field, unsigned long value); 1952a9fcbcSSean Christopherson void vmclear_error(struct vmcs *vmcs, u64 phys_addr); 2052a9fcbcSSean Christopherson void vmptrld_error(struct vmcs *vmcs, u64 phys_addr); 2152a9fcbcSSean Christopherson void invvpid_error(unsigned long ext, u16 vpid, gva_t gva); 2252a9fcbcSSean Christopherson void invept_error(unsigned long ext, u64 eptp, gpa_t gpa); 2352a9fcbcSSean Christopherson 2489b0c9f5SSean Christopherson static __always_inline void vmcs_check16(unsigned long field) 2589b0c9f5SSean Christopherson { 2689b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000, 2789b0c9f5SSean Christopherson "16-bit accessor invalid for 64-bit field"); 2889b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001, 2989b0c9f5SSean Christopherson "16-bit accessor invalid for 64-bit high field"); 3089b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000, 3189b0c9f5SSean Christopherson "16-bit accessor invalid for 32-bit high field"); 3289b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000, 3389b0c9f5SSean Christopherson "16-bit accessor invalid for natural width field"); 3489b0c9f5SSean Christopherson } 3589b0c9f5SSean Christopherson 3689b0c9f5SSean Christopherson static __always_inline void vmcs_check32(unsigned long field) 3789b0c9f5SSean Christopherson { 3889b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0, 3989b0c9f5SSean Christopherson "32-bit accessor invalid for 16-bit field"); 40*870c575aSHaiwei Li BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000, 41*870c575aSHaiwei Li "32-bit accessor invalid for 64-bit field"); 42*870c575aSHaiwei Li BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001, 43*870c575aSHaiwei Li "32-bit accessor invalid for 64-bit high field"); 4489b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000, 4589b0c9f5SSean Christopherson "32-bit accessor invalid for natural width field"); 4689b0c9f5SSean Christopherson } 4789b0c9f5SSean Christopherson 4889b0c9f5SSean Christopherson static __always_inline void vmcs_check64(unsigned long field) 4989b0c9f5SSean Christopherson { 5089b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0, 5189b0c9f5SSean Christopherson "64-bit accessor invalid for 16-bit field"); 5289b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001, 5389b0c9f5SSean Christopherson "64-bit accessor invalid for 64-bit high field"); 5489b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000, 5589b0c9f5SSean Christopherson "64-bit accessor invalid for 32-bit field"); 5689b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000, 5789b0c9f5SSean Christopherson "64-bit accessor invalid for natural width field"); 5889b0c9f5SSean Christopherson } 5989b0c9f5SSean Christopherson 6089b0c9f5SSean Christopherson static __always_inline void vmcs_checkl(unsigned long field) 6189b0c9f5SSean Christopherson { 6289b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0, 6389b0c9f5SSean Christopherson "Natural width accessor invalid for 16-bit field"); 6489b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000, 6589b0c9f5SSean Christopherson "Natural width accessor invalid for 64-bit field"); 6689b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001, 6789b0c9f5SSean Christopherson "Natural width accessor invalid for 64-bit high field"); 6889b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000, 6989b0c9f5SSean Christopherson "Natural width accessor invalid for 32-bit field"); 7089b0c9f5SSean Christopherson } 7189b0c9f5SSean Christopherson 7289b0c9f5SSean Christopherson static __always_inline unsigned long __vmcs_readl(unsigned long field) 7389b0c9f5SSean Christopherson { 7489b0c9f5SSean Christopherson unsigned long value; 7589b0c9f5SSean Christopherson 766e202097SSean Christopherson asm volatile("1: vmread %2, %1\n\t" 776e202097SSean Christopherson ".byte 0x3e\n\t" /* branch taken hint */ 786e202097SSean Christopherson "ja 3f\n\t" 79842f4be9SSean Christopherson 80842f4be9SSean Christopherson /* 81842f4be9SSean Christopherson * VMREAD failed. Push '0' for @fault, push the failing 82842f4be9SSean Christopherson * @field, and bounce through the trampoline to preserve 83842f4be9SSean Christopherson * volatile registers. 84842f4be9SSean Christopherson */ 85842f4be9SSean Christopherson "push $0\n\t" 86842f4be9SSean Christopherson "push %2\n\t" 87842f4be9SSean Christopherson "2:call vmread_error_trampoline\n\t" 88842f4be9SSean Christopherson 89842f4be9SSean Christopherson /* 90842f4be9SSean Christopherson * Unwind the stack. Note, the trampoline zeros out the 91842f4be9SSean Christopherson * memory for @fault so that the result is '0' on error. 92842f4be9SSean Christopherson */ 93842f4be9SSean Christopherson "pop %2\n\t" 94842f4be9SSean Christopherson "pop %1\n\t" 956e202097SSean Christopherson "3:\n\t" 966e202097SSean Christopherson 97842f4be9SSean Christopherson /* VMREAD faulted. As above, except push '1' for @fault. */ 986e202097SSean Christopherson ".pushsection .fixup, \"ax\"\n\t" 99842f4be9SSean Christopherson "4: push $1\n\t" 100842f4be9SSean Christopherson "push %2\n\t" 1016e202097SSean Christopherson "jmp 2b\n\t" 1026e202097SSean Christopherson ".popsection\n\t" 1036e202097SSean Christopherson _ASM_EXTABLE(1b, 4b) 1046e202097SSean Christopherson : ASM_CALL_CONSTRAINT, "=r"(value) : "r"(field) : "cc"); 10589b0c9f5SSean Christopherson return value; 10689b0c9f5SSean Christopherson } 10789b0c9f5SSean Christopherson 10889b0c9f5SSean Christopherson static __always_inline u16 vmcs_read16(unsigned long field) 10989b0c9f5SSean Christopherson { 11089b0c9f5SSean Christopherson vmcs_check16(field); 11189b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 11289b0c9f5SSean Christopherson return evmcs_read16(field); 11389b0c9f5SSean Christopherson return __vmcs_readl(field); 11489b0c9f5SSean Christopherson } 11589b0c9f5SSean Christopherson 11689b0c9f5SSean Christopherson static __always_inline u32 vmcs_read32(unsigned long field) 11789b0c9f5SSean Christopherson { 11889b0c9f5SSean Christopherson vmcs_check32(field); 11989b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 12089b0c9f5SSean Christopherson return evmcs_read32(field); 12189b0c9f5SSean Christopherson return __vmcs_readl(field); 12289b0c9f5SSean Christopherson } 12389b0c9f5SSean Christopherson 12489b0c9f5SSean Christopherson static __always_inline u64 vmcs_read64(unsigned long field) 12589b0c9f5SSean Christopherson { 12689b0c9f5SSean Christopherson vmcs_check64(field); 12789b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 12889b0c9f5SSean Christopherson return evmcs_read64(field); 12989b0c9f5SSean Christopherson #ifdef CONFIG_X86_64 13089b0c9f5SSean Christopherson return __vmcs_readl(field); 13189b0c9f5SSean Christopherson #else 13289b0c9f5SSean Christopherson return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32); 13389b0c9f5SSean Christopherson #endif 13489b0c9f5SSean Christopherson } 13589b0c9f5SSean Christopherson 13689b0c9f5SSean Christopherson static __always_inline unsigned long vmcs_readl(unsigned long field) 13789b0c9f5SSean Christopherson { 13889b0c9f5SSean Christopherson vmcs_checkl(field); 13989b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 14089b0c9f5SSean Christopherson return evmcs_read64(field); 14189b0c9f5SSean Christopherson return __vmcs_readl(field); 14289b0c9f5SSean Christopherson } 14389b0c9f5SSean Christopherson 14452a9fcbcSSean Christopherson #define vmx_asm1(insn, op1, error_args...) \ 14552a9fcbcSSean Christopherson do { \ 14652a9fcbcSSean Christopherson asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ 14752a9fcbcSSean Christopherson ".byte 0x2e\n\t" /* branch not taken hint */ \ 14852a9fcbcSSean Christopherson "jna %l[error]\n\t" \ 14952a9fcbcSSean Christopherson _ASM_EXTABLE(1b, %l[fault]) \ 15052a9fcbcSSean Christopherson : : op1 : "cc" : error, fault); \ 15152a9fcbcSSean Christopherson return; \ 15252a9fcbcSSean Christopherson error: \ 1533ebccdf3SThomas Gleixner instrumentation_begin(); \ 15452a9fcbcSSean Christopherson insn##_error(error_args); \ 1553ebccdf3SThomas Gleixner instrumentation_end(); \ 15652a9fcbcSSean Christopherson return; \ 15752a9fcbcSSean Christopherson fault: \ 15852a9fcbcSSean Christopherson kvm_spurious_fault(); \ 15952a9fcbcSSean Christopherson } while (0) 16052a9fcbcSSean Christopherson 16152a9fcbcSSean Christopherson #define vmx_asm2(insn, op1, op2, error_args...) \ 16252a9fcbcSSean Christopherson do { \ 16352a9fcbcSSean Christopherson asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ 16452a9fcbcSSean Christopherson ".byte 0x2e\n\t" /* branch not taken hint */ \ 16552a9fcbcSSean Christopherson "jna %l[error]\n\t" \ 16652a9fcbcSSean Christopherson _ASM_EXTABLE(1b, %l[fault]) \ 16752a9fcbcSSean Christopherson : : op1, op2 : "cc" : error, fault); \ 16852a9fcbcSSean Christopherson return; \ 16952a9fcbcSSean Christopherson error: \ 1703ebccdf3SThomas Gleixner instrumentation_begin(); \ 17152a9fcbcSSean Christopherson insn##_error(error_args); \ 1723ebccdf3SThomas Gleixner instrumentation_end(); \ 17352a9fcbcSSean Christopherson return; \ 17452a9fcbcSSean Christopherson fault: \ 17552a9fcbcSSean Christopherson kvm_spurious_fault(); \ 17652a9fcbcSSean Christopherson } while (0) 17789b0c9f5SSean Christopherson 17889b0c9f5SSean Christopherson static __always_inline void __vmcs_writel(unsigned long field, unsigned long value) 17989b0c9f5SSean Christopherson { 18052a9fcbcSSean Christopherson vmx_asm2(vmwrite, "r"(field), "rm"(value), field, value); 18189b0c9f5SSean Christopherson } 18289b0c9f5SSean Christopherson 18389b0c9f5SSean Christopherson static __always_inline void vmcs_write16(unsigned long field, u16 value) 18489b0c9f5SSean Christopherson { 18589b0c9f5SSean Christopherson vmcs_check16(field); 18689b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 18789b0c9f5SSean Christopherson return evmcs_write16(field, value); 18889b0c9f5SSean Christopherson 18989b0c9f5SSean Christopherson __vmcs_writel(field, value); 19089b0c9f5SSean Christopherson } 19189b0c9f5SSean Christopherson 19289b0c9f5SSean Christopherson static __always_inline void vmcs_write32(unsigned long field, u32 value) 19389b0c9f5SSean Christopherson { 19489b0c9f5SSean Christopherson vmcs_check32(field); 19589b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 19689b0c9f5SSean Christopherson return evmcs_write32(field, value); 19789b0c9f5SSean Christopherson 19889b0c9f5SSean Christopherson __vmcs_writel(field, value); 19989b0c9f5SSean Christopherson } 20089b0c9f5SSean Christopherson 20189b0c9f5SSean Christopherson static __always_inline void vmcs_write64(unsigned long field, u64 value) 20289b0c9f5SSean Christopherson { 20389b0c9f5SSean Christopherson vmcs_check64(field); 20489b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 20589b0c9f5SSean Christopherson return evmcs_write64(field, value); 20689b0c9f5SSean Christopherson 20789b0c9f5SSean Christopherson __vmcs_writel(field, value); 20889b0c9f5SSean Christopherson #ifndef CONFIG_X86_64 20989b0c9f5SSean Christopherson __vmcs_writel(field+1, value >> 32); 21089b0c9f5SSean Christopherson #endif 21189b0c9f5SSean Christopherson } 21289b0c9f5SSean Christopherson 21389b0c9f5SSean Christopherson static __always_inline void vmcs_writel(unsigned long field, unsigned long value) 21489b0c9f5SSean Christopherson { 21589b0c9f5SSean Christopherson vmcs_checkl(field); 21689b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 21789b0c9f5SSean Christopherson return evmcs_write64(field, value); 21889b0c9f5SSean Christopherson 21989b0c9f5SSean Christopherson __vmcs_writel(field, value); 22089b0c9f5SSean Christopherson } 22189b0c9f5SSean Christopherson 22289b0c9f5SSean Christopherson static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask) 22389b0c9f5SSean Christopherson { 22489b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000, 22589b0c9f5SSean Christopherson "vmcs_clear_bits does not support 64-bit fields"); 22689b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 22789b0c9f5SSean Christopherson return evmcs_write32(field, evmcs_read32(field) & ~mask); 22889b0c9f5SSean Christopherson 22989b0c9f5SSean Christopherson __vmcs_writel(field, __vmcs_readl(field) & ~mask); 23089b0c9f5SSean Christopherson } 23189b0c9f5SSean Christopherson 23289b0c9f5SSean Christopherson static __always_inline void vmcs_set_bits(unsigned long field, u32 mask) 23389b0c9f5SSean Christopherson { 23489b0c9f5SSean Christopherson BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000, 23589b0c9f5SSean Christopherson "vmcs_set_bits does not support 64-bit fields"); 23689b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 23789b0c9f5SSean Christopherson return evmcs_write32(field, evmcs_read32(field) | mask); 23889b0c9f5SSean Christopherson 23989b0c9f5SSean Christopherson __vmcs_writel(field, __vmcs_readl(field) | mask); 24089b0c9f5SSean Christopherson } 24189b0c9f5SSean Christopherson 24289b0c9f5SSean Christopherson static inline void vmcs_clear(struct vmcs *vmcs) 24389b0c9f5SSean Christopherson { 24489b0c9f5SSean Christopherson u64 phys_addr = __pa(vmcs); 24589b0c9f5SSean Christopherson 24652a9fcbcSSean Christopherson vmx_asm1(vmclear, "m"(phys_addr), vmcs, phys_addr); 24789b0c9f5SSean Christopherson } 24889b0c9f5SSean Christopherson 24989b0c9f5SSean Christopherson static inline void vmcs_load(struct vmcs *vmcs) 25089b0c9f5SSean Christopherson { 25189b0c9f5SSean Christopherson u64 phys_addr = __pa(vmcs); 25289b0c9f5SSean Christopherson 25389b0c9f5SSean Christopherson if (static_branch_unlikely(&enable_evmcs)) 25489b0c9f5SSean Christopherson return evmcs_load(phys_addr); 25589b0c9f5SSean Christopherson 25652a9fcbcSSean Christopherson vmx_asm1(vmptrld, "m"(phys_addr), vmcs, phys_addr); 25789b0c9f5SSean Christopherson } 25889b0c9f5SSean Christopherson 25989b0c9f5SSean Christopherson static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva) 26089b0c9f5SSean Christopherson { 26189b0c9f5SSean Christopherson struct { 26289b0c9f5SSean Christopherson u64 vpid : 16; 26389b0c9f5SSean Christopherson u64 rsvd : 48; 26489b0c9f5SSean Christopherson u64 gva; 26589b0c9f5SSean Christopherson } operand = { vpid, 0, gva }; 26689b0c9f5SSean Christopherson 26752a9fcbcSSean Christopherson vmx_asm2(invvpid, "r"(ext), "m"(operand), ext, vpid, gva); 26889b0c9f5SSean Christopherson } 26989b0c9f5SSean Christopherson 27089b0c9f5SSean Christopherson static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa) 27189b0c9f5SSean Christopherson { 27289b0c9f5SSean Christopherson struct { 27389b0c9f5SSean Christopherson u64 eptp, gpa; 27489b0c9f5SSean Christopherson } operand = {eptp, gpa}; 27589b0c9f5SSean Christopherson 27652a9fcbcSSean Christopherson vmx_asm2(invept, "r"(ext), "m"(operand), ext, eptp, gpa); 27789b0c9f5SSean Christopherson } 27889b0c9f5SSean Christopherson 27989b0c9f5SSean Christopherson static inline void vpid_sync_vcpu_single(int vpid) 28089b0c9f5SSean Christopherson { 28189b0c9f5SSean Christopherson if (vpid == 0) 28289b0c9f5SSean Christopherson return; 28389b0c9f5SSean Christopherson 28489b0c9f5SSean Christopherson __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vpid, 0); 28589b0c9f5SSean Christopherson } 28689b0c9f5SSean Christopherson 28789b0c9f5SSean Christopherson static inline void vpid_sync_vcpu_global(void) 28889b0c9f5SSean Christopherson { 28989b0c9f5SSean Christopherson __invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0); 29089b0c9f5SSean Christopherson } 29189b0c9f5SSean Christopherson 29289b0c9f5SSean Christopherson static inline void vpid_sync_context(int vpid) 29389b0c9f5SSean Christopherson { 29489b0c9f5SSean Christopherson if (cpu_has_vmx_invvpid_single()) 29589b0c9f5SSean Christopherson vpid_sync_vcpu_single(vpid); 296c746b3a4SSean Christopherson else if (vpid != 0) 29789b0c9f5SSean Christopherson vpid_sync_vcpu_global(); 29889b0c9f5SSean Christopherson } 29989b0c9f5SSean Christopherson 300ab4b3597SSean Christopherson static inline void vpid_sync_vcpu_addr(int vpid, gva_t addr) 3018a8b097cSSean Christopherson { 3028a8b097cSSean Christopherson if (vpid == 0) 303ab4b3597SSean Christopherson return; 3048a8b097cSSean Christopherson 305ab4b3597SSean Christopherson if (cpu_has_vmx_invvpid_individual_addr()) 3068a8b097cSSean Christopherson __invvpid(VMX_VPID_EXTENT_INDIVIDUAL_ADDR, vpid, addr); 307ab4b3597SSean Christopherson else 308ab4b3597SSean Christopherson vpid_sync_context(vpid); 3098a8b097cSSean Christopherson } 3108a8b097cSSean Christopherson 31189b0c9f5SSean Christopherson static inline void ept_sync_global(void) 31289b0c9f5SSean Christopherson { 31389b0c9f5SSean Christopherson __invept(VMX_EPT_EXTENT_GLOBAL, 0, 0); 31489b0c9f5SSean Christopherson } 31589b0c9f5SSean Christopherson 31689b0c9f5SSean Christopherson static inline void ept_sync_context(u64 eptp) 31789b0c9f5SSean Christopherson { 31889b0c9f5SSean Christopherson if (cpu_has_vmx_invept_context()) 31989b0c9f5SSean Christopherson __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0); 32089b0c9f5SSean Christopherson else 32189b0c9f5SSean Christopherson ept_sync_global(); 32289b0c9f5SSean Christopherson } 32389b0c9f5SSean Christopherson 32489b0c9f5SSean Christopherson #endif /* __KVM_X86_VMX_INSN_H */ 325