linux/arch/x86/kvm/vmenter.h
Chang S. Bae c3029c3817 KVM: VMX: Macrofy GPR swapping in __vmx_vcpu_run()
Convert the repeated register save/restore sequences into macros,
trading some level of implementation trickiness for conciseness (more
than one register can be saved/restored with one invocation) and a
smaller chance of cut and paste errors.

This is particularly useful in preparation for extended GPR support;
upcoming support for APX would need to add 32 lines to the VM entry/exit
paths.

No functional change intended.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Link: https://lore.kernel.org/6e67df0e-e5f0-43f5-aa86-22e8b01b75d2@redhat.com
Link: https://patch.msgid.link/20260512011502.53072-2-chang.seok.bae@intel.com/
[Keep kvm_vcpu_regs.h and put the macros in there. -Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2026-05-30 22:41:00 +02:00

112 lines
2.8 KiB
C

/* 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 */