1/*	$NetBSD: nvmm_x86_vmxfunc.S,v 1.6 2020/09/05 07:22:26 maxv Exp $	*/
2
3/*
4 * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
5 * All rights reserved.
6 *
7 * This code is part of the NVMM hypervisor.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/* Override user-land alignment before including asm.h */
32#define	ALIGN_DATA	.align	8
33#define ALIGN_TEXT	.align 16,0x90
34#define _ALIGN_TEXT	ALIGN_TEXT
35
36#define _LOCORE
37#include "assym.h"
38#include <machine/asm.h>
39#include <machine/segments.h>
40#include <x86/specialreg.h>
41
42#define ASM_NVMM
43#include <dev/nvmm/x86/nvmm_x86.h>
44
45	.text
46
47/*
48 * %rdi = *pa
49 */
50ENTRY(_vmx_vmxon)
51	vmxon	(%rdi)
52	jz	.Lfail_vmxon
53	jc	.Lfail_vmxon
54	xorq	%rax,%rax
55	retq
56.Lfail_vmxon:
57	movq	$-1,%rax
58	retq
59END(_vmx_vmxon)
60
61/*
62 * no arg
63 */
64ENTRY(_vmx_vmxoff)
65	vmxoff
66	jz	.Lfail_vmxoff
67	jc	.Lfail_vmxoff
68	xorq	%rax,%rax
69	retq
70.Lfail_vmxoff:
71	movq	$-1,%rax
72	retq
73END(_vmx_vmxoff)
74
75/* redef */
76#define VMCS_HOST_RSP				0x00006C14
77
78#define HOST_SAVE_GPRS		\
79	pushq	%rbx		;\
80	pushq	%rbp		;\
81	pushq	%r12		;\
82	pushq	%r13		;\
83	pushq	%r14		;\
84	pushq	%r15
85
86#define HOST_RESTORE_GPRS	\
87	popq	%r15		;\
88	popq	%r14		;\
89	popq	%r13		;\
90	popq	%r12		;\
91	popq	%rbp		;\
92	popq	%rbx
93
94#define HOST_SAVE_RAX		\
95	pushq	%rax
96
97#define HOST_RESTORE_RAX	\
98	popq	%rax
99
100#define HOST_SAVE_LDT		\
101	sldtw	%ax		;\
102	pushq	%rax
103
104#define HOST_RESTORE_LDT	\
105	popq	%rax		;\
106	lldtw	%ax
107
108/*
109 * We don't save RAX (done manually), but we do restore it.
110 */
111
112#define GUEST_SAVE_GPRS(reg)				\
113	movq	%rcx,(NVMM_X64_GPR_RCX * 8)(reg)	;\
114	movq	%rdx,(NVMM_X64_GPR_RDX * 8)(reg)	;\
115	movq	%rbx,(NVMM_X64_GPR_RBX * 8)(reg)	;\
116	movq	%rbp,(NVMM_X64_GPR_RBP * 8)(reg)	;\
117	movq	%rsi,(NVMM_X64_GPR_RSI * 8)(reg)	;\
118	movq	%rdi,(NVMM_X64_GPR_RDI * 8)(reg)	;\
119	movq	%r8,(NVMM_X64_GPR_R8 * 8)(reg)		;\
120	movq	%r9,(NVMM_X64_GPR_R9 * 8)(reg)		;\
121	movq	%r10,(NVMM_X64_GPR_R10 * 8)(reg)	;\
122	movq	%r11,(NVMM_X64_GPR_R11 * 8)(reg)	;\
123	movq	%r12,(NVMM_X64_GPR_R12 * 8)(reg)	;\
124	movq	%r13,(NVMM_X64_GPR_R13 * 8)(reg)	;\
125	movq	%r14,(NVMM_X64_GPR_R14 * 8)(reg)	;\
126	movq	%r15,(NVMM_X64_GPR_R15 * 8)(reg)
127
128#define GUEST_RESTORE_GPRS(reg)				\
129	movq	(NVMM_X64_GPR_RCX * 8)(reg),%rcx	;\
130	movq	(NVMM_X64_GPR_RDX * 8)(reg),%rdx	;\
131	movq	(NVMM_X64_GPR_RBX * 8)(reg),%rbx	;\
132	movq	(NVMM_X64_GPR_RBP * 8)(reg),%rbp	;\
133	movq	(NVMM_X64_GPR_RSI * 8)(reg),%rsi	;\
134	movq	(NVMM_X64_GPR_RDI * 8)(reg),%rdi	;\
135	movq	(NVMM_X64_GPR_R8 * 8)(reg),%r8		;\
136	movq	(NVMM_X64_GPR_R9 * 8)(reg),%r9		;\
137	movq	(NVMM_X64_GPR_R10 * 8)(reg),%r10	;\
138	movq	(NVMM_X64_GPR_R11 * 8)(reg),%r11	;\
139	movq	(NVMM_X64_GPR_R12 * 8)(reg),%r12	;\
140	movq	(NVMM_X64_GPR_R13 * 8)(reg),%r13	;\
141	movq	(NVMM_X64_GPR_R14 * 8)(reg),%r14	;\
142	movq	(NVMM_X64_GPR_R15 * 8)(reg),%r15	;\
143	movq	(NVMM_X64_GPR_RAX * 8)(reg),%rax
144
145/*
146 * %rdi = VA of guest GPR state
147 */
148ENTRY(vmx_vmlaunch)
149	/* Save the Host GPRs. */
150	HOST_SAVE_GPRS
151
152	/* Save the Host LDT. */
153	HOST_SAVE_LDT
154
155	/* Save the Host RAX. */
156	movq	%rdi,%rax
157	pushq	%rax
158
159	/* Save the Host RSP. */
160	movq	$VMCS_HOST_RSP,%rdi
161	movq	%rsp,%rsi
162	vmwrite	%rsi,%rdi
163
164	/* Restore the Guest GPRs. */
165	GUEST_RESTORE_GPRS(%rax)
166
167	/* Run the VM. */
168	vmlaunch
169
170	/* Failure. */
171	addq	$8,%rsp
172	HOST_RESTORE_LDT
173	HOST_RESTORE_GPRS
174	movq	$-1,%rax
175	retq
176END(vmx_vmlaunch)
177
178/*
179 * %rdi = VA of guest GPR state
180 */
181ENTRY(vmx_vmresume)
182	/* Save the Host GPRs. */
183	HOST_SAVE_GPRS
184
185	/* Save the Host LDT. */
186	HOST_SAVE_LDT
187
188	/* Save the Host RAX. */
189	movq	%rdi,%rax
190	pushq	%rax
191
192	/* Save the Host RSP. */
193	movq	$VMCS_HOST_RSP,%rdi
194	movq	%rsp,%rsi
195	vmwrite	%rsi,%rdi
196
197	/* Restore the Guest GPRs. */
198	GUEST_RESTORE_GPRS(%rax)
199
200	/* Run the VM. */
201	vmresume
202
203	/* Failure. */
204	addq	$8,%rsp
205	HOST_RESTORE_LDT
206	HOST_RESTORE_GPRS
207	movq	$-1,%rax
208	retq
209END(vmx_vmresume)
210
211/*
212 * The CPU jumps here after a #VMEXIT.
213 */
214ENTRY(vmx_resume_rip)
215	/* Save the Guest GPRs. RAX done manually. */
216	pushq	%rax
217	movq	8(%rsp),%rax
218	GUEST_SAVE_GPRS(%rax)
219	popq	%rbx
220	movq	%rbx,(NVMM_X64_GPR_RAX * 8)(%rax)
221	addq	$8,%rsp
222
223	/* Restore the Host LDT. */
224	HOST_RESTORE_LDT
225
226	/* Restore the Host GPRs. */
227	HOST_RESTORE_GPRS
228
229	xorq	%rax,%rax
230	retq
231END(vmx_resume_rip)
232
233ENTRY(vmx_insn_failvalid)
234	movq	$.Lvmx_validstr,%rdi
235	call	_C_LABEL(panic)
236END(vmx_insn_failvalid)
237
238ENTRY(vmx_insn_failinvalid)
239	movq	$.Lvmx_invalidstr,%rdi
240	call	_C_LABEL(panic)
241END(vmx_insn_failinvalid)
242
243	.section ".rodata"
244
245.Lvmx_validstr:
246	.string	"VMX fail valid\0"
247.Lvmx_invalidstr:
248	.string "VMX fail invalid\0"
249