vmcb.c revision 271346
1/*-
2 * Copyright (c) 2013 Anish Gupta (akgupt3@gmail.com)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/vmcb.c 271346 2014-09-10 02:35:19Z neel $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/cpuset.h>
33
34#include <machine/segments.h>
35#include <machine/specialreg.h>
36#include <machine/vmm.h>
37
38#include "vmcb.h"
39#include "svm.h"
40
41/*
42 * The VMCB aka Virtual Machine Control Block is a 4KB aligned page
43 * in memory that describes the virtual machine.
44 *
45 * The VMCB contains:
46 * - instructions or events in the guest to intercept
47 * - control bits that modify execution environment of the guest
48 * - guest processor state (e.g. general purpose registers)
49 */
50
51/*
52 * Read from segment selector, control and general purpose register of VMCB.
53 */
54int
55vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval)
56{
57	struct vmcb_state *state;
58	struct vmcb_segment *seg;
59	int err;
60
61	state = &vmcb->state;
62	err = 0;
63
64	switch (ident) {
65	case VM_REG_GUEST_CR0:
66		*retval = state->cr0;
67		break;
68
69	case VM_REG_GUEST_CR2:
70		*retval = state->cr2;
71		break;
72
73	case VM_REG_GUEST_CR3:
74		*retval = state->cr3;
75		break;
76
77	case VM_REG_GUEST_CR4:
78		*retval = state->cr4;
79		break;
80
81	case VM_REG_GUEST_DR7:
82		*retval = state->dr7;
83		break;
84
85	case VM_REG_GUEST_EFER:
86		*retval = state->efer;
87		break;
88
89	case VM_REG_GUEST_RAX:
90		*retval = state->rax;
91		break;
92
93	case VM_REG_GUEST_RFLAGS:
94		*retval = state->rflags;
95		break;
96
97	case VM_REG_GUEST_RIP:
98		*retval = state->rip;
99		break;
100
101	case VM_REG_GUEST_RSP:
102		*retval = state->rsp;
103		break;
104
105	case VM_REG_GUEST_CS:
106	case VM_REG_GUEST_DS:
107	case VM_REG_GUEST_ES:
108	case VM_REG_GUEST_FS:
109	case VM_REG_GUEST_GS:
110	case VM_REG_GUEST_SS:
111	case VM_REG_GUEST_GDTR:
112	case VM_REG_GUEST_IDTR:
113	case VM_REG_GUEST_LDTR:
114	case VM_REG_GUEST_TR:
115		seg = vmcb_seg(vmcb, ident);
116		if (seg == NULL) {
117			ERR("Invalid seg type %d\n", ident);
118			err = EINVAL;
119			break;
120		}
121
122		*retval = seg->selector;
123		break;
124
125	default:
126		err =  EINVAL;
127		break;
128	}
129
130	return (err);
131}
132
133/*
134 * Write to segment selector, control and general purpose register of VMCB.
135 */
136int
137vmcb_write(struct vmcb *vmcb, int ident, uint64_t val)
138{
139	struct vmcb_state *state;
140	struct vmcb_segment *seg;
141	int err;
142
143	state = &vmcb->state;
144	err = 0;
145
146	switch (ident) {
147	case VM_REG_GUEST_CR0:
148		state->cr0 = val;
149		break;
150
151	case VM_REG_GUEST_CR2:
152		state->cr2 = val;
153		break;
154
155	case VM_REG_GUEST_CR3:
156		state->cr3 = val;
157		break;
158
159	case VM_REG_GUEST_CR4:
160		state->cr4 = val;
161		break;
162
163	case VM_REG_GUEST_DR7:
164		state->dr7 = val;
165		break;
166
167	case VM_REG_GUEST_EFER:
168		/* EFER_SVM must always be set when the guest is executing */
169		state->efer = val | EFER_SVM;
170		break;
171
172	case VM_REG_GUEST_RAX:
173		state->rax = val;
174		break;
175
176	case VM_REG_GUEST_RFLAGS:
177		state->rflags = val;
178		break;
179
180	case VM_REG_GUEST_RIP:
181		state->rip = val;
182		break;
183
184	case VM_REG_GUEST_RSP:
185		state->rsp = val;
186		break;
187
188	case VM_REG_GUEST_CS:
189	case VM_REG_GUEST_DS:
190	case VM_REG_GUEST_ES:
191	case VM_REG_GUEST_FS:
192	case VM_REG_GUEST_GS:
193	case VM_REG_GUEST_SS:
194	case VM_REG_GUEST_GDTR:
195	case VM_REG_GUEST_IDTR:
196	case VM_REG_GUEST_LDTR:
197	case VM_REG_GUEST_TR:
198		seg = vmcb_seg(vmcb, ident);
199		if (seg == NULL) {
200			ERR("Invalid segment type %d\n", ident);
201			err = EINVAL;
202			break;
203		}
204
205		seg->selector = val;
206		break;
207
208	default:
209		err = EINVAL;
210	}
211
212	return (err);
213}
214
215/*
216 * Return VMCB segment area.
217 */
218struct vmcb_segment *
219vmcb_seg(struct vmcb *vmcb, int type)
220{
221	struct vmcb_state *state;
222	struct vmcb_segment *seg;
223
224	state = &vmcb->state;
225
226	switch (type) {
227	case VM_REG_GUEST_CS:
228		seg = &state->cs;
229		break;
230
231	case VM_REG_GUEST_DS:
232		seg = &state->ds;
233		break;
234
235	case VM_REG_GUEST_ES:
236		seg = &state->es;
237		break;
238
239	case VM_REG_GUEST_FS:
240		seg = &state->fs;
241		break;
242
243	case VM_REG_GUEST_GS:
244		seg = &state->gs;
245		break;
246
247	case VM_REG_GUEST_SS:
248		seg = &state->ss;
249		break;
250
251	case VM_REG_GUEST_GDTR:
252		seg = &state->gdt;
253		break;
254
255	case VM_REG_GUEST_IDTR:
256		seg = &state->idt;
257		break;
258
259	case VM_REG_GUEST_LDTR:
260		seg = &state->ldt;
261		break;
262
263	case VM_REG_GUEST_TR:
264		seg = &state->tr;
265		break;
266
267	default:
268		seg = NULL;
269		break;
270	}
271
272	return (seg);
273}
274