]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/vmm/intel/vmx_support.S
MFC 260802,260836,260863,261001,261074,261617:
[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
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  */
104 ENTRY(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
137 guest_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
153 do_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
166 invept_error:
167         movl    $VMX_INVEPT_ERROR, %eax
168         jmp     decode_inst_error
169
170 decode_inst_error:
171         movl    $VM_FAIL_VALID, %r11d
172         jz      inst_error
173         movl    $VM_FAIL_INVALID, %r11d
174 inst_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
191 END(vmx_enter_guest)
192
193 /*
194  * void vmx_exit_guest(void)
195  * %rsp points to the struct vmxctx
196  */
197 ENTRY(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
237 END(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  */
245 ENTRY(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
255 END(vmx_call_isr)