xref: /freebsd/sys/amd64/vmm/vmm.c (revision 7ce04d0a)
1366f6083SPeter Grehan /*-
2366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
3366f6083SPeter Grehan  * All rights reserved.
4366f6083SPeter Grehan  *
5366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
6366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
7366f6083SPeter Grehan  * are met:
8366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
9366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
10366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
12366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
13366f6083SPeter Grehan  *
14366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24366f6083SPeter Grehan  * SUCH DAMAGE.
25366f6083SPeter Grehan  *
26366f6083SPeter Grehan  * $FreeBSD$
27366f6083SPeter Grehan  */
28366f6083SPeter Grehan 
29366f6083SPeter Grehan #include <sys/cdefs.h>
30366f6083SPeter Grehan __FBSDID("$FreeBSD$");
31366f6083SPeter Grehan 
32366f6083SPeter Grehan #include <sys/param.h>
3338f1b189SPeter Grehan #include <sys/systm.h>
34366f6083SPeter Grehan #include <sys/kernel.h>
35366f6083SPeter Grehan #include <sys/module.h>
36366f6083SPeter Grehan #include <sys/sysctl.h>
37366f6083SPeter Grehan #include <sys/malloc.h>
38366f6083SPeter Grehan #include <sys/pcpu.h>
39366f6083SPeter Grehan #include <sys/lock.h>
40366f6083SPeter Grehan #include <sys/mutex.h>
41366f6083SPeter Grehan #include <sys/proc.h>
42366f6083SPeter Grehan #include <sys/sched.h>
43366f6083SPeter Grehan #include <sys/smp.h>
44366f6083SPeter Grehan #include <sys/systm.h>
45366f6083SPeter Grehan 
46366f6083SPeter Grehan #include <vm/vm.h>
47366f6083SPeter Grehan 
48366f6083SPeter Grehan #include <machine/vm.h>
49366f6083SPeter Grehan #include <machine/pcb.h>
5034a6b2d6SJohn Baldwin #include <x86/apicreg.h>
51366f6083SPeter Grehan 
52366f6083SPeter Grehan #include <machine/vmm.h>
53366f6083SPeter Grehan #include "vmm_mem.h"
54366f6083SPeter Grehan #include "vmm_util.h"
55366f6083SPeter Grehan #include <machine/vmm_dev.h>
56366f6083SPeter Grehan #include "vlapic.h"
57366f6083SPeter Grehan #include "vmm_msr.h"
58366f6083SPeter Grehan #include "vmm_ipi.h"
59366f6083SPeter Grehan #include "vmm_stat.h"
60366f6083SPeter Grehan 
61366f6083SPeter Grehan #include "io/ppt.h"
62366f6083SPeter Grehan #include "io/iommu.h"
63366f6083SPeter Grehan 
64366f6083SPeter Grehan struct vlapic;
65366f6083SPeter Grehan 
66366f6083SPeter Grehan struct vcpu {
67366f6083SPeter Grehan 	int		flags;
68366f6083SPeter Grehan 	int		pincpu;		/* host cpuid this vcpu is bound to */
69366f6083SPeter Grehan 	int		hostcpu;	/* host cpuid this vcpu last ran on */
70366f6083SPeter Grehan 	uint64_t	guest_msrs[VMM_MSR_NUM];
71366f6083SPeter Grehan 	struct vlapic	*vlapic;
72366f6083SPeter Grehan 	int		 vcpuid;
7338f1b189SPeter Grehan 	struct savefpu	*guestfpu;	/* guest fpu state */
74366f6083SPeter Grehan 	void		*stats;
7598ed632cSNeel Natu 	struct vm_exit	exitinfo;
76e9027382SNeel Natu 	enum x2apic_state x2apic_state;
77366f6083SPeter Grehan };
78366f6083SPeter Grehan #define	VCPU_F_PINNED	0x0001
79366f6083SPeter Grehan #define	VCPU_F_RUNNING	0x0002
80366f6083SPeter Grehan 
81366f6083SPeter Grehan #define	VCPU_PINCPU(vm, vcpuid)	\
82366f6083SPeter Grehan     ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1)
83366f6083SPeter Grehan 
84366f6083SPeter Grehan #define	VCPU_UNPIN(vm, vcpuid)	(vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED)
85366f6083SPeter Grehan 
86366f6083SPeter Grehan #define	VCPU_PIN(vm, vcpuid, host_cpuid)				\
87366f6083SPeter Grehan do {									\
88366f6083SPeter Grehan 	vm->vcpu[vcpuid].flags |= VCPU_F_PINNED;			\
89366f6083SPeter Grehan 	vm->vcpu[vcpuid].pincpu = host_cpuid;				\
90366f6083SPeter Grehan } while(0)
91366f6083SPeter Grehan 
92366f6083SPeter Grehan #define	VM_MAX_MEMORY_SEGMENTS	2
93366f6083SPeter Grehan 
94366f6083SPeter Grehan struct vm {
95366f6083SPeter Grehan 	void		*cookie;	/* processor-specific data */
96366f6083SPeter Grehan 	void		*iommu;		/* iommu-specific data */
97366f6083SPeter Grehan 	struct vcpu	vcpu[VM_MAXCPU];
98366f6083SPeter Grehan 	int		num_mem_segs;
99366f6083SPeter Grehan 	struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS];
100366f6083SPeter Grehan 	char		name[VM_MAX_NAMELEN];
101366f6083SPeter Grehan 
102366f6083SPeter Grehan 	/*
103a5615c90SPeter Grehan 	 * Set of active vcpus.
104366f6083SPeter Grehan 	 * An active vcpu is one that has been started implicitly (BSP) or
105366f6083SPeter Grehan 	 * explicitly (AP) by sending it a startup ipi.
106366f6083SPeter Grehan 	 */
107a5615c90SPeter Grehan 	cpuset_t	active_cpus;
108366f6083SPeter Grehan };
109366f6083SPeter Grehan 
110366f6083SPeter Grehan static struct vmm_ops *ops;
111366f6083SPeter Grehan #define	VMM_INIT()	(ops != NULL ? (*ops->init)() : 0)
112366f6083SPeter Grehan #define	VMM_CLEANUP()	(ops != NULL ? (*ops->cleanup)() : 0)
113366f6083SPeter Grehan 
114366f6083SPeter Grehan #define	VMINIT(vm)	(ops != NULL ? (*ops->vminit)(vm): NULL)
11598ed632cSNeel Natu #define	VMRUN(vmi, vcpu, rip) \
11698ed632cSNeel Natu 	(ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip) : ENXIO)
117366f6083SPeter Grehan #define	VMCLEANUP(vmi)	(ops != NULL ? (*ops->vmcleanup)(vmi) : NULL)
118bda273f2SNeel Natu #define	VMMMAP_SET(vmi, gpa, hpa, len, attr, prot, spm)			\
119bda273f2SNeel Natu     	(ops != NULL ? 							\
120bda273f2SNeel Natu     	(*ops->vmmmap_set)(vmi, gpa, hpa, len, attr, prot, spm) :	\
121bda273f2SNeel Natu 	ENXIO)
122bda273f2SNeel Natu #define	VMMMAP_GET(vmi, gpa) \
123bda273f2SNeel Natu 	(ops != NULL ? (*ops->vmmmap_get)(vmi, gpa) : ENXIO)
124366f6083SPeter Grehan #define	VMGETREG(vmi, vcpu, num, retval)		\
125366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO)
126366f6083SPeter Grehan #define	VMSETREG(vmi, vcpu, num, val)		\
127366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO)
128366f6083SPeter Grehan #define	VMGETDESC(vmi, vcpu, num, desc)		\
129366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO)
130366f6083SPeter Grehan #define	VMSETDESC(vmi, vcpu, num, desc)		\
131366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO)
132366f6083SPeter Grehan #define	VMINJECT(vmi, vcpu, type, vec, ec, ecv)	\
133366f6083SPeter Grehan 	(ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO)
134366f6083SPeter Grehan #define	VMNMI(vmi, vcpu)	\
135366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmnmi)(vmi, vcpu) : ENXIO)
136366f6083SPeter Grehan #define	VMGETCAP(vmi, vcpu, num, retval)	\
137366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO)
138366f6083SPeter Grehan #define	VMSETCAP(vmi, vcpu, num, val)		\
139366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO)
140366f6083SPeter Grehan 
14138f1b189SPeter Grehan #define	fpu_start_emulating()	start_emulating()
14238f1b189SPeter Grehan #define	fpu_stop_emulating()	stop_emulating()
143366f6083SPeter Grehan 
144366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm");
145366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64);	/* msr_mask can keep track of up to 64 msrs */
146366f6083SPeter Grehan 
147366f6083SPeter Grehan /* statistics */
148366f6083SPeter Grehan static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime");
149366f6083SPeter Grehan 
150366f6083SPeter Grehan static void
151366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu)
152366f6083SPeter Grehan {
153366f6083SPeter Grehan 	vlapic_cleanup(vcpu->vlapic);
154366f6083SPeter Grehan 	vmm_stat_free(vcpu->stats);
15538f1b189SPeter Grehan 	fpu_save_area_free(vcpu->guestfpu);
156366f6083SPeter Grehan }
157366f6083SPeter Grehan 
158366f6083SPeter Grehan static void
159366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id)
160366f6083SPeter Grehan {
161366f6083SPeter Grehan 	struct vcpu *vcpu;
162366f6083SPeter Grehan 
163366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpu_id];
164366f6083SPeter Grehan 
165366f6083SPeter Grehan 	vcpu->hostcpu = -1;
166366f6083SPeter Grehan 	vcpu->vcpuid = vcpu_id;
167366f6083SPeter Grehan 	vcpu->vlapic = vlapic_init(vm, vcpu_id);
16873820fb0SNeel Natu 	vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED);
16938f1b189SPeter Grehan 	vcpu->guestfpu = fpu_save_area_alloc();
17038f1b189SPeter Grehan 	fpu_save_area_reset(vcpu->guestfpu);
171366f6083SPeter Grehan 	vcpu->stats = vmm_stat_alloc();
172366f6083SPeter Grehan }
173366f6083SPeter Grehan 
17498ed632cSNeel Natu struct vm_exit *
17598ed632cSNeel Natu vm_exitinfo(struct vm *vm, int cpuid)
17698ed632cSNeel Natu {
17798ed632cSNeel Natu 	struct vcpu *vcpu;
17898ed632cSNeel Natu 
17998ed632cSNeel Natu 	if (cpuid < 0 || cpuid >= VM_MAXCPU)
18098ed632cSNeel Natu 		panic("vm_exitinfo: invalid cpuid %d", cpuid);
18198ed632cSNeel Natu 
18298ed632cSNeel Natu 	vcpu = &vm->vcpu[cpuid];
18398ed632cSNeel Natu 
18498ed632cSNeel Natu 	return (&vcpu->exitinfo);
18598ed632cSNeel Natu }
18698ed632cSNeel Natu 
187366f6083SPeter Grehan static int
188366f6083SPeter Grehan vmm_init(void)
189366f6083SPeter Grehan {
190366f6083SPeter Grehan 	int error;
191366f6083SPeter Grehan 
192366f6083SPeter Grehan 	vmm_ipi_init();
193366f6083SPeter Grehan 
194366f6083SPeter Grehan 	error = vmm_mem_init();
195366f6083SPeter Grehan 	if (error)
196366f6083SPeter Grehan 		return (error);
197366f6083SPeter Grehan 
198366f6083SPeter Grehan 	if (vmm_is_intel())
199366f6083SPeter Grehan 		ops = &vmm_ops_intel;
200366f6083SPeter Grehan 	else if (vmm_is_amd())
201366f6083SPeter Grehan 		ops = &vmm_ops_amd;
202366f6083SPeter Grehan 	else
203366f6083SPeter Grehan 		return (ENXIO);
204366f6083SPeter Grehan 
205366f6083SPeter Grehan 	vmm_msr_init();
206366f6083SPeter Grehan 
207366f6083SPeter Grehan 	return (VMM_INIT());
208366f6083SPeter Grehan }
209366f6083SPeter Grehan 
210366f6083SPeter Grehan static int
211366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg)
212366f6083SPeter Grehan {
213366f6083SPeter Grehan 	int error;
214366f6083SPeter Grehan 
215366f6083SPeter Grehan 	switch (what) {
216366f6083SPeter Grehan 	case MOD_LOAD:
217366f6083SPeter Grehan 		vmmdev_init();
218366f6083SPeter Grehan 		iommu_init();
219366f6083SPeter Grehan 		error = vmm_init();
220366f6083SPeter Grehan 		break;
221366f6083SPeter Grehan 	case MOD_UNLOAD:
222366f6083SPeter Grehan 		vmmdev_cleanup();
223366f6083SPeter Grehan 		iommu_cleanup();
224366f6083SPeter Grehan 		vmm_ipi_cleanup();
225366f6083SPeter Grehan 		error = VMM_CLEANUP();
226366f6083SPeter Grehan 		break;
227366f6083SPeter Grehan 	default:
228366f6083SPeter Grehan 		error = 0;
229366f6083SPeter Grehan 		break;
230366f6083SPeter Grehan 	}
231366f6083SPeter Grehan 	return (error);
232366f6083SPeter Grehan }
233366f6083SPeter Grehan 
234366f6083SPeter Grehan static moduledata_t vmm_kmod = {
235366f6083SPeter Grehan 	"vmm",
236366f6083SPeter Grehan 	vmm_handler,
237366f6083SPeter Grehan 	NULL
238366f6083SPeter Grehan };
239366f6083SPeter Grehan 
240366f6083SPeter Grehan /*
241366f6083SPeter Grehan  * Execute the module load handler after the pci passthru driver has had
242366f6083SPeter Grehan  * a chance to claim devices. We need this information at the time we do
243366f6083SPeter Grehan  * iommu initialization.
244366f6083SPeter Grehan  */
245366f6083SPeter Grehan DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY);
246366f6083SPeter Grehan MODULE_VERSION(vmm, 1);
247366f6083SPeter Grehan 
248366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL);
249366f6083SPeter Grehan 
250366f6083SPeter Grehan struct vm *
251366f6083SPeter Grehan vm_create(const char *name)
252366f6083SPeter Grehan {
253366f6083SPeter Grehan 	int i;
254366f6083SPeter Grehan 	struct vm *vm;
255366f6083SPeter Grehan 	vm_paddr_t maxaddr;
256366f6083SPeter Grehan 
257366f6083SPeter Grehan 	const int BSP = 0;
258366f6083SPeter Grehan 
259366f6083SPeter Grehan 	if (name == NULL || strlen(name) >= VM_MAX_NAMELEN)
260366f6083SPeter Grehan 		return (NULL);
261366f6083SPeter Grehan 
262366f6083SPeter Grehan 	vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO);
263366f6083SPeter Grehan 	strcpy(vm->name, name);
264366f6083SPeter Grehan 	vm->cookie = VMINIT(vm);
265366f6083SPeter Grehan 
266366f6083SPeter Grehan 	for (i = 0; i < VM_MAXCPU; i++) {
267366f6083SPeter Grehan 		vcpu_init(vm, i);
268366f6083SPeter Grehan 		guest_msrs_init(vm, i);
269366f6083SPeter Grehan 	}
270366f6083SPeter Grehan 
271366f6083SPeter Grehan 	maxaddr = vmm_mem_maxaddr();
272366f6083SPeter Grehan 	vm->iommu = iommu_create_domain(maxaddr);
273366f6083SPeter Grehan 	vm_activate_cpu(vm, BSP);
274366f6083SPeter Grehan 
275366f6083SPeter Grehan 	return (vm);
276366f6083SPeter Grehan }
277366f6083SPeter Grehan 
278f7d51510SNeel Natu static void
279f7d51510SNeel Natu vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg)
280f7d51510SNeel Natu {
281f7d51510SNeel Natu 	size_t len;
282f7d51510SNeel Natu 	vm_paddr_t hpa;
2837ce04d0aSNeel Natu 	void *host_domain;
2847ce04d0aSNeel Natu 
2857ce04d0aSNeel Natu 	host_domain = iommu_host_domain();
286f7d51510SNeel Natu 
287f7d51510SNeel Natu 	len = 0;
288f7d51510SNeel Natu 	while (len < seg->len) {
289f7d51510SNeel Natu 		hpa = vm_gpa2hpa(vm, seg->gpa + len, PAGE_SIZE);
290f7d51510SNeel Natu 		if (hpa == (vm_paddr_t)-1) {
291f7d51510SNeel Natu 			panic("vm_free_mem_segs: cannot free hpa "
292f7d51510SNeel Natu 			      "associated with gpa 0x%016lx", seg->gpa + len);
293f7d51510SNeel Natu 		}
294f7d51510SNeel Natu 
2957ce04d0aSNeel Natu 		/*
2967ce04d0aSNeel Natu 		 * Remove the 'gpa' to 'hpa' mapping in VMs domain.
2977ce04d0aSNeel Natu 		 * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'.
2987ce04d0aSNeel Natu 		 */
2997ce04d0aSNeel Natu 		iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE);
3007ce04d0aSNeel Natu 		iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE);
3017ce04d0aSNeel Natu 
302f7d51510SNeel Natu 		vmm_mem_free(hpa, PAGE_SIZE);
303f7d51510SNeel Natu 
304f7d51510SNeel Natu 		len += PAGE_SIZE;
305f7d51510SNeel Natu 	}
306f7d51510SNeel Natu 
3077ce04d0aSNeel Natu 	/*
3087ce04d0aSNeel Natu 	 * Invalidate cached translations associated with 'vm->iommu' since
3097ce04d0aSNeel Natu 	 * we have now moved some pages from it.
3107ce04d0aSNeel Natu 	 */
3117ce04d0aSNeel Natu 	iommu_invalidate_tlb(vm->iommu);
3127ce04d0aSNeel Natu 
313f7d51510SNeel Natu 	bzero(seg, sizeof(struct vm_memory_segment));
314f7d51510SNeel Natu }
315f7d51510SNeel Natu 
316366f6083SPeter Grehan void
317366f6083SPeter Grehan vm_destroy(struct vm *vm)
318366f6083SPeter Grehan {
319366f6083SPeter Grehan 	int i;
320366f6083SPeter Grehan 
321366f6083SPeter Grehan 	ppt_unassign_all(vm);
322366f6083SPeter Grehan 
323366f6083SPeter Grehan 	for (i = 0; i < vm->num_mem_segs; i++)
324f7d51510SNeel Natu 		vm_free_mem_seg(vm, &vm->mem_segs[i]);
325f7d51510SNeel Natu 
326f7d51510SNeel Natu 	vm->num_mem_segs = 0;
327366f6083SPeter Grehan 
328366f6083SPeter Grehan 	for (i = 0; i < VM_MAXCPU; i++)
329366f6083SPeter Grehan 		vcpu_cleanup(&vm->vcpu[i]);
330366f6083SPeter Grehan 
331366f6083SPeter Grehan 	iommu_destroy_domain(vm->iommu);
332366f6083SPeter Grehan 
333366f6083SPeter Grehan 	VMCLEANUP(vm->cookie);
334366f6083SPeter Grehan 
335366f6083SPeter Grehan 	free(vm, M_VM);
336366f6083SPeter Grehan }
337366f6083SPeter Grehan 
338366f6083SPeter Grehan const char *
339366f6083SPeter Grehan vm_name(struct vm *vm)
340366f6083SPeter Grehan {
341366f6083SPeter Grehan 	return (vm->name);
342366f6083SPeter Grehan }
343366f6083SPeter Grehan 
344366f6083SPeter Grehan int
345366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
346366f6083SPeter Grehan {
347366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
348366f6083SPeter Grehan 
349bda273f2SNeel Natu 	return (VMMMAP_SET(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE,
350366f6083SPeter Grehan 			   VM_PROT_RW, spok));
351366f6083SPeter Grehan }
352366f6083SPeter Grehan 
353366f6083SPeter Grehan int
354366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len)
355366f6083SPeter Grehan {
356366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
357366f6083SPeter Grehan 
358bda273f2SNeel Natu 	return (VMMMAP_SET(vm->cookie, gpa, 0, len, 0,
359366f6083SPeter Grehan 			   VM_PROT_NONE, spok));
360366f6083SPeter Grehan }
361366f6083SPeter Grehan 
362341f19c9SNeel Natu /*
363341f19c9SNeel Natu  * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise
364341f19c9SNeel Natu  */
365341f19c9SNeel Natu static boolean_t
366341f19c9SNeel Natu vm_gpa_available(struct vm *vm, vm_paddr_t gpa)
367366f6083SPeter Grehan {
368341f19c9SNeel Natu 	int i;
369341f19c9SNeel Natu 	vm_paddr_t gpabase, gpalimit;
370341f19c9SNeel Natu 
371341f19c9SNeel Natu 	if (gpa & PAGE_MASK)
372341f19c9SNeel Natu 		panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa);
373341f19c9SNeel Natu 
374341f19c9SNeel Natu 	for (i = 0; i < vm->num_mem_segs; i++) {
375341f19c9SNeel Natu 		gpabase = vm->mem_segs[i].gpa;
376341f19c9SNeel Natu 		gpalimit = gpabase + vm->mem_segs[i].len;
377341f19c9SNeel Natu 		if (gpa >= gpabase && gpa < gpalimit)
378341f19c9SNeel Natu 			return (FALSE);
379341f19c9SNeel Natu 	}
380341f19c9SNeel Natu 
381341f19c9SNeel Natu 	return (TRUE);
382341f19c9SNeel Natu }
383341f19c9SNeel Natu 
384341f19c9SNeel Natu int
385341f19c9SNeel Natu vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len)
386341f19c9SNeel Natu {
387341f19c9SNeel Natu 	int error, available, allocated;
388f7d51510SNeel Natu 	struct vm_memory_segment *seg;
389341f19c9SNeel Natu 	vm_paddr_t g, hpa;
3907ce04d0aSNeel Natu 	void *host_domain;
391366f6083SPeter Grehan 
392366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
393366f6083SPeter Grehan 
394341f19c9SNeel Natu 	if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0)
395341f19c9SNeel Natu 		return (EINVAL);
396341f19c9SNeel Natu 
397341f19c9SNeel Natu 	available = allocated = 0;
398341f19c9SNeel Natu 	g = gpa;
399341f19c9SNeel Natu 	while (g < gpa + len) {
400341f19c9SNeel Natu 		if (vm_gpa_available(vm, g))
401341f19c9SNeel Natu 			available++;
402341f19c9SNeel Natu 		else
403341f19c9SNeel Natu 			allocated++;
404341f19c9SNeel Natu 
405341f19c9SNeel Natu 		g += PAGE_SIZE;
406341f19c9SNeel Natu 	}
407341f19c9SNeel Natu 
408366f6083SPeter Grehan 	/*
409341f19c9SNeel Natu 	 * If there are some allocated and some available pages in the address
410341f19c9SNeel Natu 	 * range then it is an error.
411366f6083SPeter Grehan 	 */
412341f19c9SNeel Natu 	if (allocated && available)
413341f19c9SNeel Natu 		return (EINVAL);
414341f19c9SNeel Natu 
415341f19c9SNeel Natu 	/*
416341f19c9SNeel Natu 	 * If the entire address range being requested has already been
417341f19c9SNeel Natu 	 * allocated then there isn't anything more to do.
418341f19c9SNeel Natu 	 */
419341f19c9SNeel Natu 	if (allocated && available == 0)
420341f19c9SNeel Natu 		return (0);
421366f6083SPeter Grehan 
422366f6083SPeter Grehan 	if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS)
423366f6083SPeter Grehan 		return (E2BIG);
424366f6083SPeter Grehan 
4257ce04d0aSNeel Natu 	host_domain = iommu_host_domain();
4267ce04d0aSNeel Natu 
427f7d51510SNeel Natu 	seg = &vm->mem_segs[vm->num_mem_segs];
428366f6083SPeter Grehan 
4297ce04d0aSNeel Natu 	error = 0;
430f7d51510SNeel Natu 	seg->gpa = gpa;
431f7d51510SNeel Natu 	seg->len = 0;
432f7d51510SNeel Natu 	while (seg->len < len) {
433f7d51510SNeel Natu 		hpa = vmm_mem_alloc(PAGE_SIZE);
434f7d51510SNeel Natu 		if (hpa == 0) {
435f7d51510SNeel Natu 			error = ENOMEM;
436f7d51510SNeel Natu 			break;
437f7d51510SNeel Natu 		}
438f7d51510SNeel Natu 
439f7d51510SNeel Natu 		error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE,
440f7d51510SNeel Natu 				   VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok);
441f7d51510SNeel Natu 		if (error)
442f7d51510SNeel Natu 			break;
443f7d51510SNeel Natu 
4447ce04d0aSNeel Natu 		/*
4457ce04d0aSNeel Natu 		 * Remove the 1:1 mapping for 'hpa' from the 'host_domain'.
4467ce04d0aSNeel Natu 		 * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain.
4477ce04d0aSNeel Natu 		 */
4487ce04d0aSNeel Natu 		iommu_remove_mapping(host_domain, hpa, PAGE_SIZE);
449f7d51510SNeel Natu 		iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE);
450f7d51510SNeel Natu 
451f7d51510SNeel Natu 		seg->len += PAGE_SIZE;
452f7d51510SNeel Natu 	}
453f7d51510SNeel Natu 
4547ce04d0aSNeel Natu 	if (error) {
455f7d51510SNeel Natu 		vm_free_mem_seg(vm, seg);
456366f6083SPeter Grehan 		return (error);
457366f6083SPeter Grehan 	}
458366f6083SPeter Grehan 
4597ce04d0aSNeel Natu 	/*
4607ce04d0aSNeel Natu 	 * Invalidate cached translations associated with 'host_domain' since
4617ce04d0aSNeel Natu 	 * we have now moved some pages from it.
4627ce04d0aSNeel Natu 	 */
4637ce04d0aSNeel Natu 	iommu_invalidate_tlb(host_domain);
4647ce04d0aSNeel Natu 
465366f6083SPeter Grehan 	vm->num_mem_segs++;
466341f19c9SNeel Natu 
467366f6083SPeter Grehan 	return (0);
468366f6083SPeter Grehan }
469366f6083SPeter Grehan 
470366f6083SPeter Grehan vm_paddr_t
471366f6083SPeter Grehan vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len)
472366f6083SPeter Grehan {
4734db4fb2cSNeel Natu 	vm_paddr_t nextpage;
4744db4fb2cSNeel Natu 
4754db4fb2cSNeel Natu 	nextpage = rounddown(gpa + PAGE_SIZE, PAGE_SIZE);
4764db4fb2cSNeel Natu 	if (len > nextpage - gpa)
4774db4fb2cSNeel Natu 		panic("vm_gpa2hpa: invalid gpa/len: 0x%016lx/%lu", gpa, len);
478366f6083SPeter Grehan 
479bda273f2SNeel Natu 	return (VMMMAP_GET(vm->cookie, gpa));
480366f6083SPeter Grehan }
481366f6083SPeter Grehan 
482366f6083SPeter Grehan int
483366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase,
484366f6083SPeter Grehan 		  struct vm_memory_segment *seg)
485366f6083SPeter Grehan {
486366f6083SPeter Grehan 	int i;
487366f6083SPeter Grehan 
488366f6083SPeter Grehan 	for (i = 0; i < vm->num_mem_segs; i++) {
489366f6083SPeter Grehan 		if (gpabase == vm->mem_segs[i].gpa) {
490366f6083SPeter Grehan 			*seg = vm->mem_segs[i];
491366f6083SPeter Grehan 			return (0);
492366f6083SPeter Grehan 		}
493366f6083SPeter Grehan 	}
494366f6083SPeter Grehan 	return (-1);
495366f6083SPeter Grehan }
496366f6083SPeter Grehan 
497366f6083SPeter Grehan int
498366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval)
499366f6083SPeter Grehan {
500366f6083SPeter Grehan 
501366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
502366f6083SPeter Grehan 		return (EINVAL);
503366f6083SPeter Grehan 
504366f6083SPeter Grehan 	if (reg >= VM_REG_LAST)
505366f6083SPeter Grehan 		return (EINVAL);
506366f6083SPeter Grehan 
507366f6083SPeter Grehan 	return (VMGETREG(vm->cookie, vcpu, reg, retval));
508366f6083SPeter Grehan }
509366f6083SPeter Grehan 
510366f6083SPeter Grehan int
511366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val)
512366f6083SPeter Grehan {
513366f6083SPeter Grehan 
514366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
515366f6083SPeter Grehan 		return (EINVAL);
516366f6083SPeter Grehan 
517366f6083SPeter Grehan 	if (reg >= VM_REG_LAST)
518366f6083SPeter Grehan 		return (EINVAL);
519366f6083SPeter Grehan 
520366f6083SPeter Grehan 	return (VMSETREG(vm->cookie, vcpu, reg, val));
521366f6083SPeter Grehan }
522366f6083SPeter Grehan 
523366f6083SPeter Grehan static boolean_t
524366f6083SPeter Grehan is_descriptor_table(int reg)
525366f6083SPeter Grehan {
526366f6083SPeter Grehan 
527366f6083SPeter Grehan 	switch (reg) {
528366f6083SPeter Grehan 	case VM_REG_GUEST_IDTR:
529366f6083SPeter Grehan 	case VM_REG_GUEST_GDTR:
530366f6083SPeter Grehan 		return (TRUE);
531366f6083SPeter Grehan 	default:
532366f6083SPeter Grehan 		return (FALSE);
533366f6083SPeter Grehan 	}
534366f6083SPeter Grehan }
535366f6083SPeter Grehan 
536366f6083SPeter Grehan static boolean_t
537366f6083SPeter Grehan is_segment_register(int reg)
538366f6083SPeter Grehan {
539366f6083SPeter Grehan 
540366f6083SPeter Grehan 	switch (reg) {
541366f6083SPeter Grehan 	case VM_REG_GUEST_ES:
542366f6083SPeter Grehan 	case VM_REG_GUEST_CS:
543366f6083SPeter Grehan 	case VM_REG_GUEST_SS:
544366f6083SPeter Grehan 	case VM_REG_GUEST_DS:
545366f6083SPeter Grehan 	case VM_REG_GUEST_FS:
546366f6083SPeter Grehan 	case VM_REG_GUEST_GS:
547366f6083SPeter Grehan 	case VM_REG_GUEST_TR:
548366f6083SPeter Grehan 	case VM_REG_GUEST_LDTR:
549366f6083SPeter Grehan 		return (TRUE);
550366f6083SPeter Grehan 	default:
551366f6083SPeter Grehan 		return (FALSE);
552366f6083SPeter Grehan 	}
553366f6083SPeter Grehan }
554366f6083SPeter Grehan 
555366f6083SPeter Grehan int
556366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg,
557366f6083SPeter Grehan 		struct seg_desc *desc)
558366f6083SPeter Grehan {
559366f6083SPeter Grehan 
560366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
561366f6083SPeter Grehan 		return (EINVAL);
562366f6083SPeter Grehan 
563366f6083SPeter Grehan 	if (!is_segment_register(reg) && !is_descriptor_table(reg))
564366f6083SPeter Grehan 		return (EINVAL);
565366f6083SPeter Grehan 
566366f6083SPeter Grehan 	return (VMGETDESC(vm->cookie, vcpu, reg, desc));
567366f6083SPeter Grehan }
568366f6083SPeter Grehan 
569366f6083SPeter Grehan int
570366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg,
571366f6083SPeter Grehan 		struct seg_desc *desc)
572366f6083SPeter Grehan {
573366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
574366f6083SPeter Grehan 		return (EINVAL);
575366f6083SPeter Grehan 
576366f6083SPeter Grehan 	if (!is_segment_register(reg) && !is_descriptor_table(reg))
577366f6083SPeter Grehan 		return (EINVAL);
578366f6083SPeter Grehan 
579366f6083SPeter Grehan 	return (VMSETDESC(vm->cookie, vcpu, reg, desc));
580366f6083SPeter Grehan }
581366f6083SPeter Grehan 
582366f6083SPeter Grehan int
583366f6083SPeter Grehan vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid)
584366f6083SPeter Grehan {
585366f6083SPeter Grehan 
586366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
587366f6083SPeter Grehan 		return (EINVAL);
588366f6083SPeter Grehan 
589366f6083SPeter Grehan 	*cpuid = VCPU_PINCPU(vm, vcpuid);
590366f6083SPeter Grehan 
591366f6083SPeter Grehan 	return (0);
592366f6083SPeter Grehan }
593366f6083SPeter Grehan 
594366f6083SPeter Grehan int
595366f6083SPeter Grehan vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid)
596366f6083SPeter Grehan {
597366f6083SPeter Grehan 	struct thread *td;
598366f6083SPeter Grehan 
599366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
600366f6083SPeter Grehan 		return (EINVAL);
601366f6083SPeter Grehan 
602366f6083SPeter Grehan 	td = curthread;		/* XXXSMP only safe when muxing vcpus */
603366f6083SPeter Grehan 
604366f6083SPeter Grehan 	/* unpin */
605366f6083SPeter Grehan 	if (host_cpuid < 0) {
606366f6083SPeter Grehan 		VCPU_UNPIN(vm, vcpuid);
607366f6083SPeter Grehan 		thread_lock(td);
608366f6083SPeter Grehan 		sched_unbind(td);
609366f6083SPeter Grehan 		thread_unlock(td);
610366f6083SPeter Grehan 		return (0);
611366f6083SPeter Grehan 	}
612366f6083SPeter Grehan 
613366f6083SPeter Grehan 	if (CPU_ABSENT(host_cpuid))
614366f6083SPeter Grehan 		return (EINVAL);
615366f6083SPeter Grehan 
616366f6083SPeter Grehan 	/*
617366f6083SPeter Grehan 	 * XXX we should check that 'host_cpuid' has not already been pinned
618366f6083SPeter Grehan 	 * by another vm.
619366f6083SPeter Grehan 	 */
620366f6083SPeter Grehan 	thread_lock(td);
621366f6083SPeter Grehan 	sched_bind(td, host_cpuid);
622366f6083SPeter Grehan 	thread_unlock(td);
623366f6083SPeter Grehan 	VCPU_PIN(vm, vcpuid, host_cpuid);
624366f6083SPeter Grehan 
625366f6083SPeter Grehan 	return (0);
626366f6083SPeter Grehan }
627366f6083SPeter Grehan 
628366f6083SPeter Grehan static void
629366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu)
630366f6083SPeter Grehan {
631366f6083SPeter Grehan 
63238f1b189SPeter Grehan 	/* flush host state to the pcb */
63338f1b189SPeter Grehan 	fpuexit(curthread);
634366f6083SPeter Grehan 	fpu_stop_emulating();
63538f1b189SPeter Grehan 	fpurestore(vcpu->guestfpu);
636366f6083SPeter Grehan }
637366f6083SPeter Grehan 
638366f6083SPeter Grehan static void
639366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu)
640366f6083SPeter Grehan {
641366f6083SPeter Grehan 
64238f1b189SPeter Grehan 	fpusave(vcpu->guestfpu);
643366f6083SPeter Grehan 	fpu_start_emulating();
644366f6083SPeter Grehan }
645366f6083SPeter Grehan 
646366f6083SPeter Grehan int
647366f6083SPeter Grehan vm_run(struct vm *vm, struct vm_run *vmrun)
648366f6083SPeter Grehan {
649366f6083SPeter Grehan 	int error, vcpuid;
650366f6083SPeter Grehan 	struct vcpu *vcpu;
651366f6083SPeter Grehan 	struct pcb *pcb;
652366f6083SPeter Grehan 	uint64_t tscval;
653366f6083SPeter Grehan 
654366f6083SPeter Grehan 	vcpuid = vmrun->cpuid;
655366f6083SPeter Grehan 
656366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
657366f6083SPeter Grehan 		return (EINVAL);
658366f6083SPeter Grehan 
659366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
660366f6083SPeter Grehan 
661366f6083SPeter Grehan 	critical_enter();
662366f6083SPeter Grehan 
663366f6083SPeter Grehan 	tscval = rdtsc();
664366f6083SPeter Grehan 
665366f6083SPeter Grehan 	pcb = PCPU_GET(curpcb);
66634a6b2d6SJohn Baldwin 	set_pcb_flags(pcb, PCB_FULL_IRET);
667366f6083SPeter Grehan 
668366f6083SPeter Grehan 	vcpu->hostcpu = curcpu;
669366f6083SPeter Grehan 
670366f6083SPeter Grehan 	restore_guest_msrs(vm, vcpuid);
671366f6083SPeter Grehan 	restore_guest_fpustate(vcpu);
67298ed632cSNeel Natu 	error = VMRUN(vm->cookie, vcpuid, vmrun->rip);
673366f6083SPeter Grehan 	save_guest_fpustate(vcpu);
674366f6083SPeter Grehan 	restore_host_msrs(vm, vcpuid);
675366f6083SPeter Grehan 
676366f6083SPeter Grehan 	vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval);
677366f6083SPeter Grehan 
67898ed632cSNeel Natu 	/* copy the exit information */
67998ed632cSNeel Natu 	bcopy(&vcpu->exitinfo, &vmrun->vm_exit, sizeof(struct vm_exit));
68098ed632cSNeel Natu 
681366f6083SPeter Grehan 	critical_exit();
682366f6083SPeter Grehan 
683366f6083SPeter Grehan 	return (error);
684366f6083SPeter Grehan }
685366f6083SPeter Grehan 
686366f6083SPeter Grehan int
687366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type,
688366f6083SPeter Grehan 		int vector, uint32_t code, int code_valid)
689366f6083SPeter Grehan {
690366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
691366f6083SPeter Grehan 		return (EINVAL);
692366f6083SPeter Grehan 
693366f6083SPeter Grehan 	if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0)
694366f6083SPeter Grehan 		return (EINVAL);
695366f6083SPeter Grehan 
696366f6083SPeter Grehan 	if (vector < 0 || vector > 255)
697366f6083SPeter Grehan 		return (EINVAL);
698366f6083SPeter Grehan 
699366f6083SPeter Grehan 	return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid));
700366f6083SPeter Grehan }
701366f6083SPeter Grehan 
702366f6083SPeter Grehan int
703366f6083SPeter Grehan vm_inject_nmi(struct vm *vm, int vcpu)
704366f6083SPeter Grehan {
705366f6083SPeter Grehan 	int error;
706366f6083SPeter Grehan 
707366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
708366f6083SPeter Grehan 		return (EINVAL);
709366f6083SPeter Grehan 
710366f6083SPeter Grehan 	error = VMNMI(vm->cookie, vcpu);
711366f6083SPeter Grehan 	vm_interrupt_hostcpu(vm, vcpu);
712366f6083SPeter Grehan 	return (error);
713366f6083SPeter Grehan }
714366f6083SPeter Grehan 
715366f6083SPeter Grehan int
716366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval)
717366f6083SPeter Grehan {
718366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
719366f6083SPeter Grehan 		return (EINVAL);
720366f6083SPeter Grehan 
721366f6083SPeter Grehan 	if (type < 0 || type >= VM_CAP_MAX)
722366f6083SPeter Grehan 		return (EINVAL);
723366f6083SPeter Grehan 
724366f6083SPeter Grehan 	return (VMGETCAP(vm->cookie, vcpu, type, retval));
725366f6083SPeter Grehan }
726366f6083SPeter Grehan 
727366f6083SPeter Grehan int
728366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val)
729366f6083SPeter Grehan {
730366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
731366f6083SPeter Grehan 		return (EINVAL);
732366f6083SPeter Grehan 
733366f6083SPeter Grehan 	if (type < 0 || type >= VM_CAP_MAX)
734366f6083SPeter Grehan 		return (EINVAL);
735366f6083SPeter Grehan 
736366f6083SPeter Grehan 	return (VMSETCAP(vm->cookie, vcpu, type, val));
737366f6083SPeter Grehan }
738366f6083SPeter Grehan 
739366f6083SPeter Grehan uint64_t *
740366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu)
741366f6083SPeter Grehan {
742366f6083SPeter Grehan 	return (vm->vcpu[cpu].guest_msrs);
743366f6083SPeter Grehan }
744366f6083SPeter Grehan 
745366f6083SPeter Grehan struct vlapic *
746366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu)
747366f6083SPeter Grehan {
748366f6083SPeter Grehan 	return (vm->vcpu[cpu].vlapic);
749366f6083SPeter Grehan }
750366f6083SPeter Grehan 
751366f6083SPeter Grehan boolean_t
752366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func)
753366f6083SPeter Grehan {
754366f6083SPeter Grehan 	int found, b, s, f, n;
755366f6083SPeter Grehan 	char *val, *cp, *cp2;
756366f6083SPeter Grehan 
757366f6083SPeter Grehan 	/*
758366f6083SPeter Grehan 	 * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12"
759366f6083SPeter Grehan 	 */
760366f6083SPeter Grehan 	found = 0;
761366f6083SPeter Grehan 	cp = val = getenv("pptdevs");
762366f6083SPeter Grehan 	while (cp != NULL && *cp != '\0') {
763366f6083SPeter Grehan 		if ((cp2 = strchr(cp, ' ')) != NULL)
764366f6083SPeter Grehan 			*cp2 = '\0';
765366f6083SPeter Grehan 
766366f6083SPeter Grehan 		n = sscanf(cp, "%d/%d/%d", &b, &s, &f);
767366f6083SPeter Grehan 		if (n == 3 && bus == b && slot == s && func == f) {
768366f6083SPeter Grehan 			found = 1;
769366f6083SPeter Grehan 			break;
770366f6083SPeter Grehan 		}
771366f6083SPeter Grehan 
772366f6083SPeter Grehan 		if (cp2 != NULL)
773366f6083SPeter Grehan 			*cp2++ = ' ';
774366f6083SPeter Grehan 
775366f6083SPeter Grehan 		cp = cp2;
776366f6083SPeter Grehan 	}
777366f6083SPeter Grehan 	freeenv(val);
778366f6083SPeter Grehan 	return (found);
779366f6083SPeter Grehan }
780366f6083SPeter Grehan 
781366f6083SPeter Grehan void *
782366f6083SPeter Grehan vm_iommu_domain(struct vm *vm)
783366f6083SPeter Grehan {
784366f6083SPeter Grehan 
785366f6083SPeter Grehan 	return (vm->iommu);
786366f6083SPeter Grehan }
787366f6083SPeter Grehan 
788366f6083SPeter Grehan void
789366f6083SPeter Grehan vm_set_run_state(struct vm *vm, int vcpuid, int state)
790366f6083SPeter Grehan {
791366f6083SPeter Grehan 	struct vcpu *vcpu;
792366f6083SPeter Grehan 
793366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
794366f6083SPeter Grehan 		panic("vm_set_run_state: invalid vcpuid %d", vcpuid);
795366f6083SPeter Grehan 
796366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
797366f6083SPeter Grehan 
798366f6083SPeter Grehan 	if (state == VCPU_RUNNING) {
799366f6083SPeter Grehan 		if (vcpu->flags & VCPU_F_RUNNING) {
800366f6083SPeter Grehan 			panic("vm_set_run_state: %s[%d] is already running",
801366f6083SPeter Grehan 			      vm_name(vm), vcpuid);
802366f6083SPeter Grehan 		}
803366f6083SPeter Grehan 		vcpu->flags |= VCPU_F_RUNNING;
804366f6083SPeter Grehan 	} else {
805366f6083SPeter Grehan 		if ((vcpu->flags & VCPU_F_RUNNING) == 0) {
806366f6083SPeter Grehan 			panic("vm_set_run_state: %s[%d] is already stopped",
807366f6083SPeter Grehan 			      vm_name(vm), vcpuid);
808366f6083SPeter Grehan 		}
809366f6083SPeter Grehan 		vcpu->flags &= ~VCPU_F_RUNNING;
810366f6083SPeter Grehan 	}
811366f6083SPeter Grehan }
812366f6083SPeter Grehan 
813366f6083SPeter Grehan int
814366f6083SPeter Grehan vm_get_run_state(struct vm *vm, int vcpuid, int *cpuptr)
815366f6083SPeter Grehan {
816366f6083SPeter Grehan 	int retval, hostcpu;
817366f6083SPeter Grehan 	struct vcpu *vcpu;
818366f6083SPeter Grehan 
819366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
820366f6083SPeter Grehan 		panic("vm_get_run_state: invalid vcpuid %d", vcpuid);
821366f6083SPeter Grehan 
822366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
823366f6083SPeter Grehan 	if (vcpu->flags & VCPU_F_RUNNING) {
824366f6083SPeter Grehan 		retval = VCPU_RUNNING;
825366f6083SPeter Grehan 		hostcpu = vcpu->hostcpu;
826366f6083SPeter Grehan 	} else {
827366f6083SPeter Grehan 		retval = VCPU_STOPPED;
828366f6083SPeter Grehan 		hostcpu = -1;
829366f6083SPeter Grehan 	}
830366f6083SPeter Grehan 
831366f6083SPeter Grehan 	if (cpuptr)
832366f6083SPeter Grehan 		*cpuptr = hostcpu;
833366f6083SPeter Grehan 
834366f6083SPeter Grehan 	return (retval);
835366f6083SPeter Grehan }
836366f6083SPeter Grehan 
837366f6083SPeter Grehan void
838366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid)
839366f6083SPeter Grehan {
840366f6083SPeter Grehan 
841366f6083SPeter Grehan 	if (vcpuid >= 0 && vcpuid < VM_MAXCPU)
842a5615c90SPeter Grehan 		CPU_SET(vcpuid, &vm->active_cpus);
843366f6083SPeter Grehan }
844366f6083SPeter Grehan 
845a5615c90SPeter Grehan cpuset_t
846366f6083SPeter Grehan vm_active_cpus(struct vm *vm)
847366f6083SPeter Grehan {
848366f6083SPeter Grehan 
849366f6083SPeter Grehan 	return (vm->active_cpus);
850366f6083SPeter Grehan }
851366f6083SPeter Grehan 
852366f6083SPeter Grehan void *
853366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid)
854366f6083SPeter Grehan {
855366f6083SPeter Grehan 
856366f6083SPeter Grehan 	return (vm->vcpu[vcpuid].stats);
857366f6083SPeter Grehan }
858e9027382SNeel Natu 
859e9027382SNeel Natu int
860e9027382SNeel Natu vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state)
861e9027382SNeel Natu {
862e9027382SNeel Natu 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
863e9027382SNeel Natu 		return (EINVAL);
864e9027382SNeel Natu 
865e9027382SNeel Natu 	*state = vm->vcpu[vcpuid].x2apic_state;
866e9027382SNeel Natu 
867e9027382SNeel Natu 	return (0);
868e9027382SNeel Natu }
869e9027382SNeel Natu 
870e9027382SNeel Natu int
871e9027382SNeel Natu vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)
872e9027382SNeel Natu {
873e9027382SNeel Natu 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
874e9027382SNeel Natu 		return (EINVAL);
875e9027382SNeel Natu 
876e9027382SNeel Natu 	if (state < 0 || state >= X2APIC_STATE_LAST)
877e9027382SNeel Natu 		return (EINVAL);
878e9027382SNeel Natu 
879e9027382SNeel Natu 	vm->vcpu[vcpuid].x2apic_state = state;
880e9027382SNeel Natu 
88173820fb0SNeel Natu 	vlapic_set_x2apic_state(vm, vcpuid, state);
88273820fb0SNeel Natu 
883e9027382SNeel Natu 	return (0);
884e9027382SNeel Natu }
885