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: stable/11/sys/amd64/vmm/intel/vmcs.c 331722 2018-03-29 02:50:57Z eadler $ 27221828Sgrehan */ 28221828Sgrehan 29222605Sjhb#include "opt_ddb.h" 30222605Sjhb 31221828Sgrehan#include <sys/cdefs.h> 32221828Sgrehan__FBSDID("$FreeBSD: stable/11/sys/amd64/vmm/intel/vmcs.c 331722 2018-03-29 02:50:57Z eadler $"); 33221828Sgrehan 34221828Sgrehan#include <sys/param.h> 35330704Stychon#include <sys/sysctl.h> 36221828Sgrehan#include <sys/systm.h> 37221828Sgrehan#include <sys/pcpu.h> 38221828Sgrehan 39221828Sgrehan#include <vm/vm.h> 40221828Sgrehan#include <vm/pmap.h> 41221828Sgrehan 42221828Sgrehan#include <machine/segments.h> 43221828Sgrehan#include <machine/vmm.h> 44242275Sneel#include "vmm_host.h" 45259542Sneel#include "vmx_cpufunc.h" 46221828Sgrehan#include "vmcs.h" 47221828Sgrehan#include "ept.h" 48221828Sgrehan#include "vmx.h" 49221828Sgrehan 50222605Sjhb#ifdef DDB 51222605Sjhb#include <ddb/ddb.h> 52222605Sjhb#endif 53222605Sjhb 54330704StychonSYSCTL_DECL(_hw_vmm_vmx); 55330704Stychon 56330704Stychonstatic int no_flush_rsb; 57330704StychonSYSCTL_INT(_hw_vmm_vmx, OID_AUTO, no_flush_rsb, CTLFLAG_RW, 58330704Stychon &no_flush_rsb, 0, "Do not flush RSB upon vmexit"); 59330704Stychon 60221828Sgrehanstatic uint64_t 61221828Sgrehanvmcs_fix_regval(uint32_t encoding, uint64_t val) 62221828Sgrehan{ 63221828Sgrehan 64221828Sgrehan switch (encoding) { 65221828Sgrehan case VMCS_GUEST_CR0: 66221828Sgrehan val = vmx_fix_cr0(val); 67221828Sgrehan break; 68221828Sgrehan case VMCS_GUEST_CR4: 69221828Sgrehan val = vmx_fix_cr4(val); 70221828Sgrehan break; 71221828Sgrehan default: 72221828Sgrehan break; 73221828Sgrehan } 74221828Sgrehan return (val); 75221828Sgrehan} 76221828Sgrehan 77221828Sgrehanstatic uint32_t 78221828Sgrehanvmcs_field_encoding(int ident) 79221828Sgrehan{ 80221828Sgrehan switch (ident) { 81221828Sgrehan case VM_REG_GUEST_CR0: 82221828Sgrehan return (VMCS_GUEST_CR0); 83221828Sgrehan case VM_REG_GUEST_CR3: 84221828Sgrehan return (VMCS_GUEST_CR3); 85221828Sgrehan case VM_REG_GUEST_CR4: 86221828Sgrehan return (VMCS_GUEST_CR4); 87221828Sgrehan case VM_REG_GUEST_DR7: 88221828Sgrehan return (VMCS_GUEST_DR7); 89221828Sgrehan case VM_REG_GUEST_RSP: 90221828Sgrehan return (VMCS_GUEST_RSP); 91221828Sgrehan case VM_REG_GUEST_RIP: 92221828Sgrehan return (VMCS_GUEST_RIP); 93221828Sgrehan case VM_REG_GUEST_RFLAGS: 94221828Sgrehan return (VMCS_GUEST_RFLAGS); 95221828Sgrehan case VM_REG_GUEST_ES: 96221828Sgrehan return (VMCS_GUEST_ES_SELECTOR); 97221828Sgrehan case VM_REG_GUEST_CS: 98221828Sgrehan return (VMCS_GUEST_CS_SELECTOR); 99221828Sgrehan case VM_REG_GUEST_SS: 100221828Sgrehan return (VMCS_GUEST_SS_SELECTOR); 101221828Sgrehan case VM_REG_GUEST_DS: 102221828Sgrehan return (VMCS_GUEST_DS_SELECTOR); 103221828Sgrehan case VM_REG_GUEST_FS: 104221828Sgrehan return (VMCS_GUEST_FS_SELECTOR); 105221828Sgrehan case VM_REG_GUEST_GS: 106221828Sgrehan return (VMCS_GUEST_GS_SELECTOR); 107221828Sgrehan case VM_REG_GUEST_TR: 108221828Sgrehan return (VMCS_GUEST_TR_SELECTOR); 109221828Sgrehan case VM_REG_GUEST_LDTR: 110221828Sgrehan return (VMCS_GUEST_LDTR_SELECTOR); 111221828Sgrehan case VM_REG_GUEST_EFER: 112221828Sgrehan return (VMCS_GUEST_IA32_EFER); 113268777Sneel case VM_REG_GUEST_PDPTE0: 114268777Sneel return (VMCS_GUEST_PDPTE0); 115268777Sneel case VM_REG_GUEST_PDPTE1: 116268777Sneel return (VMCS_GUEST_PDPTE1); 117268777Sneel case VM_REG_GUEST_PDPTE2: 118268777Sneel return (VMCS_GUEST_PDPTE2); 119268777Sneel case VM_REG_GUEST_PDPTE3: 120268777Sneel return (VMCS_GUEST_PDPTE3); 121221828Sgrehan default: 122221828Sgrehan return (-1); 123221828Sgrehan } 124221828Sgrehan 125221828Sgrehan} 126221828Sgrehan 127221828Sgrehanstatic int 128221828Sgrehanvmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc) 129221828Sgrehan{ 130221828Sgrehan 131221828Sgrehan switch (seg) { 132221828Sgrehan case VM_REG_GUEST_ES: 133221828Sgrehan *base = VMCS_GUEST_ES_BASE; 134221828Sgrehan *lim = VMCS_GUEST_ES_LIMIT; 135221828Sgrehan *acc = VMCS_GUEST_ES_ACCESS_RIGHTS; 136221828Sgrehan break; 137221828Sgrehan case VM_REG_GUEST_CS: 138221828Sgrehan *base = VMCS_GUEST_CS_BASE; 139221828Sgrehan *lim = VMCS_GUEST_CS_LIMIT; 140221828Sgrehan *acc = VMCS_GUEST_CS_ACCESS_RIGHTS; 141221828Sgrehan break; 142221828Sgrehan case VM_REG_GUEST_SS: 143221828Sgrehan *base = VMCS_GUEST_SS_BASE; 144221828Sgrehan *lim = VMCS_GUEST_SS_LIMIT; 145221828Sgrehan *acc = VMCS_GUEST_SS_ACCESS_RIGHTS; 146221828Sgrehan break; 147221828Sgrehan case VM_REG_GUEST_DS: 148221828Sgrehan *base = VMCS_GUEST_DS_BASE; 149221828Sgrehan *lim = VMCS_GUEST_DS_LIMIT; 150221828Sgrehan *acc = VMCS_GUEST_DS_ACCESS_RIGHTS; 151221828Sgrehan break; 152221828Sgrehan case VM_REG_GUEST_FS: 153221828Sgrehan *base = VMCS_GUEST_FS_BASE; 154221828Sgrehan *lim = VMCS_GUEST_FS_LIMIT; 155221828Sgrehan *acc = VMCS_GUEST_FS_ACCESS_RIGHTS; 156221828Sgrehan break; 157221828Sgrehan case VM_REG_GUEST_GS: 158221828Sgrehan *base = VMCS_GUEST_GS_BASE; 159221828Sgrehan *lim = VMCS_GUEST_GS_LIMIT; 160221828Sgrehan *acc = VMCS_GUEST_GS_ACCESS_RIGHTS; 161221828Sgrehan break; 162221828Sgrehan case VM_REG_GUEST_TR: 163221828Sgrehan *base = VMCS_GUEST_TR_BASE; 164221828Sgrehan *lim = VMCS_GUEST_TR_LIMIT; 165221828Sgrehan *acc = VMCS_GUEST_TR_ACCESS_RIGHTS; 166221828Sgrehan break; 167221828Sgrehan case VM_REG_GUEST_LDTR: 168221828Sgrehan *base = VMCS_GUEST_LDTR_BASE; 169221828Sgrehan *lim = VMCS_GUEST_LDTR_LIMIT; 170221828Sgrehan *acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS; 171221828Sgrehan break; 172221828Sgrehan case VM_REG_GUEST_IDTR: 173221828Sgrehan *base = VMCS_GUEST_IDTR_BASE; 174221828Sgrehan *lim = VMCS_GUEST_IDTR_LIMIT; 175221828Sgrehan *acc = VMCS_INVALID_ENCODING; 176221828Sgrehan break; 177221828Sgrehan case VM_REG_GUEST_GDTR: 178221828Sgrehan *base = VMCS_GUEST_GDTR_BASE; 179221828Sgrehan *lim = VMCS_GUEST_GDTR_LIMIT; 180221828Sgrehan *acc = VMCS_INVALID_ENCODING; 181221828Sgrehan break; 182221828Sgrehan default: 183221828Sgrehan return (EINVAL); 184221828Sgrehan } 185221828Sgrehan 186221828Sgrehan return (0); 187221828Sgrehan} 188221828Sgrehan 189221828Sgrehanint 190249879Sgrehanvmcs_getreg(struct vmcs *vmcs, int running, int ident, uint64_t *retval) 191221828Sgrehan{ 192221828Sgrehan int error; 193221828Sgrehan uint32_t encoding; 194221828Sgrehan 195221828Sgrehan /* 196221828Sgrehan * If we need to get at vmx-specific state in the VMCS we can bypass 197221828Sgrehan * the translation of 'ident' to 'encoding' by simply setting the 198221828Sgrehan * sign bit. As it so happens the upper 16 bits are reserved (i.e 199221828Sgrehan * set to 0) in the encodings for the VMCS so we are free to use the 200221828Sgrehan * sign bit. 201221828Sgrehan */ 202221828Sgrehan if (ident < 0) 203221828Sgrehan encoding = ident & 0x7fffffff; 204221828Sgrehan else 205221828Sgrehan encoding = vmcs_field_encoding(ident); 206221828Sgrehan 207221828Sgrehan if (encoding == (uint32_t)-1) 208221828Sgrehan return (EINVAL); 209221828Sgrehan 210249879Sgrehan if (!running) 211249879Sgrehan VMPTRLD(vmcs); 212249879Sgrehan 213221828Sgrehan error = vmread(encoding, retval); 214249879Sgrehan 215249879Sgrehan if (!running) 216249879Sgrehan VMCLEAR(vmcs); 217249879Sgrehan 218221828Sgrehan return (error); 219221828Sgrehan} 220221828Sgrehan 221221828Sgrehanint 222249879Sgrehanvmcs_setreg(struct vmcs *vmcs, int running, int ident, uint64_t val) 223221828Sgrehan{ 224221828Sgrehan int error; 225221828Sgrehan uint32_t encoding; 226221828Sgrehan 227221828Sgrehan if (ident < 0) 228221828Sgrehan encoding = ident & 0x7fffffff; 229221828Sgrehan else 230221828Sgrehan encoding = vmcs_field_encoding(ident); 231221828Sgrehan 232221828Sgrehan if (encoding == (uint32_t)-1) 233221828Sgrehan return (EINVAL); 234221828Sgrehan 235221828Sgrehan val = vmcs_fix_regval(encoding, val); 236221828Sgrehan 237249879Sgrehan if (!running) 238249879Sgrehan VMPTRLD(vmcs); 239249879Sgrehan 240221828Sgrehan error = vmwrite(encoding, val); 241249879Sgrehan 242249879Sgrehan if (!running) 243249879Sgrehan VMCLEAR(vmcs); 244249879Sgrehan 245221828Sgrehan return (error); 246221828Sgrehan} 247221828Sgrehan 248221828Sgrehanint 249266550Sneelvmcs_setdesc(struct vmcs *vmcs, int running, int seg, struct seg_desc *desc) 250221828Sgrehan{ 251221828Sgrehan int error; 252221828Sgrehan uint32_t base, limit, access; 253221828Sgrehan 254221828Sgrehan error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 255221828Sgrehan if (error != 0) 256221828Sgrehan panic("vmcs_setdesc: invalid segment register %d", seg); 257221828Sgrehan 258266550Sneel if (!running) 259266550Sneel VMPTRLD(vmcs); 260221828Sgrehan if ((error = vmwrite(base, desc->base)) != 0) 261221828Sgrehan goto done; 262221828Sgrehan 263221828Sgrehan if ((error = vmwrite(limit, desc->limit)) != 0) 264221828Sgrehan goto done; 265221828Sgrehan 266221828Sgrehan if (access != VMCS_INVALID_ENCODING) { 267221828Sgrehan if ((error = vmwrite(access, desc->access)) != 0) 268221828Sgrehan goto done; 269221828Sgrehan } 270221828Sgrehandone: 271266550Sneel if (!running) 272266550Sneel VMCLEAR(vmcs); 273221828Sgrehan return (error); 274221828Sgrehan} 275221828Sgrehan 276221828Sgrehanint 277266550Sneelvmcs_getdesc(struct vmcs *vmcs, int running, int seg, struct seg_desc *desc) 278221828Sgrehan{ 279221828Sgrehan int error; 280221828Sgrehan uint32_t base, limit, access; 281221828Sgrehan uint64_t u64; 282221828Sgrehan 283221828Sgrehan error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 284221828Sgrehan if (error != 0) 285221828Sgrehan panic("vmcs_getdesc: invalid segment register %d", seg); 286221828Sgrehan 287266550Sneel if (!running) 288266550Sneel VMPTRLD(vmcs); 289221828Sgrehan if ((error = vmread(base, &u64)) != 0) 290221828Sgrehan goto done; 291221828Sgrehan desc->base = u64; 292221828Sgrehan 293221828Sgrehan if ((error = vmread(limit, &u64)) != 0) 294221828Sgrehan goto done; 295221828Sgrehan desc->limit = u64; 296221828Sgrehan 297221828Sgrehan if (access != VMCS_INVALID_ENCODING) { 298221828Sgrehan if ((error = vmread(access, &u64)) != 0) 299221828Sgrehan goto done; 300221828Sgrehan desc->access = u64; 301221828Sgrehan } 302221828Sgrehandone: 303266550Sneel if (!running) 304266550Sneel VMCLEAR(vmcs); 305221828Sgrehan return (error); 306221828Sgrehan} 307221828Sgrehan 308221828Sgrehanint 309221828Sgrehanvmcs_set_msr_save(struct vmcs *vmcs, u_long g_area, u_int g_count) 310221828Sgrehan{ 311221828Sgrehan int error; 312221828Sgrehan 313221828Sgrehan VMPTRLD(vmcs); 314221828Sgrehan 315221828Sgrehan /* 316221828Sgrehan * Guest MSRs are saved in the VM-exit MSR-store area. 317221828Sgrehan * Guest MSRs are loaded from the VM-entry MSR-load area. 318221828Sgrehan * Both areas point to the same location in memory. 319221828Sgrehan */ 320221828Sgrehan if ((error = vmwrite(VMCS_EXIT_MSR_STORE, g_area)) != 0) 321221828Sgrehan goto done; 322221828Sgrehan if ((error = vmwrite(VMCS_EXIT_MSR_STORE_COUNT, g_count)) != 0) 323221828Sgrehan goto done; 324221828Sgrehan 325221828Sgrehan if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD, g_area)) != 0) 326221828Sgrehan goto done; 327221828Sgrehan if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD_COUNT, g_count)) != 0) 328221828Sgrehan goto done; 329221828Sgrehan 330221828Sgrehan error = 0; 331221828Sgrehandone: 332221828Sgrehan VMCLEAR(vmcs); 333221828Sgrehan return (error); 334221828Sgrehan} 335221828Sgrehan 336221828Sgrehanint 337260380Sneelvmcs_init(struct vmcs *vmcs) 338221828Sgrehan{ 339221828Sgrehan int error, codesel, datasel, tsssel; 340221828Sgrehan u_long cr0, cr4, efer; 341256072Sneel uint64_t pat, fsbase, idtrbase; 342221828Sgrehan 343242275Sneel codesel = vmm_get_host_codesel(); 344242275Sneel datasel = vmm_get_host_datasel(); 345242275Sneel tsssel = vmm_get_host_tsssel(); 346221828Sgrehan 347221828Sgrehan /* 348221828Sgrehan * Make sure we have a "current" VMCS to work with. 349221828Sgrehan */ 350221828Sgrehan VMPTRLD(vmcs); 351221828Sgrehan 352221828Sgrehan /* Host state */ 353221828Sgrehan 354221828Sgrehan /* Initialize host IA32_PAT MSR */ 355242275Sneel pat = vmm_get_host_pat(); 356221828Sgrehan if ((error = vmwrite(VMCS_HOST_IA32_PAT, pat)) != 0) 357221828Sgrehan goto done; 358221828Sgrehan 359221828Sgrehan /* Load the IA32_EFER MSR */ 360242275Sneel efer = vmm_get_host_efer(); 361221828Sgrehan if ((error = vmwrite(VMCS_HOST_IA32_EFER, efer)) != 0) 362221828Sgrehan goto done; 363221828Sgrehan 364221828Sgrehan /* Load the control registers */ 365242122Sneel 366242275Sneel cr0 = vmm_get_host_cr0(); 367221828Sgrehan if ((error = vmwrite(VMCS_HOST_CR0, cr0)) != 0) 368221828Sgrehan goto done; 369221828Sgrehan 370242275Sneel cr4 = vmm_get_host_cr4() | CR4_VMXE; 371221828Sgrehan if ((error = vmwrite(VMCS_HOST_CR4, cr4)) != 0) 372221828Sgrehan goto done; 373221828Sgrehan 374221828Sgrehan /* Load the segment selectors */ 375221828Sgrehan if ((error = vmwrite(VMCS_HOST_ES_SELECTOR, datasel)) != 0) 376221828Sgrehan goto done; 377221828Sgrehan 378221828Sgrehan if ((error = vmwrite(VMCS_HOST_CS_SELECTOR, codesel)) != 0) 379221828Sgrehan goto done; 380221828Sgrehan 381221828Sgrehan if ((error = vmwrite(VMCS_HOST_SS_SELECTOR, datasel)) != 0) 382221828Sgrehan goto done; 383221828Sgrehan 384221828Sgrehan if ((error = vmwrite(VMCS_HOST_DS_SELECTOR, datasel)) != 0) 385221828Sgrehan goto done; 386221828Sgrehan 387221828Sgrehan if ((error = vmwrite(VMCS_HOST_FS_SELECTOR, datasel)) != 0) 388221828Sgrehan goto done; 389221828Sgrehan 390221828Sgrehan if ((error = vmwrite(VMCS_HOST_GS_SELECTOR, datasel)) != 0) 391221828Sgrehan goto done; 392221828Sgrehan 393221828Sgrehan if ((error = vmwrite(VMCS_HOST_TR_SELECTOR, tsssel)) != 0) 394221828Sgrehan goto done; 395221828Sgrehan 396221828Sgrehan /* 397221828Sgrehan * Load the Base-Address for %fs and idtr. 398221828Sgrehan * 399221828Sgrehan * Note that we exclude %gs, tss and gdtr here because their base 400221828Sgrehan * address is pcpu specific. 401221828Sgrehan */ 402242275Sneel fsbase = vmm_get_host_fsbase(); 403242275Sneel if ((error = vmwrite(VMCS_HOST_FS_BASE, fsbase)) != 0) 404221828Sgrehan goto done; 405221828Sgrehan 406242275Sneel idtrbase = vmm_get_host_idtrbase(); 407242275Sneel if ((error = vmwrite(VMCS_HOST_IDTR_BASE, idtrbase)) != 0) 408221828Sgrehan goto done; 409221828Sgrehan 410221828Sgrehan /* instruction pointer */ 411330704Stychon if (no_flush_rsb) { 412330704Stychon if ((error = vmwrite(VMCS_HOST_RIP, 413330704Stychon (u_long)vmx_exit_guest)) != 0) 414330704Stychon goto done; 415330704Stychon } else { 416330704Stychon if ((error = vmwrite(VMCS_HOST_RIP, 417330704Stychon (u_long)vmx_exit_guest_flush_rsb)) != 0) 418330704Stychon goto done; 419330704Stychon } 420221828Sgrehan 421221828Sgrehan /* link pointer */ 422221828Sgrehan if ((error = vmwrite(VMCS_LINK_POINTER, ~0)) != 0) 423221828Sgrehan goto done; 424221828Sgrehandone: 425221828Sgrehan VMCLEAR(vmcs); 426221828Sgrehan return (error); 427221828Sgrehan} 428221828Sgrehan 429222605Sjhb#ifdef DDB 430222605Sjhbextern int vmxon_enabled[]; 431222605Sjhb 432222605SjhbDB_SHOW_COMMAND(vmcs, db_show_vmcs) 433222605Sjhb{ 434222605Sjhb uint64_t cur_vmcs, val; 435222605Sjhb uint32_t exit; 436222605Sjhb 437222605Sjhb if (!vmxon_enabled[curcpu]) { 438222605Sjhb db_printf("VMX not enabled\n"); 439222605Sjhb return; 440222605Sjhb } 441222605Sjhb 442222605Sjhb if (have_addr) { 443222605Sjhb db_printf("Only current VMCS supported\n"); 444222605Sjhb return; 445222605Sjhb } 446222605Sjhb 447222605Sjhb vmptrst(&cur_vmcs); 448222605Sjhb if (cur_vmcs == VMCS_INITIAL) { 449222605Sjhb db_printf("No current VM context\n"); 450222605Sjhb return; 451222605Sjhb } 452222605Sjhb db_printf("VMCS: %jx\n", cur_vmcs); 453222605Sjhb db_printf("VPID: %lu\n", vmcs_read(VMCS_VPID)); 454222605Sjhb db_printf("Activity: "); 455222605Sjhb val = vmcs_read(VMCS_GUEST_ACTIVITY); 456222605Sjhb switch (val) { 457222605Sjhb case 0: 458222605Sjhb db_printf("Active"); 459222605Sjhb break; 460222605Sjhb case 1: 461222605Sjhb db_printf("HLT"); 462222605Sjhb break; 463222605Sjhb case 2: 464222605Sjhb db_printf("Shutdown"); 465222605Sjhb break; 466222605Sjhb case 3: 467222605Sjhb db_printf("Wait for SIPI"); 468222605Sjhb break; 469222605Sjhb default: 470222605Sjhb db_printf("Unknown: %#lx", val); 471222605Sjhb } 472222605Sjhb db_printf("\n"); 473222605Sjhb exit = vmcs_read(VMCS_EXIT_REASON); 474222605Sjhb if (exit & 0x80000000) 475222605Sjhb db_printf("Entry Failure Reason: %u\n", exit & 0xffff); 476222605Sjhb else 477222605Sjhb db_printf("Exit Reason: %u\n", exit & 0xffff); 478222605Sjhb db_printf("Qualification: %#lx\n", vmcs_exit_qualification()); 479222605Sjhb db_printf("Guest Linear Address: %#lx\n", 480222605Sjhb vmcs_read(VMCS_GUEST_LINEAR_ADDRESS)); 481222605Sjhb switch (exit & 0x8000ffff) { 482222605Sjhb case EXIT_REASON_EXCEPTION: 483222605Sjhb case EXIT_REASON_EXT_INTR: 484260531Sneel val = vmcs_read(VMCS_EXIT_INTR_INFO); 485222605Sjhb db_printf("Interrupt Type: "); 486222605Sjhb switch (val >> 8 & 0x7) { 487222605Sjhb case 0: 488222605Sjhb db_printf("external"); 489222605Sjhb break; 490222605Sjhb case 2: 491222605Sjhb db_printf("NMI"); 492222605Sjhb break; 493222605Sjhb case 3: 494222605Sjhb db_printf("HW exception"); 495222605Sjhb break; 496222605Sjhb case 4: 497222605Sjhb db_printf("SW exception"); 498222605Sjhb break; 499222605Sjhb default: 500222605Sjhb db_printf("?? %lu", val >> 8 & 0x7); 501222605Sjhb break; 502222605Sjhb } 503222605Sjhb db_printf(" Vector: %lu", val & 0xff); 504222605Sjhb if (val & 0x800) 505222605Sjhb db_printf(" Error Code: %lx", 506260531Sneel vmcs_read(VMCS_EXIT_INTR_ERRCODE)); 507222605Sjhb db_printf("\n"); 508222605Sjhb break; 509222605Sjhb case EXIT_REASON_EPT_FAULT: 510222605Sjhb case EXIT_REASON_EPT_MISCONFIG: 511222605Sjhb db_printf("Guest Physical Address: %#lx\n", 512222605Sjhb vmcs_read(VMCS_GUEST_PHYSICAL_ADDRESS)); 513222605Sjhb break; 514222605Sjhb } 515222605Sjhb db_printf("VM-instruction error: %#lx\n", vmcs_instruction_error()); 516222605Sjhb} 517222605Sjhb#endif 518