21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  *
  28  * $FreeBSD$
  29  */
  30 /*
  31  * This file and its contents are supplied under the terms of the
  32  * Common Development and Distribution License ("CDDL"), version 1.0.
  33  * You may only use this file in accordance with the terms of version
  34  * 1.0 of the CDDL.
  35  *
  36  * A full copy of the text of the CDDL should have accompanied this
  37  * source.  A copy of the CDDL is also available via the Internet at
  38  * http://www.illumos.org/license/CDDL.
  39  *
  40  * Copyright 2015 Pluribus Networks Inc.
  41  * Copyright 2021 Joyent, Inc.
  42  * Copyright 2021 Oxide Computer Company
  43  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
  44  */
  45 
  46 #include <sys/cdefs.h>
  47 __FBSDID("$FreeBSD$");
  48 
  49 #include <sys/param.h>
  50 #include <sys/systm.h>
  51 #include <sys/kernel.h>
  52 #include <sys/module.h>
  53 #include <sys/sysctl.h>
  54 #include <sys/malloc.h>
  55 #include <sys/pcpu.h>
  56 #include <sys/lock.h>
  57 #include <sys/mutex.h>
  58 #include <sys/proc.h>
  59 #include <sys/rwlock.h>
  60 #include <sys/sched.h>
  61 #include <sys/smp.h>
 
 172         struct vatpic   *vatpic;                /* (i) virtual atpic */
 173         struct vatpit   *vatpit;                /* (i) virtual atpit */
 174         struct vpmtmr   *vpmtmr;                /* (i) virtual ACPI PM timer */
 175         struct vrtc     *vrtc;                  /* (o) virtual RTC */
 176         volatile cpuset_t active_cpus;          /* (i) active vcpus */
 177         volatile cpuset_t debug_cpus;           /* (i) vcpus stopped for dbg */
 178         int             suspend;                /* (i) stop VM execution */
 179         volatile cpuset_t suspended_cpus;       /* (i) suspended vcpus */
 180         volatile cpuset_t halted_cpus;          /* (x) cpus in a hard halt */
 181         struct mem_map  mem_maps[VM_MAX_MEMMAPS]; /* (i) guest address space */
 182         struct mem_seg  mem_segs[VM_MAX_MEMSEGS]; /* (o) guest memory regions */
 183         struct vmspace  *vmspace;               /* (o) guest's address space */
 184         char            name[VM_MAX_NAMELEN];   /* (o) virtual machine name */
 185         struct vcpu     vcpu[VM_MAXCPU];        /* (i) guest vcpus */
 186         /* The following describe the vm cpu topology */
 187         uint16_t        sockets;                /* (o) num of sockets */
 188         uint16_t        cores;                  /* (o) num of cores/socket */
 189         uint16_t        threads;                /* (o) num of threads/core */
 190         uint16_t        maxcpus;                /* (o) max pluggable cpus */
 191         uint64_t        boot_tsc_offset;        /* (i) TSC offset at VM boot */
 192         size_t          arc_resv;               /* # of pages take from ARC */
 193 
 194         struct ioport_config ioports;           /* (o) ioport handling */
 195 };
 196 
 197 static int vmm_initialized;
 198 
 199 
 200 static void
 201 nullop_panic(void)
 202 {
 203         panic("null vmm operation call");
 204 }
 205 
 206 /* Do not allow use of an un-set `ops` to do anything but panic */
 207 static struct vmm_ops vmm_ops_null = {
 208         .init           = (vmm_init_func_t)nullop_panic,
 209         .cleanup        = (vmm_cleanup_func_t)nullop_panic,
 210         .resume         = (vmm_resume_func_t)nullop_panic,
 211         .vminit         = (vmi_init_func_t)nullop_panic,
 212         .vmrun          = (vmi_run_func_t)nullop_panic,
 
 258     NULL);
 259 
 260 /*
 261  * Halt the guest if all vcpus are executing a HLT instruction with
 262  * interrupts disabled.
 263  */
 264 static int halt_detection_enabled = 1;
 265 
 266 /* IPI vector used for vcpu notifications */
 267 static int vmm_ipinum;
 268 
 269 /* Trap into hypervisor on all guest exceptions and reflect them back */
 270 static int trace_guest_exceptions;
 271 
 272 static void vm_free_memmap(struct vm *vm, int ident);
 273 static bool sysmem_mapping(struct vm *vm, struct mem_map *mm);
 274 static void vcpu_notify_event_locked(struct vcpu *vcpu, vcpu_notify_t);
 275 static bool vcpu_sleep_bailout_checks(struct vm *vm, int vcpuid);
 276 static int vcpu_vector_sipi(struct vm *vm, int vcpuid, uint8_t vector);
 277 
 278 extern int arc_virt_machine_reserve(size_t);
 279 extern void arc_virt_machine_release(size_t);
 280 
 281 /* Flags for vtc_status */
 282 #define VTCS_FPU_RESTORED       1 /* guest FPU restored, host FPU saved */
 283 #define VTCS_FPU_CTX_CRITICAL   2 /* in ctx where FPU restore cannot be lazy */
 284 
 285 typedef struct vm_thread_ctx {
 286         struct vm       *vtc_vm;
 287         int             vtc_vcpuid;
 288         uint_t          vtc_status;
 289         enum vcpu_ustate vtc_ustate;
 290 } vm_thread_ctx_t;
 291 
 292 #ifdef KTR
 293 static const char *
 294 vcpu_state2str(enum vcpu_state state)
 295 {
 296 
 297         switch (state) {
 298         case VCPU_IDLE:
 299                 return ("idle");
 300         case VCPU_FROZEN:
 
 606                 mm = &vm->mem_maps[i];
 607                 if (destroy || !sysmem_mapping(vm, mm)) {
 608                         vm_free_memmap(vm, i);
 609                 } else {
 610                         /*
 611                          * We need to reset the IOMMU flag so this mapping can
 612                          * be reused when a VM is rebooted. Since the IOMMU
 613                          * domain has already been destroyed we can just reset
 614                          * the flag here.
 615                          */
 616                         mm->flags &= ~VM_MEMMAP_F_IOMMU;
 617                 }
 618         }
 619 
 620         if (destroy) {
 621                 for (i = 0; i < VM_MAX_MEMSEGS; i++)
 622                         vm_free_memseg(vm, i);
 623 
 624                 VMSPACE_FREE(vm->vmspace);
 625                 vm->vmspace = NULL;
 626 
 627                 arc_virt_machine_release(vm->arc_resv);
 628                 vm->arc_resv = 0;
 629         }
 630 }
 631 
 632 void
 633 vm_destroy(struct vm *vm)
 634 {
 635         vm_cleanup(vm, true);
 636         free(vm, M_VM);
 637 }
 638 
 639 int
 640 vm_reinit(struct vm *vm)
 641 {
 642         int error;
 643 
 644         /*
 645          * A virtual machine can be reset only if all vcpus are suspended.
 646          */
 647         if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) {
 648                 vm_cleanup(vm, false);
 
3646 
3647 int
3648 vmm_kstat_update_vcpu(struct kstat *ksp, int rw)
3649 {
3650         struct vm *vm = ksp->ks_private;
3651         vmm_vcpu_kstats_t *vvk = ksp->ks_data;
3652         const int vcpuid = vvk->vvk_vcpu.value.ui32;
3653         struct vcpu *vcpu = &vm->vcpu[vcpuid];
3654 
3655         ASSERT3U(vcpuid, <, VM_MAXCPU);
3656 
3657         vvk->vvk_time_init.value.ui64 = vcpu->ustate_total[VU_INIT];
3658         vvk->vvk_time_run.value.ui64 = vcpu->ustate_total[VU_RUN];
3659         vvk->vvk_time_idle.value.ui64 = vcpu->ustate_total[VU_IDLE];
3660         vvk->vvk_time_emu_kern.value.ui64 = vcpu->ustate_total[VU_EMU_KERN];
3661         vvk->vvk_time_emu_user.value.ui64 = vcpu->ustate_total[VU_EMU_USER];
3662         vvk->vvk_time_sched.value.ui64 = vcpu->ustate_total[VU_SCHED];
3663 
3664         return (0);
3665 }
3666 
3667 int
3668 vm_arc_resv(struct vm *vm, uint64_t len)
3669 {
3670         /* Since we already have the compat macros included, we use those */
3671         size_t pages = (size_t)roundup2(len, PAGE_SIZE) >> PAGE_SHIFT;
3672         int err = 0;
3673 
3674         err = arc_virt_machine_reserve(pages);
3675         if (err != 0)
3676                 return (err);
3677 
3678         vm->arc_resv += pages;
3679         return (0);
3680 }
 | 
 
 
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  *
  28  * $FreeBSD$
  29  */
  30 /*
  31  * This file and its contents are supplied under the terms of the
  32  * Common Development and Distribution License ("CDDL"), version 1.0.
  33  * You may only use this file in accordance with the terms of version
  34  * 1.0 of the CDDL.
  35  *
  36  * A full copy of the text of the CDDL should have accompanied this
  37  * source.  A copy of the CDDL is also available via the Internet at
  38  * http://www.illumos.org/license/CDDL.
  39  *
  40  * Copyright 2015 Pluribus Networks Inc.
  41  * Copyright 2018 Joyent, Inc.
  42  * Copyright 2021 Oxide Computer Company
  43  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
  44  */
  45 
  46 #include <sys/cdefs.h>
  47 __FBSDID("$FreeBSD$");
  48 
  49 #include <sys/param.h>
  50 #include <sys/systm.h>
  51 #include <sys/kernel.h>
  52 #include <sys/module.h>
  53 #include <sys/sysctl.h>
  54 #include <sys/malloc.h>
  55 #include <sys/pcpu.h>
  56 #include <sys/lock.h>
  57 #include <sys/mutex.h>
  58 #include <sys/proc.h>
  59 #include <sys/rwlock.h>
  60 #include <sys/sched.h>
  61 #include <sys/smp.h>
 
 172         struct vatpic   *vatpic;                /* (i) virtual atpic */
 173         struct vatpit   *vatpit;                /* (i) virtual atpit */
 174         struct vpmtmr   *vpmtmr;                /* (i) virtual ACPI PM timer */
 175         struct vrtc     *vrtc;                  /* (o) virtual RTC */
 176         volatile cpuset_t active_cpus;          /* (i) active vcpus */
 177         volatile cpuset_t debug_cpus;           /* (i) vcpus stopped for dbg */
 178         int             suspend;                /* (i) stop VM execution */
 179         volatile cpuset_t suspended_cpus;       /* (i) suspended vcpus */
 180         volatile cpuset_t halted_cpus;          /* (x) cpus in a hard halt */
 181         struct mem_map  mem_maps[VM_MAX_MEMMAPS]; /* (i) guest address space */
 182         struct mem_seg  mem_segs[VM_MAX_MEMSEGS]; /* (o) guest memory regions */
 183         struct vmspace  *vmspace;               /* (o) guest's address space */
 184         char            name[VM_MAX_NAMELEN];   /* (o) virtual machine name */
 185         struct vcpu     vcpu[VM_MAXCPU];        /* (i) guest vcpus */
 186         /* The following describe the vm cpu topology */
 187         uint16_t        sockets;                /* (o) num of sockets */
 188         uint16_t        cores;                  /* (o) num of cores/socket */
 189         uint16_t        threads;                /* (o) num of threads/core */
 190         uint16_t        maxcpus;                /* (o) max pluggable cpus */
 191         uint64_t        boot_tsc_offset;        /* (i) TSC offset at VM boot */
 192 
 193         struct ioport_config ioports;           /* (o) ioport handling */
 194 };
 195 
 196 static int vmm_initialized;
 197 
 198 
 199 static void
 200 nullop_panic(void)
 201 {
 202         panic("null vmm operation call");
 203 }
 204 
 205 /* Do not allow use of an un-set `ops` to do anything but panic */
 206 static struct vmm_ops vmm_ops_null = {
 207         .init           = (vmm_init_func_t)nullop_panic,
 208         .cleanup        = (vmm_cleanup_func_t)nullop_panic,
 209         .resume         = (vmm_resume_func_t)nullop_panic,
 210         .vminit         = (vmi_init_func_t)nullop_panic,
 211         .vmrun          = (vmi_run_func_t)nullop_panic,
 
 257     NULL);
 258 
 259 /*
 260  * Halt the guest if all vcpus are executing a HLT instruction with
 261  * interrupts disabled.
 262  */
 263 static int halt_detection_enabled = 1;
 264 
 265 /* IPI vector used for vcpu notifications */
 266 static int vmm_ipinum;
 267 
 268 /* Trap into hypervisor on all guest exceptions and reflect them back */
 269 static int trace_guest_exceptions;
 270 
 271 static void vm_free_memmap(struct vm *vm, int ident);
 272 static bool sysmem_mapping(struct vm *vm, struct mem_map *mm);
 273 static void vcpu_notify_event_locked(struct vcpu *vcpu, vcpu_notify_t);
 274 static bool vcpu_sleep_bailout_checks(struct vm *vm, int vcpuid);
 275 static int vcpu_vector_sipi(struct vm *vm, int vcpuid, uint8_t vector);
 276 
 277 /* Flags for vtc_status */
 278 #define VTCS_FPU_RESTORED       1 /* guest FPU restored, host FPU saved */
 279 #define VTCS_FPU_CTX_CRITICAL   2 /* in ctx where FPU restore cannot be lazy */
 280 
 281 typedef struct vm_thread_ctx {
 282         struct vm       *vtc_vm;
 283         int             vtc_vcpuid;
 284         uint_t          vtc_status;
 285         enum vcpu_ustate vtc_ustate;
 286 } vm_thread_ctx_t;
 287 
 288 #ifdef KTR
 289 static const char *
 290 vcpu_state2str(enum vcpu_state state)
 291 {
 292 
 293         switch (state) {
 294         case VCPU_IDLE:
 295                 return ("idle");
 296         case VCPU_FROZEN:
 
 602                 mm = &vm->mem_maps[i];
 603                 if (destroy || !sysmem_mapping(vm, mm)) {
 604                         vm_free_memmap(vm, i);
 605                 } else {
 606                         /*
 607                          * We need to reset the IOMMU flag so this mapping can
 608                          * be reused when a VM is rebooted. Since the IOMMU
 609                          * domain has already been destroyed we can just reset
 610                          * the flag here.
 611                          */
 612                         mm->flags &= ~VM_MEMMAP_F_IOMMU;
 613                 }
 614         }
 615 
 616         if (destroy) {
 617                 for (i = 0; i < VM_MAX_MEMSEGS; i++)
 618                         vm_free_memseg(vm, i);
 619 
 620                 VMSPACE_FREE(vm->vmspace);
 621                 vm->vmspace = NULL;
 622         }
 623 }
 624 
 625 void
 626 vm_destroy(struct vm *vm)
 627 {
 628         vm_cleanup(vm, true);
 629         free(vm, M_VM);
 630 }
 631 
 632 int
 633 vm_reinit(struct vm *vm)
 634 {
 635         int error;
 636 
 637         /*
 638          * A virtual machine can be reset only if all vcpus are suspended.
 639          */
 640         if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) {
 641                 vm_cleanup(vm, false);
 
3639 
3640 int
3641 vmm_kstat_update_vcpu(struct kstat *ksp, int rw)
3642 {
3643         struct vm *vm = ksp->ks_private;
3644         vmm_vcpu_kstats_t *vvk = ksp->ks_data;
3645         const int vcpuid = vvk->vvk_vcpu.value.ui32;
3646         struct vcpu *vcpu = &vm->vcpu[vcpuid];
3647 
3648         ASSERT3U(vcpuid, <, VM_MAXCPU);
3649 
3650         vvk->vvk_time_init.value.ui64 = vcpu->ustate_total[VU_INIT];
3651         vvk->vvk_time_run.value.ui64 = vcpu->ustate_total[VU_RUN];
3652         vvk->vvk_time_idle.value.ui64 = vcpu->ustate_total[VU_IDLE];
3653         vvk->vvk_time_emu_kern.value.ui64 = vcpu->ustate_total[VU_EMU_KERN];
3654         vvk->vvk_time_emu_user.value.ui64 = vcpu->ustate_total[VU_EMU_USER];
3655         vvk->vvk_time_sched.value.ui64 = vcpu->ustate_total[VU_SCHED];
3656 
3657         return (0);
3658 }
 |