1/*
2 * Copyright (c) 2018-2021 Maxime Villard, m00nbsd.net
3 * All rights reserved.
4 *
5 * This code is part of the NVMM hypervisor.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#define LOCORE
30#include <machine/asmacros.h>
31#include <machine/segments.h>
32#include "assym.s"
33
34#define ASM_NVMM
35#include "nvmm_x86.h"
36
37	.text
38
39#define HOST_SAVE_GPRS		\
40	pushq	%rbx		;\
41	pushq	%rbp		;\
42	pushq	%r12		;\
43	pushq	%r13		;\
44	pushq	%r14		;\
45	pushq	%r15
46
47#define HOST_RESTORE_GPRS	\
48	popq	%r15		;\
49	popq	%r14		;\
50	popq	%r13		;\
51	popq	%r12		;\
52	popq	%rbp		;\
53	popq	%rbx
54
55#define HOST_SAVE_MSR(msr)	\
56	movq	$msr,%rcx	;\
57	rdmsr			;\
58	pushq	%rdx		;\
59	pushq	%rax
60
61#define HOST_RESTORE_MSR(msr)	\
62	popq	%rax		;\
63	popq	%rdx		;\
64	movq	$msr,%rcx	;\
65	wrmsr
66
67#define HOST_SAVE_TR		\
68	strw	%ax		;\
69	pushq	%rax
70
71/* In DragonFly, PCPU(tss_gdt) points directly to the gdt[] entry for the
72 * current CPU's TSS descriptor; while NetBSD's CPUVAR(GDT) points to the
73 * gdtstore[] table. */
74#define HOST_RESTORE_TR				\
75	popq	%rax				;\
76	movzwq	%ax,%rdx			;\
77	movq	PCPU(tss_gdt),%rax		;\
78	/* Clear the busy bit for reloading. */	\
79	andq	$~0x0200,4(%rax)		;\
80	ltrw	%dx
81
82#define HOST_SAVE_LDT		\
83	sldtw	%ax		;\
84	pushq	%rax
85
86#define HOST_RESTORE_LDT	\
87	popq	%rax		;\
88	lldtw	%ax
89
90/*
91 * All GPRs except RAX and RSP, which are taken care of in VMCB.
92 */
93
94#define GUEST_SAVE_GPRS(reg)				\
95	movq	%rcx,(NVMM_X64_GPR_RCX * 8)(reg)	;\
96	movq	%rdx,(NVMM_X64_GPR_RDX * 8)(reg)	;\
97	movq	%rbx,(NVMM_X64_GPR_RBX * 8)(reg)	;\
98	movq	%rbp,(NVMM_X64_GPR_RBP * 8)(reg)	;\
99	movq	%rsi,(NVMM_X64_GPR_RSI * 8)(reg)	;\
100	movq	%rdi,(NVMM_X64_GPR_RDI * 8)(reg)	;\
101	movq	%r8,(NVMM_X64_GPR_R8 * 8)(reg)		;\
102	movq	%r9,(NVMM_X64_GPR_R9 * 8)(reg)		;\
103	movq	%r10,(NVMM_X64_GPR_R10 * 8)(reg)	;\
104	movq	%r11,(NVMM_X64_GPR_R11 * 8)(reg)	;\
105	movq	%r12,(NVMM_X64_GPR_R12 * 8)(reg)	;\
106	movq	%r13,(NVMM_X64_GPR_R13 * 8)(reg)	;\
107	movq	%r14,(NVMM_X64_GPR_R14 * 8)(reg)	;\
108	movq	%r15,(NVMM_X64_GPR_R15 * 8)(reg)
109
110#define GUEST_RESTORE_GPRS(reg)				\
111	movq	(NVMM_X64_GPR_RCX * 8)(reg),%rcx	;\
112	movq	(NVMM_X64_GPR_RDX * 8)(reg),%rdx	;\
113	movq	(NVMM_X64_GPR_RBX * 8)(reg),%rbx	;\
114	movq	(NVMM_X64_GPR_RBP * 8)(reg),%rbp	;\
115	movq	(NVMM_X64_GPR_RSI * 8)(reg),%rsi	;\
116	movq	(NVMM_X64_GPR_RDI * 8)(reg),%rdi	;\
117	movq	(NVMM_X64_GPR_R8 * 8)(reg),%r8		;\
118	movq	(NVMM_X64_GPR_R9 * 8)(reg),%r9		;\
119	movq	(NVMM_X64_GPR_R10 * 8)(reg),%r10	;\
120	movq	(NVMM_X64_GPR_R11 * 8)(reg),%r11	;\
121	movq	(NVMM_X64_GPR_R12 * 8)(reg),%r12	;\
122	movq	(NVMM_X64_GPR_R13 * 8)(reg),%r13	;\
123	movq	(NVMM_X64_GPR_R14 * 8)(reg),%r14	;\
124	movq	(NVMM_X64_GPR_R15 * 8)(reg),%r15
125
126/*
127 * %rdi = PA of VMCB
128 * %rsi = VA of guest GPR state
129 */
130ENTRY(svm_vmrun)
131	/* Save the Host GPRs. */
132	HOST_SAVE_GPRS
133
134	/* Save the Host TR. */
135	HOST_SAVE_TR
136
137	/* Save the Host GSBASE. */
138	HOST_SAVE_MSR(MSR_GSBASE)
139
140	/* Reset DS and ES. */
141	movq	$GSEL(GUDATA_SEL, SEL_UPL),%rax
142	movw	%ax,%ds
143	movw	%ax,%es
144
145	/* Save the Host LDT. */
146	HOST_SAVE_LDT
147
148	/* Prepare RAX. */
149	pushq	%rsi
150	pushq	%rdi
151
152	/* Restore the Guest GPRs. */
153	movq	%rsi,%rax
154	GUEST_RESTORE_GPRS(%rax)
155
156	/* Set RAX. */
157	popq	%rax
158
159	/* Run the VM. */
160	vmload	%rax
161	vmrun	%rax
162	vmsave	%rax
163
164	/* Get RAX. */
165	popq	%rax
166
167	/* Save the Guest GPRs. */
168	GUEST_SAVE_GPRS(%rax)
169
170	/* Restore the Host LDT. */
171	HOST_RESTORE_LDT
172
173	/* Reset FS and GS. */
174	xorq	%rax,%rax
175	movw	%ax,%fs
176	movw	%ax,%gs
177
178	/* Restore the Host GSBASE. */
179	HOST_RESTORE_MSR(MSR_GSBASE)
180
181	/* Restore the Host TR. */
182	HOST_RESTORE_TR
183
184	/* Restore the Host GPRs. */
185	HOST_RESTORE_GPRS
186
187	retq
188END(svm_vmrun)
189