summaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx/vmenter.S
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2019-01-25 16:41:12 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2019-02-20 22:48:13 +0100
commit5e0781df18990497f4cd96a959ca583d83b6d1e0 (patch)
tree191aea7cc7477ff88d9d678fee228a801ca5d5d3 /arch/x86/kvm/vmx/vmenter.S
parentKVM: VMX: Create a stack frame in vCPU-run (diff)
downloadlinux-5e0781df18990497f4cd96a959ca583d83b6d1e0.tar.xz
linux-5e0781df18990497f4cd96a959ca583d83b6d1e0.zip
KVM: VMX: Move vCPU-run code to a proper assembly routine
As evidenced by the myriad patches leading up to this moment, using an inline asm blob for vCPU-run is nothing short of horrific. It's also been called "unholy", "an abomination" and likely a whole host of other names that would violate the Code of Conduct if recorded here and now. The code is relocated nearly verbatim, e.g. quotes, newlines, tabs and __stringify need to be dropped, but other than those cosmetic changes the only functional changees are to add the "call" and replace the final "jmp" with a "ret". Note that STACK_FRAME_NON_STANDARD is also dropped from __vmx_vcpu_run(). Suggested-by: Andi Kleen <ak@linux.intel.com> Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx/vmenter.S')
-rw-r--r--arch/x86/kvm/vmx/vmenter.S144
1 files changed, 144 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S
index bcef2c7e9bc4..e64617f3b196 100644
--- a/arch/x86/kvm/vmx/vmenter.S
+++ b/arch/x86/kvm/vmx/vmenter.S
@@ -1,6 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/asm.h>
+#include <asm/bitsperlong.h>
+#include <asm/kvm_vcpu_regs.h>
+
+#define WORD_SIZE (BITS_PER_LONG / 8)
+
+#define VCPU_RAX __VCPU_REGS_RAX * WORD_SIZE
+#define VCPU_RCX __VCPU_REGS_RCX * WORD_SIZE
+#define VCPU_RDX __VCPU_REGS_RDX * WORD_SIZE
+#define VCPU_RBX __VCPU_REGS_RBX * WORD_SIZE
+/* Intentionally omit RSP as it's context switched by hardware */
+#define VCPU_RBP __VCPU_REGS_RBP * WORD_SIZE
+#define VCPU_RSI __VCPU_REGS_RSI * WORD_SIZE
+#define VCPU_RDI __VCPU_REGS_RDI * WORD_SIZE
+
+#ifdef CONFIG_X86_64
+#define VCPU_R8 __VCPU_REGS_R8 * WORD_SIZE
+#define VCPU_R9 __VCPU_REGS_R9 * WORD_SIZE
+#define VCPU_R10 __VCPU_REGS_R10 * WORD_SIZE
+#define VCPU_R11 __VCPU_REGS_R11 * WORD_SIZE
+#define VCPU_R12 __VCPU_REGS_R12 * WORD_SIZE
+#define VCPU_R13 __VCPU_REGS_R13 * WORD_SIZE
+#define VCPU_R14 __VCPU_REGS_R14 * WORD_SIZE
+#define VCPU_R15 __VCPU_REGS_R15 * WORD_SIZE
+#endif
.text
@@ -55,3 +79,123 @@ ENDPROC(vmx_vmenter)
ENTRY(vmx_vmexit)
ret
ENDPROC(vmx_vmexit)
+
+/**
+ * ____vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
+ * @vmx: struct vcpu_vmx *
+ * @regs: unsigned long * (to guest registers)
+ * %RBX: VMCS launched status (non-zero indicates already launched)
+ *
+ * Returns:
+ * %RBX is 0 on VM-Exit, 1 on VM-Fail
+ */
+ENTRY(____vmx_vcpu_run)
+ push %_ASM_BP
+ mov %_ASM_SP, %_ASM_BP
+
+ /*
+ * Save @regs, _ASM_ARG2 may be modified by vmx_update_host_rsp() and
+ * @regs is needed after VM-Exit to save the guest's register values.
+ */
+ push %_ASM_ARG2
+
+ /* Adjust RSP to account for the CALL to vmx_vmenter(). */
+ lea -WORD_SIZE(%_ASM_SP), %_ASM_ARG2
+ call vmx_update_host_rsp
+
+ /* Load @regs to RCX. */
+ mov (%_ASM_SP), %_ASM_CX
+
+ /* Check if vmlaunch or vmresume is needed */
+ cmpb $0, %bl
+
+ /* Load guest registers. Don't clobber flags. */
+ mov VCPU_RAX(%_ASM_CX), %_ASM_AX
+ mov VCPU_RBX(%_ASM_CX), %_ASM_BX
+ mov VCPU_RDX(%_ASM_CX), %_ASM_DX
+ mov VCPU_RSI(%_ASM_CX), %_ASM_SI
+ mov VCPU_RDI(%_ASM_CX), %_ASM_DI
+ mov VCPU_RBP(%_ASM_CX), %_ASM_BP
+#ifdef CONFIG_X86_64
+ mov VCPU_R8 (%_ASM_CX), %r8
+ mov VCPU_R9 (%_ASM_CX), %r9
+ mov VCPU_R10(%_ASM_CX), %r10
+ mov VCPU_R11(%_ASM_CX), %r11
+ mov VCPU_R12(%_ASM_CX), %r12
+ mov VCPU_R13(%_ASM_CX), %r13
+ mov VCPU_R14(%_ASM_CX), %r14
+ mov VCPU_R15(%_ASM_CX), %r15
+#endif
+ /* Load guest RCX. This kills the vmx_vcpu pointer! */
+ mov VCPU_RCX(%_ASM_CX), %_ASM_CX
+
+ /* Enter guest mode */
+ call vmx_vmenter
+
+ /* Jump on VM-Fail. */
+ jbe 2f
+
+ /* Temporarily save guest's RCX. */
+ push %_ASM_CX
+
+ /* Reload @regs to RCX. */
+ mov WORD_SIZE(%_ASM_SP), %_ASM_CX
+
+ /* Save all guest registers, including RCX from the stack */
+ mov %_ASM_AX, VCPU_RAX(%_ASM_CX)
+ mov %_ASM_BX, VCPU_RBX(%_ASM_CX)
+ __ASM_SIZE(pop) VCPU_RCX(%_ASM_CX)
+ mov %_ASM_DX, VCPU_RDX(%_ASM_CX)
+ mov %_ASM_SI, VCPU_RSI(%_ASM_CX)
+ mov %_ASM_DI, VCPU_RDI(%_ASM_CX)
+ mov %_ASM_BP, VCPU_RBP(%_ASM_CX)
+#ifdef CONFIG_X86_64
+ mov %r8, VCPU_R8 (%_ASM_CX)
+ mov %r9, VCPU_R9 (%_ASM_CX)
+ mov %r10, VCPU_R10(%_ASM_CX)
+ mov %r11, VCPU_R11(%_ASM_CX)
+ mov %r12, VCPU_R12(%_ASM_CX)
+ mov %r13, VCPU_R13(%_ASM_CX)
+ mov %r14, VCPU_R14(%_ASM_CX)
+ mov %r15, VCPU_R15(%_ASM_CX)
+#endif
+
+ /* Clear EBX to indicate VM-Exit (as opposed to VM-Fail). */
+ xor %ebx, %ebx
+
+ /*
+ * Clear all general purpose registers except RSP and RBX to prevent
+ * speculative use of the guest's values, even those that are reloaded
+ * via the stack. In theory, an L1 cache miss when restoring registers
+ * could lead to speculative execution with the guest's values.
+ * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
+ * free. RSP and RBX are exempt as RSP is restored by hardware during
+ * VM-Exit and RBX is explicitly loaded with 0 or 1 to "return" VM-Fail.
+ */
+1:
+#ifdef CONFIG_X86_64
+ xor %r8d, %r8d
+ xor %r9d, %r9d
+ xor %r10d, %r10d
+ xor %r11d, %r11d
+ xor %r12d, %r12d
+ xor %r13d, %r13d
+ xor %r14d, %r14d
+ xor %r15d, %r15d
+#endif
+ xor %eax, %eax
+ xor %ecx, %ecx
+ xor %edx, %edx
+ xor %esi, %esi
+ xor %edi, %edi
+ xor %ebp, %ebp
+
+ /* "POP" @regs. */
+ add $WORD_SIZE, %_ASM_SP
+ pop %_ASM_BP
+ ret
+
+ /* VM-Fail. Out-of-line to avoid a taken Jcc after VM-Exit. */
+2: mov $1, %ebx
+ jmp 1b
+ENDPROC(____vmx_vcpu_run)