2 * Copyright (c) 2011 NetApp, Inc.
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <machine/asmacros.h>
31 #include <machine/specialreg.h>
33 #include "vmx_assym.h"
41 /* Be friendly to DTrace FBT's prologue/epilogue pattern matching */
42 #define VENTER push %rbp ; mov %rsp,%rbp
43 #define VLEAVE pop %rbp
46 * Save the guest context.
48 #define VMX_GUEST_SAVE \
49 movq %rdi,VMXCTX_GUEST_RDI(%rsp); \
50 movq %rsi,VMXCTX_GUEST_RSI(%rsp); \
51 movq %rdx,VMXCTX_GUEST_RDX(%rsp); \
52 movq %rcx,VMXCTX_GUEST_RCX(%rsp); \
53 movq %r8,VMXCTX_GUEST_R8(%rsp); \
54 movq %r9,VMXCTX_GUEST_R9(%rsp); \
55 movq %rax,VMXCTX_GUEST_RAX(%rsp); \
56 movq %rbx,VMXCTX_GUEST_RBX(%rsp); \
57 movq %rbp,VMXCTX_GUEST_RBP(%rsp); \
58 movq %r10,VMXCTX_GUEST_R10(%rsp); \
59 movq %r11,VMXCTX_GUEST_R11(%rsp); \
60 movq %r12,VMXCTX_GUEST_R12(%rsp); \
61 movq %r13,VMXCTX_GUEST_R13(%rsp); \
62 movq %r14,VMXCTX_GUEST_R14(%rsp); \
63 movq %r15,VMXCTX_GUEST_R15(%rsp); \
65 movq %rdi,VMXCTX_GUEST_CR2(%rsp); \
69 * Assumes that %rdi holds a pointer to the 'vmxctx'.
71 * On "return" all registers are updated to reflect guest state. The two
72 * exceptions are %rip and %rsp. These registers are atomically switched
73 * by hardware from the guest area of the vmcs.
75 * We modify %rsp to point to the 'vmxctx' so we can use it to restore
76 * host context in case of an error with 'vmlaunch' or 'vmresume'.
78 #define VMX_GUEST_RESTORE \
80 movq VMXCTX_GUEST_CR2(%rdi),%rsi; \
82 movq VMXCTX_GUEST_RSI(%rdi),%rsi; \
83 movq VMXCTX_GUEST_RDX(%rdi),%rdx; \
84 movq VMXCTX_GUEST_RCX(%rdi),%rcx; \
85 movq VMXCTX_GUEST_R8(%rdi),%r8; \
86 movq VMXCTX_GUEST_R9(%rdi),%r9; \
87 movq VMXCTX_GUEST_RAX(%rdi),%rax; \
88 movq VMXCTX_GUEST_RBX(%rdi),%rbx; \
89 movq VMXCTX_GUEST_RBP(%rdi),%rbp; \
90 movq VMXCTX_GUEST_R10(%rdi),%r10; \
91 movq VMXCTX_GUEST_R11(%rdi),%r11; \
92 movq VMXCTX_GUEST_R12(%rdi),%r12; \
93 movq VMXCTX_GUEST_R13(%rdi),%r13; \
94 movq VMXCTX_GUEST_R14(%rdi),%r14; \
95 movq VMXCTX_GUEST_R15(%rdi),%r15; \
96 movq VMXCTX_GUEST_RDI(%rdi),%rdi; /* restore rdi the last */
99 * Clobber the remaining registers with guest contents so they can't
102 #define VMX_GUEST_CLOBBER \
113 * Save and restore the host context.
115 * Assumes that %rdi holds a pointer to the 'vmxctx'.
117 #define VMX_HOST_SAVE \
118 movq %r15, VMXCTX_HOST_R15(%rdi); \
119 movq %r14, VMXCTX_HOST_R14(%rdi); \
120 movq %r13, VMXCTX_HOST_R13(%rdi); \
121 movq %r12, VMXCTX_HOST_R12(%rdi); \
122 movq %rbp, VMXCTX_HOST_RBP(%rdi); \
123 movq %rsp, VMXCTX_HOST_RSP(%rdi); \
124 movq %rbx, VMXCTX_HOST_RBX(%rdi); \
126 #define VMX_HOST_RESTORE \
127 movq VMXCTX_HOST_R15(%rdi), %r15; \
128 movq VMXCTX_HOST_R14(%rdi), %r14; \
129 movq VMXCTX_HOST_R13(%rdi), %r13; \
130 movq VMXCTX_HOST_R12(%rdi), %r12; \
131 movq VMXCTX_HOST_RBP(%rdi), %rbp; \
132 movq VMXCTX_HOST_RSP(%rdi), %rsp; \
133 movq VMXCTX_HOST_RBX(%rdi), %rbx; \
136 * vmx_enter_guest(struct vmxctx *vmxctx, int launched)
137 * %rdi: pointer to the 'vmxctx'
138 * %rsi: pointer to the 'vmx'
139 * %edx: launch state of the VMCS
140 * Interrupts must be disabled on entry.
142 ENTRY(vmx_enter_guest)
145 * Save host state before doing anything else.
150 * Activate guest pmap on this cpu.
152 movq VMXCTX_PMAP(%rdi), %r11
153 movl PCPU(CPUID), %eax
154 LK btsl %eax, PM_ACTIVE(%r11)
157 * If 'vmx->eptgen[curcpu]' is not identical to 'pmap->pm_eptgen'
158 * then we must invalidate all mappings associated with this EPTP.
160 movq PM_EPTGEN(%r11), %r10
161 cmpq %r10, VMX_EPTGEN(%rsi, %rax, 8)
164 /* Refresh 'vmx->eptgen[curcpu]' */
165 movq %r10, VMX_EPTGEN(%rsi, %rax, 8)
167 /* Setup the invept descriptor on the host stack */
169 movq VMX_EPTP(%rsi), %rax
172 mov $0x1, %eax /* Single context invalidate */
173 invept -16(%r11), %rax
174 jbe invept_error /* Check invept instruction error */
179 * Flush L1D cache if requested. Use IA32_FLUSH_CMD MSR if available,
180 * otherwise load enough of the data from the zero_region to flush
181 * existing L1D content.
183 #define L1D_FLUSH_SIZE (64 * 1024)
185 cmpb $0, guest_l1d_flush(%rip)
187 movq vmx_msr_flush_cmd(%rip), %rax
192 movl $MSR_IA32_FLUSH_CMD, %ecx
195 1: movq $KERNBASE, %r9
196 movq $-L1D_FLUSH_SIZE, %rcx
198 * pass 1: Preload TLB.
199 * Kernel text is mapped using superpages, TLB preload is
200 * done for the benefit of older CPUs which split 2M page
201 * into 4k TLB entries.
203 2: movb L1D_FLUSH_SIZE(%r9, %rcx), %al
204 addq $PAGE_SIZE, %rcx
208 movq $-L1D_FLUSH_SIZE, %rcx
209 /* pass 2: Read each cache line */
210 3: movb L1D_FLUSH_SIZE(%r9, %rcx), %al
214 #undef L1D_FLUSH_SIZE
221 * In the common case 'vmresume' returns back to the host through
222 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
224 * If there is an error we return VMX_VMRESUME_ERROR to the caller.
226 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */
227 movl $VMX_VMRESUME_ERROR, %eax
228 jmp decode_inst_error
234 * In the common case 'vmlaunch' returns back to the host through
235 * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
237 * If there is an error we return VMX_VMLAUNCH_ERROR to the caller.
239 movq %rsp, %rdi /* point %rdi back to 'vmxctx' */
240 movl $VMX_VMLAUNCH_ERROR, %eax
241 jmp decode_inst_error
244 movl $VMX_INVEPT_ERROR, %eax
245 jmp decode_inst_error
248 movl $VM_FAIL_VALID, %r11d
250 movl $VM_FAIL_INVALID, %r11d
252 movl %r11d, VMXCTX_INST_FAIL_STATUS(%rdi)
255 * The return value is already populated in %eax so we cannot use
256 * it as a scratch register beyond this point.
260 * Deactivate guest pmap from this cpu.
262 movq VMXCTX_PMAP(%rdi), %r11
263 movl PCPU(CPUID), %r10d
264 LK btrl %r10d, PM_ACTIVE(%r11)
271 * Non-error VM-exit from the guest. Make this a label so it can
272 * be used by C code when setting up the VMCS.
273 * The VMCS-restored %rsp points to the struct vmxctx
276 .globl vmx_exit_guest_flush_rsb
277 vmx_exit_guest_flush_rsb:
279 * Save guest state that is not automatically saved in the vmcs.
284 * Deactivate guest pmap from this cpu.
286 movq VMXCTX_PMAP(%rdi), %r11
287 movl PCPU(CPUID), %r10d
288 LK btrl %r10d, PM_ACTIVE(%r11)
295 * To prevent malicious branch target predictions from
296 * affecting the host, overwrite all entries in the RSB upon
299 mov $16, %ecx /* 16 iterations, two calls per loop */
301 0: call 2f /* create an RSB entry. */
303 call 1b /* capture rogue speculation. */
304 2: call 2f /* create an RSB entry. */
306 call 1b /* capture rogue speculation. */
312 * This will return to the caller of 'vmx_enter_guest()' with a return
313 * value of VMX_GUEST_VMEXIT.
315 movl $VMX_GUEST_VMEXIT, %eax
319 .globl vmx_exit_guest
322 * Save guest state that is not automatically saved in the vmcs.
327 * Deactivate guest pmap from this cpu.
329 movq VMXCTX_PMAP(%rdi), %r11
330 movl PCPU(CPUID), %r10d
331 LK btrl %r10d, PM_ACTIVE(%r11)
338 * This will return to the caller of 'vmx_enter_guest()' with a return
339 * value of VMX_GUEST_VMEXIT.
341 movl $VMX_GUEST_VMEXIT, %eax
347 * %rdi = interrupt handler entry point
349 * Calling sequence described in the "Instruction Set Reference" for the "INT"
350 * instruction in Intel SDM, Vol 2.
354 mov %rsp, %r11 /* save %rsp */
355 and $~0xf, %rsp /* align on 16-byte boundary */
356 pushq $KERNEL_SS /* %ss */
357 pushq %r11 /* %rsp */
359 pushq $KERNEL_CS /* %cs */
360 cli /* disable interrupts */
361 callq *%rdi /* push %rip and call isr */