aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64/vmm/intel/vmx_support.S
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/vmm/intel/vmx_support.S')
-rw-r--r--sys/amd64/vmm/intel/vmx_support.S270
1 files changed, 270 insertions, 0 deletions
diff --git a/sys/amd64/vmm/intel/vmx_support.S b/sys/amd64/vmm/intel/vmx_support.S
new file mode 100644
index 000000000000..877e377f892d
--- /dev/null
+++ b/sys/amd64/vmm/intel/vmx_support.S
@@ -0,0 +1,270 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011 NetApp, Inc.
+ * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asmacros.h>
+#include <machine/specialreg.h>
+
+#include "vmx_assym.h"
+
+/* Be friendly to DTrace FBT's prologue/epilogue pattern matching */
+#define VENTER push %rbp ; mov %rsp,%rbp
+#define VLEAVE pop %rbp
+
+/*
+ * Save the guest context.
+ */
+#define VMX_GUEST_SAVE \
+ movq %rdi,VMXCTX_GUEST_RDI(%rsp); \
+ movq %rsi,VMXCTX_GUEST_RSI(%rsp); \
+ movq %rdx,VMXCTX_GUEST_RDX(%rsp); \
+ movq %rcx,VMXCTX_GUEST_RCX(%rsp); \
+ movq %r8,VMXCTX_GUEST_R8(%rsp); \
+ movq %r9,VMXCTX_GUEST_R9(%rsp); \
+ movq %rax,VMXCTX_GUEST_RAX(%rsp); \
+ movq %rbx,VMXCTX_GUEST_RBX(%rsp); \
+ movq %rbp,VMXCTX_GUEST_RBP(%rsp); \
+ movq %r10,VMXCTX_GUEST_R10(%rsp); \
+ movq %r11,VMXCTX_GUEST_R11(%rsp); \
+ movq %r12,VMXCTX_GUEST_R12(%rsp); \
+ movq %r13,VMXCTX_GUEST_R13(%rsp); \
+ movq %r14,VMXCTX_GUEST_R14(%rsp); \
+ movq %r15,VMXCTX_GUEST_R15(%rsp); \
+ movq %cr2,%rdi; \
+ movq %rdi,VMXCTX_GUEST_CR2(%rsp); \
+ movq %rsp,%rdi;
+
+/*
+ * Assumes that %rdi holds a pointer to the 'vmxctx'.
+ *
+ * On "return" all registers are updated to reflect guest state. The two
+ * exceptions are %rip and %rsp. These registers are atomically switched
+ * by hardware from the guest area of the vmcs.
+ *
+ * We modify %rsp to point to the 'vmxctx' so we can use it to restore
+ * host context in case of an error with 'vmlaunch' or 'vmresume'.
+ */
+#define VMX_GUEST_RESTORE \
+ movq %rdi,%rsp; \
+ movq VMXCTX_GUEST_CR2(%rdi),%rsi; \
+ movq %rsi,%cr2; \
+ movq VMXCTX_GUEST_RSI(%rdi),%rsi; \
+ movq VMXCTX_GUEST_RDX(%rdi),%rdx; \
+ movq VMXCTX_GUEST_RCX(%rdi),%rcx; \
+ movq VMXCTX_GUEST_R8(%rdi),%r8; \
+ movq VMXCTX_GUEST_R9(%rdi),%r9; \
+ movq VMXCTX_GUEST_RAX(%rdi),%rax; \
+ movq VMXCTX_GUEST_RBX(%rdi),%rbx; \
+ movq VMXCTX_GUEST_RBP(%rdi),%rbp; \
+ movq VMXCTX_GUEST_R10(%rdi),%r10; \
+ movq VMXCTX_GUEST_R11(%rdi),%r11; \
+ movq VMXCTX_GUEST_R12(%rdi),%r12; \
+ movq VMXCTX_GUEST_R13(%rdi),%r13; \
+ movq VMXCTX_GUEST_R14(%rdi),%r14; \
+ movq VMXCTX_GUEST_R15(%rdi),%r15; \
+ movq VMXCTX_GUEST_RDI(%rdi),%rdi; /* restore rdi the last */
+
+/*
+ * Clobber the remaining registers with guest contents so they can't
+ * be misused.
+ */
+#define VMX_GUEST_CLOBBER \
+ xor %rax, %rax; \
+ xor %rcx, %rcx; \
+ xor %rdx, %rdx; \
+ xor %rsi, %rsi; \
+ xor %r8, %r8; \
+ xor %r9, %r9; \
+ xor %r10, %r10; \
+ xor %r11, %r11;
+
+/*
+ * Save and restore the host context.
+ *
+ * Assumes that %rdi holds a pointer to the 'vmxctx'.
+ */
+#define VMX_HOST_SAVE \
+ movq %r15, VMXCTX_HOST_R15(%rdi); \
+ movq %r14, VMXCTX_HOST_R14(%rdi); \
+ movq %r13, VMXCTX_HOST_R13(%rdi); \
+ movq %r12, VMXCTX_HOST_R12(%rdi); \
+ movq %rbp, VMXCTX_HOST_RBP(%rdi); \
+ movq %rsp, VMXCTX_HOST_RSP(%rdi); \
+ movq %rbx, VMXCTX_HOST_RBX(%rdi); \
+
+#define VMX_HOST_RESTORE \
+ movq VMXCTX_HOST_R15(%rdi), %r15; \
+ movq VMXCTX_HOST_R14(%rdi), %r14; \
+ movq VMXCTX_HOST_R13(%rdi), %r13; \
+ movq VMXCTX_HOST_R12(%rdi), %r12; \
+ movq VMXCTX_HOST_RBP(%rdi), %rbp; \
+ movq VMXCTX_HOST_RSP(%rdi), %rsp; \
+ movq VMXCTX_HOST_RBX(%rdi), %rbx; \
+
+/*
+ * vmx_enter_guest(struct vmxctx *vmxctx, int launched)
+ * %rdi: pointer to the 'vmxctx'
+ * %rsi: pointer to the 'vmx'
+ * %edx: launch state of the VMCS
+ * Interrupts must be disabled on entry.
+ */
+ENTRY(vmx_enter_guest)
+ VENTER
+ /*
+ * Save host state before doing anything else.
+ */
+ VMX_HOST_SAVE
+
+guest_restore:
+ movl %edx, %r8d
+ cmpb $0, guest_l1d_flush_sw(%rip)
+ je after_l1d
+ call flush_l1d_sw
+after_l1d:
+ cmpl $0, %r8d
+ je do_launch
+ VMX_GUEST_RESTORE
+ vmresume
+ /*
+ * In the common case 'vmresume' returns back to the host through
+ * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
+ *
+ * If there is an error we return VMX_VMRESUME_ERROR to the caller.
+ */
+ movq %rsp, %rdi /* point %rdi back to 'vmxctx' */
+ movl $VMX_VMRESUME_ERROR, %eax
+ jmp decode_inst_error
+
+do_launch:
+ VMX_GUEST_RESTORE
+ vmlaunch
+ /*
+ * In the common case 'vmlaunch' returns back to the host through
+ * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
+ *
+ * If there is an error we return VMX_VMLAUNCH_ERROR to the caller.
+ */
+ movq %rsp, %rdi /* point %rdi back to 'vmxctx' */
+ movl $VMX_VMLAUNCH_ERROR, %eax
+ /* FALLTHROUGH */
+decode_inst_error:
+ movl $VM_FAIL_VALID, %r11d
+ movl $VM_FAIL_INVALID, %esi
+ cmovnzl %esi, %r11d
+ movl %r11d, VMXCTX_INST_FAIL_STATUS(%rdi)
+
+ /*
+ * The return value is already populated in %eax so we cannot use
+ * it as a scratch register beyond this point.
+ */
+
+ VMX_HOST_RESTORE
+ VLEAVE
+ ret
+
+/*
+ * Non-error VM-exit from the guest. Make this a label so it can
+ * be used by C code when setting up the VMCS.
+ * The VMCS-restored %rsp points to the struct vmxctx
+ */
+ ALIGN_TEXT
+ .globl vmx_exit_guest_flush_rsb
+vmx_exit_guest_flush_rsb:
+ /*
+ * Save guest state that is not automatically saved in the vmcs.
+ */
+ VMX_GUEST_SAVE
+
+ VMX_HOST_RESTORE
+
+ VMX_GUEST_CLOBBER
+
+ /*
+ * To prevent malicious branch target predictions from
+ * affecting the host, overwrite all entries in the RSB upon
+ * exiting a guest.
+ */
+ mov $16, %ecx /* 16 iterations, two calls per loop */
+ mov %rsp, %rax
+0: call 2f /* create an RSB entry. */
+1: pause
+ call 1b /* capture rogue speculation. */
+2: call 2f /* create an RSB entry. */
+1: pause
+ call 1b /* capture rogue speculation. */
+2: sub $1, %ecx
+ jnz 0b
+ mov %rax, %rsp
+
+ /*
+ * This will return to the caller of 'vmx_enter_guest()' with a return
+ * value of VMX_GUEST_VMEXIT.
+ */
+ movl $VMX_GUEST_VMEXIT, %eax
+ VLEAVE
+ ret
+
+ .globl vmx_exit_guest
+vmx_exit_guest:
+ /*
+ * Save guest state that is not automatically saved in the vmcs.
+ */
+ VMX_GUEST_SAVE
+
+ VMX_HOST_RESTORE
+
+ VMX_GUEST_CLOBBER
+
+ /*
+ * This will return to the caller of 'vmx_enter_guest()' with a return
+ * value of VMX_GUEST_VMEXIT.
+ */
+ movl $VMX_GUEST_VMEXIT, %eax
+ VLEAVE
+ ret
+END(vmx_enter_guest)
+
+/*
+ * %rdi = interrupt handler entry point
+ *
+ * Calling sequence described in the "Instruction Set Reference" for the "INT"
+ * instruction in Intel SDM, Vol 2.
+ */
+ENTRY(vmx_call_isr)
+ VENTER
+ mov %rsp, %r11 /* save %rsp */
+ and $~0xf, %rsp /* align on 16-byte boundary */
+ pushq $KERNEL_SS /* %ss */
+ pushq %r11 /* %rsp */
+ pushfq /* %rflags */
+ pushq $KERNEL_CS /* %cs */
+ cli /* disable interrupts */
+ callq *%rdi /* push %rip and call isr */
+ VLEAVE
+ ret
+END(vmx_call_isr)