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