vmcb.c revision 271203
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 271203 2014-09-06 19:02:52Z 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 * Initialize SVM h/w context i.e. the VMCB control and saved state areas.
53 */
54void
55svm_init_vmcb(struct vmcb *vmcb, uint64_t iopm_base_pa, uint64_t msrpm_base_pa,
56    uint64_t np_pml4)
57{
58	struct vmcb_ctrl *ctrl;
59	struct vmcb_state *state;
60	uint16_t cr_shadow;
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	/*
73	 * Intercept accesses to the control registers that are not shadowed
74	 * in the VMCB - i.e. all except cr0, cr2, cr3, cr4 and cr8.
75	 */
76	cr_shadow = BIT(0) | BIT(2) | BIT(3) | BIT(4) | BIT(8);
77	ctrl->cr_write = ctrl->cr_read = ~cr_shadow;
78
79	/* Intercept Machine Check exceptions. */
80	ctrl->exception = BIT(IDT_MC);
81
82	/* Intercept various events (for e.g. I/O, MSR and CPUID accesses) */
83	ctrl->ctrl1 =  VMCB_INTCPT_IO |
84		       VMCB_INTCPT_MSR |
85		       VMCB_INTCPT_HLT |
86		       VMCB_INTCPT_CPUID |
87		       VMCB_INTCPT_INTR |
88		       VMCB_INTCPT_VINTR |
89		       VMCB_INTCPT_INIT |
90		       VMCB_INTCPT_NMI |
91		       VMCB_INTCPT_SMI |
92		       VMCB_INTCPT_FERR_FREEZE |
93		       VMCB_INTCPT_SHUTDOWN;
94
95	/*
96	 * From section "Canonicalization and Consistency Checks" in APMv2
97	 * the VMRUN intercept bit must be set to pass the consistency check.
98	 */
99	ctrl->ctrl2 = VMCB_INTCPT_VMRUN;
100
101	/*
102	 * The ASID will be set to a non-zero value just before VMRUN.
103	 */
104	ctrl->asid = 0;
105
106	/*
107	 * Section 15.21.1, Interrupt Masking in EFLAGS
108	 * Section 15.21.2, Virtualizing APIC.TPR
109	 *
110	 * This must be set for %rflag and %cr8 isolation of guest and host.
111	 */
112	ctrl->v_intr_masking = 1;
113
114	/* Enable Last Branch Record aka LBR for debugging */
115	ctrl->lbr_virt_en = 1;
116	state->dbgctl = BIT(0);
117
118	/* EFER_SVM must always be set when the guest is executing */
119	state->efer = EFER_SVM;
120
121	/* Set up the PAT to power-on state */
122	state->g_pat = PAT_VALUE(0, PAT_WRITE_BACK)	|
123	    PAT_VALUE(1, PAT_WRITE_THROUGH)	|
124	    PAT_VALUE(2, PAT_UNCACHED)		|
125	    PAT_VALUE(3, PAT_UNCACHEABLE)	|
126	    PAT_VALUE(4, PAT_WRITE_BACK)	|
127	    PAT_VALUE(5, PAT_WRITE_THROUGH)	|
128	    PAT_VALUE(6, PAT_UNCACHED)		|
129	    PAT_VALUE(7, PAT_UNCACHEABLE);
130}
131
132/*
133 * Read from segment selector, control and general purpose register of VMCB.
134 */
135int
136vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval)
137{
138	struct vmcb_state *state;
139	struct vmcb_segment *seg;
140	int err;
141
142	state = &vmcb->state;
143	err = 0;
144
145	switch (ident) {
146	case VM_REG_GUEST_CR0:
147		*retval = state->cr0;
148		break;
149
150	case VM_REG_GUEST_CR2:
151		*retval = state->cr2;
152		break;
153
154	case VM_REG_GUEST_CR3:
155		*retval = state->cr3;
156		break;
157
158	case VM_REG_GUEST_CR4:
159		*retval = state->cr4;
160		break;
161
162	case VM_REG_GUEST_DR7:
163		*retval = state->dr7;
164		break;
165
166	case VM_REG_GUEST_EFER:
167		*retval = state->efer;
168		break;
169
170	case VM_REG_GUEST_RAX:
171		*retval = state->rax;
172		break;
173
174	case VM_REG_GUEST_RFLAGS:
175		*retval = state->rflags;
176		break;
177
178	case VM_REG_GUEST_RIP:
179		*retval = state->rip;
180		break;
181
182	case VM_REG_GUEST_RSP:
183		*retval = state->rsp;
184		break;
185
186	case VM_REG_GUEST_CS:
187	case VM_REG_GUEST_DS:
188	case VM_REG_GUEST_ES:
189	case VM_REG_GUEST_FS:
190	case VM_REG_GUEST_GS:
191	case VM_REG_GUEST_SS:
192	case VM_REG_GUEST_GDTR:
193	case VM_REG_GUEST_IDTR:
194	case VM_REG_GUEST_LDTR:
195	case VM_REG_GUEST_TR:
196		seg = vmcb_seg(vmcb, ident);
197		if (seg == NULL) {
198			ERR("Invalid seg type %d\n", ident);
199			err = EINVAL;
200			break;
201		}
202
203		*retval = seg->selector;
204		break;
205
206	default:
207		err =  EINVAL;
208		break;
209	}
210
211	return (err);
212}
213
214/*
215 * Write to segment selector, control and general purpose register of VMCB.
216 */
217int
218vmcb_write(struct vmcb *vmcb, int ident, uint64_t val)
219{
220	struct vmcb_state *state;
221	struct vmcb_segment *seg;
222	int err;
223
224	state = &vmcb->state;
225	err = 0;
226
227	switch (ident) {
228	case VM_REG_GUEST_CR0:
229		state->cr0 = val;
230		break;
231
232	case VM_REG_GUEST_CR2:
233		state->cr2 = val;
234		break;
235
236	case VM_REG_GUEST_CR3:
237		state->cr3 = val;
238		break;
239
240	case VM_REG_GUEST_CR4:
241		state->cr4 = val;
242		break;
243
244	case VM_REG_GUEST_DR7:
245		state->dr7 = val;
246		break;
247
248	case VM_REG_GUEST_EFER:
249		/* EFER_SVM must always be set when the guest is executing */
250		state->efer = val | EFER_SVM;
251		break;
252
253	case VM_REG_GUEST_RAX:
254		state->rax = val;
255		break;
256
257	case VM_REG_GUEST_RFLAGS:
258		state->rflags = val;
259		break;
260
261	case VM_REG_GUEST_RIP:
262		state->rip = val;
263		break;
264
265	case VM_REG_GUEST_RSP:
266		state->rsp = val;
267		break;
268
269	case VM_REG_GUEST_CS:
270	case VM_REG_GUEST_DS:
271	case VM_REG_GUEST_ES:
272	case VM_REG_GUEST_FS:
273	case VM_REG_GUEST_GS:
274	case VM_REG_GUEST_SS:
275	case VM_REG_GUEST_GDTR:
276	case VM_REG_GUEST_IDTR:
277	case VM_REG_GUEST_LDTR:
278	case VM_REG_GUEST_TR:
279		seg = vmcb_seg(vmcb, ident);
280		if (seg == NULL) {
281			ERR("Invalid segment type %d\n", ident);
282			err = EINVAL;
283			break;
284		}
285
286		seg->selector = val;
287		break;
288
289	default:
290		err = EINVAL;
291	}
292
293	return (err);
294}
295
296/*
297 * Return VMCB segment area.
298 */
299struct vmcb_segment *
300vmcb_seg(struct vmcb *vmcb, int type)
301{
302	struct vmcb_state *state;
303	struct vmcb_segment *seg;
304
305	state = &vmcb->state;
306
307	switch (type) {
308	case VM_REG_GUEST_CS:
309		seg = &state->cs;
310		break;
311
312	case VM_REG_GUEST_DS:
313		seg = &state->ds;
314		break;
315
316	case VM_REG_GUEST_ES:
317		seg = &state->es;
318		break;
319
320	case VM_REG_GUEST_FS:
321		seg = &state->fs;
322		break;
323
324	case VM_REG_GUEST_GS:
325		seg = &state->gs;
326		break;
327
328	case VM_REG_GUEST_SS:
329		seg = &state->ss;
330		break;
331
332	case VM_REG_GUEST_GDTR:
333		seg = &state->gdt;
334		break;
335
336	case VM_REG_GUEST_IDTR:
337		seg = &state->idt;
338		break;
339
340	case VM_REG_GUEST_LDTR:
341		seg = &state->ldt;
342		break;
343
344	case VM_REG_GUEST_TR:
345		seg = &state->tr;
346		break;
347
348	default:
349		seg = NULL;
350		break;
351	}
352
353	return (seg);
354}
355
356/*
357 * Inject an event to vcpu as described in section 15.20, "Event injection".
358 */
359void
360vmcb_eventinject(struct vmcb_ctrl *ctrl, int intr_type, int vector,
361		 uint32_t error, bool ec_valid)
362{
363	KASSERT((ctrl->eventinj & VMCB_EVENTINJ_VALID) == 0,
364	    ("%s: event already pending %#lx", __func__, ctrl->eventinj));
365
366	KASSERT(vector >=0 && vector <= 255, ("%s: invalid vector %d",
367	    __func__, vector));
368
369	switch (intr_type) {
370	case VMCB_EVENTINJ_TYPE_INTR:
371	case VMCB_EVENTINJ_TYPE_NMI:
372	case VMCB_EVENTINJ_TYPE_INTn:
373		break;
374	case VMCB_EVENTINJ_TYPE_EXCEPTION:
375		if (vector >= 0 && vector <= 31 && vector != 2)
376			break;
377		/* FALLTHROUGH */
378	default:
379		panic("%s: invalid intr_type/vector: %d/%d", __func__,
380		    intr_type, vector);
381	}
382	ctrl->eventinj = vector | (intr_type << 8) | VMCB_EVENTINJ_VALID;
383	if (ec_valid) {
384		ctrl->eventinj |= VMCB_EVENTINJ_EC_VALID;
385		ctrl->eventinj |= (uint64_t)error << 32;
386	}
387}
388