vmx_support.S revision 266339
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: stable/10/sys/amd64/vmm/intel/vmx_support.S 266339 2014-05-17 19:11:08Z jhb $
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