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