| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef __KVM_X86_VMENTER_H | |
| #define __KVM_X86_VMENTER_H | |
| #include <asm/kvm_vcpu_regs.h> | |
| #define KVM_ENTER_VMRESUME BIT(0) | |
| #define KVM_ENTER_SAVE_SPEC_CTRL BIT(1) | |
| #define KVM_ENTER_CLEAR_CPU_BUFFERS_FOR_MMIO BIT(2) | |
| #ifdef __ASSEMBLER__ | |
| .macro RESTORE_GUEST_SPEC_CTRL_BODY guest_spec_ctrl:req, label:req | |
| /* | |
| * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the | |
| * host's, write the MSR. This is kept out-of-line so that the common | |
| * case does not have to jump. | |
| * | |
| * IMPORTANT: To avoid RSB underflow attacks and any other nastiness, | |
| * there must not be any returns or indirect branches between this code | |
| * and vmentry. | |
| */ | |
| #ifdef CONFIG_X86_64 | |
| mov \guest_spec_ctrl, %rdx | |
| cmp PER_CPU_VAR(x86_spec_ctrl_current), %rdx | |
| je \label | |
| movl %edx, %eax | |
| shr $32, %rdx | |
| #else | |
| mov \guest_spec_ctrl, %eax | |
| mov PER_CPU_VAR(x86_spec_ctrl_current), %ecx | |
| xor %eax, %ecx | |
| mov 4 + \guest_spec_ctrl, %edx | |
| mov PER_CPU_VAR(x86_spec_ctrl_current + 4), %esi | |
| xor %edx, %esi | |
| or %esi, %ecx | |
| je \label | |
| #endif | |
| mov $MSR_IA32_SPEC_CTRL, %ecx | |
| wrmsr | |
| .endm | |
| .macro RESTORE_HOST_SPEC_CTRL_BODY guest_spec_ctrl:req, enter_flags:req, label:req | |
| /* Same for after vmexit. */ | |
| mov $MSR_IA32_SPEC_CTRL, %ecx | |
| /* | |
| * Load the value that the guest had written into MSR_IA32_SPEC_CTRL, | |
| * if it was not intercepted during guest execution. | |
| */ | |
| testl $KVM_ENTER_SAVE_SPEC_CTRL, \enter_flags | |
| jz 998f | |
| rdmsr | |
| movl %eax, \guest_spec_ctrl | |
| movl %edx, 4 + \guest_spec_ctrl | |
| 998: | |
| /* Now restore the host value of the MSR if different from the guest's. */ | |
| #ifdef CONFIG_X86_64 | |
| mov PER_CPU_VAR(x86_spec_ctrl_current), %rdx | |
| cmp \guest_spec_ctrl, %rdx | |
| /* | |
| * For legacy IBRS, the IBRS bit always needs to be written after | |
| * transitioning from a less privileged predictor mode, regardless of | |
| * whether the guest/host values differ. | |
| */ | |
| ALTERNATIVE __stringify(je \label), "", X86_FEATURE_KERNEL_IBRS | |
| movl %edx, %eax | |
| shr $32, %rdx | |
| #else | |
| mov PER_CPU_VAR(x86_spec_ctrl_current), %eax | |
| mov \guest_spec_ctrl, %esi | |
| xor %eax, %esi | |
| mov PER_CPU_VAR(x86_spec_ctrl_current + 4), %edx | |
| mov 4 + \guest_spec_ctrl, %edi | |
| xor %edx, %edi | |
| or %edi, %esi | |
| ALTERNATIVE __stringify(je \label), "", X86_FEATURE_KERNEL_IBRS | |
| #endif | |
| wrmsr | |
| .endm | |
| #define WORD_SIZE (BITS_PER_LONG / 8) | |
| .macro LOAD_REGS src:req, regs_ofs:req, regs:vararg | |
| .irp reg, \regs | |
| REG_NUM reg_num \reg | |
| mov (\regs_ofs + reg_num * WORD_SIZE)(\src), \reg | |
| .endr | |
| .endm | |
| .macro STORE_REGS dst:req, regs_ofs:req, regs:vararg | |
| .irp reg, \regs | |
| REG_NUM reg_num \reg | |
| mov \reg, (\regs_ofs + reg_num * WORD_SIZE)(\dst) | |
| .endr | |
| .endm | |
| .macro POP_REGS dst:req, regs_ofs:req, regs:vararg | |
| .irp reg, \regs | |
| REG_NUM reg_num \reg | |
| pop (\regs_ofs + reg_num * WORD_SIZE)(\dst) | |
| .endr | |
| .endm | |
| .macro CLEAR_REGS regs:vararg | |
| .irp reg, \regs | |
| xorl \reg, \reg | |
| .endr | |
| .endm | |
| #endif /* __ASSEMBLER__ */ | |
| #endif /* __KVM_X86_VMENTER_H */ |