vmcb.c revision 249493
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, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/vmcb.c 249493 2013-04-15 04:16:12Z neel $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/vmcb.c 249493 2013-04-15 04:16:12Z neel $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/cpuset.h>
35
36#include <machine/segments.h>
37#include <machine/specialreg.h>
38#include <machine/vmm.h>
39
40#include "vmcb.h"
41
42/*
43 * The VMCB aka Virtual Machine Control Block is a 4KB aligned page
44 * in memory that describes the virtual machine.
45 *
46 * The VMCB contains:
47 * - instructions or events in the guest to intercept
48 * - control bits that modify execution environment of the guest
49 * - guest processor state (e.g. general purpose registers)
50 */
51
52/*
53 * Initialize SVM h/w context i.e. the VMCB control and saved state areas.
54 */
55int
56svm_init_vmcb(struct vmcb *vmcb, uint64_t iopm_base_pa,
57	      uint64_t msrpm_base_pa, uint64_t np_pml4)
58{
59	struct vmcb_ctrl *ctrl;
60	struct vmcb_state *state;
61
62	ctrl = &vmcb->ctrl;
63	state = &vmcb->state;
64
65	ctrl->iopm_base_pa = iopm_base_pa;
66	ctrl->msrpm_base_pa = msrpm_base_pa;
67
68	/* Enable nested paging */
69	ctrl->np_enable = 1;
70	ctrl->n_cr3 = np_pml4;
71
72	/* EFER_SVM must always be set when the guest is executing */
73	state->efer = EFER_SVM;
74
75	return (0);
76}
77
78/*
79 * Set non-persistent fields of VMCB that are cleared by VMEXIT and must
80 * be set before restarting the guest (e.g. ASID, intercepts etc).
81 *
82 * APM2, Section 15.6, VMEXIT
83 */
84int
85svm_set_vmcb(struct vmcb *vmcb, uint8_t asid)
86{
87	struct vmcb_ctrl *ctrl;
88	struct vmcb_state *state;
89	uint16_t cr_shadow;
90
91	ctrl = &vmcb->ctrl;
92	state = &vmcb->state;
93
94	/*
95	 * Intercept accesses to the control registers that are not shadowed
96	 * in the VMCB - i.e. all except cr0, cr2, cr3, cr4 and cr8.
97	 */
98	cr_shadow = BIT(0) | BIT(2) | BIT(3) | BIT(4) | BIT(8);
99	ctrl->cr_write = ctrl->cr_read = ~cr_shadow;
100
101	/* Intercept Machine Check exceptions. */
102	ctrl->exception = BIT(IDT_MC);
103
104	 /* Intercept various events (for e.g. I/O, MSR and CPUID accesses) */
105	ctrl->ctrl1 =  VMCB_INTCPT_IO |
106		       VMCB_INTCPT_MSR |
107		       VMCB_INTCPT_HLT |
108		       VMCB_INTCPT_CPUID |
109		       VMCB_INTCPT_INTR |
110		       VMCB_INTCPT_VINTR |
111		       VMCB_INTCPT_INIT |
112		       VMCB_INTCPT_NMI |
113		       VMCB_INTCPT_SMI |
114		       VMCB_INTCPT_FERR_FREEZE |
115		       VMCB_INTCPT_SHUTDOWN;
116
117	/* VMRUN intercept is required, see APM2 */
118	ctrl->ctrl2 = VMCB_INTCPT_VMRUN;
119
120	/* ASID is cleared after every #VMEXIT. */
121	ctrl->asid = asid;
122
123	/*
124	 * Section 15.21.1, Interrupt Masking in EFLAGS
125	 * Section 15.21.2, Virtualizing APIC.TPR
126	 *
127	 * This must be set for %rflag and %cr8 isolation of guest and host.
128	 */
129	ctrl->v_intr_masking = 1;
130
131	 /* Enable Last Branch Record aka LBR for debugging */
132	ctrl->lbr_virt_en = 1;
133	state->dbgctl = BIT(0);
134
135	return (0);
136}
137
138/*
139 * Read from segment selector, control and general purpose register of VMCB.
140 */
141int
142vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval)
143{
144	struct vmcb_state *state;
145	struct vmcb_segment *seg;
146	int err;
147
148	state = &vmcb->state;
149	err = 0;
150
151	switch (ident) {
152	case VM_REG_GUEST_CR0:
153		*retval = state->cr0;
154		break;
155
156	case VM_REG_GUEST_CR3:
157		*retval = state->cr3;
158		break;
159
160	case VM_REG_GUEST_CR4:
161		*retval = state->cr4;
162		break;
163
164	case VM_REG_GUEST_DR7:
165		*retval = state->dr7;
166		break;
167
168	case VM_REG_GUEST_EFER:
169		*retval = state->efer;
170		break;
171
172	case VM_REG_GUEST_RAX:
173		*retval = state->rax;
174		break;
175
176	case VM_REG_GUEST_RFLAGS:
177		*retval = state->rflags;
178		break;
179
180	case VM_REG_GUEST_RIP:
181		*retval = state->rip;
182		break;
183
184	case VM_REG_GUEST_RSP:
185		*retval = state->rsp;
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 seg type %d\n", ident);
201			err = EINVAL;
202			break;
203		}
204
205		*retval = seg->selector;
206		break;
207
208	default:
209		err =  EINVAL;
210		break;
211	}
212
213	return (err);
214}
215
216/*
217 * Write to segment selector, control and general purpose register of VMCB.
218 */
219int
220vmcb_write(struct vmcb *vmcb, int ident, uint64_t val)
221{
222	struct vmcb_state *state;
223	struct vmcb_segment *seg;
224	int err;
225
226	state = &vmcb->state;
227	err = 0;
228
229	switch (ident) {
230	case VM_REG_GUEST_CR0:
231		state->cr0 = val;
232		break;
233
234	case VM_REG_GUEST_CR3:
235		state->cr3 = val;
236		break;
237
238	case VM_REG_GUEST_CR4:
239		state->cr4 = val;
240		break;
241
242	case VM_REG_GUEST_DR7:
243		state->dr7 = val;
244		break;
245
246	case VM_REG_GUEST_EFER:
247		/* EFER_SVM must always be set when the guest is executing */
248		state->efer = val | EFER_SVM;
249		break;
250
251	case VM_REG_GUEST_RAX:
252		state->rax = val;
253		break;
254
255	case VM_REG_GUEST_RFLAGS:
256		state->rflags = val;
257		break;
258
259	case VM_REG_GUEST_RIP:
260		state->rip = val;
261		break;
262
263	case VM_REG_GUEST_RSP:
264		state->rsp = val;
265		break;
266
267	case VM_REG_GUEST_CS:
268	case VM_REG_GUEST_DS:
269	case VM_REG_GUEST_ES:
270	case VM_REG_GUEST_FS:
271	case VM_REG_GUEST_GS:
272	case VM_REG_GUEST_SS:
273	case VM_REG_GUEST_GDTR:
274	case VM_REG_GUEST_IDTR:
275	case VM_REG_GUEST_LDTR:
276	case VM_REG_GUEST_TR:
277		seg = vmcb_seg(vmcb, ident);
278		if (seg == NULL) {
279			ERR("Invalid segment type %d\n", ident);
280			err = EINVAL;
281			break;
282		}
283
284		seg->selector = val;
285		break;
286
287	default:
288		err = EINVAL;
289	}
290
291	return (err);
292}
293
294/*
295 * Return VMCB segment area.
296 */
297struct vmcb_segment *
298vmcb_seg(struct vmcb *vmcb, int type)
299{
300	struct vmcb_state *state;
301	struct vmcb_segment *seg;
302
303	state = &vmcb->state;
304
305	switch (type) {
306	case VM_REG_GUEST_CS:
307		seg = &state->cs;
308		break;
309
310	case VM_REG_GUEST_DS:
311		seg = &state->ds;
312		break;
313
314	case VM_REG_GUEST_ES:
315		seg = &state->es;
316		break;
317
318	case VM_REG_GUEST_FS:
319		seg = &state->fs;
320		break;
321
322	case VM_REG_GUEST_GS:
323		seg = &state->gs;
324		break;
325
326	case VM_REG_GUEST_SS:
327		seg = &state->ss;
328		break;
329
330	case VM_REG_GUEST_GDTR:
331		seg = &state->gdt;
332		break;
333
334	case VM_REG_GUEST_IDTR:
335		seg = &state->idt;
336		break;
337
338	case VM_REG_GUEST_LDTR:
339		seg = &state->ldt;
340		break;
341
342	case VM_REG_GUEST_TR:
343		seg = &state->tr;
344		break;
345
346	default:
347		seg = NULL;
348		break;
349	}
350
351	return (seg);
352}
353
354/*
355 * Inject an event to vcpu as described in section 15.20, "Event injection".
356 */
357int
358vmcb_eventinject(struct vmcb_ctrl *ctrl, int type, int vector,
359		 uint32_t error, boolean_t ec_valid)
360{
361	int intr_type;
362
363	static uint8_t  svm_intr_type_map[VM_EVENT_MAX] = {
364		-1,				/* VM_EVENT_NONE */
365		VMCB_EVENTINJ_TYPE_INTR,	/* VM_HW_INTR */
366		VMCB_EVENTINJ_TYPE_NMI,	 	/* VM_NMI */
367		VMCB_EVENTINJ_TYPE_EXCEPTION,	/* VM_HW_EXCEPTION */
368		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_SW_INTR, INT */
369		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_PRIV_SW_EXCEPTION */
370		VMCB_EVENTINJ_TYPE_INTn, 	/* VM_SW_EXCEPTION */
371	};
372
373	intr_type = svm_intr_type_map[type];
374	if (intr_type < VMCB_EVENTINJ_TYPE_INTR ||
375	    intr_type > VMCB_EVENTINJ_TYPE_INTn) {
376		ERR("Event:%d is not supported by SVM.\n", type);
377		return (EINVAL);
378	}
379
380	if (intr_type == VMCB_EVENTINJ_TYPE_EXCEPTION && vector == IDT_NMI) {
381		ERR("NMI with Exception type is not possible.\n");
382		return (EINVAL);
383	}
384
385	ctrl->eventinj = (vector & VMCB_EVENTINJ_VECTOR_MASK) |
386			 (intr_type << VMCB_EVENTINJ_INTR_TYPE_SHIFT)  |
387			 (ec_valid ? VMCB_EVENTINJ_EC_VALID : 0) |
388			 VMCB_EVENTINJ_VALID;
389
390	ctrl->eventinj |= (uint64_t)error << VMCB_EVENTINJ_ERRCODE_SHIFT;
391
392	return (0);
393}
394