]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/vmm/amd/vmcb.c
Merge xz 5.2.0.
[FreeBSD/FreeBSD.git] / sys / amd64 / vmm / amd / vmcb.c
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$");
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
40 #include "vmcb.h"
41 #include "svm.h"
42 #include "svm_softc.h"
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  */
57 static struct vmcb_segment *
58 vmcb_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 static int
115 vmcb_access(struct svm_softc *softc, int vcpu, int write, int ident,
116         uint64_t *val)
117 {
118         struct vmcb *vmcb;
119         int off, bytes;
120         char *ptr;
121
122         vmcb    = svm_get_vmcb(softc, vcpu);
123         off     = VMCB_ACCESS_OFFSET(ident);
124         bytes   = VMCB_ACCESS_BYTES(ident);
125
126         if ((off + bytes) >= sizeof (struct vmcb))
127                 return (EINVAL);
128
129         ptr = (char *)vmcb;
130
131         if (!write)
132                 *val = 0;
133
134         switch (bytes) {
135         case 8:
136         case 4:
137         case 2:
138                 if (write)
139                         memcpy(ptr + off, val, bytes);
140                 else
141                         memcpy(val, ptr + off, bytes);
142                 break;
143         default:
144                 VCPU_CTR1(softc->vm, vcpu,
145                     "Invalid size %d for VMCB access: %d", bytes);
146                 return (EINVAL);
147         }
148
149         /* Invalidate all VMCB state cached by h/w. */
150         if (write)
151                 svm_set_dirty(softc, vcpu, 0xffffffff);
152
153         return (0);
154 }
155
156 /*
157  * Read from segment selector, control and general purpose register of VMCB.
158  */
159 int
160 vmcb_read(struct svm_softc *sc, int vcpu, int ident, uint64_t *retval)
161 {
162         struct vmcb *vmcb;
163         struct vmcb_state *state;
164         struct vmcb_segment *seg;
165         int err;
166
167         vmcb = svm_get_vmcb(sc, vcpu);
168         state = &vmcb->state;
169         err = 0;
170
171         if (VMCB_ACCESS_OK(ident))
172                 return (vmcb_access(sc, vcpu, 0, ident, retval));
173
174         switch (ident) {
175         case VM_REG_GUEST_CR0:
176                 *retval = state->cr0;
177                 break;
178
179         case VM_REG_GUEST_CR2:
180                 *retval = state->cr2;
181                 break;
182
183         case VM_REG_GUEST_CR3:
184                 *retval = state->cr3;
185                 break;
186
187         case VM_REG_GUEST_CR4:
188                 *retval = state->cr4;
189                 break;
190
191         case VM_REG_GUEST_DR7:
192                 *retval = state->dr7;
193                 break;
194
195         case VM_REG_GUEST_EFER:
196                 *retval = state->efer;
197                 break;
198
199         case VM_REG_GUEST_RAX:
200                 *retval = state->rax;
201                 break;
202
203         case VM_REG_GUEST_RFLAGS:
204                 *retval = state->rflags;
205                 break;
206
207         case VM_REG_GUEST_RIP:
208                 *retval = state->rip;
209                 break;
210
211         case VM_REG_GUEST_RSP:
212                 *retval = state->rsp;
213                 break;
214
215         case VM_REG_GUEST_CS:
216         case VM_REG_GUEST_DS:
217         case VM_REG_GUEST_ES:
218         case VM_REG_GUEST_FS:
219         case VM_REG_GUEST_GS:
220         case VM_REG_GUEST_SS:
221         case VM_REG_GUEST_LDTR:
222         case VM_REG_GUEST_TR:
223                 seg = vmcb_segptr(vmcb, ident);
224                 KASSERT(seg != NULL, ("%s: unable to get segment %d from VMCB",
225                     __func__, ident));
226                 *retval = seg->selector;
227                 break;
228
229         case VM_REG_GUEST_GDTR:
230         case VM_REG_GUEST_IDTR:
231                 /* GDTR and IDTR don't have segment selectors */
232                 err = EINVAL;
233                 break;
234         default:
235                 err =  EINVAL;
236                 break;
237         }
238
239         return (err);
240 }
241
242 /*
243  * Write to segment selector, control and general purpose register of VMCB.
244  */
245 int
246 vmcb_write(struct svm_softc *sc, int vcpu, int ident, uint64_t val)
247 {
248         struct vmcb *vmcb;
249         struct vmcb_state *state;
250         struct vmcb_segment *seg;
251         int err, dirtyseg;
252
253         vmcb = svm_get_vmcb(sc, vcpu);
254         state = &vmcb->state;
255         dirtyseg = 0;
256         err = 0;
257
258         if (VMCB_ACCESS_OK(ident))
259                 return (vmcb_access(sc, vcpu, 1, ident, &val));
260
261         switch (ident) {
262         case VM_REG_GUEST_CR0:
263                 state->cr0 = val;
264                 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
265                 break;
266
267         case VM_REG_GUEST_CR2:
268                 state->cr2 = val;
269                 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR2);
270                 break;
271
272         case VM_REG_GUEST_CR3:
273                 state->cr3 = val;
274                 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
275                 break;
276
277         case VM_REG_GUEST_CR4:
278                 state->cr4 = val;
279                 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
280                 break;
281
282         case VM_REG_GUEST_DR7:
283                 state->dr7 = val;
284                 break;
285
286         case VM_REG_GUEST_EFER:
287                 /* EFER_SVM must always be set when the guest is executing */
288                 state->efer = val | EFER_SVM;
289                 svm_set_dirty(sc, vcpu, VMCB_CACHE_CR);
290                 break;
291
292         case VM_REG_GUEST_RAX:
293                 state->rax = val;
294                 break;
295
296         case VM_REG_GUEST_RFLAGS:
297                 state->rflags = val;
298                 break;
299
300         case VM_REG_GUEST_RIP:
301                 state->rip = val;
302                 break;
303
304         case VM_REG_GUEST_RSP:
305                 state->rsp = val;
306                 break;
307
308         case VM_REG_GUEST_CS:
309         case VM_REG_GUEST_DS:
310         case VM_REG_GUEST_ES:
311         case VM_REG_GUEST_SS:
312                 dirtyseg = 1;           /* FALLTHROUGH */
313         case VM_REG_GUEST_FS:
314         case VM_REG_GUEST_GS:
315         case VM_REG_GUEST_LDTR:
316         case VM_REG_GUEST_TR:
317                 seg = vmcb_segptr(vmcb, ident);
318                 KASSERT(seg != NULL, ("%s: unable to get segment %d from VMCB",
319                     __func__, ident));
320                 seg->selector = val;
321                 if (dirtyseg)
322                         svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
323                 break;
324
325         case VM_REG_GUEST_GDTR:
326         case VM_REG_GUEST_IDTR:
327                 /* GDTR and IDTR don't have segment selectors */
328                 err = EINVAL;
329                 break;
330         default:
331                 err = EINVAL;
332                 break;
333         }
334
335         return (err);
336 }
337
338 int
339 vmcb_seg(struct vmcb *vmcb, int ident, struct vmcb_segment *seg2)
340 {
341         struct vmcb_segment *seg;
342
343         seg = vmcb_segptr(vmcb, ident);
344         if (seg != NULL) {
345                 bcopy(seg, seg2, sizeof(struct vmcb_segment));
346                 return (0);
347         } else {
348                 return (EINVAL);
349         }
350 }
351
352 int
353 vmcb_setdesc(void *arg, int vcpu, int reg, struct seg_desc *desc)
354 {
355         struct vmcb *vmcb;
356         struct svm_softc *sc;
357         struct vmcb_segment *seg;
358         uint16_t attrib;
359
360         sc = arg;
361         vmcb = svm_get_vmcb(sc, vcpu);
362
363         seg = vmcb_segptr(vmcb, reg);
364         KASSERT(seg != NULL, ("%s: invalid segment descriptor %d",
365             __func__, reg));
366
367         seg->base = desc->base;
368         seg->limit = desc->limit;
369         if (reg != VM_REG_GUEST_GDTR && reg != VM_REG_GUEST_IDTR) {
370                 /*
371                  * Map seg_desc access to VMCB attribute format.
372                  *
373                  * SVM uses the 'P' bit in the segment attributes to indicate a
374                  * NULL segment so clear it if the segment is marked unusable.
375                  */
376                 attrib = ((desc->access & 0xF000) >> 4) | (desc->access & 0xFF);
377                 if (SEG_DESC_UNUSABLE(desc->access)) {
378                         attrib &= ~0x80;
379                 }
380                 seg->attrib = attrib;
381         }
382
383         VCPU_CTR4(sc->vm, vcpu, "Setting desc %d: base (%#lx), limit (%#x), "
384             "attrib (%#x)", reg, seg->base, seg->limit, seg->attrib);
385
386         switch (reg) {
387         case VM_REG_GUEST_CS:
388         case VM_REG_GUEST_DS:
389         case VM_REG_GUEST_ES:
390         case VM_REG_GUEST_SS:
391                 svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG);
392                 break;
393         case VM_REG_GUEST_GDTR:
394         case VM_REG_GUEST_IDTR:
395                 svm_set_dirty(sc, vcpu, VMCB_CACHE_DT);
396                 break;
397         default:
398                 break;
399         }
400
401         return (0);
402 }
403
404 int
405 vmcb_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc)
406 {
407         struct vmcb *vmcb;
408         struct svm_softc *sc;
409         struct vmcb_segment *seg;
410
411         sc = arg;
412         vmcb = svm_get_vmcb(sc, vcpu);
413         seg = vmcb_segptr(vmcb, reg);
414         KASSERT(seg != NULL, ("%s: invalid segment descriptor %d",
415             __func__, reg));
416
417         desc->base = seg->base;
418         desc->limit = seg->limit;
419         desc->access = 0;
420
421         if (reg != VM_REG_GUEST_GDTR && reg != VM_REG_GUEST_IDTR) {
422                 /* Map seg_desc access to VMCB attribute format */
423                 desc->access = ((seg->attrib & 0xF00) << 4) |
424                     (seg->attrib & 0xFF);
425
426                 /*
427                  * VT-x uses bit 16 to indicate a segment that has been loaded
428                  * with a NULL selector (aka unusable). The 'desc->access'
429                  * field is interpreted in the VT-x format by the
430                  * processor-independent code.
431                  *
432                  * SVM uses the 'P' bit to convey the same information so
433                  * convert it into the VT-x format. For more details refer to
434                  * section "Segment State in the VMCB" in APMv2.
435                  */
436                 if (reg != VM_REG_GUEST_CS && reg != VM_REG_GUEST_TR) {
437                         if ((desc->access & 0x80) == 0)
438                                 desc->access |= 0x10000;  /* Unusable segment */
439                 }
440         }
441
442         return (0);
443 }