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 }
|