root/arch/x86/kvm/vmenter.h
/* 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 */