vmcs.c revision 242275
1/*- 2 * Copyright (c) 2011 NetApp, Inc. 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$ 27 */ 28 29#include "opt_ddb.h" 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/pcpu.h> 37 38#include <vm/vm.h> 39#include <vm/pmap.h> 40 41#include <machine/segments.h> 42#include <machine/pmap.h> 43 44#include <machine/vmm.h> 45#include "vmm_host.h" 46#include "vmcs.h" 47#include "vmx_cpufunc.h" 48#include "ept.h" 49#include "vmx.h" 50 51#ifdef DDB 52#include <ddb/ddb.h> 53#endif 54 55static uint64_t 56vmcs_fix_regval(uint32_t encoding, uint64_t val) 57{ 58 59 switch (encoding) { 60 case VMCS_GUEST_CR0: 61 val = vmx_fix_cr0(val); 62 break; 63 case VMCS_GUEST_CR4: 64 val = vmx_fix_cr4(val); 65 break; 66 default: 67 break; 68 } 69 return (val); 70} 71 72static uint32_t 73vmcs_field_encoding(int ident) 74{ 75 switch (ident) { 76 case VM_REG_GUEST_CR0: 77 return (VMCS_GUEST_CR0); 78 case VM_REG_GUEST_CR3: 79 return (VMCS_GUEST_CR3); 80 case VM_REG_GUEST_CR4: 81 return (VMCS_GUEST_CR4); 82 case VM_REG_GUEST_DR7: 83 return (VMCS_GUEST_DR7); 84 case VM_REG_GUEST_RSP: 85 return (VMCS_GUEST_RSP); 86 case VM_REG_GUEST_RIP: 87 return (VMCS_GUEST_RIP); 88 case VM_REG_GUEST_RFLAGS: 89 return (VMCS_GUEST_RFLAGS); 90 case VM_REG_GUEST_ES: 91 return (VMCS_GUEST_ES_SELECTOR); 92 case VM_REG_GUEST_CS: 93 return (VMCS_GUEST_CS_SELECTOR); 94 case VM_REG_GUEST_SS: 95 return (VMCS_GUEST_SS_SELECTOR); 96 case VM_REG_GUEST_DS: 97 return (VMCS_GUEST_DS_SELECTOR); 98 case VM_REG_GUEST_FS: 99 return (VMCS_GUEST_FS_SELECTOR); 100 case VM_REG_GUEST_GS: 101 return (VMCS_GUEST_GS_SELECTOR); 102 case VM_REG_GUEST_TR: 103 return (VMCS_GUEST_TR_SELECTOR); 104 case VM_REG_GUEST_LDTR: 105 return (VMCS_GUEST_LDTR_SELECTOR); 106 case VM_REG_GUEST_EFER: 107 return (VMCS_GUEST_IA32_EFER); 108 default: 109 return (-1); 110 } 111 112} 113 114static int 115vmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc) 116{ 117 118 switch (seg) { 119 case VM_REG_GUEST_ES: 120 *base = VMCS_GUEST_ES_BASE; 121 *lim = VMCS_GUEST_ES_LIMIT; 122 *acc = VMCS_GUEST_ES_ACCESS_RIGHTS; 123 break; 124 case VM_REG_GUEST_CS: 125 *base = VMCS_GUEST_CS_BASE; 126 *lim = VMCS_GUEST_CS_LIMIT; 127 *acc = VMCS_GUEST_CS_ACCESS_RIGHTS; 128 break; 129 case VM_REG_GUEST_SS: 130 *base = VMCS_GUEST_SS_BASE; 131 *lim = VMCS_GUEST_SS_LIMIT; 132 *acc = VMCS_GUEST_SS_ACCESS_RIGHTS; 133 break; 134 case VM_REG_GUEST_DS: 135 *base = VMCS_GUEST_DS_BASE; 136 *lim = VMCS_GUEST_DS_LIMIT; 137 *acc = VMCS_GUEST_DS_ACCESS_RIGHTS; 138 break; 139 case VM_REG_GUEST_FS: 140 *base = VMCS_GUEST_FS_BASE; 141 *lim = VMCS_GUEST_FS_LIMIT; 142 *acc = VMCS_GUEST_FS_ACCESS_RIGHTS; 143 break; 144 case VM_REG_GUEST_GS: 145 *base = VMCS_GUEST_GS_BASE; 146 *lim = VMCS_GUEST_GS_LIMIT; 147 *acc = VMCS_GUEST_GS_ACCESS_RIGHTS; 148 break; 149 case VM_REG_GUEST_TR: 150 *base = VMCS_GUEST_TR_BASE; 151 *lim = VMCS_GUEST_TR_LIMIT; 152 *acc = VMCS_GUEST_TR_ACCESS_RIGHTS; 153 break; 154 case VM_REG_GUEST_LDTR: 155 *base = VMCS_GUEST_LDTR_BASE; 156 *lim = VMCS_GUEST_LDTR_LIMIT; 157 *acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS; 158 break; 159 case VM_REG_GUEST_IDTR: 160 *base = VMCS_GUEST_IDTR_BASE; 161 *lim = VMCS_GUEST_IDTR_LIMIT; 162 *acc = VMCS_INVALID_ENCODING; 163 break; 164 case VM_REG_GUEST_GDTR: 165 *base = VMCS_GUEST_GDTR_BASE; 166 *lim = VMCS_GUEST_GDTR_LIMIT; 167 *acc = VMCS_INVALID_ENCODING; 168 break; 169 default: 170 return (EINVAL); 171 } 172 173 return (0); 174} 175 176int 177vmcs_getreg(struct vmcs *vmcs, int ident, uint64_t *retval) 178{ 179 int error; 180 uint32_t encoding; 181 182 /* 183 * If we need to get at vmx-specific state in the VMCS we can bypass 184 * the translation of 'ident' to 'encoding' by simply setting the 185 * sign bit. As it so happens the upper 16 bits are reserved (i.e 186 * set to 0) in the encodings for the VMCS so we are free to use the 187 * sign bit. 188 */ 189 if (ident < 0) 190 encoding = ident & 0x7fffffff; 191 else 192 encoding = vmcs_field_encoding(ident); 193 194 if (encoding == (uint32_t)-1) 195 return (EINVAL); 196 197 VMPTRLD(vmcs); 198 error = vmread(encoding, retval); 199 VMCLEAR(vmcs); 200 return (error); 201} 202 203int 204vmcs_setreg(struct vmcs *vmcs, int ident, uint64_t val) 205{ 206 int error; 207 uint32_t encoding; 208 209 if (ident < 0) 210 encoding = ident & 0x7fffffff; 211 else 212 encoding = vmcs_field_encoding(ident); 213 214 if (encoding == (uint32_t)-1) 215 return (EINVAL); 216 217 val = vmcs_fix_regval(encoding, val); 218 219 VMPTRLD(vmcs); 220 error = vmwrite(encoding, val); 221 VMCLEAR(vmcs); 222 return (error); 223} 224 225int 226vmcs_setdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc) 227{ 228 int error; 229 uint32_t base, limit, access; 230 231 error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 232 if (error != 0) 233 panic("vmcs_setdesc: invalid segment register %d", seg); 234 235 VMPTRLD(vmcs); 236 if ((error = vmwrite(base, desc->base)) != 0) 237 goto done; 238 239 if ((error = vmwrite(limit, desc->limit)) != 0) 240 goto done; 241 242 if (access != VMCS_INVALID_ENCODING) { 243 if ((error = vmwrite(access, desc->access)) != 0) 244 goto done; 245 } 246done: 247 VMCLEAR(vmcs); 248 return (error); 249} 250 251int 252vmcs_getdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc) 253{ 254 int error; 255 uint32_t base, limit, access; 256 uint64_t u64; 257 258 error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 259 if (error != 0) 260 panic("vmcs_getdesc: invalid segment register %d", seg); 261 262 VMPTRLD(vmcs); 263 if ((error = vmread(base, &u64)) != 0) 264 goto done; 265 desc->base = u64; 266 267 if ((error = vmread(limit, &u64)) != 0) 268 goto done; 269 desc->limit = u64; 270 271 if (access != VMCS_INVALID_ENCODING) { 272 if ((error = vmread(access, &u64)) != 0) 273 goto done; 274 desc->access = u64; 275 } 276done: 277 VMCLEAR(vmcs); 278 return (error); 279} 280 281int 282vmcs_set_msr_save(struct vmcs *vmcs, u_long g_area, u_int g_count) 283{ 284 int error; 285 286 VMPTRLD(vmcs); 287 288 /* 289 * Guest MSRs are saved in the VM-exit MSR-store area. 290 * Guest MSRs are loaded from the VM-entry MSR-load area. 291 * Both areas point to the same location in memory. 292 */ 293 if ((error = vmwrite(VMCS_EXIT_MSR_STORE, g_area)) != 0) 294 goto done; 295 if ((error = vmwrite(VMCS_EXIT_MSR_STORE_COUNT, g_count)) != 0) 296 goto done; 297 298 if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD, g_area)) != 0) 299 goto done; 300 if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD_COUNT, g_count)) != 0) 301 goto done; 302 303 error = 0; 304done: 305 VMCLEAR(vmcs); 306 return (error); 307} 308 309int 310vmcs_set_defaults(struct vmcs *vmcs, 311 u_long host_rip, u_long host_rsp, u_long ept_pml4, 312 uint32_t pinbased_ctls, uint32_t procbased_ctls, 313 uint32_t procbased_ctls2, uint32_t exit_ctls, 314 uint32_t entry_ctls, u_long msr_bitmap, uint16_t vpid) 315{ 316 int error, codesel, datasel, tsssel; 317 u_long cr0, cr4, efer; 318 uint64_t eptp, pat, fsbase, idtrbase; 319 uint32_t exc_bitmap; 320 321 codesel = vmm_get_host_codesel(); 322 datasel = vmm_get_host_datasel(); 323 tsssel = vmm_get_host_tsssel(); 324 325 /* 326 * Make sure we have a "current" VMCS to work with. 327 */ 328 VMPTRLD(vmcs); 329 330 /* 331 * Load the VMX controls 332 */ 333 if ((error = vmwrite(VMCS_PIN_BASED_CTLS, pinbased_ctls)) != 0) 334 goto done; 335 if ((error = vmwrite(VMCS_PRI_PROC_BASED_CTLS, procbased_ctls)) != 0) 336 goto done; 337 if ((error = vmwrite(VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2)) != 0) 338 goto done; 339 if ((error = vmwrite(VMCS_EXIT_CTLS, exit_ctls)) != 0) 340 goto done; 341 if ((error = vmwrite(VMCS_ENTRY_CTLS, entry_ctls)) != 0) 342 goto done; 343 344 /* Guest state */ 345 346 /* Initialize guest IA32_PAT MSR with the default value */ 347 pat = PAT_VALUE(0, PAT_WRITE_BACK) | 348 PAT_VALUE(1, PAT_WRITE_THROUGH) | 349 PAT_VALUE(2, PAT_UNCACHED) | 350 PAT_VALUE(3, PAT_UNCACHEABLE) | 351 PAT_VALUE(4, PAT_WRITE_BACK) | 352 PAT_VALUE(5, PAT_WRITE_THROUGH) | 353 PAT_VALUE(6, PAT_UNCACHED) | 354 PAT_VALUE(7, PAT_UNCACHEABLE); 355 if ((error = vmwrite(VMCS_GUEST_IA32_PAT, pat)) != 0) 356 goto done; 357 358 /* Host state */ 359 360 /* Initialize host IA32_PAT MSR */ 361 pat = vmm_get_host_pat(); 362 if ((error = vmwrite(VMCS_HOST_IA32_PAT, pat)) != 0) 363 goto done; 364 365 /* Load the IA32_EFER MSR */ 366 efer = vmm_get_host_efer(); 367 if ((error = vmwrite(VMCS_HOST_IA32_EFER, efer)) != 0) 368 goto done; 369 370 /* Load the control registers */ 371 372 cr0 = vmm_get_host_cr0(); 373 if ((error = vmwrite(VMCS_HOST_CR0, cr0)) != 0) 374 goto done; 375 376 cr4 = vmm_get_host_cr4() | CR4_VMXE; 377 if ((error = vmwrite(VMCS_HOST_CR4, cr4)) != 0) 378 goto done; 379 380 /* Load the segment selectors */ 381 if ((error = vmwrite(VMCS_HOST_ES_SELECTOR, datasel)) != 0) 382 goto done; 383 384 if ((error = vmwrite(VMCS_HOST_CS_SELECTOR, codesel)) != 0) 385 goto done; 386 387 if ((error = vmwrite(VMCS_HOST_SS_SELECTOR, datasel)) != 0) 388 goto done; 389 390 if ((error = vmwrite(VMCS_HOST_DS_SELECTOR, datasel)) != 0) 391 goto done; 392 393 if ((error = vmwrite(VMCS_HOST_FS_SELECTOR, datasel)) != 0) 394 goto done; 395 396 if ((error = vmwrite(VMCS_HOST_GS_SELECTOR, datasel)) != 0) 397 goto done; 398 399 if ((error = vmwrite(VMCS_HOST_TR_SELECTOR, tsssel)) != 0) 400 goto done; 401 402 /* 403 * Load the Base-Address for %fs and idtr. 404 * 405 * Note that we exclude %gs, tss and gdtr here because their base 406 * address is pcpu specific. 407 */ 408 fsbase = vmm_get_host_fsbase(); 409 if ((error = vmwrite(VMCS_HOST_FS_BASE, fsbase)) != 0) 410 goto done; 411 412 idtrbase = vmm_get_host_idtrbase(); 413 if ((error = vmwrite(VMCS_HOST_IDTR_BASE, idtrbase)) != 0) 414 goto done; 415 416 /* instruction pointer */ 417 if ((error = vmwrite(VMCS_HOST_RIP, host_rip)) != 0) 418 goto done; 419 420 /* stack pointer */ 421 if ((error = vmwrite(VMCS_HOST_RSP, host_rsp)) != 0) 422 goto done; 423 424 /* eptp */ 425 eptp = EPTP(ept_pml4); 426 if ((error = vmwrite(VMCS_EPTP, eptp)) != 0) 427 goto done; 428 429 /* vpid */ 430 if ((error = vmwrite(VMCS_VPID, vpid)) != 0) 431 goto done; 432 433 /* msr bitmap */ 434 if ((error = vmwrite(VMCS_MSR_BITMAP, msr_bitmap)) != 0) 435 goto done; 436 437 /* exception bitmap */ 438 exc_bitmap = 1 << IDT_MC; 439 if ((error = vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap)) != 0) 440 goto done; 441 442 /* link pointer */ 443 if ((error = vmwrite(VMCS_LINK_POINTER, ~0)) != 0) 444 goto done; 445done: 446 VMCLEAR(vmcs); 447 return (error); 448} 449 450uint64_t 451vmcs_read(uint32_t encoding) 452{ 453 int error; 454 uint64_t val; 455 456 error = vmread(encoding, &val); 457 if (error != 0) 458 panic("vmcs_read(%u) error %d", encoding, error); 459 460 return (val); 461} 462 463#ifdef DDB 464extern int vmxon_enabled[]; 465 466DB_SHOW_COMMAND(vmcs, db_show_vmcs) 467{ 468 uint64_t cur_vmcs, val; 469 uint32_t exit; 470 471 if (!vmxon_enabled[curcpu]) { 472 db_printf("VMX not enabled\n"); 473 return; 474 } 475 476 if (have_addr) { 477 db_printf("Only current VMCS supported\n"); 478 return; 479 } 480 481 vmptrst(&cur_vmcs); 482 if (cur_vmcs == VMCS_INITIAL) { 483 db_printf("No current VM context\n"); 484 return; 485 } 486 db_printf("VMCS: %jx\n", cur_vmcs); 487 db_printf("VPID: %lu\n", vmcs_read(VMCS_VPID)); 488 db_printf("Activity: "); 489 val = vmcs_read(VMCS_GUEST_ACTIVITY); 490 switch (val) { 491 case 0: 492 db_printf("Active"); 493 break; 494 case 1: 495 db_printf("HLT"); 496 break; 497 case 2: 498 db_printf("Shutdown"); 499 break; 500 case 3: 501 db_printf("Wait for SIPI"); 502 break; 503 default: 504 db_printf("Unknown: %#lx", val); 505 } 506 db_printf("\n"); 507 exit = vmcs_read(VMCS_EXIT_REASON); 508 if (exit & 0x80000000) 509 db_printf("Entry Failure Reason: %u\n", exit & 0xffff); 510 else 511 db_printf("Exit Reason: %u\n", exit & 0xffff); 512 db_printf("Qualification: %#lx\n", vmcs_exit_qualification()); 513 db_printf("Guest Linear Address: %#lx\n", 514 vmcs_read(VMCS_GUEST_LINEAR_ADDRESS)); 515 switch (exit & 0x8000ffff) { 516 case EXIT_REASON_EXCEPTION: 517 case EXIT_REASON_EXT_INTR: 518 val = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO); 519 db_printf("Interrupt Type: "); 520 switch (val >> 8 & 0x7) { 521 case 0: 522 db_printf("external"); 523 break; 524 case 2: 525 db_printf("NMI"); 526 break; 527 case 3: 528 db_printf("HW exception"); 529 break; 530 case 4: 531 db_printf("SW exception"); 532 break; 533 default: 534 db_printf("?? %lu", val >> 8 & 0x7); 535 break; 536 } 537 db_printf(" Vector: %lu", val & 0xff); 538 if (val & 0x800) 539 db_printf(" Error Code: %lx", 540 vmcs_read(VMCS_EXIT_INTERRUPTION_ERROR)); 541 db_printf("\n"); 542 break; 543 case EXIT_REASON_EPT_FAULT: 544 case EXIT_REASON_EPT_MISCONFIG: 545 db_printf("Guest Physical Address: %#lx\n", 546 vmcs_read(VMCS_GUEST_PHYSICAL_ADDRESS)); 547 break; 548 } 549 db_printf("VM-instruction error: %#lx\n", vmcs_instruction_error()); 550} 551#endif 552