vmcs.c revision 242122
1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26221828Sgrehan * $FreeBSD$ 27221828Sgrehan */ 28221828Sgrehan 29222605Sjhb#include "opt_ddb.h" 30222605Sjhb 31221828Sgrehan#include <sys/cdefs.h> 32221828Sgrehan__FBSDID("$FreeBSD$"); 33221828Sgrehan 34221828Sgrehan#include <sys/param.h> 35221828Sgrehan#include <sys/systm.h> 36221828Sgrehan#include <sys/pcpu.h> 37221828Sgrehan 38221828Sgrehan#include <vm/vm.h> 39221828Sgrehan#include <vm/pmap.h> 40221828Sgrehan 41221828Sgrehan#include <machine/segments.h> 42221828Sgrehan#include <machine/pmap.h> 43221828Sgrehan 44221828Sgrehan#include <machine/vmm.h> 45221828Sgrehan#include "vmcs.h" 46221828Sgrehan#include "vmx_cpufunc.h" 47221828Sgrehan#include "ept.h" 48221828Sgrehan#include "vmx.h" 49221828Sgrehan 50222605Sjhb#ifdef DDB 51222605Sjhb#include <ddb/ddb.h> 52222605Sjhb#endif 53222605Sjhb 54221828Sgrehanstatic uint64_t 55221828Sgrehanvmcs_fix_regval(uint32_t encoding, uint64_t val) 56221828Sgrehan{ 57221828Sgrehan 58221828Sgrehan switch (encoding) { 59221828Sgrehan case VMCS_GUEST_CR0: 60221828Sgrehan val = vmx_fix_cr0(val); 61221828Sgrehan break; 62221828Sgrehan case VMCS_GUEST_CR4: 63221828Sgrehan val = vmx_fix_cr4(val); 64221828Sgrehan break; 65221828Sgrehan default: 66221828Sgrehan break; 67221828Sgrehan } 68221828Sgrehan return (val); 69221828Sgrehan} 70221828Sgrehan 71221828Sgrehanstatic uint32_t 72221828Sgrehanvmcs_field_encoding(int ident) 73221828Sgrehan{ 74221828Sgrehan switch (ident) { 75221828Sgrehan case VM_REG_GUEST_CR0: 76221828Sgrehan return (VMCS_GUEST_CR0); 77221828Sgrehan case VM_REG_GUEST_CR3: 78221828Sgrehan return (VMCS_GUEST_CR3); 79221828Sgrehan case VM_REG_GUEST_CR4: 80221828Sgrehan return (VMCS_GUEST_CR4); 81221828Sgrehan case VM_REG_GUEST_DR7: 82221828Sgrehan return (VMCS_GUEST_DR7); 83221828Sgrehan case VM_REG_GUEST_RSP: 84221828Sgrehan return (VMCS_GUEST_RSP); 85221828Sgrehan case VM_REG_GUEST_RIP: 86221828Sgrehan return (VMCS_GUEST_RIP); 87221828Sgrehan case VM_REG_GUEST_RFLAGS: 88221828Sgrehan return (VMCS_GUEST_RFLAGS); 89221828Sgrehan case VM_REG_GUEST_ES: 90221828Sgrehan return (VMCS_GUEST_ES_SELECTOR); 91221828Sgrehan case VM_REG_GUEST_CS: 92221828Sgrehan return (VMCS_GUEST_CS_SELECTOR); 93221828Sgrehan case VM_REG_GUEST_SS: 94221828Sgrehan return (VMCS_GUEST_SS_SELECTOR); 95221828Sgrehan case VM_REG_GUEST_DS: 96221828Sgrehan return (VMCS_GUEST_DS_SELECTOR); 97221828Sgrehan case VM_REG_GUEST_FS: 98221828Sgrehan return (VMCS_GUEST_FS_SELECTOR); 99221828Sgrehan case VM_REG_GUEST_GS: 100221828Sgrehan return (VMCS_GUEST_GS_SELECTOR); 101221828Sgrehan case VM_REG_GUEST_TR: 102221828Sgrehan return (VMCS_GUEST_TR_SELECTOR); 103221828Sgrehan case VM_REG_GUEST_LDTR: 104221828Sgrehan return (VMCS_GUEST_LDTR_SELECTOR); 105221828Sgrehan case VM_REG_GUEST_EFER: 106221828Sgrehan return (VMCS_GUEST_IA32_EFER); 107221828Sgrehan default: 108221828Sgrehan return (-1); 109221828Sgrehan } 110221828Sgrehan 111221828Sgrehan} 112221828Sgrehan 113221828Sgrehanstatic int 114221828Sgrehanvmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc) 115221828Sgrehan{ 116221828Sgrehan 117221828Sgrehan switch (seg) { 118221828Sgrehan case VM_REG_GUEST_ES: 119221828Sgrehan *base = VMCS_GUEST_ES_BASE; 120221828Sgrehan *lim = VMCS_GUEST_ES_LIMIT; 121221828Sgrehan *acc = VMCS_GUEST_ES_ACCESS_RIGHTS; 122221828Sgrehan break; 123221828Sgrehan case VM_REG_GUEST_CS: 124221828Sgrehan *base = VMCS_GUEST_CS_BASE; 125221828Sgrehan *lim = VMCS_GUEST_CS_LIMIT; 126221828Sgrehan *acc = VMCS_GUEST_CS_ACCESS_RIGHTS; 127221828Sgrehan break; 128221828Sgrehan case VM_REG_GUEST_SS: 129221828Sgrehan *base = VMCS_GUEST_SS_BASE; 130221828Sgrehan *lim = VMCS_GUEST_SS_LIMIT; 131221828Sgrehan *acc = VMCS_GUEST_SS_ACCESS_RIGHTS; 132221828Sgrehan break; 133221828Sgrehan case VM_REG_GUEST_DS: 134221828Sgrehan *base = VMCS_GUEST_DS_BASE; 135221828Sgrehan *lim = VMCS_GUEST_DS_LIMIT; 136221828Sgrehan *acc = VMCS_GUEST_DS_ACCESS_RIGHTS; 137221828Sgrehan break; 138221828Sgrehan case VM_REG_GUEST_FS: 139221828Sgrehan *base = VMCS_GUEST_FS_BASE; 140221828Sgrehan *lim = VMCS_GUEST_FS_LIMIT; 141221828Sgrehan *acc = VMCS_GUEST_FS_ACCESS_RIGHTS; 142221828Sgrehan break; 143221828Sgrehan case VM_REG_GUEST_GS: 144221828Sgrehan *base = VMCS_GUEST_GS_BASE; 145221828Sgrehan *lim = VMCS_GUEST_GS_LIMIT; 146221828Sgrehan *acc = VMCS_GUEST_GS_ACCESS_RIGHTS; 147221828Sgrehan break; 148221828Sgrehan case VM_REG_GUEST_TR: 149221828Sgrehan *base = VMCS_GUEST_TR_BASE; 150221828Sgrehan *lim = VMCS_GUEST_TR_LIMIT; 151221828Sgrehan *acc = VMCS_GUEST_TR_ACCESS_RIGHTS; 152221828Sgrehan break; 153221828Sgrehan case VM_REG_GUEST_LDTR: 154221828Sgrehan *base = VMCS_GUEST_LDTR_BASE; 155221828Sgrehan *lim = VMCS_GUEST_LDTR_LIMIT; 156221828Sgrehan *acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS; 157221828Sgrehan break; 158221828Sgrehan case VM_REG_GUEST_IDTR: 159221828Sgrehan *base = VMCS_GUEST_IDTR_BASE; 160221828Sgrehan *lim = VMCS_GUEST_IDTR_LIMIT; 161221828Sgrehan *acc = VMCS_INVALID_ENCODING; 162221828Sgrehan break; 163221828Sgrehan case VM_REG_GUEST_GDTR: 164221828Sgrehan *base = VMCS_GUEST_GDTR_BASE; 165221828Sgrehan *lim = VMCS_GUEST_GDTR_LIMIT; 166221828Sgrehan *acc = VMCS_INVALID_ENCODING; 167221828Sgrehan break; 168221828Sgrehan default: 169221828Sgrehan return (EINVAL); 170221828Sgrehan } 171221828Sgrehan 172221828Sgrehan return (0); 173221828Sgrehan} 174221828Sgrehan 175221828Sgrehanint 176221828Sgrehanvmcs_getreg(struct vmcs *vmcs, int ident, uint64_t *retval) 177221828Sgrehan{ 178221828Sgrehan int error; 179221828Sgrehan uint32_t encoding; 180221828Sgrehan 181221828Sgrehan /* 182221828Sgrehan * If we need to get at vmx-specific state in the VMCS we can bypass 183221828Sgrehan * the translation of 'ident' to 'encoding' by simply setting the 184221828Sgrehan * sign bit. As it so happens the upper 16 bits are reserved (i.e 185221828Sgrehan * set to 0) in the encodings for the VMCS so we are free to use the 186221828Sgrehan * sign bit. 187221828Sgrehan */ 188221828Sgrehan if (ident < 0) 189221828Sgrehan encoding = ident & 0x7fffffff; 190221828Sgrehan else 191221828Sgrehan encoding = vmcs_field_encoding(ident); 192221828Sgrehan 193221828Sgrehan if (encoding == (uint32_t)-1) 194221828Sgrehan return (EINVAL); 195221828Sgrehan 196221828Sgrehan VMPTRLD(vmcs); 197221828Sgrehan error = vmread(encoding, retval); 198221828Sgrehan VMCLEAR(vmcs); 199221828Sgrehan return (error); 200221828Sgrehan} 201221828Sgrehan 202221828Sgrehanint 203221828Sgrehanvmcs_setreg(struct vmcs *vmcs, int ident, uint64_t val) 204221828Sgrehan{ 205221828Sgrehan int error; 206221828Sgrehan uint32_t encoding; 207221828Sgrehan 208221828Sgrehan if (ident < 0) 209221828Sgrehan encoding = ident & 0x7fffffff; 210221828Sgrehan else 211221828Sgrehan encoding = vmcs_field_encoding(ident); 212221828Sgrehan 213221828Sgrehan if (encoding == (uint32_t)-1) 214221828Sgrehan return (EINVAL); 215221828Sgrehan 216221828Sgrehan val = vmcs_fix_regval(encoding, val); 217221828Sgrehan 218221828Sgrehan VMPTRLD(vmcs); 219221828Sgrehan error = vmwrite(encoding, val); 220221828Sgrehan VMCLEAR(vmcs); 221221828Sgrehan return (error); 222221828Sgrehan} 223221828Sgrehan 224221828Sgrehanint 225221828Sgrehanvmcs_setdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc) 226221828Sgrehan{ 227221828Sgrehan int error; 228221828Sgrehan uint32_t base, limit, access; 229221828Sgrehan 230221828Sgrehan error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 231221828Sgrehan if (error != 0) 232221828Sgrehan panic("vmcs_setdesc: invalid segment register %d", seg); 233221828Sgrehan 234221828Sgrehan VMPTRLD(vmcs); 235221828Sgrehan if ((error = vmwrite(base, desc->base)) != 0) 236221828Sgrehan goto done; 237221828Sgrehan 238221828Sgrehan if ((error = vmwrite(limit, desc->limit)) != 0) 239221828Sgrehan goto done; 240221828Sgrehan 241221828Sgrehan if (access != VMCS_INVALID_ENCODING) { 242221828Sgrehan if ((error = vmwrite(access, desc->access)) != 0) 243221828Sgrehan goto done; 244221828Sgrehan } 245221828Sgrehandone: 246221828Sgrehan VMCLEAR(vmcs); 247221828Sgrehan return (error); 248221828Sgrehan} 249221828Sgrehan 250221828Sgrehanint 251221828Sgrehanvmcs_getdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc) 252221828Sgrehan{ 253221828Sgrehan int error; 254221828Sgrehan uint32_t base, limit, access; 255221828Sgrehan uint64_t u64; 256221828Sgrehan 257221828Sgrehan error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 258221828Sgrehan if (error != 0) 259221828Sgrehan panic("vmcs_getdesc: invalid segment register %d", seg); 260221828Sgrehan 261221828Sgrehan VMPTRLD(vmcs); 262221828Sgrehan if ((error = vmread(base, &u64)) != 0) 263221828Sgrehan goto done; 264221828Sgrehan desc->base = u64; 265221828Sgrehan 266221828Sgrehan if ((error = vmread(limit, &u64)) != 0) 267221828Sgrehan goto done; 268221828Sgrehan desc->limit = u64; 269221828Sgrehan 270221828Sgrehan if (access != VMCS_INVALID_ENCODING) { 271221828Sgrehan if ((error = vmread(access, &u64)) != 0) 272221828Sgrehan goto done; 273221828Sgrehan desc->access = u64; 274221828Sgrehan } 275221828Sgrehandone: 276221828Sgrehan VMCLEAR(vmcs); 277221828Sgrehan return (error); 278221828Sgrehan} 279221828Sgrehan 280221828Sgrehanint 281221828Sgrehanvmcs_set_msr_save(struct vmcs *vmcs, u_long g_area, u_int g_count) 282221828Sgrehan{ 283221828Sgrehan int error; 284221828Sgrehan 285221828Sgrehan VMPTRLD(vmcs); 286221828Sgrehan 287221828Sgrehan /* 288221828Sgrehan * Guest MSRs are saved in the VM-exit MSR-store area. 289221828Sgrehan * Guest MSRs are loaded from the VM-entry MSR-load area. 290221828Sgrehan * Both areas point to the same location in memory. 291221828Sgrehan */ 292221828Sgrehan if ((error = vmwrite(VMCS_EXIT_MSR_STORE, g_area)) != 0) 293221828Sgrehan goto done; 294221828Sgrehan if ((error = vmwrite(VMCS_EXIT_MSR_STORE_COUNT, g_count)) != 0) 295221828Sgrehan goto done; 296221828Sgrehan 297221828Sgrehan if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD, g_area)) != 0) 298221828Sgrehan goto done; 299221828Sgrehan if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD_COUNT, g_count)) != 0) 300221828Sgrehan goto done; 301221828Sgrehan 302221828Sgrehan error = 0; 303221828Sgrehandone: 304221828Sgrehan VMCLEAR(vmcs); 305221828Sgrehan return (error); 306221828Sgrehan} 307221828Sgrehan 308221828Sgrehanint 309221828Sgrehanvmcs_set_defaults(struct vmcs *vmcs, 310221828Sgrehan u_long host_rip, u_long host_rsp, u_long ept_pml4, 311221828Sgrehan uint32_t pinbased_ctls, uint32_t procbased_ctls, 312221828Sgrehan uint32_t procbased_ctls2, uint32_t exit_ctls, 313221828Sgrehan uint32_t entry_ctls, u_long msr_bitmap, uint16_t vpid) 314221828Sgrehan{ 315221828Sgrehan int error, codesel, datasel, tsssel; 316221828Sgrehan u_long cr0, cr4, efer; 317221828Sgrehan uint64_t eptp, pat; 318221828Sgrehan uint32_t exc_bitmap; 319221828Sgrehan 320221828Sgrehan codesel = GSEL(GCODE_SEL, SEL_KPL); 321221828Sgrehan datasel = GSEL(GDATA_SEL, SEL_KPL); 322221828Sgrehan tsssel = GSEL(GPROC0_SEL, SEL_KPL); 323221828Sgrehan 324221828Sgrehan /* 325221828Sgrehan * Make sure we have a "current" VMCS to work with. 326221828Sgrehan */ 327221828Sgrehan VMPTRLD(vmcs); 328221828Sgrehan 329221828Sgrehan /* 330221828Sgrehan * Load the VMX controls 331221828Sgrehan */ 332221828Sgrehan if ((error = vmwrite(VMCS_PIN_BASED_CTLS, pinbased_ctls)) != 0) 333221828Sgrehan goto done; 334221828Sgrehan if ((error = vmwrite(VMCS_PRI_PROC_BASED_CTLS, procbased_ctls)) != 0) 335221828Sgrehan goto done; 336221828Sgrehan if ((error = vmwrite(VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2)) != 0) 337221828Sgrehan goto done; 338221828Sgrehan if ((error = vmwrite(VMCS_EXIT_CTLS, exit_ctls)) != 0) 339221828Sgrehan goto done; 340221828Sgrehan if ((error = vmwrite(VMCS_ENTRY_CTLS, entry_ctls)) != 0) 341221828Sgrehan goto done; 342221828Sgrehan 343221828Sgrehan /* Guest state */ 344221828Sgrehan 345221828Sgrehan /* Initialize guest IA32_PAT MSR with the default value */ 346221828Sgrehan pat = PAT_VALUE(0, PAT_WRITE_BACK) | 347221828Sgrehan PAT_VALUE(1, PAT_WRITE_THROUGH) | 348221828Sgrehan PAT_VALUE(2, PAT_UNCACHED) | 349221828Sgrehan PAT_VALUE(3, PAT_UNCACHEABLE) | 350221828Sgrehan PAT_VALUE(4, PAT_WRITE_BACK) | 351221828Sgrehan PAT_VALUE(5, PAT_WRITE_THROUGH) | 352221828Sgrehan PAT_VALUE(6, PAT_UNCACHED) | 353221828Sgrehan PAT_VALUE(7, PAT_UNCACHEABLE); 354221828Sgrehan if ((error = vmwrite(VMCS_GUEST_IA32_PAT, pat)) != 0) 355221828Sgrehan goto done; 356221828Sgrehan 357221828Sgrehan /* Host state */ 358221828Sgrehan 359221828Sgrehan /* Initialize host IA32_PAT MSR */ 360221828Sgrehan pat = rdmsr(MSR_PAT); 361221828Sgrehan if ((error = vmwrite(VMCS_HOST_IA32_PAT, pat)) != 0) 362221828Sgrehan goto done; 363221828Sgrehan 364221828Sgrehan /* Load the IA32_EFER MSR */ 365221828Sgrehan efer = rdmsr(MSR_EFER); 366221828Sgrehan if ((error = vmwrite(VMCS_HOST_IA32_EFER, efer)) != 0) 367221828Sgrehan goto done; 368221828Sgrehan 369221828Sgrehan /* Load the control registers */ 370242122Sneel 371242122Sneel /* 372242122Sneel * We always want CR0.TS to be set when the processor does a VM exit. 373242122Sneel * 374242122Sneel * With emulation turned on unconditionally after a VM exit, we are 375242122Sneel * able to trap inadvertent use of the FPU until the guest FPU state 376242122Sneel * has been safely squirreled away. 377242122Sneel */ 378242122Sneel cr0 = rcr0() | CR0_TS; 379221828Sgrehan if ((error = vmwrite(VMCS_HOST_CR0, cr0)) != 0) 380221828Sgrehan goto done; 381221828Sgrehan 382221828Sgrehan cr4 = rcr4(); 383221828Sgrehan if ((error = vmwrite(VMCS_HOST_CR4, cr4)) != 0) 384221828Sgrehan goto done; 385221828Sgrehan 386221828Sgrehan /* Load the segment selectors */ 387221828Sgrehan if ((error = vmwrite(VMCS_HOST_ES_SELECTOR, datasel)) != 0) 388221828Sgrehan goto done; 389221828Sgrehan 390221828Sgrehan if ((error = vmwrite(VMCS_HOST_CS_SELECTOR, codesel)) != 0) 391221828Sgrehan goto done; 392221828Sgrehan 393221828Sgrehan if ((error = vmwrite(VMCS_HOST_SS_SELECTOR, datasel)) != 0) 394221828Sgrehan goto done; 395221828Sgrehan 396221828Sgrehan if ((error = vmwrite(VMCS_HOST_DS_SELECTOR, datasel)) != 0) 397221828Sgrehan goto done; 398221828Sgrehan 399221828Sgrehan if ((error = vmwrite(VMCS_HOST_FS_SELECTOR, datasel)) != 0) 400221828Sgrehan goto done; 401221828Sgrehan 402221828Sgrehan if ((error = vmwrite(VMCS_HOST_GS_SELECTOR, datasel)) != 0) 403221828Sgrehan goto done; 404221828Sgrehan 405221828Sgrehan if ((error = vmwrite(VMCS_HOST_TR_SELECTOR, tsssel)) != 0) 406221828Sgrehan goto done; 407221828Sgrehan 408221828Sgrehan /* 409221828Sgrehan * Load the Base-Address for %fs and idtr. 410221828Sgrehan * 411221828Sgrehan * Note that we exclude %gs, tss and gdtr here because their base 412221828Sgrehan * address is pcpu specific. 413221828Sgrehan */ 414221828Sgrehan if ((error = vmwrite(VMCS_HOST_FS_BASE, 0)) != 0) 415221828Sgrehan goto done; 416221828Sgrehan 417221828Sgrehan if ((error = vmwrite(VMCS_HOST_IDTR_BASE, r_idt.rd_base)) != 0) 418221828Sgrehan goto done; 419221828Sgrehan 420221828Sgrehan /* instruction pointer */ 421221828Sgrehan if ((error = vmwrite(VMCS_HOST_RIP, host_rip)) != 0) 422221828Sgrehan goto done; 423221828Sgrehan 424221828Sgrehan /* stack pointer */ 425221828Sgrehan if ((error = vmwrite(VMCS_HOST_RSP, host_rsp)) != 0) 426221828Sgrehan goto done; 427221828Sgrehan 428221828Sgrehan /* eptp */ 429221828Sgrehan eptp = EPTP(ept_pml4); 430221828Sgrehan if ((error = vmwrite(VMCS_EPTP, eptp)) != 0) 431221828Sgrehan goto done; 432221828Sgrehan 433221828Sgrehan /* vpid */ 434221828Sgrehan if ((error = vmwrite(VMCS_VPID, vpid)) != 0) 435221828Sgrehan goto done; 436221828Sgrehan 437221828Sgrehan /* msr bitmap */ 438221828Sgrehan if ((error = vmwrite(VMCS_MSR_BITMAP, msr_bitmap)) != 0) 439221828Sgrehan goto done; 440221828Sgrehan 441221828Sgrehan /* exception bitmap */ 442221828Sgrehan exc_bitmap = 1 << IDT_MC; 443221828Sgrehan if ((error = vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap)) != 0) 444221828Sgrehan goto done; 445221828Sgrehan 446221828Sgrehan /* link pointer */ 447221828Sgrehan if ((error = vmwrite(VMCS_LINK_POINTER, ~0)) != 0) 448221828Sgrehan goto done; 449221828Sgrehandone: 450221828Sgrehan VMCLEAR(vmcs); 451221828Sgrehan return (error); 452221828Sgrehan} 453221828Sgrehan 454221828Sgrehanuint64_t 455221828Sgrehanvmcs_read(uint32_t encoding) 456221828Sgrehan{ 457221828Sgrehan int error; 458221828Sgrehan uint64_t val; 459221828Sgrehan 460221828Sgrehan error = vmread(encoding, &val); 461221828Sgrehan if (error != 0) 462221828Sgrehan panic("vmcs_read(%u) error %d", encoding, error); 463221828Sgrehan 464221828Sgrehan return (val); 465221828Sgrehan} 466222605Sjhb 467222605Sjhb#ifdef DDB 468222605Sjhbextern int vmxon_enabled[]; 469222605Sjhb 470222605SjhbDB_SHOW_COMMAND(vmcs, db_show_vmcs) 471222605Sjhb{ 472222605Sjhb uint64_t cur_vmcs, val; 473222605Sjhb uint32_t exit; 474222605Sjhb 475222605Sjhb if (!vmxon_enabled[curcpu]) { 476222605Sjhb db_printf("VMX not enabled\n"); 477222605Sjhb return; 478222605Sjhb } 479222605Sjhb 480222605Sjhb if (have_addr) { 481222605Sjhb db_printf("Only current VMCS supported\n"); 482222605Sjhb return; 483222605Sjhb } 484222605Sjhb 485222605Sjhb vmptrst(&cur_vmcs); 486222605Sjhb if (cur_vmcs == VMCS_INITIAL) { 487222605Sjhb db_printf("No current VM context\n"); 488222605Sjhb return; 489222605Sjhb } 490222605Sjhb db_printf("VMCS: %jx\n", cur_vmcs); 491222605Sjhb db_printf("VPID: %lu\n", vmcs_read(VMCS_VPID)); 492222605Sjhb db_printf("Activity: "); 493222605Sjhb val = vmcs_read(VMCS_GUEST_ACTIVITY); 494222605Sjhb switch (val) { 495222605Sjhb case 0: 496222605Sjhb db_printf("Active"); 497222605Sjhb break; 498222605Sjhb case 1: 499222605Sjhb db_printf("HLT"); 500222605Sjhb break; 501222605Sjhb case 2: 502222605Sjhb db_printf("Shutdown"); 503222605Sjhb break; 504222605Sjhb case 3: 505222605Sjhb db_printf("Wait for SIPI"); 506222605Sjhb break; 507222605Sjhb default: 508222605Sjhb db_printf("Unknown: %#lx", val); 509222605Sjhb } 510222605Sjhb db_printf("\n"); 511222605Sjhb exit = vmcs_read(VMCS_EXIT_REASON); 512222605Sjhb if (exit & 0x80000000) 513222605Sjhb db_printf("Entry Failure Reason: %u\n", exit & 0xffff); 514222605Sjhb else 515222605Sjhb db_printf("Exit Reason: %u\n", exit & 0xffff); 516222605Sjhb db_printf("Qualification: %#lx\n", vmcs_exit_qualification()); 517222605Sjhb db_printf("Guest Linear Address: %#lx\n", 518222605Sjhb vmcs_read(VMCS_GUEST_LINEAR_ADDRESS)); 519222605Sjhb switch (exit & 0x8000ffff) { 520222605Sjhb case EXIT_REASON_EXCEPTION: 521222605Sjhb case EXIT_REASON_EXT_INTR: 522222605Sjhb val = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO); 523222605Sjhb db_printf("Interrupt Type: "); 524222605Sjhb switch (val >> 8 & 0x7) { 525222605Sjhb case 0: 526222605Sjhb db_printf("external"); 527222605Sjhb break; 528222605Sjhb case 2: 529222605Sjhb db_printf("NMI"); 530222605Sjhb break; 531222605Sjhb case 3: 532222605Sjhb db_printf("HW exception"); 533222605Sjhb break; 534222605Sjhb case 4: 535222605Sjhb db_printf("SW exception"); 536222605Sjhb break; 537222605Sjhb default: 538222605Sjhb db_printf("?? %lu", val >> 8 & 0x7); 539222605Sjhb break; 540222605Sjhb } 541222605Sjhb db_printf(" Vector: %lu", val & 0xff); 542222605Sjhb if (val & 0x800) 543222605Sjhb db_printf(" Error Code: %lx", 544222605Sjhb vmcs_read(VMCS_EXIT_INTERRUPTION_ERROR)); 545222605Sjhb db_printf("\n"); 546222605Sjhb break; 547222605Sjhb case EXIT_REASON_EPT_FAULT: 548222605Sjhb case EXIT_REASON_EPT_MISCONFIG: 549222605Sjhb db_printf("Guest Physical Address: %#lx\n", 550222605Sjhb vmcs_read(VMCS_GUEST_PHYSICAL_ADDRESS)); 551222605Sjhb break; 552222605Sjhb } 553222605Sjhb db_printf("VM-instruction error: %#lx\n", vmcs_instruction_error()); 554222605Sjhb} 555222605Sjhb#endif 556