Deleted Added
full compact
vmcb.c (271346) vmcb.c (271939)
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

--- 11 unchanged lines hidden (view full) ---

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>
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

--- 11 unchanged lines hidden (view full) ---

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 $");
28__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/vmcb.c 271939 2014-09-21 23:42:54Z 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
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 "vmm_ktr.h"
39
38#include "vmcb.h"
39#include "svm.h"
40#include "vmcb.h"
41#include "svm.h"
42#include "svm_softc.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/*
43
44/*
45 * The VMCB aka Virtual Machine Control Block is a 4KB aligned page
46 * in memory that describes the virtual machine.
47 *
48 * The VMCB contains:
49 * - instructions or events in the guest to intercept
50 * - control bits that modify execution environment of the guest
51 * - guest processor state (e.g. general purpose registers)
52 */
53
54/*
55 * Return VMCB segment area.
56 */
57static struct vmcb_segment *
58vmcb_segptr(struct vmcb *vmcb, int type)
59{
60 struct vmcb_state *state;
61 struct vmcb_segment *seg;
62
63 state = &vmcb->state;
64
65 switch (type) {
66 case VM_REG_GUEST_CS:
67 seg = &state->cs;
68 break;
69
70 case VM_REG_GUEST_DS:
71 seg = &state->ds;
72 break;
73
74 case VM_REG_GUEST_ES:
75 seg = &state->es;
76 break;
77
78 case VM_REG_GUEST_FS:
79 seg = &state->fs;
80 break;
81
82 case VM_REG_GUEST_GS:
83 seg = &state->gs;
84 break;
85
86 case VM_REG_GUEST_SS:
87 seg = &state->ss;
88 break;
89
90 case VM_REG_GUEST_GDTR:
91 seg = &state->gdt;
92 break;
93
94 case VM_REG_GUEST_IDTR:
95 seg = &state->idt;
96 break;
97
98 case VM_REG_GUEST_LDTR:
99 seg = &state->ldt;
100 break;
101
102 case VM_REG_GUEST_TR:
103 seg = &state->tr;
104 break;
105
106 default:
107 seg = NULL;
108 break;
109 }
110
111 return (seg);
112}
113
114/*
52 * Read from segment selector, control and general purpose register of VMCB.
53 */
54int
115 * Read from segment selector, control and general purpose register of VMCB.
116 */
117int
55vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval)
118vmcb_read(struct svm_softc *sc, int vcpu, int ident, uint64_t *retval)
56{
119{
120 struct vmcb *vmcb;
57 struct vmcb_state *state;
58 struct vmcb_segment *seg;
59 int err;
60
121 struct vmcb_state *state;
122 struct vmcb_segment *seg;
123 int err;
124
125 vmcb = svm_get_vmcb(sc, vcpu);
61 state = &vmcb->state;
62 err = 0;
63
64 switch (ident) {
65 case VM_REG_GUEST_CR0:
66 *retval = state->cr0;
67 break;
68

--- 34 unchanged lines hidden (view full) ---

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:
126 state = &vmcb->state;
127 err = 0;
128
129 switch (ident) {
130 case VM_REG_GUEST_CR0:
131 *retval = state->cr0;
132 break;
133

--- 34 unchanged lines hidden (view full) ---

168 break;
169
170 case VM_REG_GUEST_CS:
171 case VM_REG_GUEST_DS:
172 case VM_REG_GUEST_ES:
173 case VM_REG_GUEST_FS:
174 case VM_REG_GUEST_GS:
175 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:
176 case VM_REG_GUEST_LDTR:
177 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
178 seg = vmcb_segptr(vmcb, ident);
179 KASSERT(seg != NULL, ("%s: unable to get segment %d from VMCB",
180 __func__, ident));
122 *retval = seg->selector;
123 break;
124
181 *retval = seg->selector;
182 break;
183
184 case VM_REG_GUEST_GDTR:
185 case VM_REG_GUEST_IDTR:
186 /* GDTR and IDTR don't have segment selectors */
187 err = EINVAL;
188 break;
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
189 default:
190 err = EINVAL;
191 break;
192 }
193
194 return (err);
195}
196
197/*
198 * Write to segment selector, control and general purpose register of VMCB.
199 */
200int
137vmcb_write(struct vmcb *vmcb, int ident, uint64_t val)
201vmcb_write(struct svm_softc *sc, int vcpu, int ident, uint64_t val)
138{
202{
203 struct vmcb *vmcb;
139 struct vmcb_state *state;
140 struct vmcb_segment *seg;
204 struct vmcb_state *state;
205 struct vmcb_segment *seg;
141 int err;
206 int err, dirtyseg;
142
207
208 vmcb = svm_get_vmcb(sc, vcpu);
143 state = &vmcb->state;
209 state = &vmcb->state;
210 dirtyseg = 0;
144 err = 0;
145
146 switch (ident) {
147 case VM_REG_GUEST_CR0:
148 state->cr0 = val;
211 err = 0;
212
213 switch (ident) {
214 case VM_REG_GUEST_CR0:
215 state->cr0 = val;
216 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
149 break;
150
151 case VM_REG_GUEST_CR2:
152 state->cr2 = val;
217 break;
218
219 case VM_REG_GUEST_CR2:
220 state->cr2 = val;
221 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR2);
153 break;
154
155 case VM_REG_GUEST_CR3:
156 state->cr3 = val;
222 break;
223
224 case VM_REG_GUEST_CR3:
225 state->cr3 = val;
226 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
157 break;
158
159 case VM_REG_GUEST_CR4:
160 state->cr4 = val;
227 break;
228
229 case VM_REG_GUEST_CR4:
230 state->cr4 = val;
231 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
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;
232 break;
233
234 case VM_REG_GUEST_DR7:
235 state->dr7 = val;
236 break;
237
238 case VM_REG_GUEST_EFER:
239 /* EFER_SVM must always be set when the guest is executing */
240 state->efer = val | EFER_SVM;
241 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
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;

--- 5 unchanged lines hidden (view full) ---

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:
242 break;
243
244 case VM_REG_GUEST_RAX:
245 state->rax = val;
246 break;
247
248 case VM_REG_GUEST_RFLAGS:
249 state->rflags = val;

--- 5 unchanged lines hidden (view full) ---

255
256 case VM_REG_GUEST_RSP:
257 state->rsp = val;
258 break;
259
260 case VM_REG_GUEST_CS:
261 case VM_REG_GUEST_DS:
262 case VM_REG_GUEST_ES:
263 case VM_REG_GUEST_SS:
264 dirtyseg = 1; /* FALLTHROUGH */
191 case VM_REG_GUEST_FS:
192 case VM_REG_GUEST_GS:
265 case VM_REG_GUEST_FS:
266 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:
267 case VM_REG_GUEST_LDTR:
268 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
269 seg = vmcb_segptr(vmcb, ident);
270 KASSERT(seg != NULL, ("%s: unable to get segment %d from VMCB",
271 __func__, ident));
205 seg->selector = val;
272 seg->selector = val;
273 if (dirtyseg)
274 svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
206 break;
207
275 break;
276
277 case VM_REG_GUEST_GDTR:
278 case VM_REG_GUEST_IDTR:
279 /* GDTR and IDTR don't have segment selectors */
280 err = EINVAL;
281 break;
208 default:
209 err = EINVAL;
282 default:
283 err = EINVAL;
284 break;
210 }
211
212 return (err);
213}
214
285 }
286
287 return (err);
288}
289
215/*
216 * Return VMCB segment area.
217 */
218struct vmcb_segment *
219vmcb_seg(struct vmcb *vmcb, int type)
290int
291vmcb_seg(struct vmcb *vmcb, int ident, struct vmcb_segment *seg2)
220{
292{
221 struct vmcb_state *state;
222 struct vmcb_segment *seg;
223
293 struct vmcb_segment *seg;
294
224 state = &vmcb->state;
295 seg = vmcb_segptr(vmcb, ident);
296 if (seg != NULL) {
297 bcopy(seg, seg2, sizeof(struct vmcb_segment));
298 return (0);
299 } else {
300 return (EINVAL);
301 }
302}
225
303
226 switch (type) {
227 case VM_REG_GUEST_CS:
228 seg = &state->cs;
229 break;
304int
305vmcb_setdesc(void *arg, int vcpu, int reg, struct seg_desc *desc)
306{
307 struct vmcb *vmcb;
308 struct svm_softc *sc;
309 struct vmcb_segment *seg;
310 uint16_t attrib;
230
311
231 case VM_REG_GUEST_DS:
232 seg = &state->ds;
233 break;
312 sc = arg;
313 vmcb = svm_get_vmcb(sc, vcpu);
234
314
235 case VM_REG_GUEST_ES:
236 seg = &state->es;
237 break;
315 seg = vmcb_segptr(vmcb, reg);
316 KASSERT(seg != NULL, ("%s: invalid segment descriptor %d",
317 __func__, reg));
238
318
239 case VM_REG_GUEST_FS:
240 seg = &state->fs;
241 break;
319 seg->base = desc->base;
320 seg->limit = desc->limit;
321 if (reg != VM_REG_GUEST_GDTR && reg != VM_REG_GUEST_IDTR) {
322 /*
323 * Map seg_desc access to VMCB attribute format.
324 *
325 * SVM uses the 'P' bit in the segment attributes to indicate a
326 * NULL segment so clear it if the segment is marked unusable.
327 */
328 attrib = ((desc->access & 0xF000) >> 4) | (desc->access & 0xFF);
329 if (SEG_DESC_UNUSABLE(desc->access)) {
330 attrib &= ~0x80;
331 }
332 seg->attrib = attrib;
333 }
242
334
243 case VM_REG_GUEST_GS:
244 seg = &state->gs;
245 break;
335 VCPU_CTR4(sc->vm, vcpu, "Setting desc %d: base (%#lx), limit (%#x), "
336 "attrib (%#x)", reg, seg->base, seg->limit, seg->attrib);
246
337
338 switch (reg) {
339 case VM_REG_GUEST_CS:
340 case VM_REG_GUEST_DS:
341 case VM_REG_GUEST_ES:
247 case VM_REG_GUEST_SS:
342 case VM_REG_GUEST_SS:
248 seg = &state->ss;
249 break;
250
343 svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
251 case VM_REG_GUEST_GDTR:
344 case VM_REG_GUEST_GDTR:
252 seg = &state->gdt;
253 break;
254
255 case VM_REG_GUEST_IDTR:
345 case VM_REG_GUEST_IDTR:
256 seg = &state->idt;
346 svm_set_dirty(sc, vcpu, VMCB_CACHE_DT);
257 break;
347 break;
258
259 case VM_REG_GUEST_LDTR:
260 seg = &state->ldt;
348 default:
261 break;
349 break;
350 }
262
351
263 case VM_REG_GUEST_TR:
264 seg = &state->tr;
265 break;
352 return (0);
353}
266
354
267 default:
268 seg = NULL;
269 break;
355int
356vmcb_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc)
357{
358 struct vmcb *vmcb;
359 struct svm_softc *sc;
360 struct vmcb_segment *seg;
361
362 sc = arg;
363 vmcb = svm_get_vmcb(sc, vcpu);
364 seg = vmcb_segptr(vmcb, reg);
365 KASSERT(seg != NULL, ("%s: invalid segment descriptor %d",
366 __func__, reg));
367
368 desc->base = seg->base;
369 desc->limit = seg->limit;
370 desc->access = 0;
371
372 if (reg != VM_REG_GUEST_GDTR && reg != VM_REG_GUEST_IDTR) {
373 /* Map seg_desc access to VMCB attribute format */
374 desc->access = ((seg->attrib & 0xF00) << 4) |
375 (seg->attrib & 0xFF);
376
377 /*
378 * VT-x uses bit 16 to indicate a segment that has been loaded
379 * with a NULL selector (aka unusable). The 'desc->access'
380 * field is interpreted in the VT-x format by the
381 * processor-independent code.
382 *
383 * SVM uses the 'P' bit to convey the same information so
384 * convert it into the VT-x format. For more details refer to
385 * section "Segment State in the VMCB" in APMv2.
386 */
387 if (reg != VM_REG_GUEST_CS && reg != VM_REG_GUEST_TR) {
388 if ((desc->access & 0x80) == 0)
389 desc->access |= 0x10000; /* Unusable segment */
390 }
270 }
271
391 }
392
272 return (seg);
393 return (0);
273}
394}