]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bhyve/bhyverun.c
MFStable-10 r259301
[FreeBSD/releng/10.0.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/segments.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <err.h>
42 #include <libgen.h>
43 #include <unistd.h>
44 #include <assert.h>
45 #include <errno.h>
46 #include <pthread.h>
47 #include <pthread_np.h>
48 #include <sysexits.h>
49
50 #include <machine/vmm.h>
51 #include <vmmapi.h>
52
53 #include "bhyverun.h"
54 #include "acpi.h"
55 #include "inout.h"
56 #include "dbgport.h"
57 #include "legacy_irq.h"
58 #include "mem.h"
59 #include "mevent.h"
60 #include "mptbl.h"
61 #include "pci_emul.h"
62 #include "pci_lpc.h"
63 #include "xmsr.h"
64 #include "ioapic.h"
65 #include "spinup_ap.h"
66 #include "rtc.h"
67
68 #define GUEST_NIO_PORT          0x488   /* guest upcalls via i/o port */
69
70 #define VMEXIT_SWITCH           0       /* force vcpu switch in mux mode */
71 #define VMEXIT_CONTINUE         1       /* continue from next instruction */
72 #define VMEXIT_RESTART          2       /* restart current instruction */
73 #define VMEXIT_ABORT            3       /* abort the vm run loop */
74 #define VMEXIT_RESET            4       /* guest machine has reset */
75
76 #define MB              (1024UL * 1024)
77 #define GB              (1024UL * MB)
78
79 typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu);
80
81 char *vmname;
82
83 int guest_ncpus;
84
85 static int pincpu = -1;
86 static int guest_vmexit_on_hlt, guest_vmexit_on_pause, disable_x2apic;
87 static int virtio_msix = 1;
88
89 static int foundcpus;
90
91 static int strictio;
92
93 static int acpi;
94
95 static char *progname;
96 static const int BSP = 0;
97
98 static int cpumask;
99
100 static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip);
101
102 struct vm_exit vmexit[VM_MAXCPU];
103
104 struct bhyvestats {
105         uint64_t        vmexit_bogus;
106         uint64_t        vmexit_bogus_switch;
107         uint64_t        vmexit_hlt;
108         uint64_t        vmexit_pause;
109         uint64_t        vmexit_mtrap;
110         uint64_t        vmexit_inst_emul;
111         uint64_t        cpu_switch_rotate;
112         uint64_t        cpu_switch_direct;
113         int             io_reset;
114 } stats;
115
116 struct mt_vmm_info {
117         pthread_t       mt_thr;
118         struct vmctx    *mt_ctx;
119         int             mt_vcpu;        
120 } mt_vmm_info[VM_MAXCPU];
121
122 static void
123 usage(int code)
124 {
125
126         fprintf(stderr,
127                 "Usage: %s [-aehAHIPW] [-g <gdb port>] [-s <pci>] [-S <pci>]\n"
128                 "       %*s [-c vcpus] [-p pincpu] [-m mem] [-l <lpc>] <vm>\n"
129                 "       -a: local apic is in XAPIC mode (default is X2APIC)\n"
130                 "       -A: create an ACPI table\n"
131                 "       -g: gdb port\n"
132                 "       -c: # cpus (default 1)\n"
133                 "       -p: pin vcpu 'n' to host cpu 'pincpu + n'\n"
134                 "       -H: vmexit from the guest on hlt\n"
135                 "       -P: vmexit from the guest on pause\n"
136                 "       -W: force virtio to use single-vector MSI\n"
137                 "       -e: exit on unhandled I/O access\n"
138                 "       -h: help\n"
139                 "       -s: <slot,driver,configinfo> PCI slot config\n"
140                 "       -S: <slot,driver,configinfo> legacy PCI slot config\n"
141                 "       -l: LPC device configuration\n"
142                 "       -m: memory size in MB\n",
143                 progname, (int)strlen(progname), "");
144
145         exit(code);
146 }
147
148 void *
149 paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
150 {
151
152         return (vm_map_gpa(ctx, gaddr, len));
153 }
154
155 int
156 fbsdrun_disable_x2apic(void)
157 {
158
159         return (disable_x2apic);
160 }
161
162 int
163 fbsdrun_vmexit_on_pause(void)
164 {
165
166         return (guest_vmexit_on_pause);
167 }
168
169 int
170 fbsdrun_vmexit_on_hlt(void)
171 {
172
173         return (guest_vmexit_on_hlt);
174 }
175
176 int
177 fbsdrun_virtio_msix(void)
178 {
179
180         return (virtio_msix);
181 }
182
183 static void *
184 fbsdrun_start_thread(void *param)
185 {
186         char tname[MAXCOMLEN + 1];
187         struct mt_vmm_info *mtp;
188         int vcpu;
189
190         mtp = param;
191         vcpu = mtp->mt_vcpu;
192
193         snprintf(tname, sizeof(tname), "vcpu %d", vcpu);
194         pthread_set_name_np(mtp->mt_thr, tname);
195
196         vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip);
197
198         /* not reached */
199         exit(1);
200         return (NULL);
201 }
202
203 void
204 fbsdrun_addcpu(struct vmctx *ctx, int vcpu, uint64_t rip)
205 {
206         int error;
207
208         if (cpumask & (1 << vcpu)) {
209                 fprintf(stderr, "addcpu: attempting to add existing cpu %d\n",
210                     vcpu);
211                 exit(1);
212         }
213
214         cpumask |= 1 << vcpu;
215         foundcpus++;
216
217         /*
218          * Set up the vmexit struct to allow execution to start
219          * at the given RIP
220          */
221         vmexit[vcpu].rip = rip;
222         vmexit[vcpu].inst_length = 0;
223
224         mt_vmm_info[vcpu].mt_ctx = ctx;
225         mt_vmm_info[vcpu].mt_vcpu = vcpu;
226
227         error = pthread_create(&mt_vmm_info[vcpu].mt_thr, NULL,
228             fbsdrun_start_thread, &mt_vmm_info[vcpu]);
229         assert(error == 0);
230 }
231
232 static int
233 vmexit_catch_reset(void)
234 {
235         stats.io_reset++;
236         return (VMEXIT_RESET);
237 }
238
239 static int
240 vmexit_catch_inout(void)
241 {
242         return (VMEXIT_ABORT);
243 }
244
245 static int
246 vmexit_handle_notify(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu,
247                      uint32_t eax)
248 {
249 #if BHYVE_DEBUG
250         /*
251          * put guest-driven debug here
252          */
253 #endif
254         return (VMEXIT_CONTINUE);
255 }
256
257 static int
258 vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
259 {
260         int error;
261         int bytes, port, in, out;
262         uint32_t eax;
263         int vcpu;
264
265         vcpu = *pvcpu;
266
267         port = vme->u.inout.port;
268         bytes = vme->u.inout.bytes;
269         eax = vme->u.inout.eax;
270         in = vme->u.inout.in;
271         out = !in;
272
273         /* We don't deal with these */
274         if (vme->u.inout.string || vme->u.inout.rep)
275                 return (VMEXIT_ABORT);
276
277         /* Special case of guest reset */
278         if (out && port == 0x64 && (uint8_t)eax == 0xFE)
279                 return (vmexit_catch_reset());
280
281         /* Extra-special case of host notifications */
282         if (out && port == GUEST_NIO_PORT)
283                 return (vmexit_handle_notify(ctx, vme, pvcpu, eax));
284
285         error = emulate_inout(ctx, vcpu, in, port, bytes, &eax, strictio);
286         if (error == 0 && in)
287                 error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, eax);
288
289         if (error == 0)
290                 return (VMEXIT_CONTINUE);
291         else {
292                 fprintf(stderr, "Unhandled %s%c 0x%04x\n",
293                         in ? "in" : "out",
294                         bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port);
295                 return (vmexit_catch_inout());
296         }
297 }
298
299 static int
300 vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
301 {
302         fprintf(stderr, "vm exit rdmsr 0x%x, cpu %d\n", vme->u.msr.code,
303             *pvcpu);
304         return (VMEXIT_ABORT);
305 }
306
307 static int
308 vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
309 {
310         int newcpu;
311         int retval = VMEXIT_CONTINUE;
312
313         newcpu = emulate_wrmsr(ctx, *pvcpu, vme->u.msr.code,vme->u.msr.wval);
314
315         return (retval);
316 }
317
318 static int
319 vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
320 {
321         int newcpu;
322         int retval = VMEXIT_CONTINUE;
323
324         newcpu = spinup_ap(ctx, *pvcpu,
325                            vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip);
326
327         return (retval);
328 }
329
330 static int
331 vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
332 {
333
334         fprintf(stderr, "vm exit[%d]\n", *pvcpu);
335         fprintf(stderr, "\treason\t\tVMX\n");
336         fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip);
337         fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length);
338         fprintf(stderr, "\terror\t\t%d\n", vmexit->u.vmx.error);
339         fprintf(stderr, "\texit_reason\t%u\n", vmexit->u.vmx.exit_reason);
340         fprintf(stderr, "\tqualification\t0x%016lx\n",
341             vmexit->u.vmx.exit_qualification);
342
343         return (VMEXIT_ABORT);
344 }
345
346 static int
347 vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
348 {
349
350         stats.vmexit_bogus++;
351
352         return (VMEXIT_RESTART);
353 }
354
355 static int
356 vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
357 {
358
359         stats.vmexit_hlt++;
360
361         /*
362          * Just continue execution with the next instruction. We use
363          * the HLT VM exit as a way to be friendly with the host
364          * scheduler.
365          */
366         return (VMEXIT_CONTINUE);
367 }
368
369 static int
370 vmexit_pause(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
371 {
372
373         stats.vmexit_pause++;
374
375         return (VMEXIT_CONTINUE);
376 }
377
378 static int
379 vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
380 {
381
382         stats.vmexit_mtrap++;
383
384         return (VMEXIT_RESTART);
385 }
386
387 static int
388 vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
389 {
390         int err;
391         stats.vmexit_inst_emul++;
392
393         err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa,
394                           &vmexit->u.inst_emul.vie);
395
396         if (err) {
397                 if (err == EINVAL) {
398                         fprintf(stderr,
399                             "Failed to emulate instruction at 0x%lx\n", 
400                             vmexit->rip);
401                 } else if (err == ESRCH) {
402                         fprintf(stderr, "Unhandled memory access to 0x%lx\n",
403                             vmexit->u.inst_emul.gpa);
404                 }
405
406                 return (VMEXIT_ABORT);
407         }
408
409         return (VMEXIT_CONTINUE);
410 }
411
412 static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
413         [VM_EXITCODE_INOUT]  = vmexit_inout,
414         [VM_EXITCODE_VMX]    = vmexit_vmx,
415         [VM_EXITCODE_BOGUS]  = vmexit_bogus,
416         [VM_EXITCODE_RDMSR]  = vmexit_rdmsr,
417         [VM_EXITCODE_WRMSR]  = vmexit_wrmsr,
418         [VM_EXITCODE_MTRAP]  = vmexit_mtrap,
419         [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
420         [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
421 };
422
423 static void
424 vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
425 {
426         cpuset_t mask;
427         int error, rc, prevcpu;
428         enum vm_exitcode exitcode;
429
430         if (pincpu >= 0) {
431                 CPU_ZERO(&mask);
432                 CPU_SET(pincpu + vcpu, &mask);
433                 error = pthread_setaffinity_np(pthread_self(),
434                                                sizeof(mask), &mask);
435                 assert(error == 0);
436         }
437
438         while (1) {
439                 error = vm_run(ctx, vcpu, rip, &vmexit[vcpu]);
440                 if (error != 0) {
441                         /*
442                          * It is possible that 'vmmctl' or some other process
443                          * has transitioned the vcpu to CANNOT_RUN state right
444                          * before we tried to transition it to RUNNING.
445                          *
446                          * This is expected to be temporary so just retry.
447                          */
448                         if (errno == EBUSY)
449                                 continue;
450                         else
451                                 break;
452                 }
453
454                 prevcpu = vcpu;
455
456                 exitcode = vmexit[vcpu].exitcode;
457                 if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) {
458                         fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n",
459                             exitcode);
460                         exit(1);
461                 }
462
463                 rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
464
465                 switch (rc) {
466                 case VMEXIT_CONTINUE:
467                         rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length;
468                         break;
469                 case VMEXIT_RESTART:
470                         rip = vmexit[vcpu].rip;
471                         break;
472                 case VMEXIT_RESET:
473                         exit(0);
474                 default:
475                         exit(1);
476                 }
477         }
478         fprintf(stderr, "vm_run error %d, errno %d\n", error, errno);
479 }
480
481 static int
482 num_vcpus_allowed(struct vmctx *ctx)
483 {
484         int tmp, error;
485
486         error = vm_get_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, &tmp);
487
488         /*
489          * The guest is allowed to spinup more than one processor only if the
490          * UNRESTRICTED_GUEST capability is available.
491          */
492         if (error == 0)
493                 return (VM_MAXCPU);
494         else
495                 return (1);
496 }
497
498 void
499 fbsdrun_set_capabilities(struct vmctx *ctx, int cpu)
500 {
501         int err, tmp;
502
503         if (fbsdrun_vmexit_on_hlt()) {
504                 err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp);
505                 if (err < 0) {
506                         fprintf(stderr, "VM exit on HLT not supported\n");
507                         exit(1);
508                 }
509                 vm_set_capability(ctx, cpu, VM_CAP_HALT_EXIT, 1);
510                 if (cpu == BSP)
511                         handler[VM_EXITCODE_HLT] = vmexit_hlt;
512         }
513
514         if (fbsdrun_vmexit_on_pause()) {
515                 /*
516                  * pause exit support required for this mode
517                  */
518                 err = vm_get_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, &tmp);
519                 if (err < 0) {
520                         fprintf(stderr,
521                             "SMP mux requested, no pause support\n");
522                         exit(1);
523                 }
524                 vm_set_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, 1);
525                 if (cpu == BSP)
526                         handler[VM_EXITCODE_PAUSE] = vmexit_pause;
527         }
528
529         if (fbsdrun_disable_x2apic())
530                 err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED);
531         else
532                 err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED);
533
534         if (err) {
535                 fprintf(stderr, "Unable to set x2apic state (%d)\n", err);
536                 exit(1);
537         }
538
539         vm_set_capability(ctx, cpu, VM_CAP_ENABLE_INVPCID, 1);
540 }
541
542 int
543 main(int argc, char *argv[])
544 {
545         int c, error, gdb_port, err, bvmcons;
546         int max_vcpus;
547         struct vmctx *ctx;
548         uint64_t rip;
549         size_t memsize;
550
551         bvmcons = 0;
552         progname = basename(argv[0]);
553         gdb_port = 0;
554         guest_ncpus = 1;
555         memsize = 256 * MB;
556
557         while ((c = getopt(argc, argv, "abehAHIPWp:g:c:s:S:m:l:")) != -1) {
558                 switch (c) {
559                 case 'a':
560                         disable_x2apic = 1;
561                         break;
562                 case 'A':
563                         acpi = 1;
564                         break;
565                 case 'b':
566                         bvmcons = 1;
567                         break;
568                 case 'p':
569                         pincpu = atoi(optarg);
570                         break;
571                 case 'c':
572                         guest_ncpus = atoi(optarg);
573                         break;
574                 case 'g':
575                         gdb_port = atoi(optarg);
576                         break;
577                 case 'l':
578                         if (lpc_device_parse(optarg) != 0) {
579                                 errx(EX_USAGE, "invalid lpc device "
580                                     "configuration '%s'", optarg);
581                         }
582                         break;
583                 case 's':
584                         if (pci_parse_slot(optarg, 0) != 0)
585                                 exit(1);
586                         else
587                                 break;
588                 case 'S':
589                         if (pci_parse_slot(optarg, 1) != 0)
590                                 exit(1);
591                         else
592                                 break;
593                 case 'm':
594                         error = vm_parse_memsize(optarg, &memsize);
595                         if (error)
596                                 errx(EX_USAGE, "invalid memsize '%s'", optarg);
597                         break;
598                 case 'H':
599                         guest_vmexit_on_hlt = 1;
600                         break;
601                 case 'I':
602                         /*
603                          * The "-I" option was used to add an ioapic to the
604                          * virtual machine.
605                          *
606                          * An ioapic is now provided unconditionally for each
607                          * virtual machine and this option is now deprecated.
608                          */
609                         break;
610                 case 'P':
611                         guest_vmexit_on_pause = 1;
612                         break;
613                 case 'e':
614                         strictio = 1;
615                         break;
616                 case 'W':
617                         virtio_msix = 0;
618                         break;
619                 case 'h':
620                         usage(0);                       
621                 default:
622                         usage(1);
623                 }
624         }
625         argc -= optind;
626         argv += optind;
627
628         if (argc != 1)
629                 usage(1);
630
631         vmname = argv[0];
632
633         ctx = vm_open(vmname);
634         if (ctx == NULL) {
635                 perror("vm_open");
636                 exit(1);
637         }
638
639         max_vcpus = num_vcpus_allowed(ctx);
640         if (guest_ncpus > max_vcpus) {
641                 fprintf(stderr, "%d vCPUs requested but only %d available\n",
642                         guest_ncpus, max_vcpus);
643                 exit(1);
644         }
645
646         fbsdrun_set_capabilities(ctx, BSP);
647
648         err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
649         if (err) {
650                 fprintf(stderr, "Unable to setup memory (%d)\n", err);
651                 exit(1);
652         }
653
654         init_mem();
655         init_inout();
656         legacy_irq_init();
657
658         rtc_init(ctx);
659
660         /*
661          * Exit if a device emulation finds an error in it's initilization
662          */
663         if (init_pci(ctx) != 0)
664                 exit(1);
665
666         ioapic_init(0);
667
668         if (gdb_port != 0)
669                 init_dbgport(gdb_port);
670
671         if (bvmcons)
672                 init_bvmcons();
673
674         error = vm_get_register(ctx, BSP, VM_REG_GUEST_RIP, &rip);
675         assert(error == 0);
676
677         /*
678          * build the guest tables, MP etc.
679          */
680         mptable_build(ctx, guest_ncpus);
681
682         if (acpi) {
683                 error = acpi_build(ctx, guest_ncpus);
684                 assert(error == 0);
685         }
686
687         /*
688          * Change the proc title to include the VM name.
689          */
690         setproctitle("%s", vmname); 
691         
692         /*
693          * Add CPU 0
694          */
695         fbsdrun_addcpu(ctx, BSP, rip);
696
697         /*
698          * Head off to the main event dispatch loop
699          */
700         mevent_dispatch();
701
702         exit(1);
703 }