/* SPDX-License-Identifier: GPL-2.0 */1#include <linux/linkage.h>2#include <asm/asm.h>3#include <asm/asm-offsets.h>4#include <asm/bitsperlong.h>5#include <asm/frame.h>6#include <asm/kvm_vcpu_regs.h>7#include <asm/nospec-branch.h>8#include "kvm-asm-offsets.h"910#define WORD_SIZE (BITS_PER_LONG / 8)1112/* Intentionally omit RAX as it's context switched by hardware */13#define VCPU_RCX (SVM_vcpu_arch_regs + __VCPU_REGS_RCX * WORD_SIZE)14#define VCPU_RDX (SVM_vcpu_arch_regs + __VCPU_REGS_RDX * WORD_SIZE)15#define VCPU_RBX (SVM_vcpu_arch_regs + __VCPU_REGS_RBX * WORD_SIZE)16/* Intentionally omit RSP as it's context switched by hardware */17#define VCPU_RBP (SVM_vcpu_arch_regs + __VCPU_REGS_RBP * WORD_SIZE)18#define VCPU_RSI (SVM_vcpu_arch_regs + __VCPU_REGS_RSI * WORD_SIZE)19#define VCPU_RDI (SVM_vcpu_arch_regs + __VCPU_REGS_RDI * WORD_SIZE)2021#ifdef CONFIG_X86_6422#define VCPU_R8 (SVM_vcpu_arch_regs + __VCPU_REGS_R8 * WORD_SIZE)23#define VCPU_R9 (SVM_vcpu_arch_regs + __VCPU_REGS_R9 * WORD_SIZE)24#define VCPU_R10 (SVM_vcpu_arch_regs + __VCPU_REGS_R10 * WORD_SIZE)25#define VCPU_R11 (SVM_vcpu_arch_regs + __VCPU_REGS_R11 * WORD_SIZE)26#define VCPU_R12 (SVM_vcpu_arch_regs + __VCPU_REGS_R12 * WORD_SIZE)27#define VCPU_R13 (SVM_vcpu_arch_regs + __VCPU_REGS_R13 * WORD_SIZE)28#define VCPU_R14 (SVM_vcpu_arch_regs + __VCPU_REGS_R14 * WORD_SIZE)29#define VCPU_R15 (SVM_vcpu_arch_regs + __VCPU_REGS_R15 * WORD_SIZE)30#endif3132#define SVM_vmcb01_pa (SVM_vmcb01 + KVM_VMCB_pa)3334.section .noinstr.text, "ax"3536.macro RESTORE_GUEST_SPEC_CTRL37/* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */38ALTERNATIVE_2 "", \39"jmp 800f", X86_FEATURE_MSR_SPEC_CTRL, \40"", X86_FEATURE_V_SPEC_CTRL41801:42.endm43.macro RESTORE_GUEST_SPEC_CTRL_BODY44800:45/*46* SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the47* host's, write the MSR. This is kept out-of-line so that the common48* case does not have to jump.49*50* IMPORTANT: To avoid RSB underflow attacks and any other nastiness,51* there must not be any returns or indirect branches between this code52* and vmentry.53*/54#ifdef CONFIG_X86_6455mov SVM_spec_ctrl(%rdi), %rdx56cmp PER_CPU_VAR(x86_spec_ctrl_current), %rdx57je 801b58movl %edx, %eax59shr $32, %rdx60#else61mov SVM_spec_ctrl(%edi), %eax62mov PER_CPU_VAR(x86_spec_ctrl_current), %ecx63xor %eax, %ecx64mov SVM_spec_ctrl + 4(%edi), %edx65mov PER_CPU_VAR(x86_spec_ctrl_current + 4), %esi66xor %edx, %esi67or %esi, %ecx68je 801b69#endif70mov $MSR_IA32_SPEC_CTRL, %ecx71wrmsr72jmp 801b73.endm7475.macro RESTORE_HOST_SPEC_CTRL76/* No need to do anything if SPEC_CTRL is unset or V_SPEC_CTRL is set */77ALTERNATIVE_2 "", \78"jmp 900f", X86_FEATURE_MSR_SPEC_CTRL, \79"", X86_FEATURE_V_SPEC_CTRL80901:81.endm82.macro RESTORE_HOST_SPEC_CTRL_BODY spec_ctrl_intercepted:req83900:84/* Same for after vmexit. */85mov $MSR_IA32_SPEC_CTRL, %ecx8687/*88* Load the value that the guest had written into MSR_IA32_SPEC_CTRL,89* if it was not intercepted during guest execution.90*/91cmpb $0, \spec_ctrl_intercepted92jnz 998f93rdmsr94movl %eax, SVM_spec_ctrl(%_ASM_DI)95movl %edx, SVM_spec_ctrl + 4(%_ASM_DI)96998:97/* Now restore the host value of the MSR if different from the guest's. */98#ifdef CONFIG_X86_6499mov PER_CPU_VAR(x86_spec_ctrl_current), %rdx100cmp SVM_spec_ctrl(%rdi), %rdx101je 901b102movl %edx, %eax103shr $32, %rdx104#else105mov PER_CPU_VAR(x86_spec_ctrl_current), %eax106mov SVM_spec_ctrl(%edi), %esi107xor %eax, %esi108mov PER_CPU_VAR(x86_spec_ctrl_current + 4), %edx109mov SVM_spec_ctrl + 4(%edi), %edi110xor %edx, %edi111or %edi, %esi112je 901b113#endif114wrmsr115jmp 901b116.endm117118#define SVM_CLEAR_CPU_BUFFERS \119ALTERNATIVE "", __CLEAR_CPU_BUFFERS, X86_FEATURE_CLEAR_CPU_BUF_VM120121/**122* __svm_vcpu_run - Run a vCPU via a transition to SVM guest mode123* @svm: struct vcpu_svm *124* @spec_ctrl_intercepted: bool125*/126SYM_FUNC_START(__svm_vcpu_run)127push %_ASM_BP128mov %_ASM_SP, %_ASM_BP129#ifdef CONFIG_X86_64130push %r15131push %r14132push %r13133push %r12134#else135push %edi136push %esi137#endif138push %_ASM_BX139140/*141* Save variables needed after vmexit on the stack, in inverse142* order compared to when they are needed.143*/144145/* Accessed directly from the stack in RESTORE_HOST_SPEC_CTRL. */146push %_ASM_ARG2147148/* Needed to restore access to percpu variables. */149__ASM_SIZE(push) PER_CPU_VAR(svm_data + SD_save_area_pa)150151/* Finally save @svm. */152push %_ASM_ARG1153154.ifnc _ASM_ARG1, _ASM_DI155/*156* Stash @svm in RDI early. On 32-bit, arguments are in RAX, RCX157* and RDX which are clobbered by RESTORE_GUEST_SPEC_CTRL.158*/159mov %_ASM_ARG1, %_ASM_DI160.endif161162/* Clobbers RAX, RCX, RDX (and ESI on 32-bit), consumes RDI (@svm). */163RESTORE_GUEST_SPEC_CTRL164165/*166* Use a single vmcb (vmcb01 because it's always valid) for167* context switching guest state via VMLOAD/VMSAVE, that way168* the state doesn't need to be copied between vmcb01 and169* vmcb02 when switching vmcbs for nested virtualization.170*/171mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX1721: vmload %_ASM_AX1732:174175/* Get svm->current_vmcb->pa into RAX. */176mov SVM_current_vmcb(%_ASM_DI), %_ASM_AX177mov KVM_VMCB_pa(%_ASM_AX), %_ASM_AX178179/* Load guest registers. */180mov VCPU_RCX(%_ASM_DI), %_ASM_CX181mov VCPU_RDX(%_ASM_DI), %_ASM_DX182mov VCPU_RBX(%_ASM_DI), %_ASM_BX183mov VCPU_RBP(%_ASM_DI), %_ASM_BP184mov VCPU_RSI(%_ASM_DI), %_ASM_SI185#ifdef CONFIG_X86_64186mov VCPU_R8 (%_ASM_DI), %r8187mov VCPU_R9 (%_ASM_DI), %r9188mov VCPU_R10(%_ASM_DI), %r10189mov VCPU_R11(%_ASM_DI), %r11190mov VCPU_R12(%_ASM_DI), %r12191mov VCPU_R13(%_ASM_DI), %r13192mov VCPU_R14(%_ASM_DI), %r14193mov VCPU_R15(%_ASM_DI), %r15194#endif195mov VCPU_RDI(%_ASM_DI), %_ASM_DI196197/* Clobbers EFLAGS.ZF */198SVM_CLEAR_CPU_BUFFERS199200/* Enter guest mode */2013: vmrun %_ASM_AX2024:203/* Pop @svm to RAX while it's the only available register. */204pop %_ASM_AX205206/* Save all guest registers. */207mov %_ASM_CX, VCPU_RCX(%_ASM_AX)208mov %_ASM_DX, VCPU_RDX(%_ASM_AX)209mov %_ASM_BX, VCPU_RBX(%_ASM_AX)210mov %_ASM_BP, VCPU_RBP(%_ASM_AX)211mov %_ASM_SI, VCPU_RSI(%_ASM_AX)212mov %_ASM_DI, VCPU_RDI(%_ASM_AX)213#ifdef CONFIG_X86_64214mov %r8, VCPU_R8 (%_ASM_AX)215mov %r9, VCPU_R9 (%_ASM_AX)216mov %r10, VCPU_R10(%_ASM_AX)217mov %r11, VCPU_R11(%_ASM_AX)218mov %r12, VCPU_R12(%_ASM_AX)219mov %r13, VCPU_R13(%_ASM_AX)220mov %r14, VCPU_R14(%_ASM_AX)221mov %r15, VCPU_R15(%_ASM_AX)222#endif223224/* @svm can stay in RDI from now on. */225mov %_ASM_AX, %_ASM_DI226227mov SVM_vmcb01_pa(%_ASM_DI), %_ASM_AX2285: vmsave %_ASM_AX2296:230231/* Restores GSBASE among other things, allowing access to percpu data. */232pop %_ASM_AX2337: vmload %_ASM_AX2348:235236/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */237FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT238239/*240* Clobbers RAX, RCX, RDX (and ESI, EDI on 32-bit), consumes RDI (@svm)241* and RSP (pointer to @spec_ctrl_intercepted).242*/243RESTORE_HOST_SPEC_CTRL244245/*246* Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be247* untrained as soon as we exit the VM and are back to the248* kernel. This should be done before re-enabling interrupts249* because interrupt handlers won't sanitize 'ret' if the return is250* from the kernel.251*/252UNTRAIN_RET_VM253254/*255* Clear all general purpose registers except RSP and RAX to prevent256* speculative use of the guest's values, even those that are reloaded257* via the stack. In theory, an L1 cache miss when restoring registers258* could lead to speculative execution with the guest's values.259* Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially260* free. RSP and RAX are exempt as they are restored by hardware261* during VM-Exit.262*/263xor %ecx, %ecx264xor %edx, %edx265xor %ebx, %ebx266xor %ebp, %ebp267xor %esi, %esi268xor %edi, %edi269#ifdef CONFIG_X86_64270xor %r8d, %r8d271xor %r9d, %r9d272xor %r10d, %r10d273xor %r11d, %r11d274xor %r12d, %r12d275xor %r13d, %r13d276xor %r14d, %r14d277xor %r15d, %r15d278#endif279280/* "Pop" @spec_ctrl_intercepted. */281pop %_ASM_BX282283pop %_ASM_BX284285#ifdef CONFIG_X86_64286pop %r12287pop %r13288pop %r14289pop %r15290#else291pop %esi292pop %edi293#endif294pop %_ASM_BP295RET296297RESTORE_GUEST_SPEC_CTRL_BODY298RESTORE_HOST_SPEC_CTRL_BODY (%_ASM_SP)29930010: cmpb $0, _ASM_RIP(kvm_rebooting)301jne 2b302ud230330: cmpb $0, _ASM_RIP(kvm_rebooting)304jne 4b305ud230650: cmpb $0, _ASM_RIP(kvm_rebooting)307jne 6b308ud230970: cmpb $0, _ASM_RIP(kvm_rebooting)310jne 8b311ud2312313_ASM_EXTABLE(1b, 10b)314_ASM_EXTABLE(3b, 30b)315_ASM_EXTABLE(5b, 50b)316_ASM_EXTABLE(7b, 70b)317318SYM_FUNC_END(__svm_vcpu_run)319320#ifdef CONFIG_KVM_AMD_SEV321322323#ifdef CONFIG_X86_64324#define SEV_ES_GPRS_BASE 0x300325#define SEV_ES_RBX (SEV_ES_GPRS_BASE + __VCPU_REGS_RBX * WORD_SIZE)326#define SEV_ES_RBP (SEV_ES_GPRS_BASE + __VCPU_REGS_RBP * WORD_SIZE)327#define SEV_ES_RSI (SEV_ES_GPRS_BASE + __VCPU_REGS_RSI * WORD_SIZE)328#define SEV_ES_RDI (SEV_ES_GPRS_BASE + __VCPU_REGS_RDI * WORD_SIZE)329#define SEV_ES_R12 (SEV_ES_GPRS_BASE + __VCPU_REGS_R12 * WORD_SIZE)330#define SEV_ES_R13 (SEV_ES_GPRS_BASE + __VCPU_REGS_R13 * WORD_SIZE)331#define SEV_ES_R14 (SEV_ES_GPRS_BASE + __VCPU_REGS_R14 * WORD_SIZE)332#define SEV_ES_R15 (SEV_ES_GPRS_BASE + __VCPU_REGS_R15 * WORD_SIZE)333#endif334335/**336* __svm_sev_es_vcpu_run - Run a SEV-ES vCPU via a transition to SVM guest mode337* @svm: struct vcpu_svm *338* @spec_ctrl_intercepted: bool339*/340SYM_FUNC_START(__svm_sev_es_vcpu_run)341FRAME_BEGIN342343/*344* Save non-volatile (callee-saved) registers to the host save area.345* Except for RAX and RSP, all GPRs are restored on #VMEXIT, but not346* saved on VMRUN.347*/348mov %rbp, SEV_ES_RBP (%rdx)349mov %r15, SEV_ES_R15 (%rdx)350mov %r14, SEV_ES_R14 (%rdx)351mov %r13, SEV_ES_R13 (%rdx)352mov %r12, SEV_ES_R12 (%rdx)353mov %rbx, SEV_ES_RBX (%rdx)354355/*356* Save volatile registers that hold arguments that are needed after357* #VMEXIT (RDI=@svm and RSI=@spec_ctrl_intercepted).358*/359mov %rdi, SEV_ES_RDI (%rdx)360mov %rsi, SEV_ES_RSI (%rdx)361362/* Clobbers RAX, RCX, and RDX (@hostsa), consumes RDI (@svm). */363RESTORE_GUEST_SPEC_CTRL364365/* Get svm->current_vmcb->pa into RAX. */366mov SVM_current_vmcb(%rdi), %rax367mov KVM_VMCB_pa(%rax), %rax368369/* Clobbers EFLAGS.ZF */370SVM_CLEAR_CPU_BUFFERS371372/* Enter guest mode */3731: vmrun %rax3742:375/* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */376FILL_RETURN_BUFFER %rax, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT377378/* Clobbers RAX, RCX, RDX, consumes RDI (@svm) and RSI (@spec_ctrl_intercepted). */379RESTORE_HOST_SPEC_CTRL380381/*382* Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be383* untrained as soon as we exit the VM and are back to the384* kernel. This should be done before re-enabling interrupts385* because interrupt handlers won't sanitize RET if the return is386* from the kernel.387*/388UNTRAIN_RET_VM389390FRAME_END391RET392393RESTORE_GUEST_SPEC_CTRL_BODY394RESTORE_HOST_SPEC_CTRL_BODY %sil3953963: cmpb $0, kvm_rebooting(%rip)397jne 2b398ud2399400_ASM_EXTABLE(1b, 3b)401402SYM_FUNC_END(__svm_sev_es_vcpu_run)403#endif /* CONFIG_KVM_AMD_SEV */404405406