xref: /freebsd/usr.sbin/bhyve/bhyverun.c (revision 9d6be09f8a5e7460f8905f0777fe493fa2e9bdfa)
1e285ef8dSPeter Grehan /*-
2e285ef8dSPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
3e285ef8dSPeter Grehan  * All rights reserved.
4e285ef8dSPeter Grehan  *
5e285ef8dSPeter Grehan  * Redistribution and use in source and binary forms, with or without
6e285ef8dSPeter Grehan  * modification, are permitted provided that the following conditions
7e285ef8dSPeter Grehan  * are met:
8e285ef8dSPeter Grehan  * 1. Redistributions of source code must retain the above copyright
9e285ef8dSPeter Grehan  *    notice, this list of conditions and the following disclaimer.
10e285ef8dSPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
11e285ef8dSPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
12e285ef8dSPeter Grehan  *    documentation and/or other materials provided with the distribution.
13e285ef8dSPeter Grehan  *
14e285ef8dSPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15e285ef8dSPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16e285ef8dSPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17e285ef8dSPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18e285ef8dSPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19e285ef8dSPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20e285ef8dSPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e285ef8dSPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22e285ef8dSPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23e285ef8dSPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24e285ef8dSPeter Grehan  * SUCH DAMAGE.
25e285ef8dSPeter Grehan  *
26e285ef8dSPeter Grehan  * $FreeBSD$
27e285ef8dSPeter Grehan  */
28e285ef8dSPeter Grehan 
29e285ef8dSPeter Grehan #include <sys/cdefs.h>
30e285ef8dSPeter Grehan __FBSDID("$FreeBSD$");
31e285ef8dSPeter Grehan 
32e285ef8dSPeter Grehan #include <sys/types.h>
33e285ef8dSPeter Grehan #include <sys/mman.h>
34e285ef8dSPeter Grehan #include <sys/time.h>
35e285ef8dSPeter Grehan 
36e285ef8dSPeter Grehan #include <machine/segments.h>
37e285ef8dSPeter Grehan 
38e285ef8dSPeter Grehan #include <stdio.h>
39e285ef8dSPeter Grehan #include <stdlib.h>
40e285ef8dSPeter Grehan #include <libgen.h>
41e285ef8dSPeter Grehan #include <unistd.h>
42e285ef8dSPeter Grehan #include <assert.h>
43e285ef8dSPeter Grehan #include <errno.h>
44e285ef8dSPeter Grehan #include <signal.h>
45e285ef8dSPeter Grehan #include <pthread.h>
46e285ef8dSPeter Grehan #include <pthread_np.h>
47e285ef8dSPeter Grehan 
48e285ef8dSPeter Grehan #include <machine/vmm.h>
49e285ef8dSPeter Grehan #include <vmmapi.h>
50e285ef8dSPeter Grehan 
51e285ef8dSPeter Grehan #include "bhyverun.h"
52e285ef8dSPeter Grehan #include "acpi.h"
53e285ef8dSPeter Grehan #include "inout.h"
54e285ef8dSPeter Grehan #include "dbgport.h"
55e285ef8dSPeter Grehan #include "mem.h"
56e285ef8dSPeter Grehan #include "mevent.h"
57e285ef8dSPeter Grehan #include "mptbl.h"
58e285ef8dSPeter Grehan #include "pci_emul.h"
59e285ef8dSPeter Grehan #include "xmsr.h"
60e285ef8dSPeter Grehan #include "ioapic.h"
61e285ef8dSPeter Grehan #include "spinup_ap.h"
62*9d6be09fSPeter Grehan #include "rtc.h"
63e285ef8dSPeter Grehan 
64e285ef8dSPeter Grehan #define	DEFAULT_GUEST_HZ	100
65e285ef8dSPeter Grehan #define	DEFAULT_GUEST_TSLICE	200
66e285ef8dSPeter Grehan 
67e285ef8dSPeter Grehan #define GUEST_NIO_PORT		0x488	/* guest upcalls via i/o port */
68e285ef8dSPeter Grehan 
69e285ef8dSPeter Grehan #define	VMEXIT_SWITCH		0	/* force vcpu switch in mux mode */
70e285ef8dSPeter Grehan #define	VMEXIT_CONTINUE		1	/* continue from next instruction */
71e285ef8dSPeter Grehan #define	VMEXIT_RESTART		2	/* restart current instruction */
72e285ef8dSPeter Grehan #define	VMEXIT_ABORT		3	/* abort the vm run loop */
73e285ef8dSPeter Grehan #define	VMEXIT_RESET		4	/* guest machine has reset */
74e285ef8dSPeter Grehan 
75e285ef8dSPeter Grehan #define MB		(1024UL * 1024)
76e285ef8dSPeter Grehan #define GB		(1024UL * MB)
77e285ef8dSPeter Grehan 
78e285ef8dSPeter Grehan typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu);
79e285ef8dSPeter Grehan 
80e285ef8dSPeter Grehan int guest_tslice = DEFAULT_GUEST_TSLICE;
81e285ef8dSPeter Grehan int guest_hz = DEFAULT_GUEST_HZ;
82e285ef8dSPeter Grehan char *vmname;
83e285ef8dSPeter Grehan 
84e285ef8dSPeter Grehan int guest_ncpus;
85e285ef8dSPeter Grehan 
86e285ef8dSPeter Grehan static int pincpu = -1;
87e285ef8dSPeter Grehan static int guest_vcpu_mux;
88e285ef8dSPeter Grehan static int guest_vmexit_on_hlt, guest_vmexit_on_pause, disable_x2apic;
89e285ef8dSPeter Grehan 
90e285ef8dSPeter Grehan static int foundcpus;
91e285ef8dSPeter Grehan 
92e285ef8dSPeter Grehan static int strictio;
93e285ef8dSPeter Grehan 
94e285ef8dSPeter Grehan static int acpi;
95e285ef8dSPeter Grehan 
96e285ef8dSPeter Grehan static char *progname;
97e285ef8dSPeter Grehan static const int BSP = 0;
98e285ef8dSPeter Grehan 
99e285ef8dSPeter Grehan static int cpumask;
100e285ef8dSPeter Grehan 
101e285ef8dSPeter Grehan static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip);
102e285ef8dSPeter Grehan 
103e285ef8dSPeter Grehan struct vm_exit vmexit[VM_MAXCPU];
104e285ef8dSPeter Grehan 
105e285ef8dSPeter Grehan struct fbsdstats {
106e285ef8dSPeter Grehan         uint64_t        vmexit_bogus;
107e285ef8dSPeter Grehan         uint64_t        vmexit_bogus_switch;
108e285ef8dSPeter Grehan         uint64_t        vmexit_hlt;
109e285ef8dSPeter Grehan         uint64_t        vmexit_pause;
110e285ef8dSPeter Grehan         uint64_t        vmexit_mtrap;
111e285ef8dSPeter Grehan         uint64_t        vmexit_paging;
112e285ef8dSPeter Grehan         uint64_t        cpu_switch_rotate;
113e285ef8dSPeter Grehan         uint64_t        cpu_switch_direct;
114e285ef8dSPeter Grehan         int             io_reset;
115e285ef8dSPeter Grehan } stats;
116e285ef8dSPeter Grehan 
117e285ef8dSPeter Grehan struct mt_vmm_info {
118e285ef8dSPeter Grehan 	pthread_t	mt_thr;
119e285ef8dSPeter Grehan 	struct vmctx	*mt_ctx;
120e285ef8dSPeter Grehan 	int		mt_vcpu;
121e285ef8dSPeter Grehan } mt_vmm_info[VM_MAXCPU];
122e285ef8dSPeter Grehan 
123e285ef8dSPeter Grehan static void
124e285ef8dSPeter Grehan usage(int code)
125e285ef8dSPeter Grehan {
126e285ef8dSPeter Grehan 
127e285ef8dSPeter Grehan         fprintf(stderr,
128e285ef8dSPeter Grehan                 "Usage: %s [-aehABHIP][-g <gdb port>][-z <hz>][-s <pci>]"
12924be8623SNeel Natu 		"[-S <pci>][-p pincpu][-n <pci>][-m lowmem][-M highmem]"
13024be8623SNeel Natu 		" <vmname>\n"
131e285ef8dSPeter Grehan 		"       -a: local apic is in XAPIC mode (default is X2APIC)\n"
132e285ef8dSPeter Grehan 		"       -A: create an ACPI table\n"
133e285ef8dSPeter Grehan 		"       -g: gdb port (default is %d and 0 means don't open)\n"
134e285ef8dSPeter Grehan 		"       -c: # cpus (default 1)\n"
135e285ef8dSPeter Grehan 		"       -p: pin vcpu 'n' to host cpu 'pincpu + n'\n"
136e285ef8dSPeter Grehan 		"       -B: inject breakpoint exception on vm entry\n"
137e285ef8dSPeter Grehan 		"       -H: vmexit from the guest on hlt\n"
138e285ef8dSPeter Grehan 		"       -I: present an ioapic to the guest\n"
139e285ef8dSPeter Grehan 		"       -P: vmexit from the guest on pause\n"
140e285ef8dSPeter Grehan 		"	-e: exit on unhandled i/o access\n"
141e285ef8dSPeter Grehan 		"       -h: help\n"
142e285ef8dSPeter Grehan 		"       -z: guest hz (default is %d)\n"
143e285ef8dSPeter Grehan 		"       -s: <slot,driver,configinfo> PCI slot config\n"
144e285ef8dSPeter Grehan 		"       -S: <slot,driver,configinfo> legacy PCI slot config\n"
145b060ba50SNeel Natu 		"       -m: memory size in MB\n"
146e285ef8dSPeter Grehan 		"       -x: mux vcpus to 1 hcpu\n"
147e285ef8dSPeter Grehan 		"       -t: mux vcpu timeslice hz (default %d)\n",
148e285ef8dSPeter Grehan 		progname, DEFAULT_GDB_PORT, DEFAULT_GUEST_HZ,
149e285ef8dSPeter Grehan 		DEFAULT_GUEST_TSLICE);
150e285ef8dSPeter Grehan 	exit(code);
151e285ef8dSPeter Grehan }
152e285ef8dSPeter Grehan 
153e285ef8dSPeter Grehan void *
154b060ba50SNeel Natu paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
155e285ef8dSPeter Grehan {
156e285ef8dSPeter Grehan 
157b060ba50SNeel Natu 	return (vm_map_gpa(ctx, gaddr, len));
158e285ef8dSPeter Grehan }
159e285ef8dSPeter Grehan 
160e285ef8dSPeter Grehan int
161e285ef8dSPeter Grehan fbsdrun_disable_x2apic(void)
162e285ef8dSPeter Grehan {
163e285ef8dSPeter Grehan 
164e285ef8dSPeter Grehan 	return (disable_x2apic);
165e285ef8dSPeter Grehan }
166e285ef8dSPeter Grehan 
167e285ef8dSPeter Grehan int
168e285ef8dSPeter Grehan fbsdrun_vmexit_on_pause(void)
169e285ef8dSPeter Grehan {
170e285ef8dSPeter Grehan 
171e285ef8dSPeter Grehan 	return (guest_vmexit_on_pause);
172e285ef8dSPeter Grehan }
173e285ef8dSPeter Grehan 
174e285ef8dSPeter Grehan int
175e285ef8dSPeter Grehan fbsdrun_vmexit_on_hlt(void)
176e285ef8dSPeter Grehan {
177e285ef8dSPeter Grehan 
178e285ef8dSPeter Grehan 	return (guest_vmexit_on_hlt);
179e285ef8dSPeter Grehan }
180e285ef8dSPeter Grehan 
181e285ef8dSPeter Grehan int
182e285ef8dSPeter Grehan fbsdrun_muxed(void)
183e285ef8dSPeter Grehan {
184e285ef8dSPeter Grehan 
185e285ef8dSPeter Grehan 	return (guest_vcpu_mux);
186e285ef8dSPeter Grehan }
187e285ef8dSPeter Grehan 
188e285ef8dSPeter Grehan static void *
189e285ef8dSPeter Grehan fbsdrun_start_thread(void *param)
190e285ef8dSPeter Grehan {
191e285ef8dSPeter Grehan 	char tname[MAXCOMLEN + 1];
192e285ef8dSPeter Grehan 	struct mt_vmm_info *mtp;
193e285ef8dSPeter Grehan 	int vcpu;
194e285ef8dSPeter Grehan 
195e285ef8dSPeter Grehan 	mtp = param;
196e285ef8dSPeter Grehan 	vcpu = mtp->mt_vcpu;
197e285ef8dSPeter Grehan 
198e285ef8dSPeter Grehan 	snprintf(tname, sizeof(tname), "%s vcpu %d", vmname, vcpu);
199e285ef8dSPeter Grehan 	pthread_set_name_np(mtp->mt_thr, tname);
200e285ef8dSPeter Grehan 
201e285ef8dSPeter Grehan 	vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip);
202e285ef8dSPeter Grehan 
203e285ef8dSPeter Grehan 	/* not reached */
204e285ef8dSPeter Grehan 	exit(1);
205e285ef8dSPeter Grehan 	return (NULL);
206e285ef8dSPeter Grehan }
207e285ef8dSPeter Grehan 
208e285ef8dSPeter Grehan void
209e285ef8dSPeter Grehan fbsdrun_addcpu(struct vmctx *ctx, int vcpu, uint64_t rip)
210e285ef8dSPeter Grehan {
211e285ef8dSPeter Grehan 	int error;
212e285ef8dSPeter Grehan 
213e285ef8dSPeter Grehan 	if (cpumask & (1 << vcpu)) {
214e285ef8dSPeter Grehan 		fprintf(stderr, "addcpu: attempting to add existing cpu %d\n",
215e285ef8dSPeter Grehan 		    vcpu);
216e285ef8dSPeter Grehan 		exit(1);
217e285ef8dSPeter Grehan 	}
218e285ef8dSPeter Grehan 
219e285ef8dSPeter Grehan 	cpumask |= 1 << vcpu;
220e285ef8dSPeter Grehan 	foundcpus++;
221e285ef8dSPeter Grehan 
222e285ef8dSPeter Grehan 	/*
223e285ef8dSPeter Grehan 	 * Set up the vmexit struct to allow execution to start
224e285ef8dSPeter Grehan 	 * at the given RIP
225e285ef8dSPeter Grehan 	 */
226e285ef8dSPeter Grehan 	vmexit[vcpu].rip = rip;
227e285ef8dSPeter Grehan 	vmexit[vcpu].inst_length = 0;
228e285ef8dSPeter Grehan 
229e285ef8dSPeter Grehan 	if (vcpu == BSP || !guest_vcpu_mux){
230e285ef8dSPeter Grehan 		mt_vmm_info[vcpu].mt_ctx = ctx;
231e285ef8dSPeter Grehan 		mt_vmm_info[vcpu].mt_vcpu = vcpu;
232e285ef8dSPeter Grehan 
233e285ef8dSPeter Grehan 		error = pthread_create(&mt_vmm_info[vcpu].mt_thr, NULL,
234e285ef8dSPeter Grehan 				fbsdrun_start_thread, &mt_vmm_info[vcpu]);
235e285ef8dSPeter Grehan 		assert(error == 0);
236e285ef8dSPeter Grehan 	}
237e285ef8dSPeter Grehan }
238e285ef8dSPeter Grehan 
239e285ef8dSPeter Grehan static int
240e285ef8dSPeter Grehan fbsdrun_get_next_cpu(int curcpu)
241e285ef8dSPeter Grehan {
242e285ef8dSPeter Grehan 
243e285ef8dSPeter Grehan 	/*
244e285ef8dSPeter Grehan 	 * Get the next available CPU. Assumes they arrive
245e285ef8dSPeter Grehan 	 * in ascending order with no gaps.
246e285ef8dSPeter Grehan 	 */
247e285ef8dSPeter Grehan 	return ((curcpu + 1) % foundcpus);
248e285ef8dSPeter Grehan }
249e285ef8dSPeter Grehan 
250e285ef8dSPeter Grehan static int
251e285ef8dSPeter Grehan vmexit_catch_reset(void)
252e285ef8dSPeter Grehan {
253e285ef8dSPeter Grehan         stats.io_reset++;
254e285ef8dSPeter Grehan         return (VMEXIT_RESET);
255e285ef8dSPeter Grehan }
256e285ef8dSPeter Grehan 
257e285ef8dSPeter Grehan static int
258e285ef8dSPeter Grehan vmexit_catch_inout(void)
259e285ef8dSPeter Grehan {
260e285ef8dSPeter Grehan 	return (VMEXIT_ABORT);
261e285ef8dSPeter Grehan }
262e285ef8dSPeter Grehan 
263e285ef8dSPeter Grehan static int
264e285ef8dSPeter Grehan vmexit_handle_notify(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu,
265e285ef8dSPeter Grehan 		     uint32_t eax)
266e285ef8dSPeter Grehan {
267e285ef8dSPeter Grehan #if PG_DEBUG /* put all types of debug here */
268e285ef8dSPeter Grehan         if (eax == 0) {
269e285ef8dSPeter Grehan 		pause_noswitch = 1;
270e285ef8dSPeter Grehan 	} else if (eax == 1) {
271e285ef8dSPeter Grehan 		pause_noswitch = 0;
272e285ef8dSPeter Grehan 	} else {
273e285ef8dSPeter Grehan 		pause_noswitch = 0;
274e285ef8dSPeter Grehan 		if (eax == 5) {
275e285ef8dSPeter Grehan 			vm_set_capability(ctx, *pvcpu, VM_CAP_MTRAP_EXIT, 1);
276e285ef8dSPeter Grehan 		}
277e285ef8dSPeter Grehan 	}
278e285ef8dSPeter Grehan #endif
279e285ef8dSPeter Grehan         return (VMEXIT_CONTINUE);
280e285ef8dSPeter Grehan }
281e285ef8dSPeter Grehan 
282e285ef8dSPeter Grehan static int
283e285ef8dSPeter Grehan vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
284e285ef8dSPeter Grehan {
285e285ef8dSPeter Grehan 	int error;
286e285ef8dSPeter Grehan 	int bytes, port, in, out;
287e285ef8dSPeter Grehan 	uint32_t eax;
288e285ef8dSPeter Grehan 	int vcpu;
289e285ef8dSPeter Grehan 
290e285ef8dSPeter Grehan 	vcpu = *pvcpu;
291e285ef8dSPeter Grehan 
292e285ef8dSPeter Grehan 	port = vme->u.inout.port;
293e285ef8dSPeter Grehan 	bytes = vme->u.inout.bytes;
294e285ef8dSPeter Grehan 	eax = vme->u.inout.eax;
295e285ef8dSPeter Grehan 	in = vme->u.inout.in;
296e285ef8dSPeter Grehan 	out = !in;
297e285ef8dSPeter Grehan 
298e285ef8dSPeter Grehan 	/* We don't deal with these */
299e285ef8dSPeter Grehan 	if (vme->u.inout.string || vme->u.inout.rep)
300e285ef8dSPeter Grehan 		return (VMEXIT_ABORT);
301e285ef8dSPeter Grehan 
302e285ef8dSPeter Grehan 	/* Special case of guest reset */
303e285ef8dSPeter Grehan 	if (out && port == 0x64 && (uint8_t)eax == 0xFE)
304e285ef8dSPeter Grehan 		return (vmexit_catch_reset());
305e285ef8dSPeter Grehan 
306e285ef8dSPeter Grehan         /* Extra-special case of host notifications */
307e285ef8dSPeter Grehan         if (out && port == GUEST_NIO_PORT)
308e285ef8dSPeter Grehan                 return (vmexit_handle_notify(ctx, vme, pvcpu, eax));
309e285ef8dSPeter Grehan 
310e285ef8dSPeter Grehan 	error = emulate_inout(ctx, vcpu, in, port, bytes, &eax, strictio);
311e285ef8dSPeter Grehan 	if (error == 0 && in)
312e285ef8dSPeter Grehan 		error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, eax);
313e285ef8dSPeter Grehan 
314e285ef8dSPeter Grehan 	if (error == 0)
315e285ef8dSPeter Grehan 		return (VMEXIT_CONTINUE);
316e285ef8dSPeter Grehan 	else {
317e285ef8dSPeter Grehan 		fprintf(stderr, "Unhandled %s%c 0x%04x\n",
318e285ef8dSPeter Grehan 			in ? "in" : "out",
319e285ef8dSPeter Grehan 			bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port);
320e285ef8dSPeter Grehan 		return (vmexit_catch_inout());
321e285ef8dSPeter Grehan 	}
322e285ef8dSPeter Grehan }
323e285ef8dSPeter Grehan 
324e285ef8dSPeter Grehan static int
325e285ef8dSPeter Grehan vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
326e285ef8dSPeter Grehan {
327e285ef8dSPeter Grehan 	fprintf(stderr, "vm exit rdmsr 0x%x, cpu %d\n", vme->u.msr.code,
328e285ef8dSPeter Grehan 	    *pvcpu);
329e285ef8dSPeter Grehan 	return (VMEXIT_ABORT);
330e285ef8dSPeter Grehan }
331e285ef8dSPeter Grehan 
332e285ef8dSPeter Grehan static int
333e285ef8dSPeter Grehan vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
334e285ef8dSPeter Grehan {
335e285ef8dSPeter Grehan 	int newcpu;
336e285ef8dSPeter Grehan 	int retval = VMEXIT_CONTINUE;
337e285ef8dSPeter Grehan 
338e285ef8dSPeter Grehan 	newcpu = emulate_wrmsr(ctx, *pvcpu, vme->u.msr.code,vme->u.msr.wval);
339e285ef8dSPeter Grehan 
340e285ef8dSPeter Grehan 	if (guest_vcpu_mux && *pvcpu != newcpu) {
341e285ef8dSPeter Grehan                 retval = VMEXIT_SWITCH;
342e285ef8dSPeter Grehan                 *pvcpu = newcpu;
343e285ef8dSPeter Grehan         }
344e285ef8dSPeter Grehan 
345e285ef8dSPeter Grehan         return (retval);
346e285ef8dSPeter Grehan }
347e285ef8dSPeter Grehan 
348e285ef8dSPeter Grehan static int
349e285ef8dSPeter Grehan vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
350e285ef8dSPeter Grehan {
351e285ef8dSPeter Grehan 	int newcpu;
352e285ef8dSPeter Grehan 	int retval = VMEXIT_CONTINUE;
353e285ef8dSPeter Grehan 
354e285ef8dSPeter Grehan 	newcpu = spinup_ap(ctx, *pvcpu,
355e285ef8dSPeter Grehan 			   vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip);
356e285ef8dSPeter Grehan 
357e285ef8dSPeter Grehan 	if (guest_vcpu_mux && *pvcpu != newcpu) {
358e285ef8dSPeter Grehan 		retval = VMEXIT_SWITCH;
359e285ef8dSPeter Grehan 		*pvcpu = newcpu;
360e285ef8dSPeter Grehan 	}
361e285ef8dSPeter Grehan 
362e285ef8dSPeter Grehan 	return (retval);
363e285ef8dSPeter Grehan }
364e285ef8dSPeter Grehan 
365e285ef8dSPeter Grehan static int
366e285ef8dSPeter Grehan vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
367e285ef8dSPeter Grehan {
368e285ef8dSPeter Grehan 
369e285ef8dSPeter Grehan 	fprintf(stderr, "vm exit[%d]\n", *pvcpu);
370e285ef8dSPeter Grehan 	fprintf(stderr, "\treason\t\tVMX\n");
371e285ef8dSPeter Grehan 	fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip);
372e285ef8dSPeter Grehan 	fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length);
373e285ef8dSPeter Grehan 	fprintf(stderr, "\terror\t\t%d\n", vmexit->u.vmx.error);
374e285ef8dSPeter Grehan 	fprintf(stderr, "\texit_reason\t%u\n", vmexit->u.vmx.exit_reason);
375e285ef8dSPeter Grehan 	fprintf(stderr, "\tqualification\t0x%016lx\n",
376e285ef8dSPeter Grehan 	    vmexit->u.vmx.exit_qualification);
377e285ef8dSPeter Grehan 
378e285ef8dSPeter Grehan 	return (VMEXIT_ABORT);
379e285ef8dSPeter Grehan }
380e285ef8dSPeter Grehan 
381e285ef8dSPeter Grehan static int bogus_noswitch = 1;
382e285ef8dSPeter Grehan 
383e285ef8dSPeter Grehan static int
384e285ef8dSPeter Grehan vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
385e285ef8dSPeter Grehan {
386e285ef8dSPeter Grehan 	stats.vmexit_bogus++;
387e285ef8dSPeter Grehan 
388e285ef8dSPeter Grehan 	if (!guest_vcpu_mux || guest_ncpus == 1 || bogus_noswitch) {
389e285ef8dSPeter Grehan 		return (VMEXIT_RESTART);
390e285ef8dSPeter Grehan 	} else {
391e285ef8dSPeter Grehan 		stats.vmexit_bogus_switch++;
392e285ef8dSPeter Grehan 		vmexit->inst_length = 0;
393e285ef8dSPeter Grehan 		*pvcpu = -1;
394e285ef8dSPeter Grehan 		return (VMEXIT_SWITCH);
395e285ef8dSPeter Grehan 	}
396e285ef8dSPeter Grehan }
397e285ef8dSPeter Grehan 
398e285ef8dSPeter Grehan static int
399e285ef8dSPeter Grehan vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
400e285ef8dSPeter Grehan {
401e285ef8dSPeter Grehan 	stats.vmexit_hlt++;
402e285ef8dSPeter Grehan 	if (fbsdrun_muxed()) {
403e285ef8dSPeter Grehan 		*pvcpu = -1;
404e285ef8dSPeter Grehan 		return (VMEXIT_SWITCH);
405e285ef8dSPeter Grehan 	} else {
406e285ef8dSPeter Grehan 		/*
407e285ef8dSPeter Grehan 		 * Just continue execution with the next instruction. We use
408e285ef8dSPeter Grehan 		 * the HLT VM exit as a way to be friendly with the host
409e285ef8dSPeter Grehan 		 * scheduler.
410e285ef8dSPeter Grehan 		 */
411e285ef8dSPeter Grehan 		return (VMEXIT_CONTINUE);
412e285ef8dSPeter Grehan 	}
413e285ef8dSPeter Grehan }
414e285ef8dSPeter Grehan 
415e285ef8dSPeter Grehan static int pause_noswitch;
416e285ef8dSPeter Grehan 
417e285ef8dSPeter Grehan static int
418e285ef8dSPeter Grehan vmexit_pause(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
419e285ef8dSPeter Grehan {
420e285ef8dSPeter Grehan 	stats.vmexit_pause++;
421e285ef8dSPeter Grehan 
422e285ef8dSPeter Grehan 	if (fbsdrun_muxed() && !pause_noswitch) {
423e285ef8dSPeter Grehan 		*pvcpu = -1;
424e285ef8dSPeter Grehan 		return (VMEXIT_SWITCH);
425e285ef8dSPeter Grehan         } else {
426e285ef8dSPeter Grehan 		return (VMEXIT_CONTINUE);
427e285ef8dSPeter Grehan 	}
428e285ef8dSPeter Grehan }
429e285ef8dSPeter Grehan 
430e285ef8dSPeter Grehan static int
431e285ef8dSPeter Grehan vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
432e285ef8dSPeter Grehan {
433e285ef8dSPeter Grehan 	stats.vmexit_mtrap++;
434e285ef8dSPeter Grehan 
435e285ef8dSPeter Grehan 	return (VMEXIT_RESTART);
436e285ef8dSPeter Grehan }
437e285ef8dSPeter Grehan 
438e285ef8dSPeter Grehan static int
439e285ef8dSPeter Grehan vmexit_paging(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
440e285ef8dSPeter Grehan {
441e285ef8dSPeter Grehan 	int err;
442e285ef8dSPeter Grehan 	stats.vmexit_paging++;
443e285ef8dSPeter Grehan 
444e285ef8dSPeter Grehan 	err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa,
445e285ef8dSPeter Grehan 			  &vmexit->u.paging.vie);
446e285ef8dSPeter Grehan 
447e285ef8dSPeter Grehan 	if (err) {
448e285ef8dSPeter Grehan 		if (err == EINVAL) {
449e285ef8dSPeter Grehan 			fprintf(stderr,
450e285ef8dSPeter Grehan 			    "Failed to emulate instruction at 0x%lx\n",
451e285ef8dSPeter Grehan 			    vmexit->rip);
452e285ef8dSPeter Grehan 		} else if (err == ESRCH) {
453e285ef8dSPeter Grehan 			fprintf(stderr, "Unhandled memory access to 0x%lx\n",
454e285ef8dSPeter Grehan 			    vmexit->u.paging.gpa);
455e285ef8dSPeter Grehan 		}
456e285ef8dSPeter Grehan 
457e285ef8dSPeter Grehan 		return (VMEXIT_ABORT);
458e285ef8dSPeter Grehan 	}
459e285ef8dSPeter Grehan 
460e285ef8dSPeter Grehan 	return (VMEXIT_CONTINUE);
461e285ef8dSPeter Grehan }
462e285ef8dSPeter Grehan 
463e285ef8dSPeter Grehan static void
464e285ef8dSPeter Grehan sigalrm(int sig)
465e285ef8dSPeter Grehan {
466e285ef8dSPeter Grehan 	return;
467e285ef8dSPeter Grehan }
468e285ef8dSPeter Grehan 
469e285ef8dSPeter Grehan static void
470e285ef8dSPeter Grehan setup_timeslice(void)
471e285ef8dSPeter Grehan {
472e285ef8dSPeter Grehan 	struct sigaction sa;
473e285ef8dSPeter Grehan 	struct itimerval itv;
474e285ef8dSPeter Grehan 	int error;
475e285ef8dSPeter Grehan 
476e285ef8dSPeter Grehan 	/*
477e285ef8dSPeter Grehan 	 * Setup a realtime timer to generate a SIGALRM at a
478e285ef8dSPeter Grehan 	 * frequency of 'guest_tslice' ticks per second.
479e285ef8dSPeter Grehan 	 */
480e285ef8dSPeter Grehan 	sigemptyset(&sa.sa_mask);
481e285ef8dSPeter Grehan 	sa.sa_flags = 0;
482e285ef8dSPeter Grehan 	sa.sa_handler = sigalrm;
483e285ef8dSPeter Grehan 
484e285ef8dSPeter Grehan 	error = sigaction(SIGALRM, &sa, NULL);
485e285ef8dSPeter Grehan 	assert(error == 0);
486e285ef8dSPeter Grehan 
487e285ef8dSPeter Grehan 	itv.it_interval.tv_sec = 0;
488e285ef8dSPeter Grehan 	itv.it_interval.tv_usec = 1000000 / guest_tslice;
489e285ef8dSPeter Grehan 	itv.it_value.tv_sec = 0;
490e285ef8dSPeter Grehan 	itv.it_value.tv_usec = 1000000 / guest_tslice;
491e285ef8dSPeter Grehan 
492e285ef8dSPeter Grehan 	error = setitimer(ITIMER_REAL, &itv, NULL);
493e285ef8dSPeter Grehan 	assert(error == 0);
494e285ef8dSPeter Grehan }
495e285ef8dSPeter Grehan 
496e285ef8dSPeter Grehan static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
497e285ef8dSPeter Grehan 	[VM_EXITCODE_INOUT]  = vmexit_inout,
498e285ef8dSPeter Grehan 	[VM_EXITCODE_VMX]    = vmexit_vmx,
499e285ef8dSPeter Grehan 	[VM_EXITCODE_BOGUS]  = vmexit_bogus,
500e285ef8dSPeter Grehan 	[VM_EXITCODE_RDMSR]  = vmexit_rdmsr,
501e285ef8dSPeter Grehan 	[VM_EXITCODE_WRMSR]  = vmexit_wrmsr,
502e285ef8dSPeter Grehan 	[VM_EXITCODE_MTRAP]  = vmexit_mtrap,
503e285ef8dSPeter Grehan 	[VM_EXITCODE_PAGING] = vmexit_paging,
504e285ef8dSPeter Grehan 	[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
505e285ef8dSPeter Grehan };
506e285ef8dSPeter Grehan 
507e285ef8dSPeter Grehan static void
508e285ef8dSPeter Grehan vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
509e285ef8dSPeter Grehan {
510485b3300SNeel Natu 	cpuset_t mask;
511e285ef8dSPeter Grehan 	int error, rc, prevcpu;
512e285ef8dSPeter Grehan 
513e285ef8dSPeter Grehan 	if (guest_vcpu_mux)
514e285ef8dSPeter Grehan 		setup_timeslice();
515e285ef8dSPeter Grehan 
516e285ef8dSPeter Grehan 	if (pincpu >= 0) {
517485b3300SNeel Natu 		CPU_ZERO(&mask);
518485b3300SNeel Natu 		CPU_SET(pincpu + vcpu, &mask);
519485b3300SNeel Natu 		error = pthread_setaffinity_np(pthread_self(),
520485b3300SNeel Natu 					       sizeof(mask), &mask);
521e285ef8dSPeter Grehan 		assert(error == 0);
522e285ef8dSPeter Grehan 	}
523e285ef8dSPeter Grehan 
524e285ef8dSPeter Grehan 	while (1) {
525e285ef8dSPeter Grehan 		error = vm_run(ctx, vcpu, rip, &vmexit[vcpu]);
526e285ef8dSPeter Grehan 		if (error != 0) {
527e285ef8dSPeter Grehan 			/*
528e285ef8dSPeter Grehan 			 * It is possible that 'vmmctl' or some other process
529e285ef8dSPeter Grehan 			 * has transitioned the vcpu to CANNOT_RUN state right
530e285ef8dSPeter Grehan 			 * before we tried to transition it to RUNNING.
531e285ef8dSPeter Grehan 			 *
532e285ef8dSPeter Grehan 			 * This is expected to be temporary so just retry.
533e285ef8dSPeter Grehan 			 */
534e285ef8dSPeter Grehan 			if (errno == EBUSY)
535e285ef8dSPeter Grehan 				continue;
536e285ef8dSPeter Grehan 			else
537e285ef8dSPeter Grehan 				break;
538e285ef8dSPeter Grehan 		}
539e285ef8dSPeter Grehan 
540e285ef8dSPeter Grehan 		prevcpu = vcpu;
541e285ef8dSPeter Grehan                 rc = (*handler[vmexit[vcpu].exitcode])(ctx, &vmexit[vcpu],
542e285ef8dSPeter Grehan                                                        &vcpu);
543e285ef8dSPeter Grehan 		switch (rc) {
544e285ef8dSPeter Grehan                 case VMEXIT_SWITCH:
545e285ef8dSPeter Grehan 			assert(guest_vcpu_mux);
546e285ef8dSPeter Grehan 			if (vcpu == -1) {
547e285ef8dSPeter Grehan 				stats.cpu_switch_rotate++;
548e285ef8dSPeter Grehan 				vcpu = fbsdrun_get_next_cpu(prevcpu);
549e285ef8dSPeter Grehan 			} else {
550e285ef8dSPeter Grehan 				stats.cpu_switch_direct++;
551e285ef8dSPeter Grehan 			}
552e285ef8dSPeter Grehan 			/* fall through */
553e285ef8dSPeter Grehan 		case VMEXIT_CONTINUE:
554e285ef8dSPeter Grehan                         rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length;
555e285ef8dSPeter Grehan 			break;
556e285ef8dSPeter Grehan 		case VMEXIT_RESTART:
557e285ef8dSPeter Grehan                         rip = vmexit[vcpu].rip;
558e285ef8dSPeter Grehan 			break;
559e285ef8dSPeter Grehan 		case VMEXIT_RESET:
560e285ef8dSPeter Grehan 			exit(0);
561e285ef8dSPeter Grehan 		default:
562e285ef8dSPeter Grehan 			exit(1);
563e285ef8dSPeter Grehan 		}
564e285ef8dSPeter Grehan 	}
565e285ef8dSPeter Grehan 	fprintf(stderr, "vm_run error %d, errno %d\n", error, errno);
566e285ef8dSPeter Grehan }
567e285ef8dSPeter Grehan 
5685f0677d3SNeel Natu static int
5695f0677d3SNeel Natu num_vcpus_allowed(struct vmctx *ctx)
5705f0677d3SNeel Natu {
5715f0677d3SNeel Natu 	int tmp, error;
5725f0677d3SNeel Natu 
5735f0677d3SNeel Natu 	error = vm_get_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, &tmp);
5745f0677d3SNeel Natu 
5755f0677d3SNeel Natu 	/*
5765f0677d3SNeel Natu 	 * The guest is allowed to spinup more than one processor only if the
5775f0677d3SNeel Natu 	 * UNRESTRICTED_GUEST capability is available.
5785f0677d3SNeel Natu 	 */
5795f0677d3SNeel Natu 	if (error == 0)
5805f0677d3SNeel Natu 		return (VM_MAXCPU);
5815f0677d3SNeel Natu 	else
5825f0677d3SNeel Natu 		return (1);
5835f0677d3SNeel Natu }
584e285ef8dSPeter Grehan 
585e285ef8dSPeter Grehan int
586e285ef8dSPeter Grehan main(int argc, char *argv[])
587e285ef8dSPeter Grehan {
588e285ef8dSPeter Grehan 	int c, error, gdb_port, inject_bkpt, tmp, err, ioapic, bvmcons;
5895f0677d3SNeel Natu 	int max_vcpus;
590e285ef8dSPeter Grehan 	struct vmctx *ctx;
591e285ef8dSPeter Grehan 	uint64_t rip;
592b060ba50SNeel Natu 	size_t memsize;
593e285ef8dSPeter Grehan 
594e285ef8dSPeter Grehan 	bvmcons = 0;
595e285ef8dSPeter Grehan 	inject_bkpt = 0;
596e285ef8dSPeter Grehan 	progname = basename(argv[0]);
597e285ef8dSPeter Grehan 	gdb_port = DEFAULT_GDB_PORT;
598e285ef8dSPeter Grehan 	guest_ncpus = 1;
599e285ef8dSPeter Grehan 	ioapic = 0;
600b060ba50SNeel Natu 	memsize = 256 * MB;
601e285ef8dSPeter Grehan 
602b060ba50SNeel Natu 	while ((c = getopt(argc, argv, "abehABHIPxp:g:c:z:s:S:n:m:")) != -1) {
603e285ef8dSPeter Grehan 		switch (c) {
604e285ef8dSPeter Grehan 		case 'a':
605e285ef8dSPeter Grehan 			disable_x2apic = 1;
606e285ef8dSPeter Grehan 			break;
607e285ef8dSPeter Grehan 		case 'A':
608e285ef8dSPeter Grehan 			acpi = 1;
609e285ef8dSPeter Grehan 			break;
610e285ef8dSPeter Grehan 		case 'b':
611e285ef8dSPeter Grehan 			bvmcons = 1;
612e285ef8dSPeter Grehan 			break;
613e285ef8dSPeter Grehan 		case 'B':
614e285ef8dSPeter Grehan 			inject_bkpt = 1;
615e285ef8dSPeter Grehan 			break;
616e285ef8dSPeter Grehan 		case 'x':
617e285ef8dSPeter Grehan 			guest_vcpu_mux = 1;
618e285ef8dSPeter Grehan 			break;
619e285ef8dSPeter Grehan 		case 'p':
620e285ef8dSPeter Grehan 			pincpu = atoi(optarg);
621e285ef8dSPeter Grehan 			break;
622e285ef8dSPeter Grehan                 case 'c':
623e285ef8dSPeter Grehan 			guest_ncpus = atoi(optarg);
624e285ef8dSPeter Grehan 			break;
625e285ef8dSPeter Grehan 		case 'g':
626e285ef8dSPeter Grehan 			gdb_port = atoi(optarg);
627e285ef8dSPeter Grehan 			break;
628e285ef8dSPeter Grehan 		case 'z':
629e285ef8dSPeter Grehan 			guest_hz = atoi(optarg);
630e285ef8dSPeter Grehan 			break;
631e285ef8dSPeter Grehan 		case 't':
632e285ef8dSPeter Grehan 			guest_tslice = atoi(optarg);
633e285ef8dSPeter Grehan 			break;
634e285ef8dSPeter Grehan 		case 's':
635b05c77ffSNeel Natu 			if (pci_parse_slot(optarg, 0) != 0)
636b05c77ffSNeel Natu 				exit(1);
637b05c77ffSNeel Natu 			else
638e285ef8dSPeter Grehan 				break;
639e285ef8dSPeter Grehan 		case 'S':
640b05c77ffSNeel Natu 			if (pci_parse_slot(optarg, 1) != 0)
641b05c77ffSNeel Natu 				exit(1);
642b05c77ffSNeel Natu 			else
643e285ef8dSPeter Grehan 				break;
644e285ef8dSPeter Grehan                 case 'm':
645b060ba50SNeel Natu 			memsize = strtoul(optarg, NULL, 0) * MB;
646e285ef8dSPeter Grehan 			break;
647e285ef8dSPeter Grehan 		case 'H':
648e285ef8dSPeter Grehan 			guest_vmexit_on_hlt = 1;
649e285ef8dSPeter Grehan 			break;
650e285ef8dSPeter Grehan 		case 'I':
651e285ef8dSPeter Grehan 			ioapic = 1;
652e285ef8dSPeter Grehan 			break;
653e285ef8dSPeter Grehan 		case 'P':
654e285ef8dSPeter Grehan 			guest_vmexit_on_pause = 1;
655e285ef8dSPeter Grehan 			break;
656e285ef8dSPeter Grehan 		case 'e':
657e285ef8dSPeter Grehan 			strictio = 1;
658e285ef8dSPeter Grehan 			break;
659e285ef8dSPeter Grehan 		case 'h':
660e285ef8dSPeter Grehan 			usage(0);
661e285ef8dSPeter Grehan 		default:
662e285ef8dSPeter Grehan 			usage(1);
663e285ef8dSPeter Grehan 		}
664e285ef8dSPeter Grehan 	}
665e285ef8dSPeter Grehan 	argc -= optind;
666e285ef8dSPeter Grehan 	argv += optind;
667e285ef8dSPeter Grehan 
668e285ef8dSPeter Grehan 	if (argc != 1)
669e285ef8dSPeter Grehan 		usage(1);
670e285ef8dSPeter Grehan 
671e285ef8dSPeter Grehan 	/* No need to mux if guest is uni-processor */
672e285ef8dSPeter Grehan 	if (guest_ncpus <= 1)
673e285ef8dSPeter Grehan 		guest_vcpu_mux = 0;
674e285ef8dSPeter Grehan 
675e285ef8dSPeter Grehan 	/* vmexit on hlt if guest is muxed */
676e285ef8dSPeter Grehan 	if (guest_vcpu_mux) {
677e285ef8dSPeter Grehan 		guest_vmexit_on_hlt = 1;
678e285ef8dSPeter Grehan 		guest_vmexit_on_pause = 1;
679e285ef8dSPeter Grehan 	}
680e285ef8dSPeter Grehan 
681e285ef8dSPeter Grehan 	vmname = argv[0];
682e285ef8dSPeter Grehan 
683e285ef8dSPeter Grehan 	ctx = vm_open(vmname);
684e285ef8dSPeter Grehan 	if (ctx == NULL) {
685e285ef8dSPeter Grehan 		perror("vm_open");
686e285ef8dSPeter Grehan 		exit(1);
687e285ef8dSPeter Grehan 	}
688e285ef8dSPeter Grehan 
6895f0677d3SNeel Natu 	max_vcpus = num_vcpus_allowed(ctx);
6905f0677d3SNeel Natu 	if (guest_ncpus > max_vcpus) {
6915f0677d3SNeel Natu 		fprintf(stderr, "%d vCPUs requested but only %d available\n",
6925f0677d3SNeel Natu 			guest_ncpus, max_vcpus);
6935f0677d3SNeel Natu 		exit(1);
6945f0677d3SNeel Natu 	}
6955f0677d3SNeel Natu 
696e285ef8dSPeter Grehan 	if (fbsdrun_vmexit_on_hlt()) {
697e285ef8dSPeter Grehan 		err = vm_get_capability(ctx, BSP, VM_CAP_HALT_EXIT, &tmp);
698e285ef8dSPeter Grehan 		if (err < 0) {
699e285ef8dSPeter Grehan 			fprintf(stderr, "VM exit on HLT not supported\n");
700e285ef8dSPeter Grehan 			exit(1);
701e285ef8dSPeter Grehan 		}
702e285ef8dSPeter Grehan 		vm_set_capability(ctx, BSP, VM_CAP_HALT_EXIT, 1);
703e285ef8dSPeter Grehan 		handler[VM_EXITCODE_HLT] = vmexit_hlt;
704e285ef8dSPeter Grehan 	}
705e285ef8dSPeter Grehan 
706e285ef8dSPeter Grehan         if (fbsdrun_vmexit_on_pause()) {
707e285ef8dSPeter Grehan 		/*
708e285ef8dSPeter Grehan 		 * pause exit support required for this mode
709e285ef8dSPeter Grehan 		 */
710e285ef8dSPeter Grehan 		err = vm_get_capability(ctx, BSP, VM_CAP_PAUSE_EXIT, &tmp);
711e285ef8dSPeter Grehan 		if (err < 0) {
712e285ef8dSPeter Grehan 			fprintf(stderr,
713e285ef8dSPeter Grehan 			    "SMP mux requested, no pause support\n");
714e285ef8dSPeter Grehan 			exit(1);
715e285ef8dSPeter Grehan 		}
716e285ef8dSPeter Grehan 		vm_set_capability(ctx, BSP, VM_CAP_PAUSE_EXIT, 1);
717e285ef8dSPeter Grehan 		handler[VM_EXITCODE_PAUSE] = vmexit_pause;
718e285ef8dSPeter Grehan         }
719e285ef8dSPeter Grehan 
720e285ef8dSPeter Grehan 	if (fbsdrun_disable_x2apic())
721e285ef8dSPeter Grehan 		err = vm_set_x2apic_state(ctx, BSP, X2APIC_DISABLED);
722e285ef8dSPeter Grehan 	else
723e285ef8dSPeter Grehan 		err = vm_set_x2apic_state(ctx, BSP, X2APIC_ENABLED);
724e285ef8dSPeter Grehan 
725e285ef8dSPeter Grehan 	if (err) {
726e285ef8dSPeter Grehan 		fprintf(stderr, "Unable to set x2apic state (%d)\n", err);
727e285ef8dSPeter Grehan 		exit(1);
728e285ef8dSPeter Grehan 	}
729e285ef8dSPeter Grehan 
730b060ba50SNeel Natu 	err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
731b060ba50SNeel Natu 	if (err) {
732b060ba50SNeel Natu 		fprintf(stderr, "Unable to setup memory (%d)\n", err);
733b060ba50SNeel Natu 		exit(1);
734e285ef8dSPeter Grehan 	}
735e285ef8dSPeter Grehan 
7360e2ca4e6SNeel Natu 	init_mem();
737e285ef8dSPeter Grehan 	init_inout();
738a38e2a64SPeter Grehan 
739*9d6be09fSPeter Grehan 	rtc_init(ctx);
740*9d6be09fSPeter Grehan 
741a38e2a64SPeter Grehan 	/*
742a38e2a64SPeter Grehan 	 * Exit if a device emulation finds an error in it's initilization
743a38e2a64SPeter Grehan 	 */
744a38e2a64SPeter Grehan 	if (init_pci(ctx) != 0)
745a38e2a64SPeter Grehan 		exit(1);
746a38e2a64SPeter Grehan 
747e285ef8dSPeter Grehan 	if (ioapic)
748e285ef8dSPeter Grehan 		ioapic_init(0);
749e285ef8dSPeter Grehan 
750e285ef8dSPeter Grehan 	if (gdb_port != 0)
751e285ef8dSPeter Grehan 		init_dbgport(gdb_port);
752e285ef8dSPeter Grehan 
753e285ef8dSPeter Grehan 	if (bvmcons)
754e285ef8dSPeter Grehan 		init_bvmcons();
755e285ef8dSPeter Grehan 
756e285ef8dSPeter Grehan 	error = vm_get_register(ctx, BSP, VM_REG_GUEST_RIP, &rip);
757e285ef8dSPeter Grehan 	assert(error == 0);
758e285ef8dSPeter Grehan 
759e285ef8dSPeter Grehan 	if (inject_bkpt) {
760e285ef8dSPeter Grehan 		error = vm_inject_event(ctx, BSP, VM_HW_EXCEPTION, IDT_BP);
761e285ef8dSPeter Grehan 		assert(error == 0);
762e285ef8dSPeter Grehan 	}
763e285ef8dSPeter Grehan 
764e285ef8dSPeter Grehan 	/*
765e285ef8dSPeter Grehan 	 * build the guest tables, MP etc.
766e285ef8dSPeter Grehan 	 */
767e285ef8dSPeter Grehan 	mptable_build(ctx, guest_ncpus, ioapic);
768e285ef8dSPeter Grehan 
769e285ef8dSPeter Grehan 	if (acpi) {
770e285ef8dSPeter Grehan 		error = acpi_build(ctx, guest_ncpus, ioapic);
771e285ef8dSPeter Grehan 		assert(error == 0);
772e285ef8dSPeter Grehan 	}
773e285ef8dSPeter Grehan 
774e285ef8dSPeter Grehan 	/*
775e285ef8dSPeter Grehan 	 * Add CPU 0
776e285ef8dSPeter Grehan 	 */
777e285ef8dSPeter Grehan 	fbsdrun_addcpu(ctx, BSP, rip);
778e285ef8dSPeter Grehan 
779e285ef8dSPeter Grehan 	/*
780e285ef8dSPeter Grehan 	 * Head off to the main event dispatch loop
781e285ef8dSPeter Grehan 	 */
782e285ef8dSPeter Grehan 	mevent_dispatch();
783e285ef8dSPeter Grehan 
784e285ef8dSPeter Grehan 	exit(1);
785e285ef8dSPeter Grehan }
786