1e285ef8dSPeter Grehan /*- 2e285ef8dSPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3e285ef8dSPeter Grehan * All rights reserved. 4e285ef8dSPeter Grehan * 5e285ef8dSPeter Grehan * Redistribution and use in source and binary forms, with or without 6e285ef8dSPeter Grehan * modification, are permitted provided that the following conditions 7e285ef8dSPeter Grehan * are met: 8e285ef8dSPeter Grehan * 1. Redistributions of source code must retain the above copyright 9e285ef8dSPeter Grehan * notice, this list of conditions and the following disclaimer. 10e285ef8dSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11e285ef8dSPeter Grehan * notice, this list of conditions and the following disclaimer in the 12e285ef8dSPeter Grehan * documentation and/or other materials provided with the distribution. 13e285ef8dSPeter Grehan * 14e285ef8dSPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15e285ef8dSPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e285ef8dSPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e285ef8dSPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18e285ef8dSPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e285ef8dSPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e285ef8dSPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e285ef8dSPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e285ef8dSPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e285ef8dSPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e285ef8dSPeter Grehan * SUCH DAMAGE. 25e285ef8dSPeter Grehan * 26e285ef8dSPeter Grehan * $FreeBSD$ 27e285ef8dSPeter Grehan */ 28e285ef8dSPeter Grehan 29e285ef8dSPeter Grehan #include <sys/cdefs.h> 30e285ef8dSPeter Grehan __FBSDID("$FreeBSD$"); 31e285ef8dSPeter Grehan 32e285ef8dSPeter Grehan #include <sys/types.h> 33e285ef8dSPeter Grehan #include <sys/mman.h> 34e285ef8dSPeter Grehan #include <sys/time.h> 35e285ef8dSPeter Grehan 361c052192SNeel Natu #include <machine/atomic.h> 37e285ef8dSPeter Grehan #include <machine/segments.h> 38e285ef8dSPeter Grehan 39e285ef8dSPeter Grehan #include <stdio.h> 40e285ef8dSPeter Grehan #include <stdlib.h> 41b5331f4dSNeel Natu #include <string.h> 42200758f1SNeel Natu #include <err.h> 43e285ef8dSPeter Grehan #include <libgen.h> 44e285ef8dSPeter Grehan #include <unistd.h> 45e285ef8dSPeter Grehan #include <assert.h> 46e285ef8dSPeter Grehan #include <errno.h> 47e285ef8dSPeter Grehan #include <pthread.h> 48e285ef8dSPeter Grehan #include <pthread_np.h> 49200758f1SNeel Natu #include <sysexits.h> 509b1aa8d6SNeel Natu #include <stdbool.h> 51e285ef8dSPeter Grehan 52e285ef8dSPeter Grehan #include <machine/vmm.h> 53e285ef8dSPeter Grehan #include <vmmapi.h> 54e285ef8dSPeter Grehan 55e285ef8dSPeter Grehan #include "bhyverun.h" 56e285ef8dSPeter Grehan #include "acpi.h" 57e285ef8dSPeter Grehan #include "inout.h" 58e285ef8dSPeter Grehan #include "dbgport.h" 5988ac6958SPeter Grehan #include "fwctl.h" 603cbf3585SJohn Baldwin #include "ioapic.h" 61e285ef8dSPeter Grehan #include "mem.h" 62e285ef8dSPeter Grehan #include "mevent.h" 63e285ef8dSPeter Grehan #include "mptbl.h" 64e285ef8dSPeter Grehan #include "pci_emul.h" 65b3e9732aSJohn Baldwin #include "pci_irq.h" 66ea7f1c8cSNeel Natu #include "pci_lpc.h" 67af5bfc53STycho Nightingale #include "smbiostbl.h" 68e285ef8dSPeter Grehan #include "xmsr.h" 69e285ef8dSPeter Grehan #include "spinup_ap.h" 709d6be09fSPeter Grehan #include "rtc.h" 71e285ef8dSPeter Grehan 72e285ef8dSPeter Grehan #define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */ 73e285ef8dSPeter Grehan 74e285ef8dSPeter Grehan #define MB (1024UL * 1024) 75e285ef8dSPeter Grehan #define GB (1024UL * MB) 76e285ef8dSPeter Grehan 77e285ef8dSPeter Grehan typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu); 783d5444c8SNeel Natu extern int vmexit_task_switch(struct vmctx *, struct vm_exit *, int *vcpu); 79e285ef8dSPeter Grehan 80e285ef8dSPeter Grehan char *vmname; 81e285ef8dSPeter Grehan 82e285ef8dSPeter Grehan int guest_ncpus; 83af5bfc53STycho Nightingale char *guest_uuid_str; 84e285ef8dSPeter Grehan 8552e5c8a2SNeel Natu static int guest_vmexit_on_hlt, guest_vmexit_on_pause; 86062b878fSPeter Grehan static int virtio_msix = 1; 8752e5c8a2SNeel Natu static int x2apic_mode = 0; /* default is xAPIC */ 88e285ef8dSPeter Grehan 89e285ef8dSPeter Grehan static int strictio; 90851d84f1SNeel Natu static int strictmsr = 1; 91e285ef8dSPeter Grehan 92e285ef8dSPeter Grehan static int acpi; 93e285ef8dSPeter Grehan 94e285ef8dSPeter Grehan static char *progname; 95e285ef8dSPeter Grehan static const int BSP = 0; 96e285ef8dSPeter Grehan 970826d045SNeel Natu static cpuset_t cpumask; 98e285ef8dSPeter Grehan 99e285ef8dSPeter Grehan static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip); 100e285ef8dSPeter Grehan 101d37f2adbSNeel Natu static struct vm_exit vmexit[VM_MAXCPU]; 102e285ef8dSPeter Grehan 10394c3b3bfSPeter Grehan struct bhyvestats { 104e285ef8dSPeter Grehan uint64_t vmexit_bogus; 105248e6799SNeel Natu uint64_t vmexit_reqidle; 106e285ef8dSPeter Grehan uint64_t vmexit_hlt; 107e285ef8dSPeter Grehan uint64_t vmexit_pause; 108e285ef8dSPeter Grehan uint64_t vmexit_mtrap; 109318224bbSNeel Natu uint64_t vmexit_inst_emul; 110e285ef8dSPeter Grehan uint64_t cpu_switch_rotate; 111e285ef8dSPeter Grehan uint64_t cpu_switch_direct; 112e285ef8dSPeter Grehan } stats; 113e285ef8dSPeter Grehan 114e285ef8dSPeter Grehan struct mt_vmm_info { 115e285ef8dSPeter Grehan pthread_t mt_thr; 116e285ef8dSPeter Grehan struct vmctx *mt_ctx; 117e285ef8dSPeter Grehan int mt_vcpu; 118e285ef8dSPeter Grehan } mt_vmm_info[VM_MAXCPU]; 119e285ef8dSPeter Grehan 1209b6155a2SNeel Natu static cpuset_t *vcpumap[VM_MAXCPU] = { NULL }; 1219b6155a2SNeel Natu 122e285ef8dSPeter Grehan static void 123e285ef8dSPeter Grehan usage(int code) 124e285ef8dSPeter Grehan { 125e285ef8dSPeter Grehan 126e285ef8dSPeter Grehan fprintf(stderr, 1279b1aa8d6SNeel Natu "Usage: %s [-abehuwxACHPSWY] [-c vcpus] [-g <gdb port>] [-l <lpc>]\n" 128cde1f5b8SJohn Baldwin " %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n" 12952e5c8a2SNeel Natu " -a: local apic is in xAPIC mode (deprecated)\n" 1305749449dSJohn Baldwin " -A: create ACPI tables\n" 131e285ef8dSPeter Grehan " -c: # cpus (default 1)\n" 1320dd10c00SNeel Natu " -C: include guest memory in core file\n" 133b5331f4dSNeel Natu " -e: exit on unhandled I/O access\n" 134cde1f5b8SJohn Baldwin " -g: gdb port\n" 135e285ef8dSPeter Grehan " -h: help\n" 136cde1f5b8SJohn Baldwin " -H: vmexit from the guest on hlt\n" 137ea7f1c8cSNeel Natu " -l: LPC device configuration\n" 138851d84f1SNeel Natu " -m: memory size in MB\n" 139cde1f5b8SJohn Baldwin " -p: pin 'vcpu' to 'hostcpu'\n" 140cde1f5b8SJohn Baldwin " -P: vmexit from the guest on pause\n" 141cde1f5b8SJohn Baldwin " -s: <slot,driver,configinfo> PCI slot config\n" 1429b1aa8d6SNeel Natu " -S: guest memory cannot be swapped\n" 143c9747678SNeel Natu " -u: RTC keeps UTC time\n" 144cde1f5b8SJohn Baldwin " -U: uuid\n" 14552e5c8a2SNeel Natu " -w: ignore unimplemented MSRs\n" 146cde1f5b8SJohn Baldwin " -W: force virtio to use single-vector MSI\n" 147af5bfc53STycho Nightingale " -x: local apic is in x2APIC mode\n" 148cde1f5b8SJohn Baldwin " -Y: disable MPtable generation\n", 149b5331f4dSNeel Natu progname, (int)strlen(progname), ""); 15094c3b3bfSPeter Grehan 151e285ef8dSPeter Grehan exit(code); 152e285ef8dSPeter Grehan } 153e285ef8dSPeter Grehan 1549b6155a2SNeel Natu static int 1559b6155a2SNeel Natu pincpu_parse(const char *opt) 1569b6155a2SNeel Natu { 1579b6155a2SNeel Natu int vcpu, pcpu; 1589b6155a2SNeel Natu 1599b6155a2SNeel Natu if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) { 1609b6155a2SNeel Natu fprintf(stderr, "invalid format: %s\n", opt); 1619b6155a2SNeel Natu return (-1); 1629b6155a2SNeel Natu } 1639b6155a2SNeel Natu 1649b6155a2SNeel Natu if (vcpu < 0 || vcpu >= VM_MAXCPU) { 1659b6155a2SNeel Natu fprintf(stderr, "vcpu '%d' outside valid range from 0 to %d\n", 1669b6155a2SNeel Natu vcpu, VM_MAXCPU - 1); 1679b6155a2SNeel Natu return (-1); 1689b6155a2SNeel Natu } 1699b6155a2SNeel Natu 1709b6155a2SNeel Natu if (pcpu < 0 || pcpu >= CPU_SETSIZE) { 1719b6155a2SNeel Natu fprintf(stderr, "hostcpu '%d' outside valid range from " 1729b6155a2SNeel Natu "0 to %d\n", pcpu, CPU_SETSIZE - 1); 1739b6155a2SNeel Natu return (-1); 1749b6155a2SNeel Natu } 1759b6155a2SNeel Natu 1769b6155a2SNeel Natu if (vcpumap[vcpu] == NULL) { 1779b6155a2SNeel Natu if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) { 1789b6155a2SNeel Natu perror("malloc"); 1799b6155a2SNeel Natu return (-1); 1809b6155a2SNeel Natu } 1819b6155a2SNeel Natu CPU_ZERO(vcpumap[vcpu]); 1829b6155a2SNeel Natu } 1839b6155a2SNeel Natu CPU_SET(pcpu, vcpumap[vcpu]); 1849b6155a2SNeel Natu return (0); 1859b6155a2SNeel Natu } 1869b6155a2SNeel Natu 187d37f2adbSNeel Natu void 188d37f2adbSNeel Natu vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid, 189d37f2adbSNeel Natu int errcode) 190d37f2adbSNeel Natu { 191d37f2adbSNeel Natu struct vmctx *ctx; 192d087a399SNeel Natu int error, restart_instruction; 193d37f2adbSNeel Natu 194d37f2adbSNeel Natu ctx = arg; 195d087a399SNeel Natu restart_instruction = 1; 196d37f2adbSNeel Natu 197d087a399SNeel Natu error = vm_inject_exception(ctx, vcpu, vector, errcode_valid, errcode, 198d087a399SNeel Natu restart_instruction); 199d087a399SNeel Natu assert(error == 0); 200d37f2adbSNeel Natu } 201d37f2adbSNeel Natu 202e285ef8dSPeter Grehan void * 203b060ba50SNeel Natu paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) 204e285ef8dSPeter Grehan { 205e285ef8dSPeter Grehan 206b060ba50SNeel Natu return (vm_map_gpa(ctx, gaddr, len)); 207e285ef8dSPeter Grehan } 208e285ef8dSPeter Grehan 209e285ef8dSPeter Grehan int 210e285ef8dSPeter Grehan fbsdrun_vmexit_on_pause(void) 211e285ef8dSPeter Grehan { 212e285ef8dSPeter Grehan 213e285ef8dSPeter Grehan return (guest_vmexit_on_pause); 214e285ef8dSPeter Grehan } 215e285ef8dSPeter Grehan 216e285ef8dSPeter Grehan int 217e285ef8dSPeter Grehan fbsdrun_vmexit_on_hlt(void) 218e285ef8dSPeter Grehan { 219e285ef8dSPeter Grehan 220e285ef8dSPeter Grehan return (guest_vmexit_on_hlt); 221e285ef8dSPeter Grehan } 222e285ef8dSPeter Grehan 223062b878fSPeter Grehan int 224062b878fSPeter Grehan fbsdrun_virtio_msix(void) 225062b878fSPeter Grehan { 226062b878fSPeter Grehan 227062b878fSPeter Grehan return (virtio_msix); 228062b878fSPeter Grehan } 229062b878fSPeter Grehan 230e285ef8dSPeter Grehan static void * 231e285ef8dSPeter Grehan fbsdrun_start_thread(void *param) 232e285ef8dSPeter Grehan { 233e285ef8dSPeter Grehan char tname[MAXCOMLEN + 1]; 234e285ef8dSPeter Grehan struct mt_vmm_info *mtp; 235e285ef8dSPeter Grehan int vcpu; 236e285ef8dSPeter Grehan 237e285ef8dSPeter Grehan mtp = param; 238e285ef8dSPeter Grehan vcpu = mtp->mt_vcpu; 239e285ef8dSPeter Grehan 2407f5487acSPeter Grehan snprintf(tname, sizeof(tname), "vcpu %d", vcpu); 241e285ef8dSPeter Grehan pthread_set_name_np(mtp->mt_thr, tname); 242e285ef8dSPeter Grehan 243e285ef8dSPeter Grehan vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip); 244e285ef8dSPeter Grehan 245e285ef8dSPeter Grehan /* not reached */ 246e285ef8dSPeter Grehan exit(1); 247e285ef8dSPeter Grehan return (NULL); 248e285ef8dSPeter Grehan } 249e285ef8dSPeter Grehan 250e285ef8dSPeter Grehan void 2510826d045SNeel Natu fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip) 252e285ef8dSPeter Grehan { 253e285ef8dSPeter Grehan int error; 254e285ef8dSPeter Grehan 2550826d045SNeel Natu assert(fromcpu == BSP); 256e285ef8dSPeter Grehan 25795ebc360SNeel Natu /* 25895ebc360SNeel Natu * The 'newcpu' must be activated in the context of 'fromcpu'. If 25995ebc360SNeel Natu * vm_activate_cpu() is delayed until newcpu's pthread starts running 26095ebc360SNeel Natu * then vmm.ko is out-of-sync with bhyve and this can create a race 26195ebc360SNeel Natu * with vm_suspend(). 26295ebc360SNeel Natu */ 26395ebc360SNeel Natu error = vm_activate_cpu(ctx, newcpu); 26468dd37f7SEnji Cooper if (error != 0) 26568dd37f7SEnji Cooper err(EX_OSERR, "could not activate CPU %d", newcpu); 26695ebc360SNeel Natu 2670826d045SNeel Natu CPU_SET_ATOMIC(newcpu, &cpumask); 268e285ef8dSPeter Grehan 269e285ef8dSPeter Grehan /* 270e285ef8dSPeter Grehan * Set up the vmexit struct to allow execution to start 271e285ef8dSPeter Grehan * at the given RIP 272e285ef8dSPeter Grehan */ 2730826d045SNeel Natu vmexit[newcpu].rip = rip; 2740826d045SNeel Natu vmexit[newcpu].inst_length = 0; 275e285ef8dSPeter Grehan 2760826d045SNeel Natu mt_vmm_info[newcpu].mt_ctx = ctx; 2770826d045SNeel Natu mt_vmm_info[newcpu].mt_vcpu = newcpu; 278e285ef8dSPeter Grehan 2790826d045SNeel Natu error = pthread_create(&mt_vmm_info[newcpu].mt_thr, NULL, 2800826d045SNeel Natu fbsdrun_start_thread, &mt_vmm_info[newcpu]); 281e285ef8dSPeter Grehan assert(error == 0); 282e285ef8dSPeter Grehan } 283e285ef8dSPeter Grehan 284e285ef8dSPeter Grehan static int 2851c052192SNeel Natu fbsdrun_deletecpu(struct vmctx *ctx, int vcpu) 2861c052192SNeel Natu { 2871c052192SNeel Natu 2880826d045SNeel Natu if (!CPU_ISSET(vcpu, &cpumask)) { 28906782425SNeel Natu fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu); 2901c052192SNeel Natu exit(1); 2911c052192SNeel Natu } 2921c052192SNeel Natu 2930826d045SNeel Natu CPU_CLR_ATOMIC(vcpu, &cpumask); 2940826d045SNeel Natu return (CPU_EMPTY(&cpumask)); 2951c052192SNeel Natu } 2961c052192SNeel Natu 2971c052192SNeel Natu static int 298e285ef8dSPeter Grehan vmexit_handle_notify(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu, 299e285ef8dSPeter Grehan uint32_t eax) 300e285ef8dSPeter Grehan { 30194c3b3bfSPeter Grehan #if BHYVE_DEBUG 30294c3b3bfSPeter Grehan /* 30394c3b3bfSPeter Grehan * put guest-driven debug here 30494c3b3bfSPeter Grehan */ 305e285ef8dSPeter Grehan #endif 306e285ef8dSPeter Grehan return (VMEXIT_CONTINUE); 307e285ef8dSPeter Grehan } 308e285ef8dSPeter Grehan 309e285ef8dSPeter Grehan static int 310e285ef8dSPeter Grehan vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) 311e285ef8dSPeter Grehan { 312e285ef8dSPeter Grehan int error; 3133ec1cff5SMarcelo Araujo int bytes, port, in, out; 314e285ef8dSPeter Grehan int vcpu; 315e285ef8dSPeter Grehan 316e285ef8dSPeter Grehan vcpu = *pvcpu; 317e285ef8dSPeter Grehan 318e285ef8dSPeter Grehan port = vme->u.inout.port; 319e285ef8dSPeter Grehan bytes = vme->u.inout.bytes; 320e285ef8dSPeter Grehan in = vme->u.inout.in; 321e285ef8dSPeter Grehan out = !in; 322e285ef8dSPeter Grehan 323e285ef8dSPeter Grehan /* Extra-special case of host notifications */ 324d17b5104SNeel Natu if (out && port == GUEST_NIO_PORT) { 325d17b5104SNeel Natu error = vmexit_handle_notify(ctx, vme, pvcpu, vme->u.inout.eax); 326d17b5104SNeel Natu return (error); 327d17b5104SNeel Natu } 328e285ef8dSPeter Grehan 329d17b5104SNeel Natu error = emulate_inout(ctx, vcpu, vme, strictio); 330afd5e8baSNeel Natu if (error) { 3313b65fbe4STycho Nightingale fprintf(stderr, "Unhandled %s%c 0x%04x at 0x%lx\n", 3323b65fbe4STycho Nightingale in ? "in" : "out", 3333b65fbe4STycho Nightingale bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), 3343b65fbe4STycho Nightingale port, vmexit->rip); 335ee2dbd02SNeel Natu return (VMEXIT_ABORT); 336afd5e8baSNeel Natu } else { 337afd5e8baSNeel Natu return (VMEXIT_CONTINUE); 338e285ef8dSPeter Grehan } 339e285ef8dSPeter Grehan } 340e285ef8dSPeter Grehan 341e285ef8dSPeter Grehan static int 342e285ef8dSPeter Grehan vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) 343e285ef8dSPeter Grehan { 344851d84f1SNeel Natu uint64_t val; 345851d84f1SNeel Natu uint32_t eax, edx; 346851d84f1SNeel Natu int error; 347851d84f1SNeel Natu 348851d84f1SNeel Natu val = 0; 349851d84f1SNeel Natu error = emulate_rdmsr(ctx, *pvcpu, vme->u.msr.code, &val); 350851d84f1SNeel Natu if (error != 0) { 351851d84f1SNeel Natu fprintf(stderr, "rdmsr to register %#x on vcpu %d\n", 352851d84f1SNeel Natu vme->u.msr.code, *pvcpu); 353dc506506SNeel Natu if (strictmsr) { 354d37f2adbSNeel Natu vm_inject_gp(ctx, *pvcpu); 355d087a399SNeel Natu return (VMEXIT_CONTINUE); 356dc506506SNeel Natu } 357e285ef8dSPeter Grehan } 358e285ef8dSPeter Grehan 359851d84f1SNeel Natu eax = val; 360851d84f1SNeel Natu error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RAX, eax); 361851d84f1SNeel Natu assert(error == 0); 362851d84f1SNeel Natu 363851d84f1SNeel Natu edx = val >> 32; 364851d84f1SNeel Natu error = vm_set_register(ctx, *pvcpu, VM_REG_GUEST_RDX, edx); 365851d84f1SNeel Natu assert(error == 0); 366851d84f1SNeel Natu 367851d84f1SNeel Natu return (VMEXIT_CONTINUE); 368851d84f1SNeel Natu } 369851d84f1SNeel Natu 370e285ef8dSPeter Grehan static int 371e285ef8dSPeter Grehan vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) 372e285ef8dSPeter Grehan { 373851d84f1SNeel Natu int error; 374e285ef8dSPeter Grehan 375851d84f1SNeel Natu error = emulate_wrmsr(ctx, *pvcpu, vme->u.msr.code, vme->u.msr.wval); 376851d84f1SNeel Natu if (error != 0) { 377851d84f1SNeel Natu fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n", 378851d84f1SNeel Natu vme->u.msr.code, vme->u.msr.wval, *pvcpu); 379dc506506SNeel Natu if (strictmsr) { 380d37f2adbSNeel Natu vm_inject_gp(ctx, *pvcpu); 381d087a399SNeel Natu return (VMEXIT_CONTINUE); 382dc506506SNeel Natu } 383851d84f1SNeel Natu } 384851d84f1SNeel Natu return (VMEXIT_CONTINUE); 385e285ef8dSPeter Grehan } 386e285ef8dSPeter Grehan 387e285ef8dSPeter Grehan static int 388e285ef8dSPeter Grehan vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) 389e285ef8dSPeter Grehan { 390e285ef8dSPeter Grehan int newcpu; 391e285ef8dSPeter Grehan int retval = VMEXIT_CONTINUE; 392e285ef8dSPeter Grehan 393e285ef8dSPeter Grehan newcpu = spinup_ap(ctx, *pvcpu, 394e285ef8dSPeter Grehan vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip); 395e285ef8dSPeter Grehan 396e285ef8dSPeter Grehan return (retval); 397e285ef8dSPeter Grehan } 398e285ef8dSPeter Grehan 39964fe7235SNeel Natu #define DEBUG_EPT_MISCONFIG 40064fe7235SNeel Natu #ifdef DEBUG_EPT_MISCONFIG 40164fe7235SNeel Natu #define EXIT_REASON_EPT_MISCONFIG 49 40264fe7235SNeel Natu #define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 40364fe7235SNeel Natu #define VMCS_IDENT(x) ((x) | 0x80000000) 40464fe7235SNeel Natu 40564fe7235SNeel Natu static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4]; 40664fe7235SNeel Natu static int ept_misconfig_ptenum; 40764fe7235SNeel Natu #endif 40864fe7235SNeel Natu 409e285ef8dSPeter Grehan static int 410e285ef8dSPeter Grehan vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 411e285ef8dSPeter Grehan { 412e285ef8dSPeter Grehan 413e285ef8dSPeter Grehan fprintf(stderr, "vm exit[%d]\n", *pvcpu); 414e285ef8dSPeter Grehan fprintf(stderr, "\treason\t\tVMX\n"); 415e285ef8dSPeter Grehan fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip); 416e285ef8dSPeter Grehan fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length); 4170492757cSNeel Natu fprintf(stderr, "\tstatus\t\t%d\n", vmexit->u.vmx.status); 418e285ef8dSPeter Grehan fprintf(stderr, "\texit_reason\t%u\n", vmexit->u.vmx.exit_reason); 419e285ef8dSPeter Grehan fprintf(stderr, "\tqualification\t0x%016lx\n", 420e285ef8dSPeter Grehan vmexit->u.vmx.exit_qualification); 4210492757cSNeel Natu fprintf(stderr, "\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type); 4220492757cSNeel Natu fprintf(stderr, "\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error); 42364fe7235SNeel Natu #ifdef DEBUG_EPT_MISCONFIG 42464fe7235SNeel Natu if (vmexit->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) { 42564fe7235SNeel Natu vm_get_register(ctx, *pvcpu, 42664fe7235SNeel Natu VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS), 42764fe7235SNeel Natu &ept_misconfig_gpa); 42864fe7235SNeel Natu vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte, 42964fe7235SNeel Natu &ept_misconfig_ptenum); 43064fe7235SNeel Natu fprintf(stderr, "\tEPT misconfiguration:\n"); 43164fe7235SNeel Natu fprintf(stderr, "\t\tGPA: %#lx\n", ept_misconfig_gpa); 43264fe7235SNeel Natu fprintf(stderr, "\t\tPTE(%d): %#lx %#lx %#lx %#lx\n", 43364fe7235SNeel Natu ept_misconfig_ptenum, ept_misconfig_pte[0], 43464fe7235SNeel Natu ept_misconfig_pte[1], ept_misconfig_pte[2], 43564fe7235SNeel Natu ept_misconfig_pte[3]); 43664fe7235SNeel Natu } 43764fe7235SNeel Natu #endif /* DEBUG_EPT_MISCONFIG */ 438e285ef8dSPeter Grehan return (VMEXIT_ABORT); 439e285ef8dSPeter Grehan } 440e285ef8dSPeter Grehan 441e285ef8dSPeter Grehan static int 442bbadcde4SNeel Natu vmexit_svm(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 443bbadcde4SNeel Natu { 444bbadcde4SNeel Natu 445bbadcde4SNeel Natu fprintf(stderr, "vm exit[%d]\n", *pvcpu); 446bbadcde4SNeel Natu fprintf(stderr, "\treason\t\tSVM\n"); 447bbadcde4SNeel Natu fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip); 448bbadcde4SNeel Natu fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length); 449bbadcde4SNeel Natu fprintf(stderr, "\texitcode\t%#lx\n", vmexit->u.svm.exitcode); 450bbadcde4SNeel Natu fprintf(stderr, "\texitinfo1\t%#lx\n", vmexit->u.svm.exitinfo1); 451bbadcde4SNeel Natu fprintf(stderr, "\texitinfo2\t%#lx\n", vmexit->u.svm.exitinfo2); 452bbadcde4SNeel Natu return (VMEXIT_ABORT); 453bbadcde4SNeel Natu } 454bbadcde4SNeel Natu 455bbadcde4SNeel Natu static int 456e285ef8dSPeter Grehan vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 457e285ef8dSPeter Grehan { 45894c3b3bfSPeter Grehan 459d087a399SNeel Natu assert(vmexit->inst_length == 0); 460d087a399SNeel Natu 461e285ef8dSPeter Grehan stats.vmexit_bogus++; 462e285ef8dSPeter Grehan 463d087a399SNeel Natu return (VMEXIT_CONTINUE); 464e285ef8dSPeter Grehan } 465e285ef8dSPeter Grehan 466e285ef8dSPeter Grehan static int 467248e6799SNeel Natu vmexit_reqidle(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 468248e6799SNeel Natu { 469248e6799SNeel Natu 470248e6799SNeel Natu assert(vmexit->inst_length == 0); 471248e6799SNeel Natu 472248e6799SNeel Natu stats.vmexit_reqidle++; 473248e6799SNeel Natu 474248e6799SNeel Natu return (VMEXIT_CONTINUE); 475248e6799SNeel Natu } 476248e6799SNeel Natu 477248e6799SNeel Natu static int 478e285ef8dSPeter Grehan vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 479e285ef8dSPeter Grehan { 48094c3b3bfSPeter Grehan 481e285ef8dSPeter Grehan stats.vmexit_hlt++; 48294c3b3bfSPeter Grehan 483e285ef8dSPeter Grehan /* 484e285ef8dSPeter Grehan * Just continue execution with the next instruction. We use 485e285ef8dSPeter Grehan * the HLT VM exit as a way to be friendly with the host 486e285ef8dSPeter Grehan * scheduler. 487e285ef8dSPeter Grehan */ 488e285ef8dSPeter Grehan return (VMEXIT_CONTINUE); 489e285ef8dSPeter Grehan } 490e285ef8dSPeter Grehan 491e285ef8dSPeter Grehan static int 492e285ef8dSPeter Grehan vmexit_pause(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 493e285ef8dSPeter Grehan { 49494c3b3bfSPeter Grehan 495e285ef8dSPeter Grehan stats.vmexit_pause++; 496e285ef8dSPeter Grehan 497e285ef8dSPeter Grehan return (VMEXIT_CONTINUE); 498e285ef8dSPeter Grehan } 499e285ef8dSPeter Grehan 500e285ef8dSPeter Grehan static int 501e285ef8dSPeter Grehan vmexit_mtrap(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 502e285ef8dSPeter Grehan { 50394c3b3bfSPeter Grehan 504d087a399SNeel Natu assert(vmexit->inst_length == 0); 505d087a399SNeel Natu 506e285ef8dSPeter Grehan stats.vmexit_mtrap++; 507e285ef8dSPeter Grehan 508d087a399SNeel Natu return (VMEXIT_CONTINUE); 509e285ef8dSPeter Grehan } 510e285ef8dSPeter Grehan 511e285ef8dSPeter Grehan static int 512318224bbSNeel Natu vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 513e285ef8dSPeter Grehan { 514703e4974STycho Nightingale int err, i; 515703e4974STycho Nightingale struct vie *vie; 516703e4974STycho Nightingale 517318224bbSNeel Natu stats.vmexit_inst_emul++; 518e285ef8dSPeter Grehan 519703e4974STycho Nightingale vie = &vmexit->u.inst_emul.vie; 520318224bbSNeel Natu err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa, 521703e4974STycho Nightingale vie, &vmexit->u.inst_emul.paging); 522e285ef8dSPeter Grehan 523e285ef8dSPeter Grehan if (err) { 524703e4974STycho Nightingale if (err == ESRCH) { 525e285ef8dSPeter Grehan fprintf(stderr, "Unhandled memory access to 0x%lx\n", 526318224bbSNeel Natu vmexit->u.inst_emul.gpa); 527e285ef8dSPeter Grehan } 528e285ef8dSPeter Grehan 529703e4974STycho Nightingale fprintf(stderr, "Failed to emulate instruction ["); 530703e4974STycho Nightingale for (i = 0; i < vie->num_valid; i++) { 531703e4974STycho Nightingale fprintf(stderr, "0x%02x%s", vie->inst[i], 532703e4974STycho Nightingale i != (vie->num_valid - 1) ? " " : ""); 533703e4974STycho Nightingale } 534703e4974STycho Nightingale fprintf(stderr, "] at 0x%lx\n", vmexit->rip); 535e285ef8dSPeter Grehan return (VMEXIT_ABORT); 536e285ef8dSPeter Grehan } 537e285ef8dSPeter Grehan 538e285ef8dSPeter Grehan return (VMEXIT_CONTINUE); 539e285ef8dSPeter Grehan } 540e285ef8dSPeter Grehan 541b15a09c0SNeel Natu static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER; 542b15a09c0SNeel Natu static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER; 543b15a09c0SNeel Natu 544b15a09c0SNeel Natu static int 545b15a09c0SNeel Natu vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) 546b15a09c0SNeel Natu { 547f0fdcfe2SNeel Natu enum vm_suspend_how how; 548b15a09c0SNeel Natu 549f0fdcfe2SNeel Natu how = vmexit->u.suspended.how; 550b15a09c0SNeel Natu 551b15a09c0SNeel Natu fbsdrun_deletecpu(ctx, *pvcpu); 552b15a09c0SNeel Natu 553f0fdcfe2SNeel Natu if (*pvcpu != BSP) { 554b15a09c0SNeel Natu pthread_mutex_lock(&resetcpu_mtx); 555b15a09c0SNeel Natu pthread_cond_signal(&resetcpu_cond); 556b15a09c0SNeel Natu pthread_mutex_unlock(&resetcpu_mtx); 557b15a09c0SNeel Natu pthread_exit(NULL); 558b15a09c0SNeel Natu } 559b15a09c0SNeel Natu 560b15a09c0SNeel Natu pthread_mutex_lock(&resetcpu_mtx); 561b15a09c0SNeel Natu while (!CPU_EMPTY(&cpumask)) { 562b15a09c0SNeel Natu pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx); 563b15a09c0SNeel Natu } 564b15a09c0SNeel Natu pthread_mutex_unlock(&resetcpu_mtx); 565f0fdcfe2SNeel Natu 566e50ce2aaSNeel Natu switch (how) { 567e50ce2aaSNeel Natu case VM_SUSPEND_RESET: 568b15a09c0SNeel Natu exit(0); 569e50ce2aaSNeel Natu case VM_SUSPEND_POWEROFF: 570f0fdcfe2SNeel Natu exit(1); 571e50ce2aaSNeel Natu case VM_SUSPEND_HALT: 572e50ce2aaSNeel Natu exit(2); 573091d4532SNeel Natu case VM_SUSPEND_TRIPLEFAULT: 574091d4532SNeel Natu exit(3); 575e50ce2aaSNeel Natu default: 576e50ce2aaSNeel Natu fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how); 577e50ce2aaSNeel Natu exit(100); 578e50ce2aaSNeel Natu } 579f0fdcfe2SNeel Natu return (0); /* NOTREACHED */ 580b15a09c0SNeel Natu } 581b15a09c0SNeel Natu 582e285ef8dSPeter Grehan static vmexit_handler_t handler[VM_EXITCODE_MAX] = { 583e285ef8dSPeter Grehan [VM_EXITCODE_INOUT] = vmexit_inout, 584d17b5104SNeel Natu [VM_EXITCODE_INOUT_STR] = vmexit_inout, 585e285ef8dSPeter Grehan [VM_EXITCODE_VMX] = vmexit_vmx, 586bbadcde4SNeel Natu [VM_EXITCODE_SVM] = vmexit_svm, 587e285ef8dSPeter Grehan [VM_EXITCODE_BOGUS] = vmexit_bogus, 588248e6799SNeel Natu [VM_EXITCODE_REQIDLE] = vmexit_reqidle, 589e285ef8dSPeter Grehan [VM_EXITCODE_RDMSR] = vmexit_rdmsr, 590e285ef8dSPeter Grehan [VM_EXITCODE_WRMSR] = vmexit_wrmsr, 591e285ef8dSPeter Grehan [VM_EXITCODE_MTRAP] = vmexit_mtrap, 592318224bbSNeel Natu [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul, 593e285ef8dSPeter Grehan [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap, 5943d5444c8SNeel Natu [VM_EXITCODE_SUSPENDED] = vmexit_suspend, 5953d5444c8SNeel Natu [VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch, 596e285ef8dSPeter Grehan }; 597e285ef8dSPeter Grehan 598e285ef8dSPeter Grehan static void 599d087a399SNeel Natu vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip) 600e285ef8dSPeter Grehan { 601*cc398e21SBjoern A. Zeeb int error, rc; 6028b271170SPeter Grehan enum vm_exitcode exitcode; 60395ebc360SNeel Natu cpuset_t active_cpus; 604e285ef8dSPeter Grehan 6059b6155a2SNeel Natu if (vcpumap[vcpu] != NULL) { 606485b3300SNeel Natu error = pthread_setaffinity_np(pthread_self(), 6079b6155a2SNeel Natu sizeof(cpuset_t), vcpumap[vcpu]); 608e285ef8dSPeter Grehan assert(error == 0); 609e285ef8dSPeter Grehan } 610e285ef8dSPeter Grehan 61195ebc360SNeel Natu error = vm_active_cpus(ctx, &active_cpus); 61295ebc360SNeel Natu assert(CPU_ISSET(vcpu, &active_cpus)); 61395ebc360SNeel Natu 614d087a399SNeel Natu error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RIP, startrip); 615d087a399SNeel Natu assert(error == 0); 616d087a399SNeel Natu 617e285ef8dSPeter Grehan while (1) { 618d087a399SNeel Natu error = vm_run(ctx, vcpu, &vmexit[vcpu]); 619f80330a8SNeel Natu if (error != 0) 620e285ef8dSPeter Grehan break; 621e285ef8dSPeter Grehan 6228b271170SPeter Grehan exitcode = vmexit[vcpu].exitcode; 6238b271170SPeter Grehan if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) { 6248b271170SPeter Grehan fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n", 6258b271170SPeter Grehan exitcode); 6268b271170SPeter Grehan exit(1); 6278b271170SPeter Grehan } 6288b271170SPeter Grehan 6298b271170SPeter Grehan rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu); 6308b271170SPeter Grehan 631e285ef8dSPeter Grehan switch (rc) { 632e285ef8dSPeter Grehan case VMEXIT_CONTINUE: 633e285ef8dSPeter Grehan break; 634ee2dbd02SNeel Natu case VMEXIT_ABORT: 635ee2dbd02SNeel Natu abort(); 636e285ef8dSPeter Grehan default: 637e285ef8dSPeter Grehan exit(1); 638e285ef8dSPeter Grehan } 639e285ef8dSPeter Grehan } 640e285ef8dSPeter Grehan fprintf(stderr, "vm_run error %d, errno %d\n", error, errno); 641e285ef8dSPeter Grehan } 642e285ef8dSPeter Grehan 6435f0677d3SNeel Natu static int 6445f0677d3SNeel Natu num_vcpus_allowed(struct vmctx *ctx) 6455f0677d3SNeel Natu { 6465f0677d3SNeel Natu int tmp, error; 6475f0677d3SNeel Natu 6485f0677d3SNeel Natu error = vm_get_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, &tmp); 6495f0677d3SNeel Natu 6505f0677d3SNeel Natu /* 6515f0677d3SNeel Natu * The guest is allowed to spinup more than one processor only if the 6525f0677d3SNeel Natu * UNRESTRICTED_GUEST capability is available. 6535f0677d3SNeel Natu */ 6545f0677d3SNeel Natu if (error == 0) 6555f0677d3SNeel Natu return (VM_MAXCPU); 6565f0677d3SNeel Natu else 6575f0677d3SNeel Natu return (1); 6585f0677d3SNeel Natu } 659e285ef8dSPeter Grehan 66049cc03daSNeel Natu void 66149cc03daSNeel Natu fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) 66249cc03daSNeel Natu { 66349cc03daSNeel Natu int err, tmp; 66449cc03daSNeel Natu 66549cc03daSNeel Natu if (fbsdrun_vmexit_on_hlt()) { 66649cc03daSNeel Natu err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp); 66749cc03daSNeel Natu if (err < 0) { 66849cc03daSNeel Natu fprintf(stderr, "VM exit on HLT not supported\n"); 66949cc03daSNeel Natu exit(1); 67049cc03daSNeel Natu } 67149cc03daSNeel Natu vm_set_capability(ctx, cpu, VM_CAP_HALT_EXIT, 1); 67249cc03daSNeel Natu if (cpu == BSP) 67349cc03daSNeel Natu handler[VM_EXITCODE_HLT] = vmexit_hlt; 67449cc03daSNeel Natu } 67549cc03daSNeel Natu 67649cc03daSNeel Natu if (fbsdrun_vmexit_on_pause()) { 67749cc03daSNeel Natu /* 67849cc03daSNeel Natu * pause exit support required for this mode 67949cc03daSNeel Natu */ 68049cc03daSNeel Natu err = vm_get_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, &tmp); 68149cc03daSNeel Natu if (err < 0) { 68249cc03daSNeel Natu fprintf(stderr, 68349cc03daSNeel Natu "SMP mux requested, no pause support\n"); 68449cc03daSNeel Natu exit(1); 68549cc03daSNeel Natu } 68649cc03daSNeel Natu vm_set_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, 1); 68749cc03daSNeel Natu if (cpu == BSP) 68849cc03daSNeel Natu handler[VM_EXITCODE_PAUSE] = vmexit_pause; 68949cc03daSNeel Natu } 69049cc03daSNeel Natu 69152e5c8a2SNeel Natu if (x2apic_mode) 69249cc03daSNeel Natu err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED); 69352e5c8a2SNeel Natu else 69452e5c8a2SNeel Natu err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); 69549cc03daSNeel Natu 69649cc03daSNeel Natu if (err) { 69749cc03daSNeel Natu fprintf(stderr, "Unable to set x2apic state (%d)\n", err); 69849cc03daSNeel Natu exit(1); 69949cc03daSNeel Natu } 70049cc03daSNeel Natu 70149cc03daSNeel Natu vm_set_capability(ctx, cpu, VM_CAP_ENABLE_INVPCID, 1); 70249cc03daSNeel Natu } 70349cc03daSNeel Natu 7049b1aa8d6SNeel Natu static struct vmctx * 7059b1aa8d6SNeel Natu do_open(const char *vmname) 7069b1aa8d6SNeel Natu { 7079b1aa8d6SNeel Natu struct vmctx *ctx; 7089b1aa8d6SNeel Natu int error; 7099b1aa8d6SNeel Natu bool reinit, romboot; 7109b1aa8d6SNeel Natu 7119b1aa8d6SNeel Natu reinit = romboot = false; 7129b1aa8d6SNeel Natu 7139b1aa8d6SNeel Natu if (lpc_bootrom()) 7149b1aa8d6SNeel Natu romboot = true; 7159b1aa8d6SNeel Natu 7169b1aa8d6SNeel Natu error = vm_create(vmname); 7179b1aa8d6SNeel Natu if (error) { 7189b1aa8d6SNeel Natu if (errno == EEXIST) { 7199b1aa8d6SNeel Natu if (romboot) { 7209b1aa8d6SNeel Natu reinit = true; 7219b1aa8d6SNeel Natu } else { 7229b1aa8d6SNeel Natu /* 7239b1aa8d6SNeel Natu * The virtual machine has been setup by the 7249b1aa8d6SNeel Natu * userspace bootloader. 7259b1aa8d6SNeel Natu */ 7269b1aa8d6SNeel Natu } 7279b1aa8d6SNeel Natu } else { 7289b1aa8d6SNeel Natu perror("vm_create"); 7299b1aa8d6SNeel Natu exit(1); 7309b1aa8d6SNeel Natu } 7319b1aa8d6SNeel Natu } else { 7329b1aa8d6SNeel Natu if (!romboot) { 7339b1aa8d6SNeel Natu /* 7349b1aa8d6SNeel Natu * If the virtual machine was just created then a 7359b1aa8d6SNeel Natu * bootrom must be configured to boot it. 7369b1aa8d6SNeel Natu */ 7379b1aa8d6SNeel Natu fprintf(stderr, "virtual machine cannot be booted\n"); 7389b1aa8d6SNeel Natu exit(1); 7399b1aa8d6SNeel Natu } 7409b1aa8d6SNeel Natu } 7419b1aa8d6SNeel Natu 7429b1aa8d6SNeel Natu ctx = vm_open(vmname); 7439b1aa8d6SNeel Natu if (ctx == NULL) { 7449b1aa8d6SNeel Natu perror("vm_open"); 7459b1aa8d6SNeel Natu exit(1); 7469b1aa8d6SNeel Natu } 7479b1aa8d6SNeel Natu 7489b1aa8d6SNeel Natu if (reinit) { 7499b1aa8d6SNeel Natu error = vm_reinit(ctx); 7509b1aa8d6SNeel Natu if (error) { 7519b1aa8d6SNeel Natu perror("vm_reinit"); 7529b1aa8d6SNeel Natu exit(1); 7539b1aa8d6SNeel Natu } 7549b1aa8d6SNeel Natu } 7559b1aa8d6SNeel Natu return (ctx); 7569b1aa8d6SNeel Natu } 7579b1aa8d6SNeel Natu 758e285ef8dSPeter Grehan int 759e285ef8dSPeter Grehan main(int argc, char *argv[]) 760e285ef8dSPeter Grehan { 761a1a4cbeaSNeel Natu int c, error, gdb_port, err, bvmcons; 7629b1aa8d6SNeel Natu int max_vcpus, mptgen, memflags; 763c9747678SNeel Natu int rtc_localtime; 764e285ef8dSPeter Grehan struct vmctx *ctx; 765e285ef8dSPeter Grehan uint64_t rip; 766b060ba50SNeel Natu size_t memsize; 7679b1aa8d6SNeel Natu char *optstr; 768e285ef8dSPeter Grehan 769e285ef8dSPeter Grehan bvmcons = 0; 770e285ef8dSPeter Grehan progname = basename(argv[0]); 7714a06a0feSNeel Natu gdb_port = 0; 772e285ef8dSPeter Grehan guest_ncpus = 1; 773b060ba50SNeel Natu memsize = 256 * MB; 774b100acf2SNeel Natu mptgen = 1; 775c9747678SNeel Natu rtc_localtime = 1; 7769b1aa8d6SNeel Natu memflags = 0; 777e285ef8dSPeter Grehan 7789b1aa8d6SNeel Natu optstr = "abehuwxACHIPSWYp:g:c:s:m:l:U:"; 7799b1aa8d6SNeel Natu while ((c = getopt(argc, argv, optstr)) != -1) { 780e285ef8dSPeter Grehan switch (c) { 781e285ef8dSPeter Grehan case 'a': 78252e5c8a2SNeel Natu x2apic_mode = 0; 783e285ef8dSPeter Grehan break; 784e285ef8dSPeter Grehan case 'A': 785e285ef8dSPeter Grehan acpi = 1; 786e285ef8dSPeter Grehan break; 787e285ef8dSPeter Grehan case 'b': 788e285ef8dSPeter Grehan bvmcons = 1; 789e285ef8dSPeter Grehan break; 790e285ef8dSPeter Grehan case 'p': 7919b6155a2SNeel Natu if (pincpu_parse(optarg) != 0) { 7929b6155a2SNeel Natu errx(EX_USAGE, "invalid vcpu pinning " 7939b6155a2SNeel Natu "configuration '%s'", optarg); 7949b6155a2SNeel Natu } 795e285ef8dSPeter Grehan break; 796e285ef8dSPeter Grehan case 'c': 797e285ef8dSPeter Grehan guest_ncpus = atoi(optarg); 798e285ef8dSPeter Grehan break; 7990dd10c00SNeel Natu case 'C': 8009b1aa8d6SNeel Natu memflags |= VM_MEM_F_INCORE; 8010dd10c00SNeel Natu break; 802e285ef8dSPeter Grehan case 'g': 803e285ef8dSPeter Grehan gdb_port = atoi(optarg); 804e285ef8dSPeter Grehan break; 805ea7f1c8cSNeel Natu case 'l': 806ea7f1c8cSNeel Natu if (lpc_device_parse(optarg) != 0) { 807ea7f1c8cSNeel Natu errx(EX_USAGE, "invalid lpc device " 808ea7f1c8cSNeel Natu "configuration '%s'", optarg); 809ea7f1c8cSNeel Natu } 810ea7f1c8cSNeel Natu break; 811e285ef8dSPeter Grehan case 's': 812d2bc4816SJohn Baldwin if (pci_parse_slot(optarg) != 0) 813b05c77ffSNeel Natu exit(1); 814b05c77ffSNeel Natu else 815e285ef8dSPeter Grehan break; 8169b1aa8d6SNeel Natu case 'S': 8179b1aa8d6SNeel Natu memflags |= VM_MEM_F_WIRED; 8189b1aa8d6SNeel Natu break; 819e285ef8dSPeter Grehan case 'm': 820200758f1SNeel Natu error = vm_parse_memsize(optarg, &memsize); 821200758f1SNeel Natu if (error) 822200758f1SNeel Natu errx(EX_USAGE, "invalid memsize '%s'", optarg); 823e285ef8dSPeter Grehan break; 824e285ef8dSPeter Grehan case 'H': 825e285ef8dSPeter Grehan guest_vmexit_on_hlt = 1; 826e285ef8dSPeter Grehan break; 827e285ef8dSPeter Grehan case 'I': 828a1a4cbeaSNeel Natu /* 829a1a4cbeaSNeel Natu * The "-I" option was used to add an ioapic to the 830a1a4cbeaSNeel Natu * virtual machine. 831a1a4cbeaSNeel Natu * 832a1a4cbeaSNeel Natu * An ioapic is now provided unconditionally for each 833a1a4cbeaSNeel Natu * virtual machine and this option is now deprecated. 834a1a4cbeaSNeel Natu */ 835e285ef8dSPeter Grehan break; 836e285ef8dSPeter Grehan case 'P': 837e285ef8dSPeter Grehan guest_vmexit_on_pause = 1; 838e285ef8dSPeter Grehan break; 839e285ef8dSPeter Grehan case 'e': 840e285ef8dSPeter Grehan strictio = 1; 841e285ef8dSPeter Grehan break; 842c9747678SNeel Natu case 'u': 843c9747678SNeel Natu rtc_localtime = 0; 844c9747678SNeel Natu break; 845af5bfc53STycho Nightingale case 'U': 846af5bfc53STycho Nightingale guest_uuid_str = optarg; 847af5bfc53STycho Nightingale break; 848851d84f1SNeel Natu case 'w': 849851d84f1SNeel Natu strictmsr = 0; 850851d84f1SNeel Natu break; 851062b878fSPeter Grehan case 'W': 852062b878fSPeter Grehan virtio_msix = 0; 853062b878fSPeter Grehan break; 85452e5c8a2SNeel Natu case 'x': 85552e5c8a2SNeel Natu x2apic_mode = 1; 85652e5c8a2SNeel Natu break; 857b100acf2SNeel Natu case 'Y': 858b100acf2SNeel Natu mptgen = 0; 859b100acf2SNeel Natu break; 860e285ef8dSPeter Grehan case 'h': 861e285ef8dSPeter Grehan usage(0); 862e285ef8dSPeter Grehan default: 863e285ef8dSPeter Grehan usage(1); 864e285ef8dSPeter Grehan } 865e285ef8dSPeter Grehan } 866e285ef8dSPeter Grehan argc -= optind; 867e285ef8dSPeter Grehan argv += optind; 868e285ef8dSPeter Grehan 869e285ef8dSPeter Grehan if (argc != 1) 870e285ef8dSPeter Grehan usage(1); 871e285ef8dSPeter Grehan 872e285ef8dSPeter Grehan vmname = argv[0]; 8739b1aa8d6SNeel Natu ctx = do_open(vmname); 874e285ef8dSPeter Grehan 87577afcaddSNeel Natu if (guest_ncpus < 1) { 87677afcaddSNeel Natu fprintf(stderr, "Invalid guest vCPUs (%d)\n", guest_ncpus); 87777afcaddSNeel Natu exit(1); 87877afcaddSNeel Natu } 87977afcaddSNeel Natu 8805f0677d3SNeel Natu max_vcpus = num_vcpus_allowed(ctx); 8815f0677d3SNeel Natu if (guest_ncpus > max_vcpus) { 8825f0677d3SNeel Natu fprintf(stderr, "%d vCPUs requested but only %d available\n", 8835f0677d3SNeel Natu guest_ncpus, max_vcpus); 8845f0677d3SNeel Natu exit(1); 8855f0677d3SNeel Natu } 8865f0677d3SNeel Natu 88749cc03daSNeel Natu fbsdrun_set_capabilities(ctx, BSP); 888e285ef8dSPeter Grehan 8899b1aa8d6SNeel Natu vm_set_memflags(ctx, memflags); 890b060ba50SNeel Natu err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL); 891b060ba50SNeel Natu if (err) { 8929b1aa8d6SNeel Natu fprintf(stderr, "Unable to setup memory (%d)\n", errno); 893b060ba50SNeel Natu exit(1); 894e285ef8dSPeter Grehan } 895e285ef8dSPeter Grehan 896c3498942SNeel Natu error = init_msr(); 897c3498942SNeel Natu if (error) { 898c3498942SNeel Natu fprintf(stderr, "init_msr error %d", error); 899c3498942SNeel Natu exit(1); 900c3498942SNeel Natu } 901c3498942SNeel Natu 9020e2ca4e6SNeel Natu init_mem(); 903e285ef8dSPeter Grehan init_inout(); 904b3e9732aSJohn Baldwin pci_irq_init(ctx); 9053cbf3585SJohn Baldwin ioapic_init(ctx); 906a38e2a64SPeter Grehan 907c9747678SNeel Natu rtc_init(ctx, rtc_localtime); 908b3e9732aSJohn Baldwin sci_init(ctx); 9099d6be09fSPeter Grehan 910a38e2a64SPeter Grehan /* 911a38e2a64SPeter Grehan * Exit if a device emulation finds an error in it's initilization 912a38e2a64SPeter Grehan */ 913a38e2a64SPeter Grehan if (init_pci(ctx) != 0) 914a38e2a64SPeter Grehan exit(1); 915a38e2a64SPeter Grehan 916e285ef8dSPeter Grehan if (gdb_port != 0) 917e285ef8dSPeter Grehan init_dbgport(gdb_port); 918e285ef8dSPeter Grehan 919e285ef8dSPeter Grehan if (bvmcons) 920e285ef8dSPeter Grehan init_bvmcons(); 921e285ef8dSPeter Grehan 9229b1aa8d6SNeel Natu if (lpc_bootrom()) { 9239b1aa8d6SNeel Natu if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) { 9249b1aa8d6SNeel Natu fprintf(stderr, "ROM boot failed: unrestricted guest " 9259b1aa8d6SNeel Natu "capability not available\n"); 9269b1aa8d6SNeel Natu exit(1); 9279b1aa8d6SNeel Natu } 9289b1aa8d6SNeel Natu error = vcpu_reset(ctx, BSP); 9299b1aa8d6SNeel Natu assert(error == 0); 9309b1aa8d6SNeel Natu } 9319b1aa8d6SNeel Natu 932e285ef8dSPeter Grehan error = vm_get_register(ctx, BSP, VM_REG_GUEST_RIP, &rip); 933e285ef8dSPeter Grehan assert(error == 0); 934e285ef8dSPeter Grehan 935e285ef8dSPeter Grehan /* 936e285ef8dSPeter Grehan * build the guest tables, MP etc. 937e285ef8dSPeter Grehan */ 938b100acf2SNeel Natu if (mptgen) { 939b100acf2SNeel Natu error = mptable_build(ctx, guest_ncpus); 940b100acf2SNeel Natu if (error) 941b100acf2SNeel Natu exit(1); 942b100acf2SNeel Natu } 943e285ef8dSPeter Grehan 944af5bfc53STycho Nightingale error = smbios_build(ctx); 945af5bfc53STycho Nightingale assert(error == 0); 946af5bfc53STycho Nightingale 947e285ef8dSPeter Grehan if (acpi) { 948a1a4cbeaSNeel Natu error = acpi_build(ctx, guest_ncpus); 949e285ef8dSPeter Grehan assert(error == 0); 950e285ef8dSPeter Grehan } 951e285ef8dSPeter Grehan 95288ac6958SPeter Grehan if (lpc_bootrom()) 95388ac6958SPeter Grehan fwctl_init(); 95488ac6958SPeter Grehan 955e285ef8dSPeter Grehan /* 9567f5487acSPeter Grehan * Change the proc title to include the VM name. 9577f5487acSPeter Grehan */ 9587f5487acSPeter Grehan setproctitle("%s", vmname); 9597f5487acSPeter Grehan 9607f5487acSPeter Grehan /* 961e285ef8dSPeter Grehan * Add CPU 0 962e285ef8dSPeter Grehan */ 9630826d045SNeel Natu fbsdrun_addcpu(ctx, BSP, BSP, rip); 964e285ef8dSPeter Grehan 965e285ef8dSPeter Grehan /* 966e285ef8dSPeter Grehan * Head off to the main event dispatch loop 967e285ef8dSPeter Grehan */ 968e285ef8dSPeter Grehan mevent_dispatch(); 969e285ef8dSPeter Grehan 970e285ef8dSPeter Grehan exit(1); 971e285ef8dSPeter Grehan } 972