1*72f9c9d8SMark Johnston /*- 2*72f9c9d8SMark Johnston * SPDX-License-Identifier: BSD-2-Clause 3*72f9c9d8SMark Johnston * 4*72f9c9d8SMark Johnston * Copyright (c) 2011 NetApp, Inc. 5*72f9c9d8SMark Johnston * All rights reserved. 6*72f9c9d8SMark Johnston * 7*72f9c9d8SMark Johnston * Redistribution and use in source and binary forms, with or without 8*72f9c9d8SMark Johnston * modification, are permitted provided that the following conditions 9*72f9c9d8SMark Johnston * are met: 10*72f9c9d8SMark Johnston * 1. Redistributions of source code must retain the above copyright 11*72f9c9d8SMark Johnston * notice, this list of conditions and the following disclaimer. 12*72f9c9d8SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 13*72f9c9d8SMark Johnston * notice, this list of conditions and the following disclaimer in the 14*72f9c9d8SMark Johnston * documentation and/or other materials provided with the distribution. 15*72f9c9d8SMark Johnston * 16*72f9c9d8SMark Johnston * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17*72f9c9d8SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*72f9c9d8SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*72f9c9d8SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20*72f9c9d8SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*72f9c9d8SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*72f9c9d8SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*72f9c9d8SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*72f9c9d8SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*72f9c9d8SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*72f9c9d8SMark Johnston * SUCH DAMAGE. 27*72f9c9d8SMark Johnston */ 28*72f9c9d8SMark Johnston 29*72f9c9d8SMark Johnston #include <sys/types.h> 30*72f9c9d8SMark Johnston 31*72f9c9d8SMark Johnston #include <machine/vmm.h> 32*72f9c9d8SMark Johnston #include <machine/vmm_dev.h> 33*72f9c9d8SMark Johnston #include <machine/vmm_instruction_emul.h> 34*72f9c9d8SMark Johnston #include <amd64/vmm/intel/vmcs.h> 35*72f9c9d8SMark Johnston #include <x86/apicreg.h> 36*72f9c9d8SMark Johnston 37*72f9c9d8SMark Johnston #include <assert.h> 38*72f9c9d8SMark Johnston #include <err.h> 39*72f9c9d8SMark Johnston #include <errno.h> 40*72f9c9d8SMark Johnston #include <stdlib.h> 41*72f9c9d8SMark Johnston #include <strings.h> 42*72f9c9d8SMark Johnston #include <unistd.h> 43*72f9c9d8SMark Johnston 44*72f9c9d8SMark Johnston #include <vmmapi.h> 45*72f9c9d8SMark Johnston 46*72f9c9d8SMark Johnston #include "bhyverun.h" 47*72f9c9d8SMark Johnston #include "config.h" 48*72f9c9d8SMark Johnston #include "debug.h" 49*72f9c9d8SMark Johnston #include "gdb.h" 50*72f9c9d8SMark Johnston #include "inout.h" 51*72f9c9d8SMark Johnston #include "mem.h" 52*72f9c9d8SMark Johnston #ifdef BHYVE_SNAPSHOT 53*72f9c9d8SMark Johnston #include "snapshot.h" 54*72f9c9d8SMark Johnston #endif 55*72f9c9d8SMark Johnston #include "spinup_ap.h" 56*72f9c9d8SMark Johnston #include "vmexit.h" 57*72f9c9d8SMark Johnston #include "xmsr.h" 58*72f9c9d8SMark Johnston 59*72f9c9d8SMark Johnston static int 60*72f9c9d8SMark Johnston vmexit_inout(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun) 61*72f9c9d8SMark Johnston { 62*72f9c9d8SMark Johnston struct vm_exit *vme; 63*72f9c9d8SMark Johnston int error; 64*72f9c9d8SMark Johnston int bytes, port, in; 65*72f9c9d8SMark Johnston 66*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 67*72f9c9d8SMark Johnston port = vme->u.inout.port; 68*72f9c9d8SMark Johnston bytes = vme->u.inout.bytes; 69*72f9c9d8SMark Johnston in = vme->u.inout.in; 70*72f9c9d8SMark Johnston 71*72f9c9d8SMark Johnston error = emulate_inout(ctx, vcpu, vme); 72*72f9c9d8SMark Johnston if (error) { 73*72f9c9d8SMark Johnston fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n", 74*72f9c9d8SMark Johnston in ? "in" : "out", 75*72f9c9d8SMark Johnston bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), 76*72f9c9d8SMark Johnston port, vme->rip); 77*72f9c9d8SMark Johnston return (VMEXIT_ABORT); 78*72f9c9d8SMark Johnston } else { 79*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 80*72f9c9d8SMark Johnston } 81*72f9c9d8SMark Johnston } 82*72f9c9d8SMark Johnston 83*72f9c9d8SMark Johnston static int 84*72f9c9d8SMark Johnston vmexit_rdmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, 85*72f9c9d8SMark Johnston struct vm_run *vmrun) 86*72f9c9d8SMark Johnston { 87*72f9c9d8SMark Johnston struct vm_exit *vme; 88*72f9c9d8SMark Johnston uint64_t val; 89*72f9c9d8SMark Johnston uint32_t eax, edx; 90*72f9c9d8SMark Johnston int error; 91*72f9c9d8SMark Johnston 92*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 93*72f9c9d8SMark Johnston 94*72f9c9d8SMark Johnston val = 0; 95*72f9c9d8SMark Johnston error = emulate_rdmsr(vcpu, vme->u.msr.code, &val); 96*72f9c9d8SMark Johnston if (error != 0) { 97*72f9c9d8SMark Johnston fprintf(stderr, "rdmsr to register %#x on vcpu %d\n", 98*72f9c9d8SMark Johnston vme->u.msr.code, vcpu_id(vcpu)); 99*72f9c9d8SMark Johnston if (get_config_bool("x86.strictmsr")) { 100*72f9c9d8SMark Johnston vm_inject_gp(vcpu); 101*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 102*72f9c9d8SMark Johnston } 103*72f9c9d8SMark Johnston } 104*72f9c9d8SMark Johnston 105*72f9c9d8SMark Johnston eax = val; 106*72f9c9d8SMark Johnston error = vm_set_register(vcpu, VM_REG_GUEST_RAX, eax); 107*72f9c9d8SMark Johnston assert(error == 0); 108*72f9c9d8SMark Johnston 109*72f9c9d8SMark Johnston edx = val >> 32; 110*72f9c9d8SMark Johnston error = vm_set_register(vcpu, VM_REG_GUEST_RDX, edx); 111*72f9c9d8SMark Johnston assert(error == 0); 112*72f9c9d8SMark Johnston 113*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 114*72f9c9d8SMark Johnston } 115*72f9c9d8SMark Johnston 116*72f9c9d8SMark Johnston static int 117*72f9c9d8SMark Johnston vmexit_wrmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, 118*72f9c9d8SMark Johnston struct vm_run *vmrun) 119*72f9c9d8SMark Johnston { 120*72f9c9d8SMark Johnston struct vm_exit *vme; 121*72f9c9d8SMark Johnston int error; 122*72f9c9d8SMark Johnston 123*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 124*72f9c9d8SMark Johnston 125*72f9c9d8SMark Johnston error = emulate_wrmsr(vcpu, vme->u.msr.code, vme->u.msr.wval); 126*72f9c9d8SMark Johnston if (error != 0) { 127*72f9c9d8SMark Johnston fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n", 128*72f9c9d8SMark Johnston vme->u.msr.code, vme->u.msr.wval, vcpu_id(vcpu)); 129*72f9c9d8SMark Johnston if (get_config_bool("x86.strictmsr")) { 130*72f9c9d8SMark Johnston vm_inject_gp(vcpu); 131*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 132*72f9c9d8SMark Johnston } 133*72f9c9d8SMark Johnston } 134*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 135*72f9c9d8SMark Johnston } 136*72f9c9d8SMark Johnston 137*72f9c9d8SMark Johnston static const char * const vmx_exit_reason_desc[] = { 138*72f9c9d8SMark Johnston [EXIT_REASON_EXCEPTION] = "Exception or non-maskable interrupt (NMI)", 139*72f9c9d8SMark Johnston [EXIT_REASON_EXT_INTR] = "External interrupt", 140*72f9c9d8SMark Johnston [EXIT_REASON_TRIPLE_FAULT] = "Triple fault", 141*72f9c9d8SMark Johnston [EXIT_REASON_INIT] = "INIT signal", 142*72f9c9d8SMark Johnston [EXIT_REASON_SIPI] = "Start-up IPI (SIPI)", 143*72f9c9d8SMark Johnston [EXIT_REASON_IO_SMI] = "I/O system-management interrupt (SMI)", 144*72f9c9d8SMark Johnston [EXIT_REASON_SMI] = "Other SMI", 145*72f9c9d8SMark Johnston [EXIT_REASON_INTR_WINDOW] = "Interrupt window", 146*72f9c9d8SMark Johnston [EXIT_REASON_NMI_WINDOW] = "NMI window", 147*72f9c9d8SMark Johnston [EXIT_REASON_TASK_SWITCH] = "Task switch", 148*72f9c9d8SMark Johnston [EXIT_REASON_CPUID] = "CPUID", 149*72f9c9d8SMark Johnston [EXIT_REASON_GETSEC] = "GETSEC", 150*72f9c9d8SMark Johnston [EXIT_REASON_HLT] = "HLT", 151*72f9c9d8SMark Johnston [EXIT_REASON_INVD] = "INVD", 152*72f9c9d8SMark Johnston [EXIT_REASON_INVLPG] = "INVLPG", 153*72f9c9d8SMark Johnston [EXIT_REASON_RDPMC] = "RDPMC", 154*72f9c9d8SMark Johnston [EXIT_REASON_RDTSC] = "RDTSC", 155*72f9c9d8SMark Johnston [EXIT_REASON_RSM] = "RSM", 156*72f9c9d8SMark Johnston [EXIT_REASON_VMCALL] = "VMCALL", 157*72f9c9d8SMark Johnston [EXIT_REASON_VMCLEAR] = "VMCLEAR", 158*72f9c9d8SMark Johnston [EXIT_REASON_VMLAUNCH] = "VMLAUNCH", 159*72f9c9d8SMark Johnston [EXIT_REASON_VMPTRLD] = "VMPTRLD", 160*72f9c9d8SMark Johnston [EXIT_REASON_VMPTRST] = "VMPTRST", 161*72f9c9d8SMark Johnston [EXIT_REASON_VMREAD] = "VMREAD", 162*72f9c9d8SMark Johnston [EXIT_REASON_VMRESUME] = "VMRESUME", 163*72f9c9d8SMark Johnston [EXIT_REASON_VMWRITE] = "VMWRITE", 164*72f9c9d8SMark Johnston [EXIT_REASON_VMXOFF] = "VMXOFF", 165*72f9c9d8SMark Johnston [EXIT_REASON_VMXON] = "VMXON", 166*72f9c9d8SMark Johnston [EXIT_REASON_CR_ACCESS] = "Control-register accesses", 167*72f9c9d8SMark Johnston [EXIT_REASON_DR_ACCESS] = "MOV DR", 168*72f9c9d8SMark Johnston [EXIT_REASON_INOUT] = "I/O instruction", 169*72f9c9d8SMark Johnston [EXIT_REASON_RDMSR] = "RDMSR", 170*72f9c9d8SMark Johnston [EXIT_REASON_WRMSR] = "WRMSR", 171*72f9c9d8SMark Johnston [EXIT_REASON_INVAL_VMCS] = 172*72f9c9d8SMark Johnston "VM-entry failure due to invalid guest state", 173*72f9c9d8SMark Johnston [EXIT_REASON_INVAL_MSR] = "VM-entry failure due to MSR loading", 174*72f9c9d8SMark Johnston [EXIT_REASON_MWAIT] = "MWAIT", 175*72f9c9d8SMark Johnston [EXIT_REASON_MTF] = "Monitor trap flag", 176*72f9c9d8SMark Johnston [EXIT_REASON_MONITOR] = "MONITOR", 177*72f9c9d8SMark Johnston [EXIT_REASON_PAUSE] = "PAUSE", 178*72f9c9d8SMark Johnston [EXIT_REASON_MCE_DURING_ENTRY] = 179*72f9c9d8SMark Johnston "VM-entry failure due to machine-check event", 180*72f9c9d8SMark Johnston [EXIT_REASON_TPR] = "TPR below threshold", 181*72f9c9d8SMark Johnston [EXIT_REASON_APIC_ACCESS] = "APIC access", 182*72f9c9d8SMark Johnston [EXIT_REASON_VIRTUALIZED_EOI] = "Virtualized EOI", 183*72f9c9d8SMark Johnston [EXIT_REASON_GDTR_IDTR] = "Access to GDTR or IDTR", 184*72f9c9d8SMark Johnston [EXIT_REASON_LDTR_TR] = "Access to LDTR or TR", 185*72f9c9d8SMark Johnston [EXIT_REASON_EPT_FAULT] = "EPT violation", 186*72f9c9d8SMark Johnston [EXIT_REASON_EPT_MISCONFIG] = "EPT misconfiguration", 187*72f9c9d8SMark Johnston [EXIT_REASON_INVEPT] = "INVEPT", 188*72f9c9d8SMark Johnston [EXIT_REASON_RDTSCP] = "RDTSCP", 189*72f9c9d8SMark Johnston [EXIT_REASON_VMX_PREEMPT] = "VMX-preemption timer expired", 190*72f9c9d8SMark Johnston [EXIT_REASON_INVVPID] = "INVVPID", 191*72f9c9d8SMark Johnston [EXIT_REASON_WBINVD] = "WBINVD", 192*72f9c9d8SMark Johnston [EXIT_REASON_XSETBV] = "XSETBV", 193*72f9c9d8SMark Johnston [EXIT_REASON_APIC_WRITE] = "APIC write", 194*72f9c9d8SMark Johnston [EXIT_REASON_RDRAND] = "RDRAND", 195*72f9c9d8SMark Johnston [EXIT_REASON_INVPCID] = "INVPCID", 196*72f9c9d8SMark Johnston [EXIT_REASON_VMFUNC] = "VMFUNC", 197*72f9c9d8SMark Johnston [EXIT_REASON_ENCLS] = "ENCLS", 198*72f9c9d8SMark Johnston [EXIT_REASON_RDSEED] = "RDSEED", 199*72f9c9d8SMark Johnston [EXIT_REASON_PM_LOG_FULL] = "Page-modification log full", 200*72f9c9d8SMark Johnston [EXIT_REASON_XSAVES] = "XSAVES", 201*72f9c9d8SMark Johnston [EXIT_REASON_XRSTORS] = "XRSTORS" 202*72f9c9d8SMark Johnston }; 203*72f9c9d8SMark Johnston 204*72f9c9d8SMark Johnston static const char * 205*72f9c9d8SMark Johnston vmexit_vmx_desc(uint32_t exit_reason) 206*72f9c9d8SMark Johnston { 207*72f9c9d8SMark Johnston 208*72f9c9d8SMark Johnston if (exit_reason >= nitems(vmx_exit_reason_desc) || 209*72f9c9d8SMark Johnston vmx_exit_reason_desc[exit_reason] == NULL) 210*72f9c9d8SMark Johnston return ("Unknown"); 211*72f9c9d8SMark Johnston return (vmx_exit_reason_desc[exit_reason]); 212*72f9c9d8SMark Johnston } 213*72f9c9d8SMark Johnston 214*72f9c9d8SMark Johnston #define DEBUG_EPT_MISCONFIG 215*72f9c9d8SMark Johnston #ifdef DEBUG_EPT_MISCONFIG 216*72f9c9d8SMark Johnston #define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 217*72f9c9d8SMark Johnston 218*72f9c9d8SMark Johnston static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4]; 219*72f9c9d8SMark Johnston static int ept_misconfig_ptenum; 220*72f9c9d8SMark Johnston #endif 221*72f9c9d8SMark Johnston 222*72f9c9d8SMark Johnston static int 223*72f9c9d8SMark Johnston vmexit_vmx(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun) 224*72f9c9d8SMark Johnston { 225*72f9c9d8SMark Johnston struct vm_exit *vme; 226*72f9c9d8SMark Johnston 227*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 228*72f9c9d8SMark Johnston 229*72f9c9d8SMark Johnston fprintf(stderr, "vm exit[%d]\n", vcpu_id(vcpu)); 230*72f9c9d8SMark Johnston fprintf(stderr, "\treason\t\tVMX\n"); 231*72f9c9d8SMark Johnston fprintf(stderr, "\trip\t\t0x%016lx\n", vme->rip); 232*72f9c9d8SMark Johnston fprintf(stderr, "\tinst_length\t%d\n", vme->inst_length); 233*72f9c9d8SMark Johnston fprintf(stderr, "\tstatus\t\t%d\n", vme->u.vmx.status); 234*72f9c9d8SMark Johnston fprintf(stderr, "\texit_reason\t%u (%s)\n", vme->u.vmx.exit_reason, 235*72f9c9d8SMark Johnston vmexit_vmx_desc(vme->u.vmx.exit_reason)); 236*72f9c9d8SMark Johnston fprintf(stderr, "\tqualification\t0x%016lx\n", 237*72f9c9d8SMark Johnston vme->u.vmx.exit_qualification); 238*72f9c9d8SMark Johnston fprintf(stderr, "\tinst_type\t\t%d\n", vme->u.vmx.inst_type); 239*72f9c9d8SMark Johnston fprintf(stderr, "\tinst_error\t\t%d\n", vme->u.vmx.inst_error); 240*72f9c9d8SMark Johnston #ifdef DEBUG_EPT_MISCONFIG 241*72f9c9d8SMark Johnston if (vme->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) { 242*72f9c9d8SMark Johnston vm_get_register(vcpu, 243*72f9c9d8SMark Johnston VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS), 244*72f9c9d8SMark Johnston &ept_misconfig_gpa); 245*72f9c9d8SMark Johnston vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte, 246*72f9c9d8SMark Johnston &ept_misconfig_ptenum); 247*72f9c9d8SMark Johnston fprintf(stderr, "\tEPT misconfiguration:\n"); 248*72f9c9d8SMark Johnston fprintf(stderr, "\t\tGPA: %#lx\n", ept_misconfig_gpa); 249*72f9c9d8SMark Johnston fprintf(stderr, "\t\tPTE(%d): %#lx %#lx %#lx %#lx\n", 250*72f9c9d8SMark Johnston ept_misconfig_ptenum, ept_misconfig_pte[0], 251*72f9c9d8SMark Johnston ept_misconfig_pte[1], ept_misconfig_pte[2], 252*72f9c9d8SMark Johnston ept_misconfig_pte[3]); 253*72f9c9d8SMark Johnston } 254*72f9c9d8SMark Johnston #endif /* DEBUG_EPT_MISCONFIG */ 255*72f9c9d8SMark Johnston return (VMEXIT_ABORT); 256*72f9c9d8SMark Johnston } 257*72f9c9d8SMark Johnston 258*72f9c9d8SMark Johnston static int 259*72f9c9d8SMark Johnston vmexit_svm(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_run *vmrun) 260*72f9c9d8SMark Johnston { 261*72f9c9d8SMark Johnston struct vm_exit *vme; 262*72f9c9d8SMark Johnston 263*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 264*72f9c9d8SMark Johnston 265*72f9c9d8SMark Johnston fprintf(stderr, "vm exit[%d]\n", vcpu_id(vcpu)); 266*72f9c9d8SMark Johnston fprintf(stderr, "\treason\t\tSVM\n"); 267*72f9c9d8SMark Johnston fprintf(stderr, "\trip\t\t0x%016lx\n", vme->rip); 268*72f9c9d8SMark Johnston fprintf(stderr, "\tinst_length\t%d\n", vme->inst_length); 269*72f9c9d8SMark Johnston fprintf(stderr, "\texitcode\t%#lx\n", vme->u.svm.exitcode); 270*72f9c9d8SMark Johnston fprintf(stderr, "\texitinfo1\t%#lx\n", vme->u.svm.exitinfo1); 271*72f9c9d8SMark Johnston fprintf(stderr, "\texitinfo2\t%#lx\n", vme->u.svm.exitinfo2); 272*72f9c9d8SMark Johnston return (VMEXIT_ABORT); 273*72f9c9d8SMark Johnston } 274*72f9c9d8SMark Johnston 275*72f9c9d8SMark Johnston static int 276*72f9c9d8SMark Johnston vmexit_bogus(struct vmctx *ctx __unused, struct vcpu *vcpu __unused, 277*72f9c9d8SMark Johnston struct vm_run *vmrun) 278*72f9c9d8SMark Johnston { 279*72f9c9d8SMark Johnston assert(vmrun->vm_exit->inst_length == 0); 280*72f9c9d8SMark Johnston 281*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 282*72f9c9d8SMark Johnston } 283*72f9c9d8SMark Johnston 284*72f9c9d8SMark Johnston static int 285*72f9c9d8SMark Johnston vmexit_reqidle(struct vmctx *ctx __unused, struct vcpu *vcpu __unused, 286*72f9c9d8SMark Johnston struct vm_run *vmrun) 287*72f9c9d8SMark Johnston { 288*72f9c9d8SMark Johnston assert(vmrun->vm_exit->inst_length == 0); 289*72f9c9d8SMark Johnston 290*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 291*72f9c9d8SMark Johnston } 292*72f9c9d8SMark Johnston 293*72f9c9d8SMark Johnston static int 294*72f9c9d8SMark Johnston vmexit_hlt(struct vmctx *ctx __unused, struct vcpu *vcpu __unused, 295*72f9c9d8SMark Johnston struct vm_run *vmrun __unused) 296*72f9c9d8SMark Johnston { 297*72f9c9d8SMark Johnston /* 298*72f9c9d8SMark Johnston * Just continue execution with the next instruction. We use 299*72f9c9d8SMark Johnston * the HLT VM exit as a way to be friendly with the host 300*72f9c9d8SMark Johnston * scheduler. 301*72f9c9d8SMark Johnston */ 302*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 303*72f9c9d8SMark Johnston } 304*72f9c9d8SMark Johnston 305*72f9c9d8SMark Johnston static int 306*72f9c9d8SMark Johnston vmexit_pause(struct vmctx *ctx __unused, struct vcpu *vcpu __unused, 307*72f9c9d8SMark Johnston struct vm_run *vmrun __unused) 308*72f9c9d8SMark Johnston { 309*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 310*72f9c9d8SMark Johnston } 311*72f9c9d8SMark Johnston 312*72f9c9d8SMark Johnston static int 313*72f9c9d8SMark Johnston vmexit_mtrap(struct vmctx *ctx __unused, struct vcpu *vcpu, 314*72f9c9d8SMark Johnston struct vm_run *vmrun) 315*72f9c9d8SMark Johnston { 316*72f9c9d8SMark Johnston assert(vmrun->vm_exit->inst_length == 0); 317*72f9c9d8SMark Johnston 318*72f9c9d8SMark Johnston #ifdef BHYVE_SNAPSHOT 319*72f9c9d8SMark Johnston checkpoint_cpu_suspend(vcpu_id(vcpu)); 320*72f9c9d8SMark Johnston #endif 321*72f9c9d8SMark Johnston gdb_cpu_mtrap(vcpu); 322*72f9c9d8SMark Johnston #ifdef BHYVE_SNAPSHOT 323*72f9c9d8SMark Johnston checkpoint_cpu_resume(vcpu_id(vcpu)); 324*72f9c9d8SMark Johnston #endif 325*72f9c9d8SMark Johnston 326*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 327*72f9c9d8SMark Johnston } 328*72f9c9d8SMark Johnston 329*72f9c9d8SMark Johnston static int 330*72f9c9d8SMark Johnston vmexit_inst_emul(struct vmctx *ctx __unused, struct vcpu *vcpu, 331*72f9c9d8SMark Johnston struct vm_run *vmrun) 332*72f9c9d8SMark Johnston { 333*72f9c9d8SMark Johnston struct vm_exit *vme; 334*72f9c9d8SMark Johnston struct vie *vie; 335*72f9c9d8SMark Johnston int err, i, cs_d; 336*72f9c9d8SMark Johnston enum vm_cpu_mode mode; 337*72f9c9d8SMark Johnston 338*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 339*72f9c9d8SMark Johnston 340*72f9c9d8SMark Johnston vie = &vme->u.inst_emul.vie; 341*72f9c9d8SMark Johnston if (!vie->decoded) { 342*72f9c9d8SMark Johnston /* 343*72f9c9d8SMark Johnston * Attempt to decode in userspace as a fallback. This allows 344*72f9c9d8SMark Johnston * updating instruction decode in bhyve without rebooting the 345*72f9c9d8SMark Johnston * kernel (rapid prototyping), albeit with much slower 346*72f9c9d8SMark Johnston * emulation. 347*72f9c9d8SMark Johnston */ 348*72f9c9d8SMark Johnston vie_restart(vie); 349*72f9c9d8SMark Johnston mode = vme->u.inst_emul.paging.cpu_mode; 350*72f9c9d8SMark Johnston cs_d = vme->u.inst_emul.cs_d; 351*72f9c9d8SMark Johnston if (vmm_decode_instruction(mode, cs_d, vie) != 0) 352*72f9c9d8SMark Johnston goto fail; 353*72f9c9d8SMark Johnston if (vm_set_register(vcpu, VM_REG_GUEST_RIP, 354*72f9c9d8SMark Johnston vme->rip + vie->num_processed) != 0) 355*72f9c9d8SMark Johnston goto fail; 356*72f9c9d8SMark Johnston } 357*72f9c9d8SMark Johnston 358*72f9c9d8SMark Johnston err = emulate_mem(vcpu, vme->u.inst_emul.gpa, vie, 359*72f9c9d8SMark Johnston &vme->u.inst_emul.paging); 360*72f9c9d8SMark Johnston if (err) { 361*72f9c9d8SMark Johnston if (err == ESRCH) { 362*72f9c9d8SMark Johnston EPRINTLN("Unhandled memory access to 0x%lx\n", 363*72f9c9d8SMark Johnston vme->u.inst_emul.gpa); 364*72f9c9d8SMark Johnston } 365*72f9c9d8SMark Johnston goto fail; 366*72f9c9d8SMark Johnston } 367*72f9c9d8SMark Johnston 368*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 369*72f9c9d8SMark Johnston 370*72f9c9d8SMark Johnston fail: 371*72f9c9d8SMark Johnston fprintf(stderr, "Failed to emulate instruction sequence [ "); 372*72f9c9d8SMark Johnston for (i = 0; i < vie->num_valid; i++) 373*72f9c9d8SMark Johnston fprintf(stderr, "%02x", vie->inst[i]); 374*72f9c9d8SMark Johnston FPRINTLN(stderr, " ] at 0x%lx", vme->rip); 375*72f9c9d8SMark Johnston return (VMEXIT_ABORT); 376*72f9c9d8SMark Johnston } 377*72f9c9d8SMark Johnston 378*72f9c9d8SMark Johnston static int 379*72f9c9d8SMark Johnston vmexit_suspend(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun) 380*72f9c9d8SMark Johnston { 381*72f9c9d8SMark Johnston struct vm_exit *vme; 382*72f9c9d8SMark Johnston enum vm_suspend_how how; 383*72f9c9d8SMark Johnston int vcpuid = vcpu_id(vcpu); 384*72f9c9d8SMark Johnston 385*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 386*72f9c9d8SMark Johnston 387*72f9c9d8SMark Johnston how = vme->u.suspended.how; 388*72f9c9d8SMark Johnston 389*72f9c9d8SMark Johnston fbsdrun_deletecpu(vcpuid); 390*72f9c9d8SMark Johnston 391*72f9c9d8SMark Johnston switch (how) { 392*72f9c9d8SMark Johnston case VM_SUSPEND_RESET: 393*72f9c9d8SMark Johnston exit(0); 394*72f9c9d8SMark Johnston case VM_SUSPEND_POWEROFF: 395*72f9c9d8SMark Johnston if (get_config_bool_default("destroy_on_poweroff", false)) 396*72f9c9d8SMark Johnston vm_destroy(ctx); 397*72f9c9d8SMark Johnston exit(1); 398*72f9c9d8SMark Johnston case VM_SUSPEND_HALT: 399*72f9c9d8SMark Johnston exit(2); 400*72f9c9d8SMark Johnston case VM_SUSPEND_TRIPLEFAULT: 401*72f9c9d8SMark Johnston exit(3); 402*72f9c9d8SMark Johnston default: 403*72f9c9d8SMark Johnston fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how); 404*72f9c9d8SMark Johnston exit(100); 405*72f9c9d8SMark Johnston } 406*72f9c9d8SMark Johnston return (0); /* NOTREACHED */ 407*72f9c9d8SMark Johnston } 408*72f9c9d8SMark Johnston 409*72f9c9d8SMark Johnston static int 410*72f9c9d8SMark Johnston vmexit_debug(struct vmctx *ctx __unused, struct vcpu *vcpu, 411*72f9c9d8SMark Johnston struct vm_run *vmrun __unused) 412*72f9c9d8SMark Johnston { 413*72f9c9d8SMark Johnston 414*72f9c9d8SMark Johnston #ifdef BHYVE_SNAPSHOT 415*72f9c9d8SMark Johnston checkpoint_cpu_suspend(vcpu_id(vcpu)); 416*72f9c9d8SMark Johnston #endif 417*72f9c9d8SMark Johnston gdb_cpu_suspend(vcpu); 418*72f9c9d8SMark Johnston #ifdef BHYVE_SNAPSHOT 419*72f9c9d8SMark Johnston checkpoint_cpu_resume(vcpu_id(vcpu)); 420*72f9c9d8SMark Johnston #endif 421*72f9c9d8SMark Johnston /* 422*72f9c9d8SMark Johnston * XXX-MJ sleep for a short period to avoid chewing up the CPU in the 423*72f9c9d8SMark Johnston * window between activation of the vCPU thread and the STARTUP IPI. 424*72f9c9d8SMark Johnston */ 425*72f9c9d8SMark Johnston usleep(1000); 426*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 427*72f9c9d8SMark Johnston } 428*72f9c9d8SMark Johnston 429*72f9c9d8SMark Johnston static int 430*72f9c9d8SMark Johnston vmexit_breakpoint(struct vmctx *ctx __unused, struct vcpu *vcpu, 431*72f9c9d8SMark Johnston struct vm_run *vmrun) 432*72f9c9d8SMark Johnston { 433*72f9c9d8SMark Johnston gdb_cpu_breakpoint(vcpu, vmrun->vm_exit); 434*72f9c9d8SMark Johnston return (VMEXIT_CONTINUE); 435*72f9c9d8SMark Johnston } 436*72f9c9d8SMark Johnston 437*72f9c9d8SMark Johnston static int 438*72f9c9d8SMark Johnston vmexit_ipi(struct vmctx *ctx __unused, struct vcpu *vcpu __unused, 439*72f9c9d8SMark Johnston struct vm_run *vmrun) 440*72f9c9d8SMark Johnston { 441*72f9c9d8SMark Johnston struct vm_exit *vme; 442*72f9c9d8SMark Johnston cpuset_t *dmask; 443*72f9c9d8SMark Johnston int error = -1; 444*72f9c9d8SMark Johnston int i; 445*72f9c9d8SMark Johnston 446*72f9c9d8SMark Johnston dmask = vmrun->cpuset; 447*72f9c9d8SMark Johnston vme = vmrun->vm_exit; 448*72f9c9d8SMark Johnston 449*72f9c9d8SMark Johnston switch (vme->u.ipi.mode) { 450*72f9c9d8SMark Johnston case APIC_DELMODE_INIT: 451*72f9c9d8SMark Johnston CPU_FOREACH_ISSET(i, dmask) { 452*72f9c9d8SMark Johnston error = fbsdrun_suspendcpu(i); 453*72f9c9d8SMark Johnston if (error) { 454*72f9c9d8SMark Johnston warnx("failed to suspend cpu %d", i); 455*72f9c9d8SMark Johnston break; 456*72f9c9d8SMark Johnston } 457*72f9c9d8SMark Johnston } 458*72f9c9d8SMark Johnston break; 459*72f9c9d8SMark Johnston case APIC_DELMODE_STARTUP: 460*72f9c9d8SMark Johnston CPU_FOREACH_ISSET(i, dmask) { 461*72f9c9d8SMark Johnston spinup_ap(fbsdrun_vcpu(i), 462*72f9c9d8SMark Johnston vme->u.ipi.vector << PAGE_SHIFT); 463*72f9c9d8SMark Johnston } 464*72f9c9d8SMark Johnston error = 0; 465*72f9c9d8SMark Johnston break; 466*72f9c9d8SMark Johnston default: 467*72f9c9d8SMark Johnston break; 468*72f9c9d8SMark Johnston } 469*72f9c9d8SMark Johnston 470*72f9c9d8SMark Johnston return (error); 471*72f9c9d8SMark Johnston } 472*72f9c9d8SMark Johnston 473*72f9c9d8SMark Johnston int vmexit_task_switch(struct vmctx *, struct vcpu *, struct vm_run *); 474*72f9c9d8SMark Johnston 475*72f9c9d8SMark Johnston const vmexit_handler_t vmexit_handlers[VM_EXITCODE_MAX] = { 476*72f9c9d8SMark Johnston [VM_EXITCODE_INOUT] = vmexit_inout, 477*72f9c9d8SMark Johnston [VM_EXITCODE_INOUT_STR] = vmexit_inout, 478*72f9c9d8SMark Johnston [VM_EXITCODE_VMX] = vmexit_vmx, 479*72f9c9d8SMark Johnston [VM_EXITCODE_SVM] = vmexit_svm, 480*72f9c9d8SMark Johnston [VM_EXITCODE_BOGUS] = vmexit_bogus, 481*72f9c9d8SMark Johnston [VM_EXITCODE_REQIDLE] = vmexit_reqidle, 482*72f9c9d8SMark Johnston [VM_EXITCODE_RDMSR] = vmexit_rdmsr, 483*72f9c9d8SMark Johnston [VM_EXITCODE_WRMSR] = vmexit_wrmsr, 484*72f9c9d8SMark Johnston [VM_EXITCODE_MTRAP] = vmexit_mtrap, 485*72f9c9d8SMark Johnston [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul, 486*72f9c9d8SMark Johnston [VM_EXITCODE_SUSPENDED] = vmexit_suspend, 487*72f9c9d8SMark Johnston [VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch, 488*72f9c9d8SMark Johnston [VM_EXITCODE_DEBUG] = vmexit_debug, 489*72f9c9d8SMark Johnston [VM_EXITCODE_BPT] = vmexit_breakpoint, 490*72f9c9d8SMark Johnston [VM_EXITCODE_IPI] = vmexit_ipi, 491*72f9c9d8SMark Johnston [VM_EXITCODE_HLT] = vmexit_hlt, 492*72f9c9d8SMark Johnston [VM_EXITCODE_PAUSE] = vmexit_pause, 493*72f9c9d8SMark Johnston }; 494