xref: /illumos-gate/usr/src/cmd/bhyve/amd64/vmexit.c (revision 5c4a5fe16715fb423db76577a6883b5bbecdbe45)
1*5c4a5fe1SAndy Fiddaman /*-
2*5c4a5fe1SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
3*5c4a5fe1SAndy Fiddaman  *
4*5c4a5fe1SAndy Fiddaman  * Copyright (c) 2011 NetApp, Inc.
5*5c4a5fe1SAndy Fiddaman  * All rights reserved.
6*5c4a5fe1SAndy Fiddaman  *
7*5c4a5fe1SAndy Fiddaman  * Redistribution and use in source and binary forms, with or without
8*5c4a5fe1SAndy Fiddaman  * modification, are permitted provided that the following conditions
9*5c4a5fe1SAndy Fiddaman  * are met:
10*5c4a5fe1SAndy Fiddaman  * 1. Redistributions of source code must retain the above copyright
11*5c4a5fe1SAndy Fiddaman  *    notice, this list of conditions and the following disclaimer.
12*5c4a5fe1SAndy Fiddaman  * 2. Redistributions in binary form must reproduce the above copyright
13*5c4a5fe1SAndy Fiddaman  *    notice, this list of conditions and the following disclaimer in the
14*5c4a5fe1SAndy Fiddaman  *    documentation and/or other materials provided with the distribution.
15*5c4a5fe1SAndy Fiddaman  *
16*5c4a5fe1SAndy Fiddaman  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17*5c4a5fe1SAndy Fiddaman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*5c4a5fe1SAndy Fiddaman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*5c4a5fe1SAndy Fiddaman  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20*5c4a5fe1SAndy Fiddaman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*5c4a5fe1SAndy Fiddaman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*5c4a5fe1SAndy Fiddaman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*5c4a5fe1SAndy Fiddaman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*5c4a5fe1SAndy Fiddaman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*5c4a5fe1SAndy Fiddaman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*5c4a5fe1SAndy Fiddaman  * SUCH DAMAGE.
27*5c4a5fe1SAndy Fiddaman  */
28*5c4a5fe1SAndy Fiddaman /*
29*5c4a5fe1SAndy Fiddaman  * This file and its contents are supplied under the terms of the
30*5c4a5fe1SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
31*5c4a5fe1SAndy Fiddaman  * You may only use this file in accordance with the terms of version
32*5c4a5fe1SAndy Fiddaman  * 1.0 of the CDDL.
33*5c4a5fe1SAndy Fiddaman  *
34*5c4a5fe1SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
35*5c4a5fe1SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
36*5c4a5fe1SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
37*5c4a5fe1SAndy Fiddaman  *
38*5c4a5fe1SAndy Fiddaman  * Copyright 2015 Pluribus Networks Inc.
39*5c4a5fe1SAndy Fiddaman  * Copyright 2018 Joyent, Inc.
40*5c4a5fe1SAndy Fiddaman  * Copyright 2022 Oxide Computer Company
41*5c4a5fe1SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
42*5c4a5fe1SAndy Fiddaman  */
43*5c4a5fe1SAndy Fiddaman 
44*5c4a5fe1SAndy Fiddaman #include <sys/types.h>
45*5c4a5fe1SAndy Fiddaman 
46*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
47*5c4a5fe1SAndy Fiddaman #include <sys/cpuset.h>
48*5c4a5fe1SAndy Fiddaman #include <intel/vmcs.h>
49*5c4a5fe1SAndy Fiddaman #endif
50*5c4a5fe1SAndy Fiddaman 
51*5c4a5fe1SAndy Fiddaman #include <machine/atomic.h>
52*5c4a5fe1SAndy Fiddaman 
53*5c4a5fe1SAndy Fiddaman #ifndef WITHOUT_CAPSICUM
54*5c4a5fe1SAndy Fiddaman #include <capsicum_helpers.h>
55*5c4a5fe1SAndy Fiddaman #endif
56*5c4a5fe1SAndy Fiddaman #include <stdio.h>
57*5c4a5fe1SAndy Fiddaman #include <stdlib.h>
58*5c4a5fe1SAndy Fiddaman #include <string.h>
59*5c4a5fe1SAndy Fiddaman #include <err.h>
60*5c4a5fe1SAndy Fiddaman #include <errno.h>
61*5c4a5fe1SAndy Fiddaman #include <libgen.h>
62*5c4a5fe1SAndy Fiddaman #include <unistd.h>
63*5c4a5fe1SAndy Fiddaman #include <assert.h>
64*5c4a5fe1SAndy Fiddaman #include <pthread.h>
65*5c4a5fe1SAndy Fiddaman #include <pthread_np.h>
66*5c4a5fe1SAndy Fiddaman #include <sysexits.h>
67*5c4a5fe1SAndy Fiddaman #include <stdbool.h>
68*5c4a5fe1SAndy Fiddaman #include <stdint.h>
69*5c4a5fe1SAndy Fiddaman 
70*5c4a5fe1SAndy Fiddaman #include <machine/vmm.h>
71*5c4a5fe1SAndy Fiddaman #include <vmmapi.h>
72*5c4a5fe1SAndy Fiddaman 
73*5c4a5fe1SAndy Fiddaman #include "bhyverun.h"
74*5c4a5fe1SAndy Fiddaman #include "config.h"
75*5c4a5fe1SAndy Fiddaman #include "debug.h"
76*5c4a5fe1SAndy Fiddaman #include "gdb.h"
77*5c4a5fe1SAndy Fiddaman #include "inout.h"
78*5c4a5fe1SAndy Fiddaman #include "mem.h"
79*5c4a5fe1SAndy Fiddaman #include "spinup_ap.h"
80*5c4a5fe1SAndy Fiddaman #include "vmexit.h"
81*5c4a5fe1SAndy Fiddaman #include "xmsr.h"
82*5c4a5fe1SAndy Fiddaman 
83*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
84*5c4a5fe1SAndy Fiddaman static struct vm_entry *vmentry;
85*5c4a5fe1SAndy Fiddaman 
86*5c4a5fe1SAndy Fiddaman int
vmentry_init(int ncpus)87*5c4a5fe1SAndy Fiddaman vmentry_init(int ncpus)
88*5c4a5fe1SAndy Fiddaman {
89*5c4a5fe1SAndy Fiddaman 	vmentry = calloc(ncpus, sizeof(*vmentry));
90*5c4a5fe1SAndy Fiddaman 	return (vmentry == NULL ? -1 : 0);
91*5c4a5fe1SAndy Fiddaman }
92*5c4a5fe1SAndy Fiddaman 
93*5c4a5fe1SAndy Fiddaman struct vm_entry *
vmentry_vcpu(int vcpuid)94*5c4a5fe1SAndy Fiddaman vmentry_vcpu(int vcpuid)
95*5c4a5fe1SAndy Fiddaman {
96*5c4a5fe1SAndy Fiddaman 	return (&vmentry[vcpuid]);
97*5c4a5fe1SAndy Fiddaman }
98*5c4a5fe1SAndy Fiddaman 
99*5c4a5fe1SAndy Fiddaman static void
vmentry_mmio_read(struct vcpu * vcpu,uint64_t gpa,uint8_t bytes,uint64_t data)100*5c4a5fe1SAndy Fiddaman vmentry_mmio_read(struct vcpu *vcpu, uint64_t gpa, uint8_t bytes, uint64_t data)
101*5c4a5fe1SAndy Fiddaman {
102*5c4a5fe1SAndy Fiddaman 	struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
103*5c4a5fe1SAndy Fiddaman 	struct vm_mmio *mmio = &entry->u.mmio;
104*5c4a5fe1SAndy Fiddaman 
105*5c4a5fe1SAndy Fiddaman 	assert(entry->cmd == VEC_DEFAULT);
106*5c4a5fe1SAndy Fiddaman 
107*5c4a5fe1SAndy Fiddaman 	entry->cmd = VEC_FULFILL_MMIO;
108*5c4a5fe1SAndy Fiddaman 	mmio->bytes = bytes;
109*5c4a5fe1SAndy Fiddaman 	mmio->read = 1;
110*5c4a5fe1SAndy Fiddaman 	mmio->gpa = gpa;
111*5c4a5fe1SAndy Fiddaman 	mmio->data = data;
112*5c4a5fe1SAndy Fiddaman }
113*5c4a5fe1SAndy Fiddaman 
114*5c4a5fe1SAndy Fiddaman static void
vmentry_mmio_write(struct vcpu * vcpu,uint64_t gpa,uint8_t bytes)115*5c4a5fe1SAndy Fiddaman vmentry_mmio_write(struct vcpu *vcpu, uint64_t gpa, uint8_t bytes)
116*5c4a5fe1SAndy Fiddaman {
117*5c4a5fe1SAndy Fiddaman 	struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
118*5c4a5fe1SAndy Fiddaman 	struct vm_mmio *mmio = &entry->u.mmio;
119*5c4a5fe1SAndy Fiddaman 
120*5c4a5fe1SAndy Fiddaman 	assert(entry->cmd == VEC_DEFAULT);
121*5c4a5fe1SAndy Fiddaman 
122*5c4a5fe1SAndy Fiddaman 	entry->cmd = VEC_FULFILL_MMIO;
123*5c4a5fe1SAndy Fiddaman 	mmio->bytes = bytes;
124*5c4a5fe1SAndy Fiddaman 	mmio->read = 0;
125*5c4a5fe1SAndy Fiddaman 	mmio->gpa = gpa;
126*5c4a5fe1SAndy Fiddaman 	mmio->data = 0;
127*5c4a5fe1SAndy Fiddaman }
128*5c4a5fe1SAndy Fiddaman 
129*5c4a5fe1SAndy Fiddaman static void
vmentry_inout_read(struct vcpu * vcpu,uint16_t port,uint8_t bytes,uint32_t data)130*5c4a5fe1SAndy Fiddaman vmentry_inout_read(struct vcpu *vcpu, uint16_t port, uint8_t bytes,
131*5c4a5fe1SAndy Fiddaman     uint32_t data)
132*5c4a5fe1SAndy Fiddaman {
133*5c4a5fe1SAndy Fiddaman 	struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
134*5c4a5fe1SAndy Fiddaman 	struct vm_inout *inout = &entry->u.inout;
135*5c4a5fe1SAndy Fiddaman 
136*5c4a5fe1SAndy Fiddaman 	assert(entry->cmd == VEC_DEFAULT);
137*5c4a5fe1SAndy Fiddaman 
138*5c4a5fe1SAndy Fiddaman 	entry->cmd = VEC_FULFILL_INOUT;
139*5c4a5fe1SAndy Fiddaman 	inout->bytes = bytes;
140*5c4a5fe1SAndy Fiddaman 	inout->flags = INOUT_IN;
141*5c4a5fe1SAndy Fiddaman 	inout->port = port;
142*5c4a5fe1SAndy Fiddaman 	inout->eax = data;
143*5c4a5fe1SAndy Fiddaman }
144*5c4a5fe1SAndy Fiddaman 
145*5c4a5fe1SAndy Fiddaman static void
vmentry_inout_write(struct vcpu * vcpu,uint16_t port,uint8_t bytes)146*5c4a5fe1SAndy Fiddaman vmentry_inout_write(struct vcpu *vcpu, uint16_t port, uint8_t bytes)
147*5c4a5fe1SAndy Fiddaman {
148*5c4a5fe1SAndy Fiddaman 	struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
149*5c4a5fe1SAndy Fiddaman 	struct vm_inout *inout = &entry->u.inout;
150*5c4a5fe1SAndy Fiddaman 
151*5c4a5fe1SAndy Fiddaman 	assert(entry->cmd == VEC_DEFAULT);
152*5c4a5fe1SAndy Fiddaman 
153*5c4a5fe1SAndy Fiddaman 	entry->cmd = VEC_FULFILL_INOUT;
154*5c4a5fe1SAndy Fiddaman 	inout->bytes = bytes;
155*5c4a5fe1SAndy Fiddaman 	inout->flags = 0;
156*5c4a5fe1SAndy Fiddaman 	inout->port = port;
157*5c4a5fe1SAndy Fiddaman 	inout->eax = 0;
158*5c4a5fe1SAndy Fiddaman }
159*5c4a5fe1SAndy Fiddaman #endif
160*5c4a5fe1SAndy Fiddaman 
161*5c4a5fe1SAndy Fiddaman #ifdef	__FreeBSD__
162*5c4a5fe1SAndy Fiddaman void
vm_inject_fault(struct vcpu * vcpu,int vector,int errcode_valid,int errcode)163*5c4a5fe1SAndy Fiddaman vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid,
164*5c4a5fe1SAndy Fiddaman     int errcode)
165*5c4a5fe1SAndy Fiddaman {
166*5c4a5fe1SAndy Fiddaman 	int error, restart_instruction;
167*5c4a5fe1SAndy Fiddaman 
168*5c4a5fe1SAndy Fiddaman 	restart_instruction = 1;
169*5c4a5fe1SAndy Fiddaman 
170*5c4a5fe1SAndy Fiddaman 	error = vm_inject_exception(vcpu, vector, errcode_valid, errcode,
171*5c4a5fe1SAndy Fiddaman 	    restart_instruction);
172*5c4a5fe1SAndy Fiddaman 	assert(error == 0);
173*5c4a5fe1SAndy Fiddaman }
174*5c4a5fe1SAndy Fiddaman #endif
175*5c4a5fe1SAndy Fiddaman 
176*5c4a5fe1SAndy Fiddaman static int
vmexit_inout(struct vmctx * ctx,struct vcpu * vcpu,struct vm_exit * vme)177*5c4a5fe1SAndy Fiddaman vmexit_inout(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
178*5c4a5fe1SAndy Fiddaman {
179*5c4a5fe1SAndy Fiddaman 	int error;
180*5c4a5fe1SAndy Fiddaman 	struct vm_inout inout;
181*5c4a5fe1SAndy Fiddaman 	bool in;
182*5c4a5fe1SAndy Fiddaman 	uint8_t bytes;
183*5c4a5fe1SAndy Fiddaman 
184*5c4a5fe1SAndy Fiddaman 	inout = vme->u.inout;
185*5c4a5fe1SAndy Fiddaman 	in = (inout.flags & INOUT_IN) != 0;
186*5c4a5fe1SAndy Fiddaman 	bytes = inout.bytes;
187*5c4a5fe1SAndy Fiddaman 
188*5c4a5fe1SAndy Fiddaman 	error = emulate_inout(ctx, vcpu, &inout);
189*5c4a5fe1SAndy Fiddaman 	if (error) {
190*5c4a5fe1SAndy Fiddaman 		EPRINTLN("Unhandled %s%c 0x%04x at 0x%lx",
191*5c4a5fe1SAndy Fiddaman 		    in ? "in" : "out",
192*5c4a5fe1SAndy Fiddaman 		    bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'),
193*5c4a5fe1SAndy Fiddaman 		    inout.port, vme->rip);
194*5c4a5fe1SAndy Fiddaman 		return (VMEXIT_ABORT);
195*5c4a5fe1SAndy Fiddaman 	} else {
196*5c4a5fe1SAndy Fiddaman 		/*
197*5c4a5fe1SAndy Fiddaman 		 * Communicate the status of the inout operation back to the
198*5c4a5fe1SAndy Fiddaman 		 * in-kernel instruction emulation.
199*5c4a5fe1SAndy Fiddaman 		 */
200*5c4a5fe1SAndy Fiddaman 		if (in) {
201*5c4a5fe1SAndy Fiddaman 			vmentry_inout_read(vcpu, inout.port, bytes, inout.eax);
202*5c4a5fe1SAndy Fiddaman 		} else {
203*5c4a5fe1SAndy Fiddaman 			vmentry_inout_write(vcpu, inout.port, bytes);
204*5c4a5fe1SAndy Fiddaman 		}
205*5c4a5fe1SAndy Fiddaman 		return (VMEXIT_CONTINUE);
206*5c4a5fe1SAndy Fiddaman 	}
207*5c4a5fe1SAndy Fiddaman }
208*5c4a5fe1SAndy Fiddaman 
209*5c4a5fe1SAndy Fiddaman static int
vmexit_rdmsr(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)210*5c4a5fe1SAndy Fiddaman vmexit_rdmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
211*5c4a5fe1SAndy Fiddaman {
212*5c4a5fe1SAndy Fiddaman 	uint64_t val;
213*5c4a5fe1SAndy Fiddaman 	uint32_t eax, edx;
214*5c4a5fe1SAndy Fiddaman 	int error;
215*5c4a5fe1SAndy Fiddaman 
216*5c4a5fe1SAndy Fiddaman 	val = 0;
217*5c4a5fe1SAndy Fiddaman 	error = emulate_rdmsr(vcpu, vme->u.msr.code, &val);
218*5c4a5fe1SAndy Fiddaman 	if (error != 0) {
219*5c4a5fe1SAndy Fiddaman 		EPRINTLN("rdmsr to register %#x on vcpu %d",
220*5c4a5fe1SAndy Fiddaman 		    vme->u.msr.code, vcpu_id(vcpu));
221*5c4a5fe1SAndy Fiddaman 		if (get_config_bool("x86.strictmsr")) {
222*5c4a5fe1SAndy Fiddaman 			vm_inject_gp(vcpu);
223*5c4a5fe1SAndy Fiddaman 			return (VMEXIT_CONTINUE);
224*5c4a5fe1SAndy Fiddaman 		}
225*5c4a5fe1SAndy Fiddaman 	}
226*5c4a5fe1SAndy Fiddaman 
227*5c4a5fe1SAndy Fiddaman 	eax = val;
228*5c4a5fe1SAndy Fiddaman 	error = vm_set_register(vcpu, VM_REG_GUEST_RAX, eax);
229*5c4a5fe1SAndy Fiddaman 	assert(error == 0);
230*5c4a5fe1SAndy Fiddaman 
231*5c4a5fe1SAndy Fiddaman 	edx = val >> 32;
232*5c4a5fe1SAndy Fiddaman 	error = vm_set_register(vcpu, VM_REG_GUEST_RDX, edx);
233*5c4a5fe1SAndy Fiddaman 	assert(error == 0);
234*5c4a5fe1SAndy Fiddaman 
235*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
236*5c4a5fe1SAndy Fiddaman }
237*5c4a5fe1SAndy Fiddaman 
238*5c4a5fe1SAndy Fiddaman static int
vmexit_wrmsr(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)239*5c4a5fe1SAndy Fiddaman vmexit_wrmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
240*5c4a5fe1SAndy Fiddaman {
241*5c4a5fe1SAndy Fiddaman 	int error;
242*5c4a5fe1SAndy Fiddaman 
243*5c4a5fe1SAndy Fiddaman 	error = emulate_wrmsr(vcpu, vme->u.msr.code, vme->u.msr.wval);
244*5c4a5fe1SAndy Fiddaman 	if (error != 0) {
245*5c4a5fe1SAndy Fiddaman 		EPRINTLN("wrmsr to register %#x(%#lx) on vcpu %d",
246*5c4a5fe1SAndy Fiddaman 		    vme->u.msr.code, vme->u.msr.wval, vcpu_id(vcpu));
247*5c4a5fe1SAndy Fiddaman 		if (get_config_bool("x86.strictmsr")) {
248*5c4a5fe1SAndy Fiddaman 			vm_inject_gp(vcpu);
249*5c4a5fe1SAndy Fiddaman 			return (VMEXIT_CONTINUE);
250*5c4a5fe1SAndy Fiddaman 		}
251*5c4a5fe1SAndy Fiddaman 	}
252*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
253*5c4a5fe1SAndy Fiddaman }
254*5c4a5fe1SAndy Fiddaman 
255*5c4a5fe1SAndy Fiddaman static const char * const vmx_exit_reason_desc[] = {
256*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_EXCEPTION] = "Exception or non-maskable interrupt (NMI)",
257*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_EXT_INTR] = "External interrupt",
258*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_TRIPLE_FAULT] = "Triple fault",
259*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INIT] = "INIT signal",
260*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_SIPI] = "Start-up IPI (SIPI)",
261*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_IO_SMI] = "I/O system-management interrupt (SMI)",
262*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_SMI] = "Other SMI",
263*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INTR_WINDOW] = "Interrupt window",
264*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_NMI_WINDOW] = "NMI window",
265*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_TASK_SWITCH] = "Task switch",
266*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_CPUID] = "CPUID",
267*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_GETSEC] = "GETSEC",
268*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_HLT] = "HLT",
269*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVD] = "INVD",
270*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVLPG] = "INVLPG",
271*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDPMC] = "RDPMC",
272*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDTSC] = "RDTSC",
273*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RSM] = "RSM",
274*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMCALL] = "VMCALL",
275*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMCLEAR] = "VMCLEAR",
276*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMLAUNCH] = "VMLAUNCH",
277*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMPTRLD] = "VMPTRLD",
278*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMPTRST] = "VMPTRST",
279*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMREAD] = "VMREAD",
280*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMRESUME] = "VMRESUME",
281*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMWRITE] = "VMWRITE",
282*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMXOFF] = "VMXOFF",
283*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMXON] = "VMXON",
284*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_CR_ACCESS] = "Control-register accesses",
285*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_DR_ACCESS] = "MOV DR",
286*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INOUT] = "I/O instruction",
287*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDMSR] = "RDMSR",
288*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_WRMSR] = "WRMSR",
289*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVAL_VMCS] =
290*5c4a5fe1SAndy Fiddaman 	    "VM-entry failure due to invalid guest state",
291*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVAL_MSR] = "VM-entry failure due to MSR loading",
292*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_MWAIT] = "MWAIT",
293*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_MTF] = "Monitor trap flag",
294*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_MONITOR] = "MONITOR",
295*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_PAUSE] = "PAUSE",
296*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_MCE_DURING_ENTRY] =
297*5c4a5fe1SAndy Fiddaman 	    "VM-entry failure due to machine-check event",
298*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_TPR] = "TPR below threshold",
299*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_APIC_ACCESS] = "APIC access",
300*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VIRTUALIZED_EOI] = "Virtualized EOI",
301*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_GDTR_IDTR] = "Access to GDTR or IDTR",
302*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_LDTR_TR] = "Access to LDTR or TR",
303*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_EPT_FAULT] = "EPT violation",
304*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_EPT_MISCONFIG] = "EPT misconfiguration",
305*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVEPT] = "INVEPT",
306*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDTSCP] = "RDTSCP",
307*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMX_PREEMPT] = "VMX-preemption timer expired",
308*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVVPID] = "INVVPID",
309*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_WBINVD] = "WBINVD",
310*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_XSETBV] = "XSETBV",
311*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_APIC_WRITE] = "APIC write",
312*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDRAND] = "RDRAND",
313*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_INVPCID] = "INVPCID",
314*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_VMFUNC] = "VMFUNC",
315*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_ENCLS] = "ENCLS",
316*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_RDSEED] = "RDSEED",
317*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_PM_LOG_FULL] = "Page-modification log full",
318*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_XSAVES] = "XSAVES",
319*5c4a5fe1SAndy Fiddaman 	[EXIT_REASON_XRSTORS] = "XRSTORS"
320*5c4a5fe1SAndy Fiddaman };
321*5c4a5fe1SAndy Fiddaman 
322*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
323*5c4a5fe1SAndy Fiddaman static int
vmexit_run_state(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_exit * vme __unused)324*5c4a5fe1SAndy Fiddaman vmexit_run_state(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
325*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme __unused)
326*5c4a5fe1SAndy Fiddaman {
327*5c4a5fe1SAndy Fiddaman 	/*
328*5c4a5fe1SAndy Fiddaman 	 * Run-state transitions (INIT, SIPI, etc) are handled in-kernel, so an
329*5c4a5fe1SAndy Fiddaman 	 * exit to userspace with that code is not expected.
330*5c4a5fe1SAndy Fiddaman 	 */
331*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "unexpected run-state VM exit");
332*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
333*5c4a5fe1SAndy Fiddaman }
334*5c4a5fe1SAndy Fiddaman 
335*5c4a5fe1SAndy Fiddaman static int
vmexit_paging(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)336*5c4a5fe1SAndy Fiddaman vmexit_paging(struct vmctx *ctx __unused, struct vcpu *vcpu,
337*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme)
338*5c4a5fe1SAndy Fiddaman {
339*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "vm exit[%d]\n", vcpu_id(vcpu));
340*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "\treason\t\tPAGING\n");
341*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "\trip\t\t0x%016lx\n", vme->rip);
342*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "\tgpa\t\t0x%016lx\n", vme->u.paging.gpa);
343*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "\tfault_type\t\t%d\n", vme->u.paging.fault_type);
344*5c4a5fe1SAndy Fiddaman 
345*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
346*5c4a5fe1SAndy Fiddaman }
347*5c4a5fe1SAndy Fiddaman #endif /* __FreeBSD__ */
348*5c4a5fe1SAndy Fiddaman 
349*5c4a5fe1SAndy Fiddaman #ifdef __FreeBSD__
350*5c4a5fe1SAndy Fiddaman #define	DEBUG_EPT_MISCONFIG
351*5c4a5fe1SAndy Fiddaman #else
352*5c4a5fe1SAndy Fiddaman /* EPT misconfig debugging not possible now that raw VMCS access is gone */
353*5c4a5fe1SAndy Fiddaman #endif
354*5c4a5fe1SAndy Fiddaman 
355*5c4a5fe1SAndy Fiddaman #ifdef DEBUG_EPT_MISCONFIG
356*5c4a5fe1SAndy Fiddaman #define	VMCS_GUEST_PHYSICAL_ADDRESS	0x00002400
357*5c4a5fe1SAndy Fiddaman 
358*5c4a5fe1SAndy Fiddaman static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4];
359*5c4a5fe1SAndy Fiddaman static int ept_misconfig_ptenum;
360*5c4a5fe1SAndy Fiddaman #endif
361*5c4a5fe1SAndy Fiddaman 
362*5c4a5fe1SAndy Fiddaman static const char *
vmexit_vmx_desc(uint32_t exit_reason)363*5c4a5fe1SAndy Fiddaman vmexit_vmx_desc(uint32_t exit_reason)
364*5c4a5fe1SAndy Fiddaman {
365*5c4a5fe1SAndy Fiddaman 
366*5c4a5fe1SAndy Fiddaman 	if (exit_reason >= nitems(vmx_exit_reason_desc) ||
367*5c4a5fe1SAndy Fiddaman 	    vmx_exit_reason_desc[exit_reason] == NULL)
368*5c4a5fe1SAndy Fiddaman 		return ("Unknown");
369*5c4a5fe1SAndy Fiddaman 	return (vmx_exit_reason_desc[exit_reason]);
370*5c4a5fe1SAndy Fiddaman }
371*5c4a5fe1SAndy Fiddaman 
372*5c4a5fe1SAndy Fiddaman static int
vmexit_vmx(struct vmctx * ctx,struct vcpu * vcpu,struct vm_exit * vme)373*5c4a5fe1SAndy Fiddaman vmexit_vmx(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
374*5c4a5fe1SAndy Fiddaman {
375*5c4a5fe1SAndy Fiddaman 
376*5c4a5fe1SAndy Fiddaman 	EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
377*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\treason\t\tVMX");
378*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\trip\t\t0x%016lx", vme->rip);
379*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tinst_length\t%d", vme->inst_length);
380*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tstatus\t\t%d", vme->u.vmx.status);
381*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\texit_reason\t%u (%s)", vme->u.vmx.exit_reason,
382*5c4a5fe1SAndy Fiddaman 	    vmexit_vmx_desc(vme->u.vmx.exit_reason));
383*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tqualification\t0x%016lx",
384*5c4a5fe1SAndy Fiddaman 	    vme->u.vmx.exit_qualification);
385*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tinst_type\t\t%d", vme->u.vmx.inst_type);
386*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tinst_error\t\t%d", vme->u.vmx.inst_error);
387*5c4a5fe1SAndy Fiddaman #ifdef DEBUG_EPT_MISCONFIG
388*5c4a5fe1SAndy Fiddaman 	if (vme->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) {
389*5c4a5fe1SAndy Fiddaman 		vm_get_register(vcpu,
390*5c4a5fe1SAndy Fiddaman 		    VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS),
391*5c4a5fe1SAndy Fiddaman 		    &ept_misconfig_gpa);
392*5c4a5fe1SAndy Fiddaman 		vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte,
393*5c4a5fe1SAndy Fiddaman 		    &ept_misconfig_ptenum);
394*5c4a5fe1SAndy Fiddaman 		EPRINTLN("\tEPT misconfiguration:");
395*5c4a5fe1SAndy Fiddaman 		EPRINTLN("\t\tGPA: %#lx", ept_misconfig_gpa);
396*5c4a5fe1SAndy Fiddaman 		EPRINTLN("\t\tPTE(%d): %#lx %#lx %#lx %#lx",
397*5c4a5fe1SAndy Fiddaman 		    ept_misconfig_ptenum, ept_misconfig_pte[0],
398*5c4a5fe1SAndy Fiddaman 		    ept_misconfig_pte[1], ept_misconfig_pte[2],
399*5c4a5fe1SAndy Fiddaman 		    ept_misconfig_pte[3]);
400*5c4a5fe1SAndy Fiddaman 	}
401*5c4a5fe1SAndy Fiddaman #endif	/* DEBUG_EPT_MISCONFIG */
402*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
403*5c4a5fe1SAndy Fiddaman }
404*5c4a5fe1SAndy Fiddaman 
405*5c4a5fe1SAndy Fiddaman static int
vmexit_svm(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)406*5c4a5fe1SAndy Fiddaman vmexit_svm(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
407*5c4a5fe1SAndy Fiddaman {
408*5c4a5fe1SAndy Fiddaman 	EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
409*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\treason\t\tSVM");
410*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\trip\t\t0x%016lx", vme->rip);
411*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\tinst_length\t%d", vme->inst_length);
412*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\texitcode\t%#lx", vme->u.svm.exitcode);
413*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\texitinfo1\t%#lx", vme->u.svm.exitinfo1);
414*5c4a5fe1SAndy Fiddaman 	EPRINTLN("\texitinfo2\t%#lx", vme->u.svm.exitinfo2);
415*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
416*5c4a5fe1SAndy Fiddaman }
417*5c4a5fe1SAndy Fiddaman 
418*5c4a5fe1SAndy Fiddaman static int
vmexit_bogus(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_exit * vme)419*5c4a5fe1SAndy Fiddaman vmexit_bogus(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
420*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme)
421*5c4a5fe1SAndy Fiddaman {
422*5c4a5fe1SAndy Fiddaman 
423*5c4a5fe1SAndy Fiddaman 	assert(vme->inst_length == 0);
424*5c4a5fe1SAndy Fiddaman 
425*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
426*5c4a5fe1SAndy Fiddaman }
427*5c4a5fe1SAndy Fiddaman 
428*5c4a5fe1SAndy Fiddaman static int
vmexit_hlt(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_exit * vme __unused)429*5c4a5fe1SAndy Fiddaman vmexit_hlt(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
430*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme __unused)
431*5c4a5fe1SAndy Fiddaman {
432*5c4a5fe1SAndy Fiddaman 
433*5c4a5fe1SAndy Fiddaman 	/*
434*5c4a5fe1SAndy Fiddaman 	 * Just continue execution with the next instruction. We use
435*5c4a5fe1SAndy Fiddaman 	 * the HLT VM exit as a way to be friendly with the host
436*5c4a5fe1SAndy Fiddaman 	 * scheduler.
437*5c4a5fe1SAndy Fiddaman 	 */
438*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
439*5c4a5fe1SAndy Fiddaman }
440*5c4a5fe1SAndy Fiddaman 
441*5c4a5fe1SAndy Fiddaman static int
vmexit_pause(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_exit * vme __unused)442*5c4a5fe1SAndy Fiddaman vmexit_pause(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
443*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme __unused)
444*5c4a5fe1SAndy Fiddaman {
445*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
446*5c4a5fe1SAndy Fiddaman }
447*5c4a5fe1SAndy Fiddaman 
448*5c4a5fe1SAndy Fiddaman static int
vmexit_mtrap(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)449*5c4a5fe1SAndy Fiddaman vmexit_mtrap(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
450*5c4a5fe1SAndy Fiddaman {
451*5c4a5fe1SAndy Fiddaman 
452*5c4a5fe1SAndy Fiddaman 	assert(vme->inst_length == 0);
453*5c4a5fe1SAndy Fiddaman 
454*5c4a5fe1SAndy Fiddaman 	gdb_cpu_mtrap(vcpu);
455*5c4a5fe1SAndy Fiddaman 
456*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
457*5c4a5fe1SAndy Fiddaman }
458*5c4a5fe1SAndy Fiddaman 
459*5c4a5fe1SAndy Fiddaman static int
vmexit_inst_emul(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)460*5c4a5fe1SAndy Fiddaman vmexit_inst_emul(struct vmctx *ctx __unused, struct vcpu *vcpu,
461*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme)
462*5c4a5fe1SAndy Fiddaman {
463*5c4a5fe1SAndy Fiddaman 	uint8_t i, valid;
464*5c4a5fe1SAndy Fiddaman 
465*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "Failed to emulate instruction sequence ");
466*5c4a5fe1SAndy Fiddaman 
467*5c4a5fe1SAndy Fiddaman 	valid = vme->u.inst_emul.num_valid;
468*5c4a5fe1SAndy Fiddaman 	if (valid != 0) {
469*5c4a5fe1SAndy Fiddaman 		assert(valid <= sizeof (vme->u.inst_emul.inst));
470*5c4a5fe1SAndy Fiddaman 		fprintf(stderr, "[");
471*5c4a5fe1SAndy Fiddaman 		for (i = 0; i < valid; i++) {
472*5c4a5fe1SAndy Fiddaman 			if (i == 0) {
473*5c4a5fe1SAndy Fiddaman 				fprintf(stderr, "%02x",
474*5c4a5fe1SAndy Fiddaman 				    vme->u.inst_emul.inst[i]);
475*5c4a5fe1SAndy Fiddaman 			} else {
476*5c4a5fe1SAndy Fiddaman 				fprintf(stderr, ", %02x",
477*5c4a5fe1SAndy Fiddaman 				    vme->u.inst_emul.inst[i]);
478*5c4a5fe1SAndy Fiddaman 			}
479*5c4a5fe1SAndy Fiddaman 		}
480*5c4a5fe1SAndy Fiddaman 		fprintf(stderr, "] ");
481*5c4a5fe1SAndy Fiddaman 	}
482*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "@ %rip = %x\n", vme->rip);
483*5c4a5fe1SAndy Fiddaman 
484*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
485*5c4a5fe1SAndy Fiddaman }
486*5c4a5fe1SAndy Fiddaman 
487*5c4a5fe1SAndy Fiddaman #ifndef	__FreeBSD__
488*5c4a5fe1SAndy Fiddaman static int
vmexit_mmio(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)489*5c4a5fe1SAndy Fiddaman vmexit_mmio(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
490*5c4a5fe1SAndy Fiddaman {
491*5c4a5fe1SAndy Fiddaman 	int err;
492*5c4a5fe1SAndy Fiddaman 	struct vm_mmio mmio;
493*5c4a5fe1SAndy Fiddaman 	bool is_read;
494*5c4a5fe1SAndy Fiddaman 
495*5c4a5fe1SAndy Fiddaman 	mmio = vme->u.mmio;
496*5c4a5fe1SAndy Fiddaman 	is_read = (mmio.read != 0);
497*5c4a5fe1SAndy Fiddaman 
498*5c4a5fe1SAndy Fiddaman 	err = emulate_mem(vcpu, &mmio);
499*5c4a5fe1SAndy Fiddaman 
500*5c4a5fe1SAndy Fiddaman 	if (err == ESRCH) {
501*5c4a5fe1SAndy Fiddaman 		fprintf(stderr, "Unhandled memory access to 0x%lx\n", mmio.gpa);
502*5c4a5fe1SAndy Fiddaman 
503*5c4a5fe1SAndy Fiddaman 		/*
504*5c4a5fe1SAndy Fiddaman 		 * Access to non-existent physical addresses is not likely to
505*5c4a5fe1SAndy Fiddaman 		 * result in fatal errors on hardware machines, but rather reads
506*5c4a5fe1SAndy Fiddaman 		 * of all-ones or discarded-but-acknowledged writes.
507*5c4a5fe1SAndy Fiddaman 		 */
508*5c4a5fe1SAndy Fiddaman 		mmio.data = ~0UL;
509*5c4a5fe1SAndy Fiddaman 		err = 0;
510*5c4a5fe1SAndy Fiddaman 	}
511*5c4a5fe1SAndy Fiddaman 
512*5c4a5fe1SAndy Fiddaman 	if (err == 0) {
513*5c4a5fe1SAndy Fiddaman 		if (is_read) {
514*5c4a5fe1SAndy Fiddaman 			vmentry_mmio_read(vcpu, mmio.gpa, mmio.bytes,
515*5c4a5fe1SAndy Fiddaman 			    mmio.data);
516*5c4a5fe1SAndy Fiddaman 		} else {
517*5c4a5fe1SAndy Fiddaman 			vmentry_mmio_write(vcpu, mmio.gpa, mmio.bytes);
518*5c4a5fe1SAndy Fiddaman 		}
519*5c4a5fe1SAndy Fiddaman 		return (VMEXIT_CONTINUE);
520*5c4a5fe1SAndy Fiddaman 	}
521*5c4a5fe1SAndy Fiddaman 
522*5c4a5fe1SAndy Fiddaman 	fprintf(stderr, "Unhandled mmio error to 0x%lx: %d\n", mmio.gpa, err);
523*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_ABORT);
524*5c4a5fe1SAndy Fiddaman }
525*5c4a5fe1SAndy Fiddaman #endif /* !__FreeBSD__ */
526*5c4a5fe1SAndy Fiddaman 
527*5c4a5fe1SAndy Fiddaman static int
vmexit_suspend(struct vmctx * ctx,struct vcpu * vcpu,struct vm_exit * vme)528*5c4a5fe1SAndy Fiddaman vmexit_suspend(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
529*5c4a5fe1SAndy Fiddaman {
530*5c4a5fe1SAndy Fiddaman 	enum vm_suspend_how how;
531*5c4a5fe1SAndy Fiddaman 	int vcpuid = vcpu_id(vcpu);
532*5c4a5fe1SAndy Fiddaman 
533*5c4a5fe1SAndy Fiddaman 	how = vme->u.suspended.how;
534*5c4a5fe1SAndy Fiddaman 
535*5c4a5fe1SAndy Fiddaman 	fbsdrun_deletecpu(vcpuid);
536*5c4a5fe1SAndy Fiddaman 
537*5c4a5fe1SAndy Fiddaman 	switch (how) {
538*5c4a5fe1SAndy Fiddaman 	case VM_SUSPEND_RESET:
539*5c4a5fe1SAndy Fiddaman 		exit(0);
540*5c4a5fe1SAndy Fiddaman 	case VM_SUSPEND_POWEROFF:
541*5c4a5fe1SAndy Fiddaman 		if (get_config_bool_default("destroy_on_poweroff", false))
542*5c4a5fe1SAndy Fiddaman 			vm_destroy(ctx);
543*5c4a5fe1SAndy Fiddaman 		exit(1);
544*5c4a5fe1SAndy Fiddaman 	case VM_SUSPEND_HALT:
545*5c4a5fe1SAndy Fiddaman 		exit(2);
546*5c4a5fe1SAndy Fiddaman 	case VM_SUSPEND_TRIPLEFAULT:
547*5c4a5fe1SAndy Fiddaman 		exit(3);
548*5c4a5fe1SAndy Fiddaman 	default:
549*5c4a5fe1SAndy Fiddaman 		EPRINTLN("vmexit_suspend: invalid reason %d", how);
550*5c4a5fe1SAndy Fiddaman 		exit(100);
551*5c4a5fe1SAndy Fiddaman 	}
552*5c4a5fe1SAndy Fiddaman 	return (0);	/* NOTREACHED */
553*5c4a5fe1SAndy Fiddaman }
554*5c4a5fe1SAndy Fiddaman 
555*5c4a5fe1SAndy Fiddaman static int
vmexit_debug(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme __unused)556*5c4a5fe1SAndy Fiddaman vmexit_debug(struct vmctx *ctx __unused, struct vcpu *vcpu,
557*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme __unused)
558*5c4a5fe1SAndy Fiddaman {
559*5c4a5fe1SAndy Fiddaman 	gdb_cpu_suspend(vcpu);
560*5c4a5fe1SAndy Fiddaman 	/*
561*5c4a5fe1SAndy Fiddaman 	 * Sleep for a short period to avoid chewing up the CPU in the
562*5c4a5fe1SAndy Fiddaman 	 * window between activation of the vCPU thread and the STARTUP IPI.
563*5c4a5fe1SAndy Fiddaman 	 */
564*5c4a5fe1SAndy Fiddaman 	usleep(1000);
565*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
566*5c4a5fe1SAndy Fiddaman }
567*5c4a5fe1SAndy Fiddaman 
568*5c4a5fe1SAndy Fiddaman static int
vmexit_breakpoint(struct vmctx * ctx __unused,struct vcpu * vcpu,struct vm_exit * vme)569*5c4a5fe1SAndy Fiddaman vmexit_breakpoint(struct vmctx *ctx __unused, struct vcpu *vcpu,
570*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme)
571*5c4a5fe1SAndy Fiddaman {
572*5c4a5fe1SAndy Fiddaman 
573*5c4a5fe1SAndy Fiddaman 	gdb_cpu_breakpoint(vcpu, vme);
574*5c4a5fe1SAndy Fiddaman 	return (VMEXIT_CONTINUE);
575*5c4a5fe1SAndy Fiddaman }
576*5c4a5fe1SAndy Fiddaman 
577*5c4a5fe1SAndy Fiddaman #ifdef	__FreeBSD__
578*5c4a5fe1SAndy Fiddaman static int
vmexit_ipi(struct vmctx * ctx __unused,struct vcpu * vcpu __unused,struct vm_exit * vme)579*5c4a5fe1SAndy Fiddaman vmexit_ipi(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
580*5c4a5fe1SAndy Fiddaman     struct vm_exit *vme)
581*5c4a5fe1SAndy Fiddaman {
582*5c4a5fe1SAndy Fiddaman 	int error = -1;
583*5c4a5fe1SAndy Fiddaman 	int i;
584*5c4a5fe1SAndy Fiddaman 	switch (vme->u.ipi.mode) {
585*5c4a5fe1SAndy Fiddaman 	case APIC_DELMODE_INIT:
586*5c4a5fe1SAndy Fiddaman 		CPU_FOREACH_ISSET(i, &vme->u.ipi.dmask) {
587*5c4a5fe1SAndy Fiddaman 			error = vm_suspend_cpu(vcpu_info[i].vcpu);
588*5c4a5fe1SAndy Fiddaman 			if (error) {
589*5c4a5fe1SAndy Fiddaman 				warnx("%s: failed to suspend cpu %d\n",
590*5c4a5fe1SAndy Fiddaman 				    __func__, i);
591*5c4a5fe1SAndy Fiddaman 				break;
592*5c4a5fe1SAndy Fiddaman 			}
593*5c4a5fe1SAndy Fiddaman 		}
594*5c4a5fe1SAndy Fiddaman 		break;
595*5c4a5fe1SAndy Fiddaman 	case APIC_DELMODE_STARTUP:
596*5c4a5fe1SAndy Fiddaman 		CPU_FOREACH_ISSET(i, &vme->u.ipi.dmask) {
597*5c4a5fe1SAndy Fiddaman 			spinup_ap(vcpu_info[i].vcpu,
598*5c4a5fe1SAndy Fiddaman 			    vme->u.ipi.vector << PAGE_SHIFT);
599*5c4a5fe1SAndy Fiddaman 		}
600*5c4a5fe1SAndy Fiddaman 		error = 0;
601*5c4a5fe1SAndy Fiddaman 		break;
602*5c4a5fe1SAndy Fiddaman 	default:
603*5c4a5fe1SAndy Fiddaman 		break;
604*5c4a5fe1SAndy Fiddaman 	}
605*5c4a5fe1SAndy Fiddaman 
606*5c4a5fe1SAndy Fiddaman 	return (error);
607*5c4a5fe1SAndy Fiddaman }
608*5c4a5fe1SAndy Fiddaman #endif
609*5c4a5fe1SAndy Fiddaman 
610*5c4a5fe1SAndy Fiddaman const vmexit_handler_t vmexit_handlers[VM_EXITCODE_MAX] = {
611*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_INOUT]  = vmexit_inout,
612*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
613*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_MMIO]  = vmexit_mmio,
614*5c4a5fe1SAndy Fiddaman #endif
615*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_VMX]    = vmexit_vmx,
616*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_SVM]    = vmexit_svm,
617*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_BOGUS]  = vmexit_bogus,
618*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_RDMSR]  = vmexit_rdmsr,
619*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_WRMSR]  = vmexit_wrmsr,
620*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_MTRAP]  = vmexit_mtrap,
621*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
622*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
623*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_RUN_STATE] = vmexit_run_state,
624*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_PAGING] = vmexit_paging,
625*5c4a5fe1SAndy Fiddaman #endif
626*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_SUSPENDED] = vmexit_suspend,
627*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch,
628*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_DEBUG] = vmexit_debug,
629*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_BPT] = vmexit_breakpoint,
630*5c4a5fe1SAndy Fiddaman #ifdef	__FreeBSD__
631*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_IPI] = vmexit_ipi,
632*5c4a5fe1SAndy Fiddaman #endif
633*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_HLT] = vmexit_hlt,
634*5c4a5fe1SAndy Fiddaman 	[VM_EXITCODE_PAUSE] = vmexit_pause,
635*5c4a5fe1SAndy Fiddaman };
636