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