]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bhyve/bhyverun.c
MFC 263780,264516,265062,265101,265203,265364:
[FreeBSD/stable/10.git] / usr.sbin / bhyve / bhyverun.c
1 /*-
2  * Copyright (c) 2011 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33 #include <sys/mman.h>
34 #include <sys/time.h>
35
36 #include <machine/atomic.h>
37 #include <machine/segments.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <err.h>
43 #include <libgen.h>
44 #include <unistd.h>
45 #include <assert.h>
46 #include <errno.h>
47 #include <pthread.h>
48 #include <pthread_np.h>
49 #include <sysexits.h>
50
51 #include <machine/vmm.h>
52 #include <vmmapi.h>
53
54 #include "bhyverun.h"
55 #include "acpi.h"
56 #include "inout.h"
57 #include "dbgport.h"
58 #include "ioapic.h"
59 #include "mem.h"
60 #include "mevent.h"
61 #include "mptbl.h"
62 #include "pci_emul.h"
63 #include "pci_lpc.h"
64 #include "smbiostbl.h"
65 #include "xmsr.h"
66 #include "spinup_ap.h"
67 #include "rtc.h"
68
69 #define GUEST_NIO_PORT          0x488   /* guest upcalls via i/o port */
70
71 #define VMEXIT_SWITCH           0       /* force vcpu switch in mux mode */
72 #define VMEXIT_CONTINUE         1       /* continue from next instruction */
73 #define VMEXIT_RESTART          2       /* restart current instruction */
74 #define VMEXIT_ABORT            3       /* abort the vm run loop */
75 #define VMEXIT_RESET            4       /* guest machine has reset */
76 #define VMEXIT_POWEROFF         5       /* guest machine has powered off */
77
78 #define MB              (1024UL * 1024)
79 #define GB              (1024UL * MB)
80
81 typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu);
82
83 char *vmname;
84
85 int guest_ncpus;
86 char *guest_uuid_str;
87
88 static int guest_vmexit_on_hlt, guest_vmexit_on_pause;
89 static int virtio_msix = 1;
90 static int x2apic_mode = 0;     /* default is xAPIC */
91
92 static int strictio;
93 static int strictmsr = 1;
94
95 static int acpi;
96
97 static char *progname;
98 static const int BSP = 0;
99
100 static cpuset_t cpumask;
101
102 static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip);
103
104 struct vm_exit vmexit[VM_MAXCPU];
105
106 struct bhyvestats {
107         uint64_t        vmexit_bogus;
108         uint64_t        vmexit_bogus_switch;
109         uint64_t        vmexit_hlt;
110         uint64_t        vmexit_pause;
111         uint64_t        vmexit_mtrap;
112         uint64_t        vmexit_inst_emul;
113         uint64_t        cpu_switch_rotate;
114         uint64_t        cpu_switch_direct;
115         int             io_reset;
116         int             io_poweroff;
117 } stats;
118
119 struct mt_vmm_info {
120         pthread_t       mt_thr;
121         struct vmctx    *mt_ctx;
122         int             mt_vcpu;        
123 } mt_vmm_info[VM_MAXCPU];
124
125 static cpuset_t *vcpumap[VM_MAXCPU] = { NULL };
126
127 static void
128 usage(int code)
129 {
130
131         fprintf(stderr,
132                 "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>] [-c vcpus]\n"
133                 "       %*s [-p vcpu:hostcpu] [-m mem] [-l <lpc>] <vm>\n"
134                 "       -a: local apic is in xAPIC mode (deprecated)\n"
135                 "       -A: create an ACPI table\n"
136                 "       -g: gdb port\n"
137                 "       -c: # cpus (default 1)\n"
138                 "       -p: pin 'vcpu' to 'hostcpu'\n"
139                 "       -H: vmexit from the guest on hlt\n"
140                 "       -P: vmexit from the guest on pause\n"
141                 "       -W: force virtio to use single-vector MSI\n"
142                 "       -e: exit on unhandled I/O access\n"
143                 "       -h: help\n"
144                 "       -s: <slot,driver,configinfo> PCI slot config\n"
145                 "       -l: LPC device configuration\n"
146                 "       -m: memory size in MB\n"
147                 "       -w: ignore unimplemented MSRs\n"
148                 "       -x: local apic is in x2APIC mode\n"
149                 "       -Y: disable MPtable generation\n"
150                 "       -U: uuid\n",
151                 progname, (int)strlen(progname), "");
152
153         exit(code);
154 }
155
156 static int
157 pincpu_parse(const char *opt)
158 {
159         int vcpu, pcpu;
160
161         if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) {
162                 fprintf(stderr, "invalid format: %s\n", opt);
163                 return (-1);
164         }
165
166         if (vcpu < 0 || vcpu >= VM_MAXCPU) {
167                 fprintf(stderr, "vcpu '%d' outside valid range from 0 to %d\n",
168                     vcpu, VM_MAXCPU - 1);
169                 return (-1);
170         }
171
172         if (pcpu < 0 || pcpu >= CPU_SETSIZE) {
173                 fprintf(stderr, "hostcpu '%d' outside valid range from "
174                     "0 to %d\n", pcpu, CPU_SETSIZE - 1);
175                 return (-1);
176         }
177
178         if (vcpumap[vcpu] == NULL) {
179                 if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) {
180                         perror("malloc");
181                         return (-1);
182                 }
183                 CPU_ZERO(vcpumap[vcpu]);
184         }
185         CPU_SET(pcpu, vcpumap[vcpu]);
186         return (0);
187 }
188
189 void *
190 paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
191 {
192
193         return (vm_map_gpa(ctx, gaddr, len));
194 }
195
196 int
197 fbsdrun_vmexit_on_pause(void)
198 {
199
200         return (guest_vmexit_on_pause);
201 }
202
203 int
204 fbsdrun_vmexit_on_hlt(void)
205 {
206
207         return (guest_vmexit_on_hlt);
208 }
209
210 int
211 fbsdrun_virtio_msix(void)
212 {
213
214         return (virtio_msix);
215 }
216
217 static void *
218 fbsdrun_start_thread(void *param)
219 {
220         char tname[MAXCOMLEN + 1];
221         struct mt_vmm_info *mtp;
222         int vcpu;
223
224         mtp = param;
225         vcpu = mtp->mt_vcpu;
226
227         snprintf(tname, sizeof(tname), "vcpu %d", vcpu);
228         pthread_set_name_np(mtp->mt_thr, tname);
229
230         vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip);
231
232         /* not reached */
233         exit(1);
234         return (NULL);
235 }
236
237 void
238 fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip)
239 {
240         int error;
241
242         assert(fromcpu == BSP);
243
244         CPU_SET_ATOMIC(newcpu, &cpumask);
245
246         /*
247          * Set up the vmexit struct to allow execution to start
248          * at the given RIP
249          */
250         vmexit[newcpu].rip = rip;
251         vmexit[newcpu].inst_length = 0;
252
253         mt_vmm_info[newcpu].mt_ctx = ctx;
254         mt_vmm_info[newcpu].mt_vcpu = newcpu;
255
256         error = pthread_create(&mt_vmm_info[newcpu].mt_thr, NULL,
257             fbsdrun_start_thread, &mt_vmm_info[newcpu]);
258         assert(error == 0);
259 }
260
261 static int
262 fbsdrun_deletecpu(struct vmctx *ctx, int vcpu)
263 {
264
265         if (!CPU_ISSET(vcpu, &cpumask)) {
266                 fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu);
267                 exit(1);
268         }
269
270         CPU_CLR_ATOMIC(vcpu, &cpumask);
271         return (CPU_EMPTY(&cpumask));
272 }
273
274 static int
275 vmexit_catch_inout(void)
276 {
277         return (VMEXIT_ABORT);
278 }
279
280 static int
281 vmexit_handle_notify(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu,
282                      uint32_t eax)
283 {
284 #if BHYVE_DEBUG
285         /*
286          * put guest-driven debug here
287          */
288 #endif
289         return (VMEXIT_CONTINUE);
290 }
291
292 static int
293 vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
294 {
295         int error;
296         int bytes, port, in, out;
297         uint32_t eax;
298         int vcpu;
299
300         vcpu = *pvcpu;
301
302         port = vme->u.inout.port;
303         bytes = vme->u.inout.bytes;
304         eax = vme->u.inout.eax;
305         in = vme->u.inout.in;
306         out = !in;
307
308         /* We don't deal with these */
309         if (vme->u.inout.string || vme->u.inout.rep)
310                 return (VMEXIT_ABORT);
311
312         /* Extra-special case of host notifications */
313         if (out && port == GUEST_NIO_PORT)
314                 return (vmexit_handle_notify(ctx, vme, pvcpu, eax));
315
316         error = emulate_inout(ctx, vcpu, in, port, bytes, &eax, strictio);
317         if (error == INOUT_OK && in)
318                 error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, eax);
319
320         switch (error) {
321         case INOUT_OK:
322                 return (VMEXIT_CONTINUE);
323         case INOUT_RESET:
324                 stats.io_reset++;
325                 return (VMEXIT_RESET);
326         case INOUT_POWEROFF:
327                 stats.io_poweroff++;
328                 return (VMEXIT_POWEROFF);
329         default:
330                 fprintf(stderr, "Unhandled %s%c 0x%04x\n",
331                         in ? "in" : "out",
332                         bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port);
333                 return (vmexit_catch_inout());
334         }
335 }
336
337 static int
338 vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
339 {
340         uint64_t val;
341         uint32_t eax, edx;
342         int error;
343
344         val = 0;
345         error = emulate_rdmsr(ctx, *pvcpu, vme->u.msr.code, &val);
346         if (error != 0) {
347                 fprintf(stderr, "rdmsr to register %#x on vcpu %d\n",
348                     vme->u.msr.code, *pvcpu);
349                 if (strictmsr) {
350                         error = vm_inject_exception2(ctx, *pvcpu, IDT_GP, 0);
351                         assert(error == 0);
352                         return (VMEXIT_RESTART);
353                 }
354         }
355
356         eax = val;
357         error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RAX, eax);
358         assert(error == 0);
359
360         edx = val >> 32;
361         error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RDX, edx);
362         assert(error == 0);
363
364         return (VMEXIT_CONTINUE);
365 }
366
367 static int
368 vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
369 {
370         int error;
371
372         error = emulate_wrmsr(ctx, *pvcpu, vme->u.msr.code, vme->u.msr.wval);
373         if (error != 0) {
374                 fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n",
375                     vme->u.msr.code, vme->u.msr.wval, *pvcpu);
376                 if (strictmsr) {
377                         error = vm_inject_exception2(ctx, *pvcpu, IDT_GP, 0);
378                         assert(error == 0);
379                         return (VMEXIT_RESTART);
380                 }
381         }
382         return (VMEXIT_CONTINUE);
383 }
384
385 static int
386 vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
387 {
388         int newcpu;
389         int retval = VMEXIT_CONTINUE;
390
391         newcpu = spinup_ap(ctx, *pvcpu,
392                            vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip);
393
394         return (retval);
395 }
396
397 static int
398 vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
399 {
400
401         fprintf(stderr, "vm exit[%d]\n", *pvcpu);
402         fprintf(stderr, "\treason\t\tVMX\n");
403         fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip);
404         fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length);
405         fprintf(stderr, "\tstatus\t\t%d\n", vmexit->u.vmx.status);
406         fprintf(stderr, "\texit_reason\t%u\n", vmexit->u.vmx.exit_reason);
407         fprintf(stderr, "\tqualification\t0x%016lx\n",
408             vmexit->u.vmx.exit_qualification);
409         fprintf(stderr, "\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type);
410         fprintf(stderr, "\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error);
411
412         return (VMEXIT_ABORT);
413 }
414
415 static int
416 vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
417 {
418
419         stats.vmexit_bogus++;
420
421         return (VMEXIT_RESTART);
422 }
423
424 static int
425 vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
426 {
427
428         stats.vmexit_hlt++;
429
430         /*
431          * Just continue execution with the next instruction. We use
432          * the HLT VM exit as a way to be friendly with the host
433          * scheduler.
434          */
435         return (VMEXIT_CONTINUE);
436 }
437
438 static int
439 vmexit_pause(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
440 {
441
442         stats.vmexit_pause++;
443
444         return (VMEXIT_CONTINUE);
445 }
446
447 static int
448 vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
449 {
450
451         stats.vmexit_mtrap++;
452
453         return (VMEXIT_RESTART);
454 }
455
456 static int
457 vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
458 {
459         int err;
460         stats.vmexit_inst_emul++;
461
462         err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa,
463                           &vmexit->u.inst_emul.vie);
464
465         if (err) {
466                 if (err == EINVAL) {
467                         fprintf(stderr,
468                             "Failed to emulate instruction at 0x%lx\n", 
469                             vmexit->rip);
470                 } else if (err == ESRCH) {
471                         fprintf(stderr, "Unhandled memory access to 0x%lx\n",
472                             vmexit->u.inst_emul.gpa);
473                 }
474
475                 return (VMEXIT_ABORT);
476         }
477
478         return (VMEXIT_CONTINUE);
479 }
480
481 static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
482 static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
483
484 static int
485 vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
486 {
487         enum vm_suspend_how how;
488
489         how = vmexit->u.suspended.how;
490
491         fbsdrun_deletecpu(ctx, *pvcpu);
492
493         if (*pvcpu != BSP) {
494                 pthread_mutex_lock(&resetcpu_mtx);
495                 pthread_cond_signal(&resetcpu_cond);
496                 pthread_mutex_unlock(&resetcpu_mtx);
497                 pthread_exit(NULL);
498         }
499
500         pthread_mutex_lock(&resetcpu_mtx);
501         while (!CPU_EMPTY(&cpumask)) {
502                 pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
503         }
504         pthread_mutex_unlock(&resetcpu_mtx);
505
506         switch (how) {
507         case VM_SUSPEND_RESET:
508                 exit(0);
509         case VM_SUSPEND_POWEROFF:
510                 exit(1);
511         case VM_SUSPEND_HALT:
512                 exit(2);
513         default:
514                 fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
515                 exit(100);
516         }
517         return (0);     /* NOTREACHED */
518 }
519
520 static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
521         [VM_EXITCODE_INOUT]  = vmexit_inout,
522         [VM_EXITCODE_VMX]    = vmexit_vmx,
523         [VM_EXITCODE_BOGUS]  = vmexit_bogus,
524         [VM_EXITCODE_RDMSR]  = vmexit_rdmsr,
525         [VM_EXITCODE_WRMSR]  = vmexit_wrmsr,
526         [VM_EXITCODE_MTRAP]  = vmexit_mtrap,
527         [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
528         [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
529         [VM_EXITCODE_SUSPENDED] = vmexit_suspend
530 };
531
532 static void
533 vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
534 {
535         int error, rc, prevcpu;
536         enum vm_exitcode exitcode;
537         enum vm_suspend_how how;
538
539         if (vcpumap[vcpu] != NULL) {
540                 error = pthread_setaffinity_np(pthread_self(),
541                     sizeof(cpuset_t), vcpumap[vcpu]);
542                 assert(error == 0);
543         }
544
545         while (1) {
546                 error = vm_run(ctx, vcpu, rip, &vmexit[vcpu]);
547                 if (error != 0)
548                         break;
549
550                 prevcpu = vcpu;
551
552                 exitcode = vmexit[vcpu].exitcode;
553                 if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) {
554                         fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n",
555                             exitcode);
556                         exit(1);
557                 }
558
559                 rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
560
561                 switch (rc) {
562                 case VMEXIT_CONTINUE:
563                         rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length;
564                         break;
565                 case VMEXIT_RESTART:
566                         rip = vmexit[vcpu].rip;
567                         break;
568                 case VMEXIT_RESET:
569                 case VMEXIT_POWEROFF:
570                         if (rc == VMEXIT_RESET)
571                                 how = VM_SUSPEND_RESET;
572                         else
573                                 how = VM_SUSPEND_POWEROFF;
574                         error = vm_suspend(ctx, how);
575                         assert(error == 0 || errno == EALREADY);
576                         rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length;
577                         break;
578                 default:
579                         exit(1);
580                 }
581         }
582         fprintf(stderr, "vm_run error %d, errno %d\n", error, errno);
583 }
584
585 static int
586 num_vcpus_allowed(struct vmctx *ctx)
587 {
588         int tmp, error;
589
590         error = vm_get_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, &tmp);
591
592         /*
593          * The guest is allowed to spinup more than one processor only if the
594          * UNRESTRICTED_GUEST capability is available.
595          */
596         if (error == 0)
597                 return (VM_MAXCPU);
598         else
599                 return (1);
600 }
601
602 void
603 fbsdrun_set_capabilities(struct vmctx *ctx, int cpu)
604 {
605         int err, tmp;
606
607         if (fbsdrun_vmexit_on_hlt()) {
608                 err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp);
609                 if (err < 0) {
610                         fprintf(stderr, "VM exit on HLT not supported\n");
611                         exit(1);
612                 }
613                 vm_set_capability(ctx, cpu, VM_CAP_HALT_EXIT, 1);
614                 if (cpu == BSP)
615                         handler[VM_EXITCODE_HLT] = vmexit_hlt;
616         }
617
618         if (fbsdrun_vmexit_on_pause()) {
619                 /*
620                  * pause exit support required for this mode
621                  */
622                 err = vm_get_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, &tmp);
623                 if (err < 0) {
624                         fprintf(stderr,
625                             "SMP mux requested, no pause support\n");
626                         exit(1);
627                 }
628                 vm_set_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, 1);
629                 if (cpu == BSP)
630                         handler[VM_EXITCODE_PAUSE] = vmexit_pause;
631         }
632
633         if (x2apic_mode)
634                 err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED);
635         else
636                 err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED);
637
638         if (err) {
639                 fprintf(stderr, "Unable to set x2apic state (%d)\n", err);
640                 exit(1);
641         }
642
643         vm_set_capability(ctx, cpu, VM_CAP_ENABLE_INVPCID, 1);
644 }
645
646 int
647 main(int argc, char *argv[])
648 {
649         int c, error, gdb_port, err, bvmcons;
650         int max_vcpus, mptgen;
651         struct vmctx *ctx;
652         uint64_t rip;
653         size_t memsize;
654
655         bvmcons = 0;
656         progname = basename(argv[0]);
657         gdb_port = 0;
658         guest_ncpus = 1;
659         memsize = 256 * MB;
660         mptgen = 1;
661
662         while ((c = getopt(argc, argv, "abehwxAHIPWYp:g:c:s:m:l:U:")) != -1) {
663                 switch (c) {
664                 case 'a':
665                         x2apic_mode = 0;
666                         break;
667                 case 'A':
668                         acpi = 1;
669                         break;
670                 case 'b':
671                         bvmcons = 1;
672                         break;
673                 case 'p':
674                         if (pincpu_parse(optarg) != 0) {
675                             errx(EX_USAGE, "invalid vcpu pinning "
676                                  "configuration '%s'", optarg);
677                         }
678                         break;
679                 case 'c':
680                         guest_ncpus = atoi(optarg);
681                         break;
682                 case 'g':
683                         gdb_port = atoi(optarg);
684                         break;
685                 case 'l':
686                         if (lpc_device_parse(optarg) != 0) {
687                                 errx(EX_USAGE, "invalid lpc device "
688                                     "configuration '%s'", optarg);
689                         }
690                         break;
691                 case 's':
692                         if (pci_parse_slot(optarg) != 0)
693                                 exit(1);
694                         else
695                                 break;
696                 case 'm':
697                         error = vm_parse_memsize(optarg, &memsize);
698                         if (error)
699                                 errx(EX_USAGE, "invalid memsize '%s'", optarg);
700                         break;
701                 case 'H':
702                         guest_vmexit_on_hlt = 1;
703                         break;
704                 case 'I':
705                         /*
706                          * The "-I" option was used to add an ioapic to the
707                          * virtual machine.
708                          *
709                          * An ioapic is now provided unconditionally for each
710                          * virtual machine and this option is now deprecated.
711                          */
712                         break;
713                 case 'P':
714                         guest_vmexit_on_pause = 1;
715                         break;
716                 case 'e':
717                         strictio = 1;
718                         break;
719                 case 'U':
720                         guest_uuid_str = optarg;
721                         break;
722                 case 'w':
723                         strictmsr = 0;
724                         break;
725                 case 'W':
726                         virtio_msix = 0;
727                         break;
728                 case 'x':
729                         x2apic_mode = 1;
730                         break;
731                 case 'Y':
732                         mptgen = 0;
733                         break;
734                 case 'h':
735                         usage(0);                       
736                 default:
737                         usage(1);
738                 }
739         }
740         argc -= optind;
741         argv += optind;
742
743         if (argc != 1)
744                 usage(1);
745
746         vmname = argv[0];
747
748         ctx = vm_open(vmname);
749         if (ctx == NULL) {
750                 perror("vm_open");
751                 exit(1);
752         }
753
754         max_vcpus = num_vcpus_allowed(ctx);
755         if (guest_ncpus > max_vcpus) {
756                 fprintf(stderr, "%d vCPUs requested but only %d available\n",
757                         guest_ncpus, max_vcpus);
758                 exit(1);
759         }
760
761         fbsdrun_set_capabilities(ctx, BSP);
762
763         err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
764         if (err) {
765                 fprintf(stderr, "Unable to setup memory (%d)\n", err);
766                 exit(1);
767         }
768
769         init_mem();
770         init_inout();
771         ioapic_init(ctx);
772
773         rtc_init(ctx);
774
775         /*
776          * Exit if a device emulation finds an error in it's initilization
777          */
778         if (init_pci(ctx) != 0)
779                 exit(1);
780
781         if (gdb_port != 0)
782                 init_dbgport(gdb_port);
783
784         if (bvmcons)
785                 init_bvmcons();
786
787         error = vm_get_register(ctx, BSP, VM_REG_GUEST_RIP, &rip);
788         assert(error == 0);
789
790         /*
791          * build the guest tables, MP etc.
792          */
793         if (mptgen) {
794                 error = mptable_build(ctx, guest_ncpus);
795                 if (error)
796                         exit(1);
797         }
798
799         error = smbios_build(ctx);
800         assert(error == 0);
801
802         if (acpi) {
803                 error = acpi_build(ctx, guest_ncpus);
804                 assert(error == 0);
805         }
806
807         /*
808          * Change the proc title to include the VM name.
809          */
810         setproctitle("%s", vmname); 
811         
812         /*
813          * Add CPU 0
814          */
815         fbsdrun_addcpu(ctx, BSP, BSP, rip);
816
817         /*
818          * Head off to the main event dispatch loop
819          */
820         mevent_dispatch();
821
822         exit(1);
823 }