xref: /freebsd/usr.sbin/bhyve/bhyverun.c (revision 5ef0cd25c4c90e44b556e0420005e128b8fcc6e0)
1e285ef8dSPeter Grehan /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4e285ef8dSPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
5e285ef8dSPeter Grehan  * All rights reserved.
6e285ef8dSPeter Grehan  *
7e285ef8dSPeter Grehan  * Redistribution and use in source and binary forms, with or without
8e285ef8dSPeter Grehan  * modification, are permitted provided that the following conditions
9e285ef8dSPeter Grehan  * are met:
10e285ef8dSPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11e285ef8dSPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12e285ef8dSPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13e285ef8dSPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14e285ef8dSPeter Grehan  *    documentation and/or other materials provided with the distribution.
15e285ef8dSPeter Grehan  *
16e285ef8dSPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17e285ef8dSPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18e285ef8dSPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19e285ef8dSPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20e285ef8dSPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21e285ef8dSPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22e285ef8dSPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23e285ef8dSPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24e285ef8dSPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25e285ef8dSPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26e285ef8dSPeter Grehan  * SUCH DAMAGE.
27e285ef8dSPeter Grehan  */
28e285ef8dSPeter Grehan 
29e285ef8dSPeter Grehan #include <sys/types.h>
3000ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
3100ef17beSBartek Rutkowski #include <sys/capsicum.h>
3200ef17beSBartek Rutkowski #endif
33e285ef8dSPeter Grehan #include <sys/mman.h>
34483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
35483d953aSJohn Baldwin #include <sys/socket.h>
36483d953aSJohn Baldwin #include <sys/stat.h>
37483d953aSJohn Baldwin #endif
38e285ef8dSPeter Grehan #include <sys/time.h>
39483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
40483d953aSJohn Baldwin #include <sys/un.h>
41483d953aSJohn Baldwin #endif
42e285ef8dSPeter Grehan 
431c052192SNeel Natu #include <machine/atomic.h>
44e285ef8dSPeter Grehan 
4500ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
4600ef17beSBartek Rutkowski #include <capsicum_helpers.h>
4700ef17beSBartek Rutkowski #endif
48e285ef8dSPeter Grehan #include <stdio.h>
49e285ef8dSPeter Grehan #include <stdlib.h>
50b5331f4dSNeel Natu #include <string.h>
51200758f1SNeel Natu #include <err.h>
5200ef17beSBartek Rutkowski #include <errno.h>
53483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
54483d953aSJohn Baldwin #include <fcntl.h>
55483d953aSJohn Baldwin #endif
56e285ef8dSPeter Grehan #include <libgen.h>
57e285ef8dSPeter Grehan #include <unistd.h>
58e285ef8dSPeter Grehan #include <assert.h>
59e285ef8dSPeter Grehan #include <pthread.h>
60e285ef8dSPeter Grehan #include <pthread_np.h>
61200758f1SNeel Natu #include <sysexits.h>
629b1aa8d6SNeel Natu #include <stdbool.h>
6301d822d3SRodney W. Grimes #include <stdint.h>
64483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
65483d953aSJohn Baldwin #include <ucl.h>
66483d953aSJohn Baldwin #include <unistd.h>
67483d953aSJohn Baldwin 
68483d953aSJohn Baldwin #include <libxo/xo.h>
69483d953aSJohn Baldwin #endif
70e285ef8dSPeter Grehan 
71e285ef8dSPeter Grehan #include <vmmapi.h>
72e285ef8dSPeter Grehan 
73e285ef8dSPeter Grehan #include "acpi.h"
74f82af74cSMark Johnston #include "bhyverun.h"
75bb30b08eSConrad Meyer #include "bootrom.h"
76621b5090SJohn Baldwin #include "config.h"
7752c39ee6SConrad Meyer #include "debug.h"
78ca2cda98SMark Johnston #ifdef BHYVE_GDB
79cd377eb3SJohn Baldwin #include "gdb.h"
80ca2cda98SMark Johnston #endif
81e285ef8dSPeter Grehan #include "mem.h"
82e285ef8dSPeter Grehan #include "mevent.h"
83e285ef8dSPeter Grehan #include "pci_emul.h"
8455c13f6eSMark Johnston #ifdef __amd64__
8555c13f6eSMark Johnston #include "amd64/pci_lpc.h"
8655c13f6eSMark Johnston #endif
87d85147f3SCorvin Köhne #include "qemu_fwcfg.h"
88483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
89483d953aSJohn Baldwin #include "snapshot.h"
90483d953aSJohn Baldwin #endif
9167c26eb2SCorvin Köhne #include "tpm_device.h"
929cb339ccSConrad Meyer #include "vmgenc.h"
9372f9c9d8SMark Johnston #include "vmexit.h"
94e285ef8dSPeter Grehan 
95e285ef8dSPeter Grehan #define MB		(1024UL * 1024)
96e285ef8dSPeter Grehan #define GB		(1024UL * MB)
97e285ef8dSPeter Grehan 
98e285ef8dSPeter Grehan int guest_ncpus;
993b6cb9b4SMark Johnston uint16_t cpu_cores, cpu_sockets, cpu_threads;
10001d822d3SRodney W. Grimes 
101332eff95SVincenzo Maffione int raw_stdio = 0;
102332eff95SVincenzo Maffione 
103390e4498SMark Johnston #ifdef BHYVE_SNAPSHOT
104390e4498SMark Johnston char *restore_file;
105390e4498SMark Johnston #endif
106390e4498SMark Johnston 
107e285ef8dSPeter Grehan static const int BSP = 0;
108e285ef8dSPeter Grehan 
1090826d045SNeel Natu static cpuset_t cpumask;
110e285ef8dSPeter Grehan 
1117d9ef309SJohn Baldwin static void vm_loop(struct vmctx *ctx, struct vcpu *vcpu);
112e285ef8dSPeter Grehan 
1137d9ef309SJohn Baldwin static struct vcpu_info {
1147d9ef309SJohn Baldwin 	struct vmctx	*ctx;
1157d9ef309SJohn Baldwin 	struct vcpu	*vcpu;
1167d9ef309SJohn Baldwin 	int		vcpuid;
1177d9ef309SJohn Baldwin } *vcpu_info;
118e285ef8dSPeter Grehan 
1197261f821SJohn Baldwin static cpuset_t **vcpumap;
1209b6155a2SNeel Natu 
12101d822d3SRodney W. Grimes /*
12201d822d3SRodney W. Grimes  * XXX This parser is known to have the following issues:
123621b5090SJohn Baldwin  * 1.  It accepts null key=value tokens ",," as setting "cpus" to an
124621b5090SJohn Baldwin  *     empty string.
12501d822d3SRodney W. Grimes  *
12601d822d3SRodney W. Grimes  * The acceptance of a null specification ('-c ""') is by design to match the
12701d822d3SRodney W. Grimes  * manual page syntax specification, this results in a topology of 1 vCPU.
12801d822d3SRodney W. Grimes  */
129981f9f74SMark Johnston int
bhyve_topology_parse(const char * opt)130981f9f74SMark Johnston bhyve_topology_parse(const char *opt)
13101d822d3SRodney W. Grimes {
132ad3da829SAndy Fiddaman 	char *cp, *str, *tofree;
13301d822d3SRodney W. Grimes 
134621b5090SJohn Baldwin 	if (*opt == '\0') {
135621b5090SJohn Baldwin 		set_config_value("sockets", "1");
136621b5090SJohn Baldwin 		set_config_value("cores", "1");
137621b5090SJohn Baldwin 		set_config_value("threads", "1");
138621b5090SJohn Baldwin 		set_config_value("cpus", "1");
139621b5090SJohn Baldwin 		return (0);
140621b5090SJohn Baldwin 	}
141621b5090SJohn Baldwin 
142ad3da829SAndy Fiddaman 	tofree = str = strdup(opt);
143635a2c89SMarcelo Araujo 	if (str == NULL)
144621b5090SJohn Baldwin 		errx(4, "Failed to allocate memory");
14501d822d3SRodney W. Grimes 
14601d822d3SRodney W. Grimes 	while ((cp = strsep(&str, ",")) != NULL) {
147621b5090SJohn Baldwin 		if (strncmp(cp, "cpus=", strlen("cpus=")) == 0)
148621b5090SJohn Baldwin 			set_config_value("cpus", cp + strlen("cpus="));
149621b5090SJohn Baldwin 		else if (strncmp(cp, "sockets=", strlen("sockets=")) == 0)
150621b5090SJohn Baldwin 			set_config_value("sockets", cp + strlen("sockets="));
151621b5090SJohn Baldwin 		else if (strncmp(cp, "cores=", strlen("cores=")) == 0)
152621b5090SJohn Baldwin 			set_config_value("cores", cp + strlen("cores="));
153621b5090SJohn Baldwin 		else if (strncmp(cp, "threads=", strlen("threads=")) == 0)
154621b5090SJohn Baldwin 			set_config_value("threads", cp + strlen("threads="));
155621b5090SJohn Baldwin 		else if (strchr(cp, '=') != NULL)
156621b5090SJohn Baldwin 			goto out;
15701d822d3SRodney W. Grimes 		else
158621b5090SJohn Baldwin 			set_config_value("cpus", cp);
15901d822d3SRodney W. Grimes 	}
160ad3da829SAndy Fiddaman 	free(tofree);
16101d822d3SRodney W. Grimes 	return (0);
162ea089f8cSMarcelo Araujo 
163ea089f8cSMarcelo Araujo out:
164ad3da829SAndy Fiddaman 	free(tofree);
165ea089f8cSMarcelo Araujo 	return (-1);
16601d822d3SRodney W. Grimes }
16701d822d3SRodney W. Grimes 
1689b6155a2SNeel Natu static int
parse_int_value(const char * key,const char * value,int minval,int maxval)169621b5090SJohn Baldwin parse_int_value(const char *key, const char *value, int minval, int maxval)
170621b5090SJohn Baldwin {
171621b5090SJohn Baldwin 	char *cp;
172621b5090SJohn Baldwin 	long lval;
173621b5090SJohn Baldwin 
174621b5090SJohn Baldwin 	errno = 0;
175621b5090SJohn Baldwin 	lval = strtol(value, &cp, 0);
176621b5090SJohn Baldwin 	if (errno != 0 || *cp != '\0' || cp == value || lval < minval ||
177621b5090SJohn Baldwin 	    lval > maxval)
178621b5090SJohn Baldwin 		errx(4, "Invalid value for %s: '%s'", key, value);
179621b5090SJohn Baldwin 	return (lval);
180621b5090SJohn Baldwin }
181621b5090SJohn Baldwin 
182621b5090SJohn Baldwin /*
183621b5090SJohn Baldwin  * Set the sockets, cores, threads, and guest_cpus variables based on
184621b5090SJohn Baldwin  * the configured topology.
185621b5090SJohn Baldwin  *
186621b5090SJohn Baldwin  * The limits of UINT16_MAX are due to the types passed to
187621b5090SJohn Baldwin  * vm_set_topology().  vmm.ko may enforce tighter limits.
188621b5090SJohn Baldwin  */
189621b5090SJohn Baldwin static void
calc_topology(void)190e008f5beSMark Johnston calc_topology(void)
191621b5090SJohn Baldwin {
192621b5090SJohn Baldwin 	const char *value;
193621b5090SJohn Baldwin 	bool explicit_cpus;
194621b5090SJohn Baldwin 	uint64_t ncpus;
195621b5090SJohn Baldwin 
196621b5090SJohn Baldwin 	value = get_config_value("cpus");
197621b5090SJohn Baldwin 	if (value != NULL) {
198621b5090SJohn Baldwin 		guest_ncpus = parse_int_value("cpus", value, 1, UINT16_MAX);
199621b5090SJohn Baldwin 		explicit_cpus = true;
200621b5090SJohn Baldwin 	} else {
201621b5090SJohn Baldwin 		guest_ncpus = 1;
202621b5090SJohn Baldwin 		explicit_cpus = false;
203621b5090SJohn Baldwin 	}
204621b5090SJohn Baldwin 	value = get_config_value("cores");
205621b5090SJohn Baldwin 	if (value != NULL)
2063b6cb9b4SMark Johnston 		cpu_cores = parse_int_value("cores", value, 1, UINT16_MAX);
207621b5090SJohn Baldwin 	else
2083b6cb9b4SMark Johnston 		cpu_cores = 1;
209621b5090SJohn Baldwin 	value = get_config_value("threads");
210621b5090SJohn Baldwin 	if (value != NULL)
2113b6cb9b4SMark Johnston 		cpu_threads = parse_int_value("threads", value, 1, UINT16_MAX);
212621b5090SJohn Baldwin 	else
2133b6cb9b4SMark Johnston 		cpu_threads = 1;
214621b5090SJohn Baldwin 	value = get_config_value("sockets");
215621b5090SJohn Baldwin 	if (value != NULL)
2163b6cb9b4SMark Johnston 		cpu_sockets = parse_int_value("sockets", value, 1, UINT16_MAX);
217621b5090SJohn Baldwin 	else
2183b6cb9b4SMark Johnston 		cpu_sockets = guest_ncpus;
219621b5090SJohn Baldwin 
220621b5090SJohn Baldwin 	/*
221621b5090SJohn Baldwin 	 * Compute sockets * cores * threads avoiding overflow.  The
222621b5090SJohn Baldwin 	 * range check above insures these are 16 bit values.
223621b5090SJohn Baldwin 	 */
2243b6cb9b4SMark Johnston 	ncpus = (uint64_t)cpu_sockets * cpu_cores * cpu_threads;
225621b5090SJohn Baldwin 	if (ncpus > UINT16_MAX)
226621b5090SJohn Baldwin 		errx(4, "Computed number of vCPUs too high: %ju",
227621b5090SJohn Baldwin 		    (uintmax_t)ncpus);
228621b5090SJohn Baldwin 
229621b5090SJohn Baldwin 	if (explicit_cpus) {
230ed721684SMark Johnston 		if (guest_ncpus != (int)ncpus)
231621b5090SJohn Baldwin 			errx(4, "Topology (%d sockets, %d cores, %d threads) "
2323b6cb9b4SMark Johnston 			    "does not match %d vCPUs",
2333b6cb9b4SMark Johnston 			    cpu_sockets, cpu_cores, cpu_threads,
234621b5090SJohn Baldwin 			    guest_ncpus);
235621b5090SJohn Baldwin 	} else
236621b5090SJohn Baldwin 		guest_ncpus = ncpus;
237621b5090SJohn Baldwin }
238621b5090SJohn Baldwin 
239981f9f74SMark Johnston int
bhyve_pincpu_parse(const char * opt)240981f9f74SMark Johnston bhyve_pincpu_parse(const char *opt)
2419b6155a2SNeel Natu {
242621b5090SJohn Baldwin 	const char *value;
243621b5090SJohn Baldwin 	char *newval;
244621b5090SJohn Baldwin 	char key[16];
2459b6155a2SNeel Natu 	int vcpu, pcpu;
2469b6155a2SNeel Natu 
2479b6155a2SNeel Natu 	if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) {
2489b6155a2SNeel Natu 		fprintf(stderr, "invalid format: %s\n", opt);
2499b6155a2SNeel Natu 		return (-1);
2509b6155a2SNeel Natu 	}
2519b6155a2SNeel Natu 
252fd6f9294SJohn Baldwin 	if (vcpu < 0) {
253fd6f9294SJohn Baldwin 		fprintf(stderr, "invalid vcpu '%d'\n", vcpu);
2549b6155a2SNeel Natu 		return (-1);
2559b6155a2SNeel Natu 	}
2569b6155a2SNeel Natu 
2579b6155a2SNeel Natu 	if (pcpu < 0 || pcpu >= CPU_SETSIZE) {
2589b6155a2SNeel Natu 		fprintf(stderr, "hostcpu '%d' outside valid range from "
2599b6155a2SNeel Natu 		    "0 to %d\n", pcpu, CPU_SETSIZE - 1);
2609b6155a2SNeel Natu 		return (-1);
2619b6155a2SNeel Natu 	}
2629b6155a2SNeel Natu 
263621b5090SJohn Baldwin 	snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
264621b5090SJohn Baldwin 	value = get_config_value(key);
265621b5090SJohn Baldwin 
266621b5090SJohn Baldwin 	if (asprintf(&newval, "%s%s%d", value != NULL ? value : "",
267621b5090SJohn Baldwin 	    value != NULL ? "," : "", pcpu) == -1) {
268621b5090SJohn Baldwin 		perror("failed to build new cpuset string");
2699b6155a2SNeel Natu 		return (-1);
2709b6155a2SNeel Natu 	}
271621b5090SJohn Baldwin 
272621b5090SJohn Baldwin 	set_config_value(key, newval);
273621b5090SJohn Baldwin 	free(newval);
274621b5090SJohn Baldwin 	return (0);
275621b5090SJohn Baldwin }
276621b5090SJohn Baldwin 
277621b5090SJohn Baldwin static void
parse_cpuset(int vcpu,const char * list,cpuset_t * set)278621b5090SJohn Baldwin parse_cpuset(int vcpu, const char *list, cpuset_t *set)
279621b5090SJohn Baldwin {
280621b5090SJohn Baldwin 	char *cp, *token;
281621b5090SJohn Baldwin 	int pcpu, start;
282621b5090SJohn Baldwin 
283621b5090SJohn Baldwin 	CPU_ZERO(set);
284621b5090SJohn Baldwin 	start = -1;
285621b5090SJohn Baldwin 	token = __DECONST(char *, list);
286621b5090SJohn Baldwin 	for (;;) {
287621b5090SJohn Baldwin 		pcpu = strtoul(token, &cp, 0);
288621b5090SJohn Baldwin 		if (cp == token)
289621b5090SJohn Baldwin 			errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
290621b5090SJohn Baldwin 		if (pcpu < 0 || pcpu >= CPU_SETSIZE)
291621b5090SJohn Baldwin 			errx(4, "hostcpu '%d' outside valid range from 0 to %d",
292621b5090SJohn Baldwin 			    pcpu, CPU_SETSIZE - 1);
293621b5090SJohn Baldwin 		switch (*cp) {
294621b5090SJohn Baldwin 		case ',':
295621b5090SJohn Baldwin 		case '\0':
296621b5090SJohn Baldwin 			if (start >= 0) {
297621b5090SJohn Baldwin 				if (start > pcpu)
298621b5090SJohn Baldwin 					errx(4, "Invalid hostcpu range %d-%d",
299621b5090SJohn Baldwin 					    start, pcpu);
300621b5090SJohn Baldwin 				while (start < pcpu) {
30184874437SJohn Baldwin 					CPU_SET(start, set);
302621b5090SJohn Baldwin 					start++;
303621b5090SJohn Baldwin 				}
304621b5090SJohn Baldwin 				start = -1;
3059b6155a2SNeel Natu 			}
30684874437SJohn Baldwin 			CPU_SET(pcpu, set);
307621b5090SJohn Baldwin 			break;
308621b5090SJohn Baldwin 		case '-':
309621b5090SJohn Baldwin 			if (start >= 0)
310621b5090SJohn Baldwin 				errx(4, "invalid cpuset for vcpu %d: '%s'",
311621b5090SJohn Baldwin 				    vcpu, list);
312621b5090SJohn Baldwin 			start = pcpu;
313621b5090SJohn Baldwin 			break;
314621b5090SJohn Baldwin 		default:
315621b5090SJohn Baldwin 			errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
316621b5090SJohn Baldwin 		}
317621b5090SJohn Baldwin 		if (*cp == '\0')
318621b5090SJohn Baldwin 			break;
319621b5090SJohn Baldwin 		token = cp + 1;
320621b5090SJohn Baldwin 	}
321621b5090SJohn Baldwin }
322621b5090SJohn Baldwin 
323621b5090SJohn Baldwin static void
build_vcpumaps(void)324621b5090SJohn Baldwin build_vcpumaps(void)
325621b5090SJohn Baldwin {
326621b5090SJohn Baldwin 	char key[16];
327621b5090SJohn Baldwin 	const char *value;
328621b5090SJohn Baldwin 	int vcpu;
329621b5090SJohn Baldwin 
3307261f821SJohn Baldwin 	vcpumap = calloc(guest_ncpus, sizeof(*vcpumap));
331621b5090SJohn Baldwin 	for (vcpu = 0; vcpu < guest_ncpus; vcpu++) {
332621b5090SJohn Baldwin 		snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
333621b5090SJohn Baldwin 		value = get_config_value(key);
334621b5090SJohn Baldwin 		if (value == NULL)
335621b5090SJohn Baldwin 			continue;
336621b5090SJohn Baldwin 		vcpumap[vcpu] = malloc(sizeof(cpuset_t));
337621b5090SJohn Baldwin 		if (vcpumap[vcpu] == NULL)
338621b5090SJohn Baldwin 			err(4, "Failed to allocate cpuset for vcpu %d", vcpu);
339621b5090SJohn Baldwin 		parse_cpuset(vcpu, value, vcpumap[vcpu]);
340621b5090SJohn Baldwin 	}
3419b6155a2SNeel Natu }
3429b6155a2SNeel Natu 
343e285ef8dSPeter Grehan void *
paddr_guest2host(struct vmctx * ctx,uintptr_t gaddr,size_t len)344b060ba50SNeel Natu paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
345e285ef8dSPeter Grehan {
346e285ef8dSPeter Grehan 
347b060ba50SNeel Natu 	return (vm_map_gpa(ctx, gaddr, len));
348e285ef8dSPeter Grehan }
349e285ef8dSPeter Grehan 
350483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
351483d953aSJohn Baldwin uintptr_t
paddr_host2guest(struct vmctx * ctx,void * addr)352483d953aSJohn Baldwin paddr_host2guest(struct vmctx *ctx, void *addr)
353483d953aSJohn Baldwin {
354483d953aSJohn Baldwin 	return (vm_rev_map_gpa(ctx, addr));
355483d953aSJohn Baldwin }
356483d953aSJohn Baldwin #endif
357483d953aSJohn Baldwin 
358e285ef8dSPeter Grehan int
fbsdrun_virtio_msix(void)359062b878fSPeter Grehan fbsdrun_virtio_msix(void)
360062b878fSPeter Grehan {
361062b878fSPeter Grehan 
362621b5090SJohn Baldwin 	return (get_config_bool_default("virtio_msix", true));
363062b878fSPeter Grehan }
364062b878fSPeter Grehan 
36572f9c9d8SMark Johnston struct vcpu *
fbsdrun_vcpu(int vcpuid)36672f9c9d8SMark Johnston fbsdrun_vcpu(int vcpuid)
36772f9c9d8SMark Johnston {
36872f9c9d8SMark Johnston 	return (vcpu_info[vcpuid].vcpu);
36972f9c9d8SMark Johnston }
37072f9c9d8SMark Johnston 
371e285ef8dSPeter Grehan static void *
fbsdrun_start_thread(void * param)372e285ef8dSPeter Grehan fbsdrun_start_thread(void *param)
373e285ef8dSPeter Grehan {
374e285ef8dSPeter Grehan 	char tname[MAXCOMLEN + 1];
3757d9ef309SJohn Baldwin 	struct vcpu_info *vi = param;
3767d9ef309SJohn Baldwin 	int error;
377e285ef8dSPeter Grehan 
3787d9ef309SJohn Baldwin 	snprintf(tname, sizeof(tname), "vcpu %d", vi->vcpuid);
3797d9ef309SJohn Baldwin 	pthread_set_name_np(pthread_self(), tname);
380e285ef8dSPeter Grehan 
3817d9ef309SJohn Baldwin 	if (vcpumap[vi->vcpuid] != NULL) {
3827d9ef309SJohn Baldwin 		error = pthread_setaffinity_np(pthread_self(),
3837d9ef309SJohn Baldwin 		    sizeof(cpuset_t), vcpumap[vi->vcpuid]);
3847224a96aSJohn Baldwin 		assert(error == 0);
3857224a96aSJohn Baldwin 	}
3867224a96aSJohn Baldwin 
387483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
3887d9ef309SJohn Baldwin 	checkpoint_cpu_add(vi->vcpuid);
389483d953aSJohn Baldwin #endif
390ca2cda98SMark Johnston #ifdef BHYVE_GDB
3917d9ef309SJohn Baldwin 	gdb_cpu_add(vi->vcpu);
392ca2cda98SMark Johnston #endif
393cd377eb3SJohn Baldwin 
3947d9ef309SJohn Baldwin 	vm_loop(vi->ctx, vi->vcpu);
395e285ef8dSPeter Grehan 
396e285ef8dSPeter Grehan 	/* not reached */
397e285ef8dSPeter Grehan 	exit(1);
398e285ef8dSPeter Grehan 	return (NULL);
399e285ef8dSPeter Grehan }
400e285ef8dSPeter Grehan 
401e20b74daSMark Johnston void
fbsdrun_addcpu(int vcpuid)402e20b74daSMark Johnston fbsdrun_addcpu(int vcpuid)
403e285ef8dSPeter Grehan {
404e20b74daSMark Johnston 	struct vcpu_info *vi;
4057d9ef309SJohn Baldwin 	pthread_t thr;
406e285ef8dSPeter Grehan 	int error;
407e285ef8dSPeter Grehan 
408e20b74daSMark Johnston 	vi = &vcpu_info[vcpuid];
409e20b74daSMark Johnston 
4107d9ef309SJohn Baldwin 	error = vm_activate_cpu(vi->vcpu);
41168dd37f7SEnji Cooper 	if (error != 0)
4127d9ef309SJohn Baldwin 		err(EX_OSERR, "could not activate CPU %d", vi->vcpuid);
41395ebc360SNeel Natu 
414e20b74daSMark Johnston 	CPU_SET_ATOMIC(vcpuid, &cpumask);
415e285ef8dSPeter Grehan 
4164c5188bbSMark Johnston 	error = vm_suspend_cpu(vi->vcpu);
4174c5188bbSMark Johnston 	assert(error == 0);
4189cc9abf4SCorvin Köhne 
4197d9ef309SJohn Baldwin 	error = pthread_create(&thr, NULL, fbsdrun_start_thread, vi);
420e285ef8dSPeter Grehan 	assert(error == 0);
421e285ef8dSPeter Grehan }
422e285ef8dSPeter Grehan 
42372f9c9d8SMark Johnston void
fbsdrun_deletecpu(int vcpu)42465b8109bSMark Johnston fbsdrun_deletecpu(int vcpu)
4251c052192SNeel Natu {
426eb9fac0eSMark Johnston 	static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
427eb9fac0eSMark Johnston 	static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
4281c052192SNeel Natu 
429eb9fac0eSMark Johnston 	pthread_mutex_lock(&resetcpu_mtx);
4300826d045SNeel Natu 	if (!CPU_ISSET(vcpu, &cpumask)) {
431b0936440SJohn Baldwin 		EPRINTLN("Attempting to delete unknown cpu %d", vcpu);
432989e062bSMarcelo Araujo 		exit(4);
4331c052192SNeel Natu 	}
4341c052192SNeel Natu 
435eb9fac0eSMark Johnston 	CPU_CLR(vcpu, &cpumask);
436eb9fac0eSMark Johnston 
437eb9fac0eSMark Johnston 	if (vcpu != BSP) {
438eb9fac0eSMark Johnston 		pthread_cond_signal(&resetcpu_cond);
439eb9fac0eSMark Johnston 		pthread_mutex_unlock(&resetcpu_mtx);
440eb9fac0eSMark Johnston 		pthread_exit(NULL);
441eb9fac0eSMark Johnston 		/* NOTREACHED */
442eb9fac0eSMark Johnston 	}
443eb9fac0eSMark Johnston 
444eb9fac0eSMark Johnston 	while (!CPU_EMPTY(&cpumask)) {
445eb9fac0eSMark Johnston 		pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
446eb9fac0eSMark Johnston 	}
447eb9fac0eSMark Johnston 	pthread_mutex_unlock(&resetcpu_mtx);
4481c052192SNeel Natu }
4491c052192SNeel Natu 
45072f9c9d8SMark Johnston int
fbsdrun_suspendcpu(int vcpuid)45172f9c9d8SMark Johnston fbsdrun_suspendcpu(int vcpuid)
452e285ef8dSPeter Grehan {
45372f9c9d8SMark Johnston 	return (vm_suspend_cpu(vcpu_info[vcpuid].vcpu));
454e285ef8dSPeter Grehan }
455e285ef8dSPeter Grehan 
456e285ef8dSPeter Grehan static void
vm_loop(struct vmctx * ctx,struct vcpu * vcpu)4577d9ef309SJohn Baldwin vm_loop(struct vmctx *ctx, struct vcpu *vcpu)
458e285ef8dSPeter Grehan {
459a20c00c6SJohn Baldwin 	struct vm_exit vme;
460e17eca32SMark Johnston 	struct vm_run vmrun;
461cc398e21SBjoern A. Zeeb 	int error, rc;
4628b271170SPeter Grehan 	enum vm_exitcode exitcode;
463e17eca32SMark Johnston 	cpuset_t active_cpus, dmask;
464e285ef8dSPeter Grehan 
46595ebc360SNeel Natu 	error = vm_active_cpus(ctx, &active_cpus);
4667d9ef309SJohn Baldwin 	assert(CPU_ISSET(vcpu_id(vcpu), &active_cpus));
46795ebc360SNeel Natu 
468e17eca32SMark Johnston 	vmrun.vm_exit = &vme;
469e17eca32SMark Johnston 	vmrun.cpuset = &dmask;
470e17eca32SMark Johnston 	vmrun.cpusetsize = sizeof(dmask);
471e17eca32SMark Johnston 
472e285ef8dSPeter Grehan 	while (1) {
473e17eca32SMark Johnston 		error = vm_run(vcpu, &vmrun);
474f80330a8SNeel Natu 		if (error != 0)
475e285ef8dSPeter Grehan 			break;
476e285ef8dSPeter Grehan 
477a20c00c6SJohn Baldwin 		exitcode = vme.exitcode;
47872f9c9d8SMark Johnston 		if (exitcode >= VM_EXITCODE_MAX ||
47972f9c9d8SMark Johnston 		    vmexit_handlers[exitcode] == NULL) {
48072f9c9d8SMark Johnston 			warnx("vm_loop: unexpected exitcode 0x%x", exitcode);
481989e062bSMarcelo Araujo 			exit(4);
4828b271170SPeter Grehan 		}
4838b271170SPeter Grehan 
48472f9c9d8SMark Johnston 		rc = (*vmexit_handlers[exitcode])(ctx, vcpu, &vmrun);
4858b271170SPeter Grehan 
486e285ef8dSPeter Grehan 		switch (rc) {
487e285ef8dSPeter Grehan 		case VMEXIT_CONTINUE:
488e285ef8dSPeter Grehan 			break;
489ee2dbd02SNeel Natu 		case VMEXIT_ABORT:
490ee2dbd02SNeel Natu 			abort();
491e285ef8dSPeter Grehan 		default:
492989e062bSMarcelo Araujo 			exit(4);
493e285ef8dSPeter Grehan 		}
494e285ef8dSPeter Grehan 	}
495b0936440SJohn Baldwin 	EPRINTLN("vm_run error %d, errno %d", error, errno);
496e285ef8dSPeter Grehan }
497e285ef8dSPeter Grehan 
4985f0677d3SNeel Natu static int
num_vcpus_allowed(struct vmctx * ctx,struct vcpu * vcpu)4997d9ef309SJohn Baldwin num_vcpus_allowed(struct vmctx *ctx, struct vcpu *vcpu)
5005f0677d3SNeel Natu {
501c76e4b89SJohn Baldwin 	uint16_t sockets, cores, threads, maxcpus;
5025f0677d3SNeel Natu 	int tmp, error;
5035f0677d3SNeel Natu 
5045f0677d3SNeel Natu 	/*
5055f0677d3SNeel Natu 	 * The guest is allowed to spinup more than one processor only if the
5065f0677d3SNeel Natu 	 * UNRESTRICTED_GUEST capability is available.
5075f0677d3SNeel Natu 	 */
5087d9ef309SJohn Baldwin 	error = vm_get_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp);
509c76e4b89SJohn Baldwin 	if (error != 0)
510c76e4b89SJohn Baldwin 		return (1);
511c76e4b89SJohn Baldwin 
512c76e4b89SJohn Baldwin 	error = vm_get_topology(ctx, &sockets, &cores, &threads, &maxcpus);
5135f0677d3SNeel Natu 	if (error == 0)
514c76e4b89SJohn Baldwin 		return (maxcpus);
5155f0677d3SNeel Natu 	else
5165f0677d3SNeel Natu 		return (1);
5175f0677d3SNeel Natu }
518e285ef8dSPeter Grehan 
5199b1aa8d6SNeel Natu static struct vmctx *
do_open(const char * vmname)5209b1aa8d6SNeel Natu do_open(const char *vmname)
5219b1aa8d6SNeel Natu {
5229b1aa8d6SNeel Natu 	struct vmctx *ctx;
5239b1aa8d6SNeel Natu 	int error;
524*5ef0cd25SMark Johnston 	bool romboot;
5259b1aa8d6SNeel Natu 
52643caa2e8SMark Johnston 	romboot = bootrom_boot();
5279b1aa8d6SNeel Natu 
528*5ef0cd25SMark Johnston 	/*
529*5ef0cd25SMark Johnston 	 * If we don't have a boot ROM, the guest context must have been
530*5ef0cd25SMark Johnston 	 * initialized by bhyveload(8) or equivalent.
531*5ef0cd25SMark Johnston 	 */
532*5ef0cd25SMark Johnston 	ctx = vm_openf(vmname, romboot ? VMMAPI_OPEN_REINIT : 0);
5339b1aa8d6SNeel Natu 	if (ctx == NULL) {
534*5ef0cd25SMark Johnston 		if (errno != ENOENT)
535*5ef0cd25SMark Johnston 			err(4, "vm_openf");
536*5ef0cd25SMark Johnston 		if (!romboot)
537*5ef0cd25SMark Johnston 			errx(4, "no bootrom was configured");
538*5ef0cd25SMark Johnston 		ctx = vm_openf(vmname, VMMAPI_OPEN_CREATE);
539*5ef0cd25SMark Johnston 		if (ctx == NULL)
540*5ef0cd25SMark Johnston 			err(4, "vm_openf");
5419b1aa8d6SNeel Natu 	}
5429b1aa8d6SNeel Natu 
54300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
544fb7ce0a9SMark Johnston 	if (vm_limit_rights(ctx) != 0)
545fb7ce0a9SMark Johnston 		err(EX_OSERR, "vm_limit_rights");
54600ef17beSBartek Rutkowski #endif
54700ef17beSBartek Rutkowski 
548bb177010SJohn Baldwin 	error = vm_set_topology(ctx, cpu_sockets, cpu_cores, cpu_threads, 0);
54901d822d3SRodney W. Grimes 	if (error)
55001d822d3SRodney W. Grimes 		errx(EX_OSERR, "vm_set_topology");
5519b1aa8d6SNeel Natu 	return (ctx);
5529b1aa8d6SNeel Natu }
5539b1aa8d6SNeel Natu 
554981f9f74SMark Johnston bool
bhyve_parse_config_option(const char * option)555981f9f74SMark Johnston bhyve_parse_config_option(const char *option)
556621b5090SJohn Baldwin {
557621b5090SJohn Baldwin 	const char *value;
558621b5090SJohn Baldwin 	char *path;
559621b5090SJohn Baldwin 
560621b5090SJohn Baldwin 	value = strchr(option, '=');
561621b5090SJohn Baldwin 	if (value == NULL || value[1] == '\0')
562621b5090SJohn Baldwin 		return (false);
563621b5090SJohn Baldwin 	path = strndup(option, value - option);
564621b5090SJohn Baldwin 	if (path == NULL)
565621b5090SJohn Baldwin 		err(4, "Failed to allocate memory");
566621b5090SJohn Baldwin 	set_config_value(path, value + 1);
5671787871aSPierre Pronchery 	free(path);
568621b5090SJohn Baldwin 	return (true);
569621b5090SJohn Baldwin }
570621b5090SJohn Baldwin 
571981f9f74SMark Johnston void
bhyve_parse_simple_config_file(const char * path)572981f9f74SMark Johnston bhyve_parse_simple_config_file(const char *path)
573621b5090SJohn Baldwin {
574621b5090SJohn Baldwin 	FILE *fp;
575621b5090SJohn Baldwin 	char *line, *cp;
576621b5090SJohn Baldwin 	size_t linecap;
577621b5090SJohn Baldwin 	unsigned int lineno;
578621b5090SJohn Baldwin 
579621b5090SJohn Baldwin 	fp = fopen(path, "r");
580621b5090SJohn Baldwin 	if (fp == NULL)
581621b5090SJohn Baldwin 		err(4, "Failed to open configuration file %s", path);
582621b5090SJohn Baldwin 	line = NULL;
583621b5090SJohn Baldwin 	linecap = 0;
584621b5090SJohn Baldwin 	lineno = 1;
585621b5090SJohn Baldwin 	for (lineno = 1; getline(&line, &linecap, fp) > 0; lineno++) {
586621b5090SJohn Baldwin 		if (*line == '#' || *line == '\n')
587621b5090SJohn Baldwin 			continue;
588621b5090SJohn Baldwin 		cp = strchr(line, '\n');
589621b5090SJohn Baldwin 		if (cp != NULL)
590621b5090SJohn Baldwin 			*cp = '\0';
591981f9f74SMark Johnston 		if (!bhyve_parse_config_option(line))
592621b5090SJohn Baldwin 			errx(4, "%s line %u: invalid config option '%s'", path,
593621b5090SJohn Baldwin 			    lineno, line);
594621b5090SJohn Baldwin 	}
595621b5090SJohn Baldwin 	free(line);
596621b5090SJohn Baldwin 	fclose(fp);
597621b5090SJohn Baldwin }
598621b5090SJohn Baldwin 
599ca2cda98SMark Johnston #ifdef BHYVE_GDB
600981f9f74SMark Johnston void
bhyve_parse_gdb_options(const char * opt)601981f9f74SMark Johnston bhyve_parse_gdb_options(const char *opt)
6022cdff991SMariusz Zaborski {
6032cdff991SMariusz Zaborski 	const char *sport;
6042cdff991SMariusz Zaborski 	char *colon;
6052cdff991SMariusz Zaborski 
60665b8109bSMark Johnston 	if (opt[0] == 'w') {
6072cdff991SMariusz Zaborski 		set_config_bool("gdb.wait", true);
60865b8109bSMark Johnston 		opt++;
6092cdff991SMariusz Zaborski 	}
6102cdff991SMariusz Zaborski 
61165b8109bSMark Johnston 	colon = strrchr(opt, ':');
6122cdff991SMariusz Zaborski 	if (colon == NULL) {
61365b8109bSMark Johnston 		sport = opt;
6142cdff991SMariusz Zaborski 	} else {
6152cdff991SMariusz Zaborski 		*colon = '\0';
6162cdff991SMariusz Zaborski 		colon++;
6172cdff991SMariusz Zaborski 		sport = colon;
61865b8109bSMark Johnston 		set_config_value("gdb.address", opt);
6192cdff991SMariusz Zaborski 	}
6202cdff991SMariusz Zaborski 
6212cdff991SMariusz Zaborski 	set_config_value("gdb.port", sport);
6222cdff991SMariusz Zaborski }
623ca2cda98SMark Johnston #endif
6242cdff991SMariusz Zaborski 
625e285ef8dSPeter Grehan int
main(int argc,char * argv[])626e285ef8dSPeter Grehan main(int argc, char *argv[])
627e285ef8dSPeter Grehan {
628981f9f74SMark Johnston 	int error;
629621b5090SJohn Baldwin 	int max_vcpus, memflags;
6307d9ef309SJohn Baldwin 	struct vcpu *bsp;
631e285ef8dSPeter Grehan 	struct vmctx *ctx;
632b060ba50SNeel Natu 	size_t memsize;
633981f9f74SMark Johnston 	const char *value, *vmname;
634483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
635483d953aSJohn Baldwin 	struct restore_state rstate;
636483d953aSJohn Baldwin #endif
637e285ef8dSPeter Grehan 
638e20b74daSMark Johnston 	bhyve_init_config();
639981f9f74SMark Johnston 	bhyve_optparse(argc, argv);
640e285ef8dSPeter Grehan 	argc -= optind;
641e285ef8dSPeter Grehan 	argv += optind;
642e285ef8dSPeter Grehan 
643621b5090SJohn Baldwin 	if (argc > 1)
644981f9f74SMark Johnston 		bhyve_usage(1);
645483d953aSJohn Baldwin 
646621b5090SJohn Baldwin #ifdef BHYVE_SNAPSHOT
647483d953aSJohn Baldwin 	if (restore_file != NULL) {
648483d953aSJohn Baldwin 		error = load_restore_file(restore_file, &rstate);
649483d953aSJohn Baldwin 		if (error) {
650483d953aSJohn Baldwin 			fprintf(stderr, "Failed to read checkpoint info from "
651483d953aSJohn Baldwin 					"file: '%s'.\n", restore_file);
652483d953aSJohn Baldwin 			exit(1);
653483d953aSJohn Baldwin 		}
654483d953aSJohn Baldwin 		vmname = lookup_vmname(&rstate);
655621b5090SJohn Baldwin 		if (vmname != NULL)
656621b5090SJohn Baldwin 			set_config_value("name", vmname);
657483d953aSJohn Baldwin 	}
658621b5090SJohn Baldwin #endif
659621b5090SJohn Baldwin 
660621b5090SJohn Baldwin 	if (argc == 1)
661621b5090SJohn Baldwin 		set_config_value("name", argv[0]);
662621b5090SJohn Baldwin 
663621b5090SJohn Baldwin 	vmname = get_config_value("name");
664621b5090SJohn Baldwin 	if (vmname == NULL)
665981f9f74SMark Johnston 		bhyve_usage(1);
666e285ef8dSPeter Grehan 
667621b5090SJohn Baldwin 	if (get_config_bool_default("config.dump", false)) {
668621b5090SJohn Baldwin 		dump_config();
669621b5090SJohn Baldwin 		exit(1);
670621b5090SJohn Baldwin 	}
671621b5090SJohn Baldwin 
672e008f5beSMark Johnston 	calc_topology();
673621b5090SJohn Baldwin 	build_vcpumaps();
674621b5090SJohn Baldwin 
675621b5090SJohn Baldwin 	value = get_config_value("memory.size");
676621b5090SJohn Baldwin 	error = vm_parse_memsize(value, &memsize);
677621b5090SJohn Baldwin 	if (error)
678621b5090SJohn Baldwin 		errx(EX_USAGE, "invalid memsize '%s'", value);
679621b5090SJohn Baldwin 
6809b1aa8d6SNeel Natu 	ctx = do_open(vmname);
681e285ef8dSPeter Grehan 
682483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
683483d953aSJohn Baldwin 	if (restore_file != NULL) {
684483d953aSJohn Baldwin 		guest_ncpus = lookup_guest_ncpus(&rstate);
685483d953aSJohn Baldwin 		memflags = lookup_memflags(&rstate);
686483d953aSJohn Baldwin 		memsize = lookup_memsize(&rstate);
687483d953aSJohn Baldwin 	}
688483d953aSJohn Baldwin 
689483d953aSJohn Baldwin 	if (guest_ncpus < 1) {
690483d953aSJohn Baldwin 		fprintf(stderr, "Invalid guest vCPUs (%d)\n", guest_ncpus);
691483d953aSJohn Baldwin 		exit(1);
692483d953aSJohn Baldwin 	}
693483d953aSJohn Baldwin #endif
694483d953aSJohn Baldwin 
6957d9ef309SJohn Baldwin 	bsp = vm_vcpu_open(ctx, BSP);
6967d9ef309SJohn Baldwin 	max_vcpus = num_vcpus_allowed(ctx, bsp);
6975f0677d3SNeel Natu 	if (guest_ncpus > max_vcpus) {
6985f0677d3SNeel Natu 		fprintf(stderr, "%d vCPUs requested but only %d available\n",
6995f0677d3SNeel Natu 			guest_ncpus, max_vcpus);
700989e062bSMarcelo Araujo 		exit(4);
7015f0677d3SNeel Natu 	}
7025f0677d3SNeel Natu 
703e20b74daSMark Johnston 	bhyve_init_vcpu(bsp);
7047d9ef309SJohn Baldwin 
7057d9ef309SJohn Baldwin 	/* Allocate per-VCPU resources. */
7067d9ef309SJohn Baldwin 	vcpu_info = calloc(guest_ncpus, sizeof(*vcpu_info));
7077d9ef309SJohn Baldwin 	for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++) {
7087d9ef309SJohn Baldwin 		vcpu_info[vcpuid].ctx = ctx;
7097d9ef309SJohn Baldwin 		vcpu_info[vcpuid].vcpuid = vcpuid;
7107d9ef309SJohn Baldwin 		if (vcpuid == BSP)
7117d9ef309SJohn Baldwin 			vcpu_info[vcpuid].vcpu = bsp;
7127d9ef309SJohn Baldwin 		else
7137d9ef309SJohn Baldwin 			vcpu_info[vcpuid].vcpu = vm_vcpu_open(ctx, vcpuid);
7147d9ef309SJohn Baldwin 	}
715e285ef8dSPeter Grehan 
716621b5090SJohn Baldwin 	memflags = 0;
717621b5090SJohn Baldwin 	if (get_config_bool_default("memory.wired", false))
718621b5090SJohn Baldwin 		memflags |= VM_MEM_F_WIRED;
719621b5090SJohn Baldwin 	if (get_config_bool_default("memory.guest_in_core", false))
720621b5090SJohn Baldwin 		memflags |= VM_MEM_F_INCORE;
7219b1aa8d6SNeel Natu 	vm_set_memflags(ctx, memflags);
722956171d5SVitaliy Gusev 	error = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
723956171d5SVitaliy Gusev 	if (error) {
7249b1aa8d6SNeel Natu 		fprintf(stderr, "Unable to setup memory (%d)\n", errno);
725989e062bSMarcelo Araujo 		exit(4);
726e285ef8dSPeter Grehan 	}
727e285ef8dSPeter Grehan 
728730510dcSJohn Baldwin 	init_mem(guest_ncpus);
729bb30b08eSConrad Meyer 	init_bootrom(ctx);
730f82af74cSMark Johnston 	if (bhyve_init_platform(ctx, bsp) != 0)
731f82af74cSMark Johnston 		exit(4);
7329d6be09fSPeter Grehan 
733d85147f3SCorvin Köhne 	if (qemu_fwcfg_init(ctx) != 0) {
734b0936440SJohn Baldwin 		fprintf(stderr, "qemu fwcfg initialization error\n");
735d85147f3SCorvin Köhne 		exit(4);
736d85147f3SCorvin Köhne 	}
737d85147f3SCorvin Köhne 
738d85147f3SCorvin Köhne 	if (qemu_fwcfg_add_file("opt/bhyve/hw.ncpu", sizeof(guest_ncpus),
739d85147f3SCorvin Köhne 	    &guest_ncpus) != 0) {
740b0936440SJohn Baldwin 		fprintf(stderr, "Could not add qemu fwcfg opt/bhyve/hw.ncpu\n");
741d85147f3SCorvin Köhne 		exit(4);
742d85147f3SCorvin Köhne 	}
743d85147f3SCorvin Köhne 
744a38e2a64SPeter Grehan 	/*
7450dc159ceSElyes Haouas 	 * Exit if a device emulation finds an error in its initialization
746a38e2a64SPeter Grehan 	 */
747989e062bSMarcelo Araujo 	if (init_pci(ctx) != 0) {
748b0936440SJohn Baldwin 		EPRINTLN("Device emulation initialization error: %s",
749b0936440SJohn Baldwin 		    strerror(errno));
750989e062bSMarcelo Araujo 		exit(4);
751989e062bSMarcelo Araujo 	}
75267c26eb2SCorvin Köhne 	if (init_tpm(ctx) != 0) {
753b0936440SJohn Baldwin 		EPRINTLN("Failed to init TPM device");
75467c26eb2SCorvin Köhne 		exit(4);
75567c26eb2SCorvin Köhne 	}
756a38e2a64SPeter Grehan 
7579cb339ccSConrad Meyer 	/*
7589cb339ccSConrad Meyer 	 * Initialize after PCI, to allow a bootrom file to reserve the high
7599cb339ccSConrad Meyer 	 * region.
7609cb339ccSConrad Meyer 	 */
761621b5090SJohn Baldwin 	if (get_config_bool("acpi_tables"))
7629cb339ccSConrad Meyer 		vmgenc_init(ctx);
7639cb339ccSConrad Meyer 
764ca2cda98SMark Johnston #ifdef BHYVE_GDB
7652cdff991SMariusz Zaborski 	init_gdb(ctx);
766ca2cda98SMark Johnston #endif
767e285ef8dSPeter Grehan 
7689ff3e8b7SVitaliy Gusev 	/*
7699ff3e8b7SVitaliy Gusev 	 * Add all vCPUs.
7709ff3e8b7SVitaliy Gusev 	 */
7717d9ef309SJohn Baldwin 	for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++)
772e20b74daSMark Johnston 		bhyve_start_vcpu(vcpu_info[vcpuid].vcpu, vcpuid == BSP);
7739ff3e8b7SVitaliy Gusev 
774483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
7751e8d0c6cSCorvin Köhne 	if (restore_file != NULL) {
776b0936440SJohn Baldwin 		FPRINTLN(stdout, "Pausing pci devs...");
777b10d65a4SVitaliy Gusev 		if (vm_pause_devices() != 0) {
778b0936440SJohn Baldwin 			EPRINTLN("Failed to pause PCI device state.");
779483d953aSJohn Baldwin 			exit(1);
780483d953aSJohn Baldwin 		}
781483d953aSJohn Baldwin 
782b0936440SJohn Baldwin 		FPRINTLN(stdout, "Restoring vm mem...");
783483d953aSJohn Baldwin 		if (restore_vm_mem(ctx, &rstate) != 0) {
784b0936440SJohn Baldwin 			EPRINTLN("Failed to restore VM memory.");
785483d953aSJohn Baldwin 			exit(1);
786483d953aSJohn Baldwin 		}
787483d953aSJohn Baldwin 
788b0936440SJohn Baldwin 		FPRINTLN(stdout, "Restoring pci devs...");
789b10d65a4SVitaliy Gusev 		if (vm_restore_devices(&rstate) != 0) {
790b0936440SJohn Baldwin 			EPRINTLN("Failed to restore PCI device state.");
791483d953aSJohn Baldwin 			exit(1);
792483d953aSJohn Baldwin 		}
793483d953aSJohn Baldwin 
794b0936440SJohn Baldwin 		FPRINTLN(stdout, "Restoring kernel structs...");
795483d953aSJohn Baldwin 		if (vm_restore_kern_structs(ctx, &rstate) != 0) {
796b0936440SJohn Baldwin 			EPRINTLN("Failed to restore kernel structs.");
797483d953aSJohn Baldwin 			exit(1);
798483d953aSJohn Baldwin 		}
799483d953aSJohn Baldwin 
800b0936440SJohn Baldwin 		FPRINTLN(stdout, "Resuming pci devs...");
801b10d65a4SVitaliy Gusev 		if (vm_resume_devices() != 0) {
802b0936440SJohn Baldwin 			EPRINTLN("Failed to resume PCI device state.");
803483d953aSJohn Baldwin 			exit(1);
804483d953aSJohn Baldwin 		}
805483d953aSJohn Baldwin 	}
8061e8d0c6cSCorvin Köhne #endif
807483d953aSJohn Baldwin 
808f82af74cSMark Johnston 	if (bhyve_init_platform_late(ctx, bsp) != 0)
809989e062bSMarcelo Araujo 		exit(4);
81088ac6958SPeter Grehan 
811dcbebe85SMariusz Zaborski 	/*
812dcbebe85SMariusz Zaborski 	 * Change the proc title to include the VM name.
813dcbebe85SMariusz Zaborski 	 */
814dcbebe85SMariusz Zaborski 	setproctitle("%s", vmname);
815dcbebe85SMariusz Zaborski 
8169a9a2489SVitaliy Gusev #ifdef BHYVE_SNAPSHOT
8179a9a2489SVitaliy Gusev 	/*
8189a9a2489SVitaliy Gusev 	 * checkpointing thread for communication with bhyvectl
8199a9a2489SVitaliy Gusev 	 */
8209a9a2489SVitaliy Gusev 	if (init_checkpoint_thread(ctx) != 0)
8219a9a2489SVitaliy Gusev 		errx(EX_OSERR, "Failed to start checkpoint thread");
8229a9a2489SVitaliy Gusev #endif
8239a9a2489SVitaliy Gusev 
82400ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
82500ef17beSBartek Rutkowski 	caph_cache_catpages();
82600ef17beSBartek Rutkowski 
82700ef17beSBartek Rutkowski 	if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1)
82800ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
82900ef17beSBartek Rutkowski 
8307672a014SMariusz Zaborski 	if (caph_enter() == -1)
83100ef17beSBartek Rutkowski 		errx(EX_OSERR, "cap_enter() failed");
83200ef17beSBartek Rutkowski #endif
83300ef17beSBartek Rutkowski 
834483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
8351e8d0c6cSCorvin Köhne 	if (restore_file != NULL) {
8369ff3e8b7SVitaliy Gusev 		destroy_restore_state(&rstate);
837d213429eSVitaliy Gusev 		if (vm_restore_time(ctx) < 0)
838d213429eSVitaliy Gusev 			err(EX_OSERR, "Unable to restore time");
839483d953aSJohn Baldwin 
8407d9ef309SJohn Baldwin 		for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++)
8417d9ef309SJohn Baldwin 			vm_resume_cpu(vcpu_info[vcpuid].vcpu);
8427d9ef309SJohn Baldwin 	} else
8439ff3e8b7SVitaliy Gusev #endif
8447d9ef309SJohn Baldwin 		vm_resume_cpu(bsp);
845483d953aSJohn Baldwin 
846e285ef8dSPeter Grehan 	/*
847e285ef8dSPeter Grehan 	 * Head off to the main event dispatch loop
848e285ef8dSPeter Grehan 	 */
849e285ef8dSPeter Grehan 	mevent_dispatch();
850e285ef8dSPeter Grehan 
851989e062bSMarcelo Araujo 	exit(4);
852e285ef8dSPeter Grehan }
853