]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/vmm/intel/vmx_support.S
Revis manual pages. [SA-18:08.tcp]
[FreeBSD/FreeBSD.git] / sys / amd64 / vmm / intel / vmx_support.S
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 #include <machine/specialreg.h>
32
33 #include "vmx_assym.h"
34
35 #ifdef SMP
36 #define LK      lock ;
37 #else
38 #define LK
39 #endif
40
41 /* Be friendly to DTrace FBT's prologue/epilogue pattern matching */
42 #define VENTER  push %rbp ; mov %rsp,%rbp
43 #define VLEAVE  pop %rbp
44
45 /*
46  * Save the guest context.
47  */
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);                            \
64         movq    %cr2,%rdi;                                              \
65         movq    %rdi,VMXCTX_GUEST_CR2(%rsp);                            \
66         movq    %rsp,%rdi;
67
68 /*
69  * Assumes that %rdi holds a pointer to the 'vmxctx'.
70  *
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.
74  *
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'.
77  */
78 #define VMX_GUEST_RESTORE                                               \
79         movq    %rdi,%rsp;                                              \
80         movq    VMXCTX_GUEST_CR2(%rdi),%rsi;                            \
81         movq    %rsi,%cr2;                                              \
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 */
97
98 /*
99  * Clobber the remaining registers with guest contents so they can't
100  * be misused.
101  */
102 #define VMX_GUEST_CLOBBER                                               \
103         xor     %rax, %rax;                                             \
104         xor     %rcx, %rcx;                                             \
105         xor     %rdx, %rdx;                                             \
106         xor     %rsi, %rsi;                                             \
107         xor     %r8, %r8;                                               \
108         xor     %r9, %r9;                                               \
109         xor     %r10, %r10;                                             \
110         xor     %r11, %r11;
111
112 /*
113  * Save and restore the host context.
114  *
115  * Assumes that %rdi holds a pointer to the 'vmxctx'.
116  */
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);                            \
125
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;                            \
134
135 /*
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.
141  */
142 ENTRY(vmx_enter_guest)
143         VENTER
144         /*
145          * Save host state before doing anything else.
146          */
147         VMX_HOST_SAVE
148
149         /*
150          * Activate guest pmap on this cpu.
151          */
152         movq    VMXCTX_PMAP(%rdi), %r11
153         movl    PCPU(CPUID), %eax
154         LK btsl %eax, PM_ACTIVE(%r11)
155
156         /*
157          * If 'vmx->eptgen[curcpu]' is not identical to 'pmap->pm_eptgen'
158          * then we must invalidate all mappings associated with this EPTP.
159          */
160         movq    PM_EPTGEN(%r11), %r10
161         cmpq    %r10, VMX_EPTGEN(%rsi, %rax, 8)
162         je      guest_restore
163
164         /* Refresh 'vmx->eptgen[curcpu]' */
165         movq    %r10, VMX_EPTGEN(%rsi, %rax, 8)
166
167         /* Setup the invept descriptor on the host stack */
168         mov     %rsp, %r11
169         movq    VMX_EPTP(%rsi), %rax
170         movq    %rax, -16(%r11)
171         movq    $0x0, -8(%r11)
172         mov     $0x1, %eax              /* Single context invalidate */
173         invept  -16(%r11), %rax
174         jbe     invept_error            /* Check invept instruction error */
175
176 guest_restore:
177
178         /*
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.
182          */
183 #define L1D_FLUSH_SIZE  (64 * 1024)
184         movl    %edx, %r8d
185         cmpb    $0, guest_l1d_flush(%rip)
186         je      after_l1d
187         movq    vmx_msr_flush_cmd(%rip), %rax
188         testq   %rax, %rax
189         jz      1f
190         movq    %rax, %rdx
191         shrq    $32, %rdx
192         movl    $MSR_IA32_FLUSH_CMD, %ecx
193         wrmsr
194         jmp     after_l1d
195 1:      movq    $KERNBASE, %r9
196         movq    $-L1D_FLUSH_SIZE, %rcx
197         /*
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.
202          */
203 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
204         addq    $PAGE_SIZE, %rcx
205         jne     2b
206         xorl    %eax, %eax
207         cpuid
208         movq    $-L1D_FLUSH_SIZE, %rcx
209         /* pass 2: Read each cache line */
210 3:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
211         addq    $64, %rcx
212         jne     3b
213         lfence
214 #undef  L1D_FLUSH_SIZE
215 after_l1d:
216         cmpl    $0, %r8d
217         je      do_launch
218         VMX_GUEST_RESTORE
219         vmresume
220         /*
221          * In the common case 'vmresume' returns back to the host through
222          * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
223          *
224          * If there is an error we return VMX_VMRESUME_ERROR to the caller.
225          */
226         movq    %rsp, %rdi              /* point %rdi back to 'vmxctx' */
227         movl    $VMX_VMRESUME_ERROR, %eax
228         jmp     decode_inst_error
229
230 do_launch:
231         VMX_GUEST_RESTORE
232         vmlaunch
233         /*
234          * In the common case 'vmlaunch' returns back to the host through
235          * 'vmx_exit_guest' with %rsp pointing to 'vmxctx'.
236          *
237          * If there is an error we return VMX_VMLAUNCH_ERROR to the caller.
238          */
239         movq    %rsp, %rdi              /* point %rdi back to 'vmxctx' */
240         movl    $VMX_VMLAUNCH_ERROR, %eax
241         jmp     decode_inst_error
242
243 invept_error:
244         movl    $VMX_INVEPT_ERROR, %eax
245         jmp     decode_inst_error
246
247 decode_inst_error:
248         movl    $VM_FAIL_VALID, %r11d
249         jz      inst_error
250         movl    $VM_FAIL_INVALID, %r11d
251 inst_error:
252         movl    %r11d, VMXCTX_INST_FAIL_STATUS(%rdi)
253
254         /*
255          * The return value is already populated in %eax so we cannot use
256          * it as a scratch register beyond this point.
257          */
258
259         /*
260          * Deactivate guest pmap from this cpu.
261          */
262         movq    VMXCTX_PMAP(%rdi), %r11
263         movl    PCPU(CPUID), %r10d
264         LK btrl %r10d, PM_ACTIVE(%r11)
265
266         VMX_HOST_RESTORE
267         VLEAVE
268         ret
269
270 /*
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
274  */
275         ALIGN_TEXT
276         .globl  vmx_exit_guest_flush_rsb
277 vmx_exit_guest_flush_rsb:
278         /*
279          * Save guest state that is not automatically saved in the vmcs.
280          */
281         VMX_GUEST_SAVE
282
283         /*
284          * Deactivate guest pmap from this cpu.
285          */
286         movq    VMXCTX_PMAP(%rdi), %r11
287         movl    PCPU(CPUID), %r10d
288         LK btrl %r10d, PM_ACTIVE(%r11)
289
290         VMX_HOST_RESTORE
291
292         VMX_GUEST_CLOBBER
293
294         /*
295          * To prevent malicious branch target predictions from
296          * affecting the host, overwrite all entries in the RSB upon
297          * exiting a guest.
298          */
299         mov     $16, %ecx       /* 16 iterations, two calls per loop */
300         mov     %rsp, %rax
301 0:      call    2f              /* create an RSB entry. */
302 1:      pause
303         call    1b              /* capture rogue speculation. */
304 2:      call    2f              /* create an RSB entry. */
305 1:      pause
306         call    1b              /* capture rogue speculation. */
307 2:      sub     $1, %ecx
308         jnz     0b
309         mov     %rax, %rsp
310
311         /*
312          * This will return to the caller of 'vmx_enter_guest()' with a return
313          * value of VMX_GUEST_VMEXIT.
314          */
315         movl    $VMX_GUEST_VMEXIT, %eax
316         VLEAVE
317         ret
318
319         .globl  vmx_exit_guest
320 vmx_exit_guest:
321         /*
322          * Save guest state that is not automatically saved in the vmcs.
323          */
324         VMX_GUEST_SAVE
325
326         /*
327          * Deactivate guest pmap from this cpu.
328          */
329         movq    VMXCTX_PMAP(%rdi), %r11
330         movl    PCPU(CPUID), %r10d
331         LK btrl %r10d, PM_ACTIVE(%r11)
332
333         VMX_HOST_RESTORE
334
335         VMX_GUEST_CLOBBER
336
337         /*
338          * This will return to the caller of 'vmx_enter_guest()' with a return
339          * value of VMX_GUEST_VMEXIT.
340          */
341         movl    $VMX_GUEST_VMEXIT, %eax
342         VLEAVE
343         ret
344 END(vmx_enter_guest)
345
346 /*
347  * %rdi = interrupt handler entry point
348  *
349  * Calling sequence described in the "Instruction Set Reference" for the "INT"
350  * instruction in Intel SDM, Vol 2.
351  */
352 ENTRY(vmx_call_isr)
353         VENTER
354         mov     %rsp, %r11                      /* save %rsp */
355         and     $~0xf, %rsp                     /* align on 16-byte boundary */
356         pushq   $KERNEL_SS                      /* %ss */
357         pushq   %r11                            /* %rsp */
358         pushfq                                  /* %rflags */
359         pushq   $KERNEL_CS                      /* %cs */
360         cli                                     /* disable interrupts */
361         callq   *%rdi                           /* push %rip and call isr */
362         VLEAVE
363         ret
364 END(vmx_call_isr)