1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32#include <machine/asmacros.h> 33#include <machine/specialreg.h> 34 35#include "vmx_assym.h" 36 37#ifdef SMP 38#define LK lock ; 39#else 40#define LK 41#endif 42 43/* Be friendly to DTrace FBT's prologue/epilogue pattern matching */ 44#define VENTER push %rbp ; mov %rsp,%rbp 45#define VLEAVE pop %rbp 46 47/* 48 * Save the guest context. 49 */ 50#define VMX_GUEST_SAVE \ 51 movq %rdi,VMXCTX_GUEST_RDI(%rsp); \ 52 movq %rsi,VMXCTX_GUEST_RSI(%rsp); \ 53 movq %rdx,VMXCTX_GUEST_RDX(%rsp); \ 54 movq %rcx,VMXCTX_GUEST_RCX(%rsp); \ 55 movq %r8,VMXCTX_GUEST_R8(%rsp); \ 56 movq %r9,VMXCTX_GUEST_R9(%rsp); \ 57 movq %rax,VMXCTX_GUEST_RAX(%rsp); \ 58 movq %rbx,VMXCTX_GUEST_RBX(%rsp); \ 59 movq %rbp,VMXCTX_GUEST_RBP(%rsp); \ 60 movq %r10,VMXCTX_GUEST_R10(%rsp); \ 61 movq %r11,VMXCTX_GUEST_R11(%rsp); \ 62 movq %r12,VMXCTX_GUEST_R12(%rsp); \ 63 movq %r13,VMXCTX_GUEST_R13(%rsp); \ 64 movq %r14,VMXCTX_GUEST_R14(%rsp); \ 65 movq %r15,VMXCTX_GUEST_R15(%rsp); \ 66 movq %cr2,%rdi; \ 67 movq %rdi,VMXCTX_GUEST_CR2(%rsp); \ 68 movq %rsp,%rdi; 69 70/* 71 * Assumes that %rdi holds a pointer to the 'vmxctx'. 72 * 73 * On "return" all registers are updated to reflect guest state. The two 74 * exceptions are %rip and %rsp. These registers are atomically switched 75 * by hardware from the guest area of the vmcs. 76 * 77 * We modify %rsp to point to the 'vmxctx' so we can use it to restore 78 * host context in case of an error with 'vmlaunch' or 'vmresume'. 79 */ 80#define VMX_GUEST_RESTORE \ 81 movq %rdi,%rsp; \ 82 movq VMXCTX_GUEST_CR2(%rdi),%rsi; \ 83 movq %rsi,%cr2; \ 84 movq VMXCTX_GUEST_RSI(%rdi),%rsi; \ 85 movq VMXCTX_GUEST_RDX(%rdi),%rdx; \ 86 movq VMXCTX_GUEST_RCX(%rdi),%rcx; \ 87 movq VMXCTX_GUEST_R8(%rdi),%r8; \ 88 movq VMXCTX_GUEST_R9(%rdi),%r9; \ 89 movq VMXCTX_GUEST_RAX(%rdi),%rax; \ 90 movq VMXCTX_GUEST_RBX(%rdi),%rbx; \ 91 movq VMXCTX_GUEST_RBP(%rdi),%rbp; \ 92 movq VMXCTX_GUEST_R10(%rdi),%r10; \ 93 movq VMXCTX_GUEST_R11(%rdi),%r11; \ 94 movq VMXCTX_GUEST_R12(%rdi),%r12; \ 95 movq VMXCTX_GUEST_R13(%rdi),%r13; \ 96 movq VMXCTX_GUEST_R14(%rdi),%r14; \ 97 movq VMXCTX_GUEST_R15(%rdi),%r15; \ 98 movq VMXCTX_GUEST_RDI(%rdi),%rdi; /* restore rdi the last */ 99 100/* 101 * Clobber the remaining registers with guest contents so they can't 102 * be misused. 103 */ 104#define VMX_GUEST_CLOBBER \ 105 xor %rax, %rax; \ 106 xor %rcx, %rcx; \ 107 xor %rdx, %rdx; \ 108 xor %rsi, %rsi; \ 109 xor %r8, %r8; \ 110 xor %r9, %r9; \ 111 xor %r10, %r10; \ 112 xor %r11, %r11; 113 114/* 115 * Save and restore the host context. 116 * 117 * Assumes that %rdi holds a pointer to the 'vmxctx'. 118 */ 119#define VMX_HOST_SAVE \ 120 movq %r15, VMXCTX_HOST_R15(%rdi); \ 121 movq %r14, VMXCTX_HOST_R14(%rdi); \ 122 movq %r13, VMXCTX_HOST_R13(%rdi); \ 123 movq %r12, VMXCTX_HOST_R12(%rdi); \ 124 movq %rbp, VMXCTX_HOST_RBP(%rdi); \ 125 movq %rsp, VMXCTX_HOST_RSP(%rdi); \ 126 movq %rbx, VMXCTX_HOST_RBX(%rdi); \ 127 128#define VMX_HOST_RESTORE \ 129 movq VMXCTX_HOST_R15(%rdi), %r15; \ 130 movq VMXCTX_HOST_R14(%rdi), %r14; \ 131 movq VMXCTX_HOST_R13(%rdi), %r13; \ 132 movq VMXCTX_HOST_R12(%rdi), %r12; \ 133 movq VMXCTX_HOST_RBP(%rdi), %rbp; \ 134 movq VMXCTX_HOST_RSP(%rdi), %rsp; \ 135 movq VMXCTX_HOST_RBX(%rdi), %rbx; \ 136 137/* 138 * vmx_enter_guest(struct vmxctx *vmxctx, int launched) 139 * %rdi: pointer to the 'vmxctx' 140 * %rsi: pointer to the 'vmx' 141 * %edx: launch state of the VMCS 142 * Interrupts must be disabled on entry. 143 */ 144ENTRY(vmx_enter_guest) 145 VENTER 146 /* 147 * Save host state before doing anything else. 148 */ 149 VMX_HOST_SAVE 150 151 /* 152 * Activate guest pmap on this cpu. 153 */ 154 movq VMXCTX_PMAP(%rdi), %r11 155 movl PCPU(CPUID), %eax 156 LK btsl %eax, PM_ACTIVE(%r11) 157 158 /* 159 * If 'vmx->eptgen[curcpu]' is not identical to 'pmap->pm_eptgen' 160 * then we must invalidate all mappings associated with this EPTP. 161 */ 162 movq PM_EPTGEN(%r11), %r10 163 cmpq %r10, VMX_EPTGEN(%rsi, %rax, 8) 164 je guest_restore 165 166 /* Refresh 'vmx->eptgen[curcpu]' */ 167 movq %r10, VMX_EPTGEN(%rsi, %rax, 8) 168 169 /* Setup the invept descriptor on the host stack */ 170 mov %rsp, %r11 171 movq VMX_EPTP(%rsi), %rax 172 movq %rax, -16(%r11) 173 movq $0x0, -8(%r11) 174 mov $0x1, %eax /* Single context invalidate */ 175 invept -16(%r11), %rax 176 jbe invept_error /* Check invept instruction error */ 177 178guest_restore: 179 180 /* 181 * Flush L1D cache if requested. Use IA32_FLUSH_CMD MSR if available, 182 * otherwise load enough of the data from the zero_region to flush 183 * existing L1D content. 184 */ 185#define L1D_FLUSH_SIZE (64 * 1024) 186 movl %edx, %r8d 187 cmpb $0, guest_l1d_flush(%rip) 188 je after_l1d 189 movq vmx_msr_flush_cmd(%rip), %rax 190 testq %rax, %rax 191 jz 1f 192 movq %rax, %rdx 193 shrq $32, %rdx 194 movl $MSR_IA32_FLUSH_CMD, %ecx 195 wrmsr 196 jmp after_l1d 1971: movq $KERNBASE, %r9 198 movq $-L1D_FLUSH_SIZE, %rcx 199 /* 200 * pass 1: Preload TLB. 201 * Kernel text is mapped using superpages. TLB preload is 202 * done for the benefit of older CPUs which split 2M page 203 * into 4k TLB entries. 204 */ 2052: movb L1D_FLUSH_SIZE(%r9, %rcx), %al 206 addq $PAGE_SIZE, %rcx 207 jne 2b 208 xorl %eax, %eax 209 cpuid 210 movq $-L1D_FLUSH_SIZE, %rcx 211 /* pass 2: Read each cache line */ 2123: movb L1D_FLUSH_SIZE(%r9, %rcx), %al 213 addq $64, %rcx 214 jne 3b 215 lfence 216#undef L1D_FLUSH_SIZE 217after_l1d: 218 cmpl $0, %r8d 219 je do_launch 220 VMX_GUEST_RESTORE 221 vmresume 222 /* 223 * In the common case 'vmresume' returns back to the host through 224 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'. 225 * 226 * If there is an error we return VMX_VMRESUME_ERROR to the caller. 227 */ 228 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */ 229 movl $VMX_VMRESUME_ERROR, %eax 230 jmp decode_inst_error 231 232do_launch: 233 VMX_GUEST_RESTORE 234 vmlaunch 235 /* 236 * In the common case 'vmlaunch' returns back to the host through 237 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'. 238 * 239 * If there is an error we return VMX_VMLAUNCH_ERROR to the caller. 240 */ 241 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */ 242 movl $VMX_VMLAUNCH_ERROR, %eax 243 jmp decode_inst_error 244 245invept_error: 246 movl $VMX_INVEPT_ERROR, %eax 247 jmp decode_inst_error 248 249decode_inst_error: 250 movl $VM_FAIL_VALID, %r11d 251 jz inst_error 252 movl $VM_FAIL_INVALID, %r11d 253inst_error: 254 movl %r11d, VMXCTX_INST_FAIL_STATUS(%rdi) 255 256 /* 257 * The return value is already populated in %eax so we cannot use 258 * it as a scratch register beyond this point. 259 */ 260 261 /* 262 * Deactivate guest pmap from this cpu. 263 */ 264 movq VMXCTX_PMAP(%rdi), %r11 265 movl PCPU(CPUID), %r10d 266 LK btrl %r10d, PM_ACTIVE(%r11) 267 268 VMX_HOST_RESTORE 269 VLEAVE 270 ret 271 272/* 273 * Non-error VM-exit from the guest. Make this a label so it can 274 * be used by C code when setting up the VMCS. 275 * The VMCS-restored %rsp points to the struct vmxctx 276 */ 277 ALIGN_TEXT 278 .globl vmx_exit_guest_flush_rsb 279vmx_exit_guest_flush_rsb: 280 /* 281 * Save guest state that is not automatically saved in the vmcs. 282 */ 283 VMX_GUEST_SAVE 284 285 /* 286 * Deactivate guest pmap from this cpu. 287 */ 288 movq VMXCTX_PMAP(%rdi), %r11 289 movl PCPU(CPUID), %r10d 290 LK btrl %r10d, PM_ACTIVE(%r11) 291 292 VMX_HOST_RESTORE 293 294 VMX_GUEST_CLOBBER 295 296 /* 297 * To prevent malicious branch target predictions from 298 * affecting the host, overwrite all entries in the RSB upon 299 * exiting a guest. 300 */ 301 mov $16, %ecx /* 16 iterations, two calls per loop */ 302 mov %rsp, %rax 3030: call 2f /* create an RSB entry. */ 3041: pause 305 call 1b /* capture rogue speculation. */ 3062: call 2f /* create an RSB entry. */ 3071: pause 308 call 1b /* capture rogue speculation. */ 3092: sub $1, %ecx 310 jnz 0b 311 mov %rax, %rsp 312 313 /* 314 * This will return to the caller of 'vmx_enter_guest()' with a return 315 * value of VMX_GUEST_VMEXIT. 316 */ 317 movl $VMX_GUEST_VMEXIT, %eax 318 VLEAVE 319 ret 320 321 .globl vmx_exit_guest 322vmx_exit_guest: 323 /* 324 * Save guest state that is not automatically saved in the vmcs. 325 */ 326 VMX_GUEST_SAVE 327 328 /* 329 * Deactivate guest pmap from this cpu. 330 */ 331 movq VMXCTX_PMAP(%rdi), %r11 332 movl PCPU(CPUID), %r10d 333 LK btrl %r10d, PM_ACTIVE(%r11) 334 335 VMX_HOST_RESTORE 336 337 VMX_GUEST_CLOBBER 338 339 /* 340 * This will return to the caller of 'vmx_enter_guest()' with a return 341 * value of VMX_GUEST_VMEXIT. 342 */ 343 movl $VMX_GUEST_VMEXIT, %eax 344 VLEAVE 345 ret 346END(vmx_enter_guest) 347 348/* 349 * %rdi = interrupt handler entry point 350 * 351 * Calling sequence described in the "Instruction Set Reference" for the "INT" 352 * instruction in Intel SDM, Vol 2. 353 */ 354ENTRY(vmx_call_isr) 355 VENTER 356 mov %rsp, %r11 /* save %rsp */ 357 and $~0xf, %rsp /* align on 16-byte boundary */ 358 pushq $KERNEL_SS /* %ss */ 359 pushq %r11 /* %rsp */ 360 pushfq /* %rflags */ 361 pushq $KERNEL_CS /* %cs */ 362 cli /* disable interrupts */ 363 callq *%rdi /* push %rip and call isr */ 364 VLEAVE 365 ret 366END(vmx_call_isr) 367