]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/bhyverun.c
bhyve: Move legacy PCI interrupt handling under amd64/
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / bhyverun.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2011 NetApp, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
31 #ifndef WITHOUT_CAPSICUM
32 #include <sys/capsicum.h>
33 #endif
34 #include <sys/mman.h>
35 #ifdef BHYVE_SNAPSHOT
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #endif
39 #include <sys/time.h>
40 #ifdef BHYVE_SNAPSHOT
41 #include <sys/un.h>
42 #endif
43
44 #include <machine/atomic.h>
45
46 #ifndef WITHOUT_CAPSICUM
47 #include <capsicum_helpers.h>
48 #endif
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <err.h>
53 #include <errno.h>
54 #ifdef BHYVE_SNAPSHOT
55 #include <fcntl.h>
56 #endif
57 #include <libgen.h>
58 #include <unistd.h>
59 #include <assert.h>
60 #include <pthread.h>
61 #include <pthread_np.h>
62 #include <sysexits.h>
63 #include <stdbool.h>
64 #include <stdint.h>
65 #ifdef BHYVE_SNAPSHOT
66 #include <ucl.h>
67 #include <unistd.h>
68
69 #include <libxo/xo.h>
70 #endif
71
72 #include <vmmapi.h>
73
74 #include "bhyverun.h"
75 #include "acpi.h"
76 #ifdef __amd64__
77 #include "amd64/atkbdc.h"
78 #endif
79 #include "bootrom.h"
80 #include "config.h"
81 #include "inout.h"
82 #include "debug.h"
83 #ifdef __amd64__
84 #include "amd64/e820.h"
85 #include "amd64/fwctl.h"
86 #endif
87 #include "gdb.h"
88 #ifdef __amd64__
89 #include "amd64/ioapic.h"
90 #include "amd64/kernemu_dev.h"
91 #endif
92 #include "mem.h"
93 #include "mevent.h"
94 #ifdef __amd64__
95 #include "amd64/mptbl.h"
96 #endif
97 #include "pci_emul.h"
98 #ifdef __amd64__
99 #include "amd64/pci_irq.h"
100 #include "amd64/pci_lpc.h"
101 #endif
102 #include "qemu_fwcfg.h"
103 #include "smbiostbl.h"
104 #ifdef BHYVE_SNAPSHOT
105 #include "snapshot.h"
106 #endif
107 #include "tpm_device.h"
108 #ifdef __amd64__
109 #include "amd64/rtc.h"
110 #endif
111 #include "vmgenc.h"
112 #include "vmexit.h"
113 #ifdef __amd64__
114 #include "amd64/xmsr.h"
115 #endif
116
117 #define MB              (1024UL * 1024)
118 #define GB              (1024UL * MB)
119
120 int guest_ncpus;
121 uint16_t cpu_cores, cpu_sockets, cpu_threads;
122
123 int raw_stdio = 0;
124
125 static char *progname;
126 static const int BSP = 0;
127
128 static cpuset_t cpumask;
129
130 static void vm_loop(struct vmctx *ctx, struct vcpu *vcpu);
131
132 static struct vcpu_info {
133         struct vmctx    *ctx;
134         struct vcpu     *vcpu;
135         int             vcpuid;
136 } *vcpu_info;
137
138 static cpuset_t **vcpumap;
139
140 static void
141 usage(int code)
142 {
143
144         fprintf(stderr,
145                 "Usage: %s [-AaCDeHhPSuWwxY]\n"
146                 "       %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
147                 "       %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n"
148                 "       %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
149                 "       -A: create ACPI tables\n"
150                 "       -a: local apic is in xAPIC mode (deprecated)\n"
151                 "       -C: include guest memory in core file\n"
152                 "       -c: number of CPUs and/or topology specification\n"
153                 "       -D: destroy on power-off\n"
154                 "       -e: exit on unhandled I/O access\n"
155                 "       -G: start a debug server\n"
156                 "       -H: vmexit from the guest on HLT\n"
157                 "       -h: help\n"
158                 "       -k: key=value flat config file\n"
159                 "       -K: PS2 keyboard layout\n"
160                 "       -l: LPC device configuration\n"
161                 "       -m: memory size\n"
162                 "       -o: set config 'var' to 'value'\n"
163                 "       -P: vmexit from the guest on pause\n"
164                 "       -p: pin 'vcpu' to 'hostcpu'\n"
165 #ifdef BHYVE_SNAPSHOT
166                 "       -r: path to checkpoint file\n"
167 #endif
168                 "       -S: guest memory cannot be swapped\n"
169                 "       -s: <slot,driver,configinfo> PCI slot config\n"
170                 "       -U: UUID\n"
171                 "       -u: RTC keeps UTC time\n"
172                 "       -W: force virtio to use single-vector MSI\n"
173                 "       -w: ignore unimplemented MSRs\n"
174                 "       -x: local APIC is in x2APIC mode\n"
175                 "       -Y: disable MPtable generation\n",
176                 progname, (int)strlen(progname), "", (int)strlen(progname), "",
177                 (int)strlen(progname), "");
178
179         exit(code);
180 }
181
182 /*
183  * XXX This parser is known to have the following issues:
184  * 1.  It accepts null key=value tokens ",," as setting "cpus" to an
185  *     empty string.
186  *
187  * The acceptance of a null specification ('-c ""') is by design to match the
188  * manual page syntax specification, this results in a topology of 1 vCPU.
189  */
190 static int
191 topology_parse(const char *opt)
192 {
193         char *cp, *str, *tofree;
194
195         if (*opt == '\0') {
196                 set_config_value("sockets", "1");
197                 set_config_value("cores", "1");
198                 set_config_value("threads", "1");
199                 set_config_value("cpus", "1");
200                 return (0);
201         }
202
203         tofree = str = strdup(opt);
204         if (str == NULL)
205                 errx(4, "Failed to allocate memory");
206
207         while ((cp = strsep(&str, ",")) != NULL) {
208                 if (strncmp(cp, "cpus=", strlen("cpus=")) == 0)
209                         set_config_value("cpus", cp + strlen("cpus="));
210                 else if (strncmp(cp, "sockets=", strlen("sockets=")) == 0)
211                         set_config_value("sockets", cp + strlen("sockets="));
212                 else if (strncmp(cp, "cores=", strlen("cores=")) == 0)
213                         set_config_value("cores", cp + strlen("cores="));
214                 else if (strncmp(cp, "threads=", strlen("threads=")) == 0)
215                         set_config_value("threads", cp + strlen("threads="));
216                 else if (strchr(cp, '=') != NULL)
217                         goto out;
218                 else
219                         set_config_value("cpus", cp);
220         }
221         free(tofree);
222         return (0);
223
224 out:
225         free(tofree);
226         return (-1);
227 }
228
229 static int
230 parse_int_value(const char *key, const char *value, int minval, int maxval)
231 {
232         char *cp;
233         long lval;
234
235         errno = 0;
236         lval = strtol(value, &cp, 0);
237         if (errno != 0 || *cp != '\0' || cp == value || lval < minval ||
238             lval > maxval)
239                 errx(4, "Invalid value for %s: '%s'", key, value);
240         return (lval);
241 }
242
243 /*
244  * Set the sockets, cores, threads, and guest_cpus variables based on
245  * the configured topology.
246  *
247  * The limits of UINT16_MAX are due to the types passed to
248  * vm_set_topology().  vmm.ko may enforce tighter limits.
249  */
250 static void
251 calc_topology(void)
252 {
253         const char *value;
254         bool explicit_cpus;
255         uint64_t ncpus;
256
257         value = get_config_value("cpus");
258         if (value != NULL) {
259                 guest_ncpus = parse_int_value("cpus", value, 1, UINT16_MAX);
260                 explicit_cpus = true;
261         } else {
262                 guest_ncpus = 1;
263                 explicit_cpus = false;
264         }
265         value = get_config_value("cores");
266         if (value != NULL)
267                 cpu_cores = parse_int_value("cores", value, 1, UINT16_MAX);
268         else
269                 cpu_cores = 1;
270         value = get_config_value("threads");
271         if (value != NULL)
272                 cpu_threads = parse_int_value("threads", value, 1, UINT16_MAX);
273         else
274                 cpu_threads = 1;
275         value = get_config_value("sockets");
276         if (value != NULL)
277                 cpu_sockets = parse_int_value("sockets", value, 1, UINT16_MAX);
278         else
279                 cpu_sockets = guest_ncpus;
280
281         /*
282          * Compute sockets * cores * threads avoiding overflow.  The
283          * range check above insures these are 16 bit values.
284          */
285         ncpus = (uint64_t)cpu_sockets * cpu_cores * cpu_threads;
286         if (ncpus > UINT16_MAX)
287                 errx(4, "Computed number of vCPUs too high: %ju",
288                     (uintmax_t)ncpus);
289
290         if (explicit_cpus) {
291                 if (guest_ncpus != (int)ncpus)
292                         errx(4, "Topology (%d sockets, %d cores, %d threads) "
293                             "does not match %d vCPUs",
294                             cpu_sockets, cpu_cores, cpu_threads,
295                             guest_ncpus);
296         } else
297                 guest_ncpus = ncpus;
298 }
299
300 static int
301 pincpu_parse(const char *opt)
302 {
303         const char *value;
304         char *newval;
305         char key[16];
306         int vcpu, pcpu;
307
308         if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) {
309                 fprintf(stderr, "invalid format: %s\n", opt);
310                 return (-1);
311         }
312
313         if (vcpu < 0) {
314                 fprintf(stderr, "invalid vcpu '%d'\n", vcpu);
315                 return (-1);
316         }
317
318         if (pcpu < 0 || pcpu >= CPU_SETSIZE) {
319                 fprintf(stderr, "hostcpu '%d' outside valid range from "
320                     "0 to %d\n", pcpu, CPU_SETSIZE - 1);
321                 return (-1);
322         }
323
324         snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
325         value = get_config_value(key);
326
327         if (asprintf(&newval, "%s%s%d", value != NULL ? value : "",
328             value != NULL ? "," : "", pcpu) == -1) {
329                 perror("failed to build new cpuset string");
330                 return (-1);
331         }
332
333         set_config_value(key, newval);
334         free(newval);
335         return (0);
336 }
337
338 static void
339 parse_cpuset(int vcpu, const char *list, cpuset_t *set)
340 {
341         char *cp, *token;
342         int pcpu, start;
343
344         CPU_ZERO(set);
345         start = -1;
346         token = __DECONST(char *, list);
347         for (;;) {
348                 pcpu = strtoul(token, &cp, 0);
349                 if (cp == token)
350                         errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
351                 if (pcpu < 0 || pcpu >= CPU_SETSIZE)
352                         errx(4, "hostcpu '%d' outside valid range from 0 to %d",
353                             pcpu, CPU_SETSIZE - 1);
354                 switch (*cp) {
355                 case ',':
356                 case '\0':
357                         if (start >= 0) {
358                                 if (start > pcpu)
359                                         errx(4, "Invalid hostcpu range %d-%d",
360                                             start, pcpu);
361                                 while (start < pcpu) {
362                                         CPU_SET(start, set);
363                                         start++;
364                                 }
365                                 start = -1;
366                         }
367                         CPU_SET(pcpu, set);
368                         break;
369                 case '-':
370                         if (start >= 0)
371                                 errx(4, "invalid cpuset for vcpu %d: '%s'",
372                                     vcpu, list);
373                         start = pcpu;
374                         break;
375                 default:
376                         errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
377                 }
378                 if (*cp == '\0')
379                         break;
380                 token = cp + 1;
381         }
382 }
383
384 static void
385 build_vcpumaps(void)
386 {
387         char key[16];
388         const char *value;
389         int vcpu;
390
391         vcpumap = calloc(guest_ncpus, sizeof(*vcpumap));
392         for (vcpu = 0; vcpu < guest_ncpus; vcpu++) {
393                 snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
394                 value = get_config_value(key);
395                 if (value == NULL)
396                         continue;
397                 vcpumap[vcpu] = malloc(sizeof(cpuset_t));
398                 if (vcpumap[vcpu] == NULL)
399                         err(4, "Failed to allocate cpuset for vcpu %d", vcpu);
400                 parse_cpuset(vcpu, value, vcpumap[vcpu]);
401         }
402 }
403
404 void
405 vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid,
406     int errcode)
407 {
408         int error, restart_instruction;
409
410         restart_instruction = 1;
411
412         error = vm_inject_exception(vcpu, vector, errcode_valid, errcode,
413             restart_instruction);
414         assert(error == 0);
415 }
416
417 void *
418 paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
419 {
420
421         return (vm_map_gpa(ctx, gaddr, len));
422 }
423
424 #ifdef BHYVE_SNAPSHOT
425 uintptr_t
426 paddr_host2guest(struct vmctx *ctx, void *addr)
427 {
428         return (vm_rev_map_gpa(ctx, addr));
429 }
430 #endif
431
432 int
433 fbsdrun_virtio_msix(void)
434 {
435
436         return (get_config_bool_default("virtio_msix", true));
437 }
438
439 struct vcpu *
440 fbsdrun_vcpu(int vcpuid)
441 {
442         return (vcpu_info[vcpuid].vcpu);
443 }
444
445 static void *
446 fbsdrun_start_thread(void *param)
447 {
448         char tname[MAXCOMLEN + 1];
449         struct vcpu_info *vi = param;
450         int error;
451
452         snprintf(tname, sizeof(tname), "vcpu %d", vi->vcpuid);
453         pthread_set_name_np(pthread_self(), tname);
454
455         if (vcpumap[vi->vcpuid] != NULL) {
456                 error = pthread_setaffinity_np(pthread_self(),
457                     sizeof(cpuset_t), vcpumap[vi->vcpuid]);
458                 assert(error == 0);
459         }
460
461 #ifdef BHYVE_SNAPSHOT
462         checkpoint_cpu_add(vi->vcpuid);
463 #endif
464         gdb_cpu_add(vi->vcpu);
465
466         vm_loop(vi->ctx, vi->vcpu);
467
468         /* not reached */
469         exit(1);
470         return (NULL);
471 }
472
473 static void
474 fbsdrun_addcpu(struct vcpu_info *vi)
475 {
476         pthread_t thr;
477         int error;
478
479         error = vm_activate_cpu(vi->vcpu);
480         if (error != 0)
481                 err(EX_OSERR, "could not activate CPU %d", vi->vcpuid);
482
483         CPU_SET_ATOMIC(vi->vcpuid, &cpumask);
484
485         vm_suspend_cpu(vi->vcpu);
486
487         error = pthread_create(&thr, NULL, fbsdrun_start_thread, vi);
488         assert(error == 0);
489 }
490
491 void
492 fbsdrun_deletecpu(int vcpu)
493 {
494         static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
495         static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
496
497         pthread_mutex_lock(&resetcpu_mtx);
498         if (!CPU_ISSET(vcpu, &cpumask)) {
499                 fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu);
500                 exit(4);
501         }
502
503         CPU_CLR(vcpu, &cpumask);
504
505         if (vcpu != BSP) {
506                 pthread_cond_signal(&resetcpu_cond);
507                 pthread_mutex_unlock(&resetcpu_mtx);
508                 pthread_exit(NULL);
509                 /* NOTREACHED */
510         }
511
512         while (!CPU_EMPTY(&cpumask)) {
513                 pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
514         }
515         pthread_mutex_unlock(&resetcpu_mtx);
516 }
517
518 int
519 fbsdrun_suspendcpu(int vcpuid)
520 {
521         return (vm_suspend_cpu(vcpu_info[vcpuid].vcpu));
522 }
523
524 static void
525 vm_loop(struct vmctx *ctx, struct vcpu *vcpu)
526 {
527         struct vm_exit vme;
528         struct vm_run vmrun;
529         int error, rc;
530         enum vm_exitcode exitcode;
531         cpuset_t active_cpus, dmask;
532
533         error = vm_active_cpus(ctx, &active_cpus);
534         assert(CPU_ISSET(vcpu_id(vcpu), &active_cpus));
535
536         vmrun.vm_exit = &vme;
537         vmrun.cpuset = &dmask;
538         vmrun.cpusetsize = sizeof(dmask);
539
540         while (1) {
541                 error = vm_run(vcpu, &vmrun);
542                 if (error != 0)
543                         break;
544
545                 exitcode = vme.exitcode;
546                 if (exitcode >= VM_EXITCODE_MAX ||
547                     vmexit_handlers[exitcode] == NULL) {
548                         warnx("vm_loop: unexpected exitcode 0x%x", exitcode);
549                         exit(4);
550                 }
551
552                 rc = (*vmexit_handlers[exitcode])(ctx, vcpu, &vmrun);
553
554                 switch (rc) {
555                 case VMEXIT_CONTINUE:
556                         break;
557                 case VMEXIT_ABORT:
558                         abort();
559                 default:
560                         exit(4);
561                 }
562         }
563         fprintf(stderr, "vm_run error %d, errno %d\n", error, errno);
564 }
565
566 static int
567 num_vcpus_allowed(struct vmctx *ctx, struct vcpu *vcpu)
568 {
569         uint16_t sockets, cores, threads, maxcpus;
570         int tmp, error;
571
572         /*
573          * The guest is allowed to spinup more than one processor only if the
574          * UNRESTRICTED_GUEST capability is available.
575          */
576         error = vm_get_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp);
577         if (error != 0)
578                 return (1);
579
580         error = vm_get_topology(ctx, &sockets, &cores, &threads, &maxcpus);
581         if (error == 0)
582                 return (maxcpus);
583         else
584                 return (1);
585 }
586
587 static void
588 fbsdrun_set_capabilities(struct vcpu *vcpu)
589 {
590         int err, tmp;
591
592         if (get_config_bool_default("x86.vmexit_on_hlt", false)) {
593                 err = vm_get_capability(vcpu, VM_CAP_HALT_EXIT, &tmp);
594                 if (err < 0) {
595                         fprintf(stderr, "VM exit on HLT not supported\n");
596                         exit(4);
597                 }
598                 vm_set_capability(vcpu, VM_CAP_HALT_EXIT, 1);
599         }
600
601         if (get_config_bool_default("x86.vmexit_on_pause", false)) {
602                 /*
603                  * pause exit support required for this mode
604                  */
605                 err = vm_get_capability(vcpu, VM_CAP_PAUSE_EXIT, &tmp);
606                 if (err < 0) {
607                         fprintf(stderr,
608                             "SMP mux requested, no pause support\n");
609                         exit(4);
610                 }
611                 vm_set_capability(vcpu, VM_CAP_PAUSE_EXIT, 1);
612         }
613
614         if (get_config_bool_default("x86.x2apic", false))
615                 err = vm_set_x2apic_state(vcpu, X2APIC_ENABLED);
616         else
617                 err = vm_set_x2apic_state(vcpu, X2APIC_DISABLED);
618
619         if (err) {
620                 fprintf(stderr, "Unable to set x2apic state (%d)\n", err);
621                 exit(4);
622         }
623
624         vm_set_capability(vcpu, VM_CAP_ENABLE_INVPCID, 1);
625
626         err = vm_set_capability(vcpu, VM_CAP_IPI_EXIT, 1);
627         assert(err == 0);
628 }
629
630 static struct vmctx *
631 do_open(const char *vmname)
632 {
633         struct vmctx *ctx;
634         int error;
635         bool reinit, romboot;
636
637         reinit = romboot = false;
638
639 #ifdef __amd64__
640         if (lpc_bootrom())
641                 romboot = true;
642 #endif
643
644         error = vm_create(vmname);
645         if (error) {
646                 if (errno == EEXIST) {
647                         if (romboot) {
648                                 reinit = true;
649                         } else {
650                                 /*
651                                  * The virtual machine has been setup by the
652                                  * userspace bootloader.
653                                  */
654                         }
655                 } else {
656                         perror("vm_create");
657                         exit(4);
658                 }
659         } else {
660                 if (!romboot) {
661                         /*
662                          * If the virtual machine was just created then a
663                          * bootrom must be configured to boot it.
664                          */
665                         fprintf(stderr, "virtual machine cannot be booted\n");
666                         exit(4);
667                 }
668         }
669
670         ctx = vm_open(vmname);
671         if (ctx == NULL) {
672                 perror("vm_open");
673                 exit(4);
674         }
675
676 #ifndef WITHOUT_CAPSICUM
677         if (vm_limit_rights(ctx) != 0)
678                 err(EX_OSERR, "vm_limit_rights");
679 #endif
680
681         if (reinit) {
682                 error = vm_reinit(ctx);
683                 if (error) {
684                         perror("vm_reinit");
685                         exit(4);
686                 }
687         }
688         error = vm_set_topology(ctx, cpu_sockets, cpu_cores, cpu_threads, 0);
689         if (error)
690                 errx(EX_OSERR, "vm_set_topology");
691         return (ctx);
692 }
693
694 static void
695 spinup_vcpu(struct vcpu_info *vi, bool bsp)
696 {
697         int error;
698
699         if (!bsp) {
700                 fbsdrun_set_capabilities(vi->vcpu);
701
702                 /*
703                  * Enable the 'unrestricted guest' mode for APs.
704                  *
705                  * APs startup in power-on 16-bit mode.
706                  */
707                 error = vm_set_capability(vi->vcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
708                 assert(error == 0);
709         }
710
711         fbsdrun_addcpu(vi);
712 }
713
714 static bool
715 parse_config_option(const char *option)
716 {
717         const char *value;
718         char *path;
719
720         value = strchr(option, '=');
721         if (value == NULL || value[1] == '\0')
722                 return (false);
723         path = strndup(option, value - option);
724         if (path == NULL)
725                 err(4, "Failed to allocate memory");
726         set_config_value(path, value + 1);
727         return (true);
728 }
729
730 static void
731 parse_simple_config_file(const char *path)
732 {
733         FILE *fp;
734         char *line, *cp;
735         size_t linecap;
736         unsigned int lineno;
737
738         fp = fopen(path, "r");
739         if (fp == NULL)
740                 err(4, "Failed to open configuration file %s", path);
741         line = NULL;
742         linecap = 0;
743         lineno = 1;
744         for (lineno = 1; getline(&line, &linecap, fp) > 0; lineno++) {
745                 if (*line == '#' || *line == '\n')
746                         continue;
747                 cp = strchr(line, '\n');
748                 if (cp != NULL)
749                         *cp = '\0';
750                 if (!parse_config_option(line))
751                         errx(4, "%s line %u: invalid config option '%s'", path,
752                             lineno, line);
753         }
754         free(line);
755         fclose(fp);
756 }
757
758 static void
759 parse_gdb_options(const char *opt)
760 {
761         const char *sport;
762         char *colon;
763
764         if (opt[0] == 'w') {
765                 set_config_bool("gdb.wait", true);
766                 opt++;
767         }
768
769         colon = strrchr(opt, ':');
770         if (colon == NULL) {
771                 sport = opt;
772         } else {
773                 *colon = '\0';
774                 colon++;
775                 sport = colon;
776                 set_config_value("gdb.address", opt);
777         }
778
779         set_config_value("gdb.port", sport);
780 }
781
782 static void
783 set_defaults(void)
784 {
785
786         set_config_bool("acpi_tables", true);
787         set_config_bool("acpi_tables_in_memory", true);
788         set_config_value("memory.size", "256M");
789         set_config_bool("x86.strictmsr", true);
790         set_config_value("lpc.fwcfg", "bhyve");
791 }
792
793 int
794 main(int argc, char *argv[])
795 {
796         int c, error;
797         int max_vcpus, memflags;
798         struct vcpu *bsp;
799         struct vmctx *ctx;
800         size_t memsize;
801         const char *optstr, *value, *vmname;
802 #ifdef BHYVE_SNAPSHOT
803         char *restore_file;
804         struct restore_state rstate;
805
806         restore_file = NULL;
807 #endif
808
809         init_config();
810         set_defaults();
811         progname = basename(argv[0]);
812
813 #ifdef BHYVE_SNAPSHOT
814         optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:";
815 #else
816         optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
817 #endif
818         while ((c = getopt(argc, argv, optstr)) != -1) {
819                 switch (c) {
820                 case 'a':
821                         set_config_bool("x86.x2apic", false);
822                         break;
823                 case 'A':
824                         /*
825                          * NOP. For backward compatibility. Most systems don't
826                          * work properly without sane ACPI tables. Therefore,
827                          * we're always generating them.
828                          */
829                         break;
830                 case 'D':
831                         set_config_bool("destroy_on_poweroff", true);
832                         break;
833                 case 'p':
834                         if (pincpu_parse(optarg) != 0) {
835                                 errx(EX_USAGE, "invalid vcpu pinning "
836                                     "configuration '%s'", optarg);
837                         }
838                         break;
839                 case 'c':
840                         if (topology_parse(optarg) != 0) {
841                             errx(EX_USAGE, "invalid cpu topology "
842                                 "'%s'", optarg);
843                         }
844                         break;
845                 case 'C':
846                         set_config_bool("memory.guest_in_core", true);
847                         break;
848                 case 'f':
849                         if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) {
850                             errx(EX_USAGE, "invalid fwcfg item '%s'", optarg);
851                         }
852                         break;
853                 case 'G':
854                         parse_gdb_options(optarg);
855                         break;
856                 case 'k':
857                         parse_simple_config_file(optarg);
858                         break;
859                 case 'K':
860                         set_config_value("keyboard.layout", optarg);
861                         break;
862 #ifdef __amd64__
863                 case 'l':
864                         if (strncmp(optarg, "help", strlen(optarg)) == 0) {
865                                 lpc_print_supported_devices();
866                                 exit(0);
867                         } else if (lpc_device_parse(optarg) != 0) {
868                                 errx(EX_USAGE, "invalid lpc device "
869                                     "configuration '%s'", optarg);
870                         }
871                         break;
872 #endif
873 #ifdef BHYVE_SNAPSHOT
874                 case 'r':
875                         restore_file = optarg;
876                         break;
877 #endif
878                 case 's':
879                         if (strncmp(optarg, "help", strlen(optarg)) == 0) {
880                                 pci_print_supported_devices();
881                                 exit(0);
882                         } else if (pci_parse_slot(optarg) != 0)
883                                 exit(4);
884                         else
885                                 break;
886                 case 'S':
887                         set_config_bool("memory.wired", true);
888                         break;
889                 case 'm':
890                         set_config_value("memory.size", optarg);
891                         break;
892                 case 'o':
893                         if (!parse_config_option(optarg))
894                                 errx(EX_USAGE, "invalid configuration option '%s'", optarg);
895                         break;
896                 case 'H':
897                         set_config_bool("x86.vmexit_on_hlt", true);
898                         break;
899                 case 'I':
900                         /*
901                          * The "-I" option was used to add an ioapic to the
902                          * virtual machine.
903                          *
904                          * An ioapic is now provided unconditionally for each
905                          * virtual machine and this option is now deprecated.
906                          */
907                         break;
908                 case 'P':
909                         set_config_bool("x86.vmexit_on_pause", true);
910                         break;
911                 case 'e':
912                         set_config_bool("x86.strictio", true);
913                         break;
914 #ifdef __amd64__
915                 case 'u':
916                         set_config_bool("rtc.use_localtime", false);
917                         break;
918 #endif
919                 case 'U':
920                         set_config_value("uuid", optarg);
921                         break;
922                 case 'w':
923                         set_config_bool("x86.strictmsr", false);
924                         break;
925                 case 'W':
926                         set_config_bool("virtio_msix", false);
927                         break;
928                 case 'x':
929                         set_config_bool("x86.x2apic", true);
930                         break;
931 #ifdef __amd64__
932                 case 'Y':
933                         set_config_bool("x86.mptable", false);
934                         break;
935 #endif
936                 case 'h':
937                         usage(0);
938                 default:
939                         usage(1);
940                 }
941         }
942         argc -= optind;
943         argv += optind;
944
945         if (argc > 1)
946                 usage(1);
947
948 #ifdef BHYVE_SNAPSHOT
949         if (restore_file != NULL) {
950                 error = load_restore_file(restore_file, &rstate);
951                 if (error) {
952                         fprintf(stderr, "Failed to read checkpoint info from "
953                                         "file: '%s'.\n", restore_file);
954                         exit(1);
955                 }
956                 vmname = lookup_vmname(&rstate);
957                 if (vmname != NULL)
958                         set_config_value("name", vmname);
959         }
960 #endif
961
962         if (argc == 1)
963                 set_config_value("name", argv[0]);
964
965         vmname = get_config_value("name");
966         if (vmname == NULL)
967                 usage(1);
968
969         if (get_config_bool_default("config.dump", false)) {
970                 dump_config();
971                 exit(1);
972         }
973
974         calc_topology();
975         build_vcpumaps();
976
977         value = get_config_value("memory.size");
978         error = vm_parse_memsize(value, &memsize);
979         if (error)
980                 errx(EX_USAGE, "invalid memsize '%s'", value);
981
982         ctx = do_open(vmname);
983
984 #ifdef BHYVE_SNAPSHOT
985         if (restore_file != NULL) {
986                 guest_ncpus = lookup_guest_ncpus(&rstate);
987                 memflags = lookup_memflags(&rstate);
988                 memsize = lookup_memsize(&rstate);
989         }
990
991         if (guest_ncpus < 1) {
992                 fprintf(stderr, "Invalid guest vCPUs (%d)\n", guest_ncpus);
993                 exit(1);
994         }
995 #endif
996
997         bsp = vm_vcpu_open(ctx, BSP);
998         max_vcpus = num_vcpus_allowed(ctx, bsp);
999         if (guest_ncpus > max_vcpus) {
1000                 fprintf(stderr, "%d vCPUs requested but only %d available\n",
1001                         guest_ncpus, max_vcpus);
1002                 exit(4);
1003         }
1004
1005         fbsdrun_set_capabilities(bsp);
1006
1007         /* Allocate per-VCPU resources. */
1008         vcpu_info = calloc(guest_ncpus, sizeof(*vcpu_info));
1009         for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++) {
1010                 vcpu_info[vcpuid].ctx = ctx;
1011                 vcpu_info[vcpuid].vcpuid = vcpuid;
1012                 if (vcpuid == BSP)
1013                         vcpu_info[vcpuid].vcpu = bsp;
1014                 else
1015                         vcpu_info[vcpuid].vcpu = vm_vcpu_open(ctx, vcpuid);
1016         }
1017
1018         memflags = 0;
1019         if (get_config_bool_default("memory.wired", false))
1020                 memflags |= VM_MEM_F_WIRED;
1021         if (get_config_bool_default("memory.guest_in_core", false))
1022                 memflags |= VM_MEM_F_INCORE;
1023         vm_set_memflags(ctx, memflags);
1024         error = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
1025         if (error) {
1026                 fprintf(stderr, "Unable to setup memory (%d)\n", errno);
1027                 exit(4);
1028         }
1029
1030 #ifdef __amd64__
1031         error = init_msr();
1032         if (error) {
1033                 fprintf(stderr, "init_msr error %d", error);
1034                 exit(4);
1035         }
1036 #endif
1037
1038         init_mem(guest_ncpus);
1039         init_inout();
1040 #ifdef __amd64__
1041         kernemu_dev_init();
1042 #endif
1043         init_bootrom(ctx);
1044 #ifdef __amd64__
1045         atkbdc_init(ctx);
1046         pci_irq_init(ctx);
1047         ioapic_init(ctx);
1048 #endif
1049
1050 #ifdef __amd64__
1051         rtc_init(ctx);
1052         sci_init(ctx);
1053 #endif
1054
1055         if (qemu_fwcfg_init(ctx) != 0) {
1056                 fprintf(stderr, "qemu fwcfg initialization error");
1057                 exit(4);
1058         }
1059
1060         if (qemu_fwcfg_add_file("opt/bhyve/hw.ncpu", sizeof(guest_ncpus),
1061             &guest_ncpus) != 0) {
1062                 fprintf(stderr, "Could not add qemu fwcfg opt/bhyve/hw.ncpu");
1063                 exit(4);
1064         }
1065
1066 #ifdef __amd64__
1067         if (e820_init(ctx) != 0) {
1068                 fprintf(stderr, "Unable to setup E820");
1069                 exit(4);
1070         }
1071 #endif
1072
1073         /*
1074          * Exit if a device emulation finds an error in its initialization
1075          */
1076         if (init_pci(ctx) != 0) {
1077                 perror("device emulation initialization error");
1078                 exit(4);
1079         }
1080         if (init_tpm(ctx) != 0) {
1081                 fprintf(stderr, "Failed to init TPM device");
1082                 exit(4);
1083         }
1084
1085         /*
1086          * Initialize after PCI, to allow a bootrom file to reserve the high
1087          * region.
1088          */
1089         if (get_config_bool("acpi_tables"))
1090                 vmgenc_init(ctx);
1091
1092         init_gdb(ctx);
1093
1094 #ifdef __amd64__
1095         if (lpc_bootrom()) {
1096                 if (vm_set_capability(bsp, VM_CAP_UNRESTRICTED_GUEST, 1)) {
1097                         fprintf(stderr, "ROM boot failed: unrestricted guest "
1098                             "capability not available\n");
1099                         exit(4);
1100                 }
1101                 error = vcpu_reset(bsp);
1102                 assert(error == 0);
1103         }
1104 #endif
1105
1106         /*
1107          * Add all vCPUs.
1108          */
1109         for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++)
1110                 spinup_vcpu(&vcpu_info[vcpuid], vcpuid == BSP);
1111
1112 #ifdef BHYVE_SNAPSHOT
1113         if (restore_file != NULL) {
1114                 fprintf(stdout, "Pausing pci devs...\r\n");
1115                 if (vm_pause_devices() != 0) {
1116                         fprintf(stderr, "Failed to pause PCI device state.\n");
1117                         exit(1);
1118                 }
1119
1120                 fprintf(stdout, "Restoring vm mem...\r\n");
1121                 if (restore_vm_mem(ctx, &rstate) != 0) {
1122                         fprintf(stderr, "Failed to restore VM memory.\n");
1123                         exit(1);
1124                 }
1125
1126                 fprintf(stdout, "Restoring pci devs...\r\n");
1127                 if (vm_restore_devices(&rstate) != 0) {
1128                         fprintf(stderr, "Failed to restore PCI device state.\n");
1129                         exit(1);
1130                 }
1131
1132                 fprintf(stdout, "Restoring kernel structs...\r\n");
1133                 if (vm_restore_kern_structs(ctx, &rstate) != 0) {
1134                         fprintf(stderr, "Failed to restore kernel structs.\n");
1135                         exit(1);
1136                 }
1137
1138                 fprintf(stdout, "Resuming pci devs...\r\n");
1139                 if (vm_resume_devices() != 0) {
1140                         fprintf(stderr, "Failed to resume PCI device state.\n");
1141                         exit(1);
1142                 }
1143         }
1144 #endif
1145
1146 #ifdef __amd64__
1147         if (get_config_bool_default("x86.mptable", true)) {
1148                 error = mptable_build(ctx, guest_ncpus);
1149                 if (error) {
1150                         perror("error to build the guest tables");
1151                         exit(4);
1152                 }
1153         }
1154 #endif
1155
1156         error = smbios_build(ctx);
1157         if (error != 0)
1158                 exit(4);
1159
1160         if (get_config_bool("acpi_tables")) {
1161                 error = acpi_build(ctx, guest_ncpus);
1162                 assert(error == 0);
1163         }
1164
1165 #ifdef __amd64__
1166         error = e820_finalize();
1167         if (error != 0)
1168                 exit(4);
1169 #endif
1170
1171 #ifdef __amd64__
1172         if (lpc_bootrom() && strcmp(lpc_fwcfg(), "bhyve") == 0) {
1173                 fwctl_init();
1174         }
1175 #endif
1176
1177         /*
1178          * Change the proc title to include the VM name.
1179          */
1180         setproctitle("%s", vmname);
1181
1182 #ifdef BHYVE_SNAPSHOT
1183         /* initialize mutex/cond variables */
1184         init_snapshot();
1185
1186         /*
1187          * checkpointing thread for communication with bhyvectl
1188          */
1189         if (init_checkpoint_thread(ctx) != 0)
1190                 errx(EX_OSERR, "Failed to start checkpoint thread");
1191 #endif
1192
1193 #ifndef WITHOUT_CAPSICUM
1194         caph_cache_catpages();
1195
1196         if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1)
1197                 errx(EX_OSERR, "Unable to apply rights for sandbox");
1198
1199         if (caph_enter() == -1)
1200                 errx(EX_OSERR, "cap_enter() failed");
1201 #endif
1202
1203 #ifdef BHYVE_SNAPSHOT
1204         if (restore_file != NULL) {
1205                 destroy_restore_state(&rstate);
1206                 if (vm_restore_time(ctx) < 0)
1207                         err(EX_OSERR, "Unable to restore time");
1208
1209                 for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++)
1210                         vm_resume_cpu(vcpu_info[vcpuid].vcpu);
1211         } else
1212 #endif
1213                 vm_resume_cpu(bsp);
1214
1215         /*
1216          * Head off to the main event dispatch loop
1217          */
1218         mevent_dispatch();
1219
1220         exit(4);
1221 }