1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#include <machine/asmacros.h> 31 32#include "vmx_assym.s" 33 34#ifdef SMP 35#define LK lock ; 36#else 37#define LK 38#endif 39 40/* 41 * Assumes that %rdi holds a pointer to the 'vmxctx'. 42 * 43 * On "return" all registers are updated to reflect guest state. The two 44 * exceptions are %rip and %rsp. These registers are atomically switched 45 * by hardware from the guest area of the vmcs. 46 * 47 * We modify %rsp to point to the 'vmxctx' so we can use it to restore 48 * host context in case of an error with 'vmlaunch' or 'vmresume'. 49 */ 50#define VMX_GUEST_RESTORE \ 51 movq %rdi,%rsp; \ 52 movq VMXCTX_GUEST_CR2(%rdi),%rsi; \ 53 movq %rsi,%cr2; \ 54 movq VMXCTX_GUEST_RSI(%rdi),%rsi; \ 55 movq VMXCTX_GUEST_RDX(%rdi),%rdx; \ 56 movq VMXCTX_GUEST_RCX(%rdi),%rcx; \ 57 movq VMXCTX_GUEST_R8(%rdi),%r8; \ 58 movq VMXCTX_GUEST_R9(%rdi),%r9; \ 59 movq VMXCTX_GUEST_RAX(%rdi),%rax; \ 60 movq VMXCTX_GUEST_RBX(%rdi),%rbx; \ 61 movq VMXCTX_GUEST_RBP(%rdi),%rbp; \ 62 movq VMXCTX_GUEST_R10(%rdi),%r10; \ 63 movq VMXCTX_GUEST_R11(%rdi),%r11; \ 64 movq VMXCTX_GUEST_R12(%rdi),%r12; \ 65 movq VMXCTX_GUEST_R13(%rdi),%r13; \ 66 movq VMXCTX_GUEST_R14(%rdi),%r14; \ 67 movq VMXCTX_GUEST_R15(%rdi),%r15; \ 68 movq VMXCTX_GUEST_RDI(%rdi),%rdi; /* restore rdi the last */ 69 70/* 71 * Save and restore the host context. 72 * 73 * Assumes that %rdi holds a pointer to the 'vmxctx'. 74 */ 75#define VMX_HOST_SAVE(tmpreg) \ 76 movq (%rsp), tmpreg; /* return address */ \ 77 movq %r15, VMXCTX_HOST_R15(%rdi); \ 78 movq %r14, VMXCTX_HOST_R14(%rdi); \ 79 movq %r13, VMXCTX_HOST_R13(%rdi); \ 80 movq %r12, VMXCTX_HOST_R12(%rdi); \ 81 movq %rbp, VMXCTX_HOST_RBP(%rdi); \ 82 movq %rsp, VMXCTX_HOST_RSP(%rdi); \ 83 movq %rbx, VMXCTX_HOST_RBX(%rdi); \ 84 movq tmpreg, VMXCTX_HOST_RIP(%rdi) 85 86#define VMX_HOST_RESTORE(tmpreg) \ 87 movq VMXCTX_HOST_R15(%rdi), %r15; \ 88 movq VMXCTX_HOST_R14(%rdi), %r14; \ 89 movq VMXCTX_HOST_R13(%rdi), %r13; \ 90 movq VMXCTX_HOST_R12(%rdi), %r12; \ 91 movq VMXCTX_HOST_RBP(%rdi), %rbp; \ 92 movq VMXCTX_HOST_RSP(%rdi), %rsp; \ 93 movq VMXCTX_HOST_RBX(%rdi), %rbx; \ 94 movq VMXCTX_HOST_RIP(%rdi), tmpreg; \ 95 movq tmpreg, (%rsp) /* return address */ 96 97/* 98 * vmx_enter_guest(struct vmxctx *vmxctx, int launched) 99 * %rdi: pointer to the 'vmxctx' 100 * %rsi: pointer to the 'vmx' 101 * %edx: launch state of the VMCS 102 * Interrupts must be disabled on entry. 103 */ 104ENTRY(vmx_enter_guest) 105 /* 106 * Save host state before doing anything else. 107 */ 108 VMX_HOST_SAVE(%r10) 109 110 /* 111 * Activate guest pmap on this cpu. 112 */ 113 movq VMXCTX_PMAP(%rdi), %r11 114 movl PCPU(CPUID), %eax 115 LK btsl %eax, PM_ACTIVE(%r11) 116 117 /* 118 * If 'vmx->eptgen[curcpu]' is not identical to 'pmap->pm_eptgen' 119 * then we must invalidate all mappings associated with this EPTP. 120 */ 121 movq PM_EPTGEN(%r11), %r10 122 cmpq %r10, VMX_EPTGEN(%rsi, %rax, 8) 123 je guest_restore 124 125 /* Refresh 'vmx->eptgen[curcpu]' */ 126 movq %r10, VMX_EPTGEN(%rsi, %rax, 8) 127 128 /* Setup the invept descriptor on the host stack */ 129 mov %rsp, %r11 130 movq VMX_EPTP(%rsi), %rax 131 movq %rax, -16(%r11) 132 movq $0x0, -8(%r11) 133 mov $0x1, %eax /* Single context invalidate */ 134 invept -16(%r11), %rax 135 jbe invept_error /* Check invept instruction error */ 136 137guest_restore: 138 cmpl $0, %edx 139 je do_launch 140 141 VMX_GUEST_RESTORE 142 vmresume 143 /* 144 * In the common case 'vmresume' returns back to the host through 145 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'. 146 * 147 * If there is an error we return VMX_VMRESUME_ERROR to the caller. 148 */ 149 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */ 150 movl $VMX_VMRESUME_ERROR, %eax 151 jmp decode_inst_error 152 153do_launch: 154 VMX_GUEST_RESTORE 155 vmlaunch 156 /* 157 * In the common case 'vmlaunch' returns back to the host through 158 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'. 159 * 160 * If there is an error we return VMX_VMLAUNCH_ERROR to the caller. 161 */ 162 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */ 163 movl $VMX_VMLAUNCH_ERROR, %eax 164 jmp decode_inst_error 165 166invept_error: 167 movl $VMX_INVEPT_ERROR, %eax 168 jmp decode_inst_error 169 170decode_inst_error: 171 movl $VM_FAIL_VALID, %r11d 172 jz inst_error 173 movl $VM_FAIL_INVALID, %r11d 174inst_error: 175 movl %r11d, VMXCTX_INST_FAIL_STATUS(%rdi) 176 177 /* 178 * The return value is already populated in %eax so we cannot use 179 * it as a scratch register beyond this point. 180 */ 181 182 /* 183 * Deactivate guest pmap from this cpu. 184 */ 185 movq VMXCTX_PMAP(%rdi), %r11 186 movl PCPU(CPUID), %r10d 187 LK btrl %r10d, PM_ACTIVE(%r11) 188 189 VMX_HOST_RESTORE(%r10) 190 ret 191END(vmx_enter_guest) 192 193/* 194 * void vmx_exit_guest(void) 195 * %rsp points to the struct vmxctx 196 */ 197ENTRY(vmx_exit_guest) 198 /* 199 * Save guest state that is not automatically saved in the vmcs. 200 */ 201 movq %rdi,VMXCTX_GUEST_RDI(%rsp) 202 movq %rsi,VMXCTX_GUEST_RSI(%rsp) 203 movq %rdx,VMXCTX_GUEST_RDX(%rsp) 204 movq %rcx,VMXCTX_GUEST_RCX(%rsp) 205 movq %r8,VMXCTX_GUEST_R8(%rsp) 206 movq %r9,VMXCTX_GUEST_R9(%rsp) 207 movq %rax,VMXCTX_GUEST_RAX(%rsp) 208 movq %rbx,VMXCTX_GUEST_RBX(%rsp) 209 movq %rbp,VMXCTX_GUEST_RBP(%rsp) 210 movq %r10,VMXCTX_GUEST_R10(%rsp) 211 movq %r11,VMXCTX_GUEST_R11(%rsp) 212 movq %r12,VMXCTX_GUEST_R12(%rsp) 213 movq %r13,VMXCTX_GUEST_R13(%rsp) 214 movq %r14,VMXCTX_GUEST_R14(%rsp) 215 movq %r15,VMXCTX_GUEST_R15(%rsp) 216 217 movq %cr2,%rdi 218 movq %rdi,VMXCTX_GUEST_CR2(%rsp) 219 220 movq %rsp,%rdi 221 222 /* 223 * Deactivate guest pmap from this cpu. 224 */ 225 movq VMXCTX_PMAP(%rdi), %r11 226 movl PCPU(CPUID), %r10d 227 LK btrl %r10d, PM_ACTIVE(%r11) 228 229 VMX_HOST_RESTORE(%r10) 230 231 /* 232 * This will return to the caller of 'vmx_enter_guest()' with a return 233 * value of VMX_GUEST_VMEXIT. 234 */ 235 movl $VMX_GUEST_VMEXIT, %eax 236 ret 237END(vmx_exit_guest) 238 239/* 240 * %rdi = interrupt handler entry point 241 * 242 * Calling sequence described in the "Instruction Set Reference" for the "INT" 243 * instruction in Intel SDM, Vol 2. 244 */ 245ENTRY(vmx_call_isr) 246 mov %rsp, %r11 /* save %rsp */ 247 and $~0xf, %rsp /* align on 16-byte boundary */ 248 pushq $KERNEL_SS /* %ss */ 249 pushq %r11 /* %rsp */ 250 pushfq /* %rflags */ 251 pushq $KERNEL_CS /* %cs */ 252 cli /* disable interrupts */ 253 callq *%rdi /* push %rip and call isr */ 254 ret 255END(vmx_call_isr) 256