xref: /freebsd/sys/amd64/vmm/vmm.c (revision 34a6b2d6274e0adeae33754556652f985a07e96f)
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>
33366f6083SPeter Grehan #include <sys/kernel.h>
34366f6083SPeter Grehan #include <sys/module.h>
35366f6083SPeter Grehan #include <sys/sysctl.h>
36366f6083SPeter Grehan #include <sys/malloc.h>
37366f6083SPeter Grehan #include <sys/pcpu.h>
38366f6083SPeter Grehan #include <sys/lock.h>
39366f6083SPeter Grehan #include <sys/mutex.h>
40366f6083SPeter Grehan #include <sys/proc.h>
41366f6083SPeter Grehan #include <sys/sched.h>
42366f6083SPeter Grehan #include <sys/smp.h>
43366f6083SPeter Grehan #include <sys/systm.h>
44366f6083SPeter Grehan 
45366f6083SPeter Grehan #include <vm/vm.h>
46366f6083SPeter Grehan 
47366f6083SPeter Grehan #include <machine/vm.h>
48366f6083SPeter Grehan #include <machine/pcb.h>
49*34a6b2d6SJohn Baldwin #include <x86/apicreg.h>
50366f6083SPeter Grehan 
51366f6083SPeter Grehan #include <machine/vmm.h>
52366f6083SPeter Grehan #include "vmm_mem.h"
53366f6083SPeter Grehan #include "vmm_util.h"
54366f6083SPeter Grehan #include <machine/vmm_dev.h>
55366f6083SPeter Grehan #include "vlapic.h"
56366f6083SPeter Grehan #include "vmm_msr.h"
57366f6083SPeter Grehan #include "vmm_ipi.h"
58366f6083SPeter Grehan #include "vmm_stat.h"
59366f6083SPeter Grehan 
60366f6083SPeter Grehan #include "io/ppt.h"
61366f6083SPeter Grehan #include "io/iommu.h"
62366f6083SPeter Grehan 
63366f6083SPeter Grehan struct vlapic;
64366f6083SPeter Grehan 
65366f6083SPeter Grehan struct vcpu {
66366f6083SPeter Grehan 	int		flags;
67366f6083SPeter Grehan 	int		pincpu;		/* host cpuid this vcpu is bound to */
68366f6083SPeter Grehan 	int		hostcpu;	/* host cpuid this vcpu last ran on */
69366f6083SPeter Grehan 	uint64_t	guest_msrs[VMM_MSR_NUM];
70366f6083SPeter Grehan 	struct vlapic	*vlapic;
71366f6083SPeter Grehan 	int		 vcpuid;
72366f6083SPeter Grehan 	struct savefpu	savefpu;	/* guest fpu state */
73366f6083SPeter Grehan 	void		*stats;
74366f6083SPeter Grehan };
75366f6083SPeter Grehan #define	VCPU_F_PINNED	0x0001
76366f6083SPeter Grehan #define	VCPU_F_RUNNING	0x0002
77366f6083SPeter Grehan 
78366f6083SPeter Grehan #define	VCPU_PINCPU(vm, vcpuid)	\
79366f6083SPeter Grehan     ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1)
80366f6083SPeter Grehan 
81366f6083SPeter Grehan #define	VCPU_UNPIN(vm, vcpuid)	(vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED)
82366f6083SPeter Grehan 
83366f6083SPeter Grehan #define	VCPU_PIN(vm, vcpuid, host_cpuid)				\
84366f6083SPeter Grehan do {									\
85366f6083SPeter Grehan 	vm->vcpu[vcpuid].flags |= VCPU_F_PINNED;			\
86366f6083SPeter Grehan 	vm->vcpu[vcpuid].pincpu = host_cpuid;				\
87366f6083SPeter Grehan } while(0)
88366f6083SPeter Grehan 
89366f6083SPeter Grehan #define	VM_MAX_MEMORY_SEGMENTS	2
90366f6083SPeter Grehan 
91366f6083SPeter Grehan struct vm {
92366f6083SPeter Grehan 	void		*cookie;	/* processor-specific data */
93366f6083SPeter Grehan 	void		*iommu;		/* iommu-specific data */
94366f6083SPeter Grehan 	struct vcpu	vcpu[VM_MAXCPU];
95366f6083SPeter Grehan 	int		num_mem_segs;
96366f6083SPeter Grehan 	struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS];
97366f6083SPeter Grehan 	char		name[VM_MAX_NAMELEN];
98366f6083SPeter Grehan 
99366f6083SPeter Grehan 	/*
100366f6083SPeter Grehan 	 * Mask of active vcpus.
101366f6083SPeter Grehan 	 * An active vcpu is one that has been started implicitly (BSP) or
102366f6083SPeter Grehan 	 * explicitly (AP) by sending it a startup ipi.
103366f6083SPeter Grehan 	 */
104366f6083SPeter Grehan 	cpumask_t	active_cpus;
105366f6083SPeter Grehan };
106366f6083SPeter Grehan 
107366f6083SPeter Grehan static struct vmm_ops *ops;
108366f6083SPeter Grehan #define	VMM_INIT()	(ops != NULL ? (*ops->init)() : 0)
109366f6083SPeter Grehan #define	VMM_CLEANUP()	(ops != NULL ? (*ops->cleanup)() : 0)
110366f6083SPeter Grehan 
111366f6083SPeter Grehan #define	VMINIT(vm)	(ops != NULL ? (*ops->vminit)(vm): NULL)
112366f6083SPeter Grehan #define	VMRUN(vmi, vcpu, rip, vmexit) \
113366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, vmexit) : ENXIO)
114366f6083SPeter Grehan #define	VMCLEANUP(vmi)	(ops != NULL ? (*ops->vmcleanup)(vmi) : NULL)
115366f6083SPeter Grehan #define	VMMMAP(vmi, gpa, hpa, len, attr, prot, spm)	\
116366f6083SPeter Grehan     (ops != NULL ? (*ops->vmmmap)(vmi, gpa, hpa, len, attr, prot, spm) : ENXIO)
117366f6083SPeter Grehan #define	VMGETREG(vmi, vcpu, num, retval)		\
118366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO)
119366f6083SPeter Grehan #define	VMSETREG(vmi, vcpu, num, val)		\
120366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO)
121366f6083SPeter Grehan #define	VMGETDESC(vmi, vcpu, num, desc)		\
122366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO)
123366f6083SPeter Grehan #define	VMSETDESC(vmi, vcpu, num, desc)		\
124366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO)
125366f6083SPeter Grehan #define	VMINJECT(vmi, vcpu, type, vec, ec, ecv)	\
126366f6083SPeter Grehan 	(ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO)
127366f6083SPeter Grehan #define	VMNMI(vmi, vcpu)	\
128366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmnmi)(vmi, vcpu) : ENXIO)
129366f6083SPeter Grehan #define	VMGETCAP(vmi, vcpu, num, retval)	\
130366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO)
131366f6083SPeter Grehan #define	VMSETCAP(vmi, vcpu, num, val)		\
132366f6083SPeter Grehan 	(ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO)
133366f6083SPeter Grehan 
134366f6083SPeter Grehan #define	fxrstor(addr)		__asm("fxrstor %0" : : "m" (*(addr)))
135366f6083SPeter Grehan #define	fxsave(addr)		__asm __volatile("fxsave %0" : "=m" (*(addr)))
136366f6083SPeter Grehan #define	fpu_start_emulating()	__asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
137366f6083SPeter Grehan 				      : : "n" (CR0_TS) : "ax")
138366f6083SPeter Grehan #define	fpu_stop_emulating()	__asm("clts")
139366f6083SPeter Grehan 
140366f6083SPeter Grehan static MALLOC_DEFINE(M_VM, "vm", "vm");
141366f6083SPeter Grehan CTASSERT(VMM_MSR_NUM <= 64);	/* msr_mask can keep track of up to 64 msrs */
142366f6083SPeter Grehan 
143366f6083SPeter Grehan /* statistics */
144366f6083SPeter Grehan static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime");
145366f6083SPeter Grehan 
146366f6083SPeter Grehan static void
147366f6083SPeter Grehan vcpu_cleanup(struct vcpu *vcpu)
148366f6083SPeter Grehan {
149366f6083SPeter Grehan 	vlapic_cleanup(vcpu->vlapic);
150366f6083SPeter Grehan 	vmm_stat_free(vcpu->stats);
151366f6083SPeter Grehan }
152366f6083SPeter Grehan 
153366f6083SPeter Grehan static void
154366f6083SPeter Grehan vcpu_init(struct vm *vm, uint32_t vcpu_id)
155366f6083SPeter Grehan {
156366f6083SPeter Grehan 	struct vcpu *vcpu;
157366f6083SPeter Grehan 
158366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpu_id];
159366f6083SPeter Grehan 
160366f6083SPeter Grehan 	vcpu->hostcpu = -1;
161366f6083SPeter Grehan 	vcpu->vcpuid = vcpu_id;
162366f6083SPeter Grehan 	vcpu->vlapic = vlapic_init(vm, vcpu_id);
163*34a6b2d6SJohn Baldwin 	fpugetregs(curthread);
164*34a6b2d6SJohn Baldwin 	vcpu->savefpu = curthread->td_pcb->pcb_user_save;
165366f6083SPeter Grehan 	vcpu->stats = vmm_stat_alloc();
166366f6083SPeter Grehan }
167366f6083SPeter Grehan 
168366f6083SPeter Grehan static int
169366f6083SPeter Grehan vmm_init(void)
170366f6083SPeter Grehan {
171366f6083SPeter Grehan 	int error;
172366f6083SPeter Grehan 
173366f6083SPeter Grehan 	vmm_ipi_init();
174366f6083SPeter Grehan 
175366f6083SPeter Grehan 	error = vmm_mem_init();
176366f6083SPeter Grehan 	if (error)
177366f6083SPeter Grehan 		return (error);
178366f6083SPeter Grehan 
179366f6083SPeter Grehan 	if (vmm_is_intel())
180366f6083SPeter Grehan 		ops = &vmm_ops_intel;
181366f6083SPeter Grehan 	else if (vmm_is_amd())
182366f6083SPeter Grehan 		ops = &vmm_ops_amd;
183366f6083SPeter Grehan 	else
184366f6083SPeter Grehan 		return (ENXIO);
185366f6083SPeter Grehan 
186366f6083SPeter Grehan 	vmm_msr_init();
187366f6083SPeter Grehan 
188366f6083SPeter Grehan 	return (VMM_INIT());
189366f6083SPeter Grehan }
190366f6083SPeter Grehan 
191366f6083SPeter Grehan static int
192366f6083SPeter Grehan vmm_handler(module_t mod, int what, void *arg)
193366f6083SPeter Grehan {
194366f6083SPeter Grehan 	int error;
195366f6083SPeter Grehan 
196366f6083SPeter Grehan 	switch (what) {
197366f6083SPeter Grehan 	case MOD_LOAD:
198366f6083SPeter Grehan 		vmmdev_init();
199366f6083SPeter Grehan 		iommu_init();
200366f6083SPeter Grehan 		error = vmm_init();
201366f6083SPeter Grehan 		break;
202366f6083SPeter Grehan 	case MOD_UNLOAD:
203366f6083SPeter Grehan 		vmmdev_cleanup();
204366f6083SPeter Grehan 		iommu_cleanup();
205366f6083SPeter Grehan 		vmm_ipi_cleanup();
206366f6083SPeter Grehan 		error = VMM_CLEANUP();
207366f6083SPeter Grehan 		break;
208366f6083SPeter Grehan 	default:
209366f6083SPeter Grehan 		error = 0;
210366f6083SPeter Grehan 		break;
211366f6083SPeter Grehan 	}
212366f6083SPeter Grehan 	return (error);
213366f6083SPeter Grehan }
214366f6083SPeter Grehan 
215366f6083SPeter Grehan static moduledata_t vmm_kmod = {
216366f6083SPeter Grehan 	"vmm",
217366f6083SPeter Grehan 	vmm_handler,
218366f6083SPeter Grehan 	NULL
219366f6083SPeter Grehan };
220366f6083SPeter Grehan 
221366f6083SPeter Grehan /*
222366f6083SPeter Grehan  * Execute the module load handler after the pci passthru driver has had
223366f6083SPeter Grehan  * a chance to claim devices. We need this information at the time we do
224366f6083SPeter Grehan  * iommu initialization.
225366f6083SPeter Grehan  */
226366f6083SPeter Grehan DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY);
227366f6083SPeter Grehan MODULE_VERSION(vmm, 1);
228366f6083SPeter Grehan 
229366f6083SPeter Grehan SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL);
230366f6083SPeter Grehan 
231366f6083SPeter Grehan struct vm *
232366f6083SPeter Grehan vm_create(const char *name)
233366f6083SPeter Grehan {
234366f6083SPeter Grehan 	int i;
235366f6083SPeter Grehan 	struct vm *vm;
236366f6083SPeter Grehan 	vm_paddr_t maxaddr;
237366f6083SPeter Grehan 
238366f6083SPeter Grehan 	const int BSP = 0;
239366f6083SPeter Grehan 
240366f6083SPeter Grehan 	if (name == NULL || strlen(name) >= VM_MAX_NAMELEN)
241366f6083SPeter Grehan 		return (NULL);
242366f6083SPeter Grehan 
243366f6083SPeter Grehan 	vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO);
244366f6083SPeter Grehan 	strcpy(vm->name, name);
245366f6083SPeter Grehan 	vm->cookie = VMINIT(vm);
246366f6083SPeter Grehan 
247366f6083SPeter Grehan 	for (i = 0; i < VM_MAXCPU; i++) {
248366f6083SPeter Grehan 		vcpu_init(vm, i);
249366f6083SPeter Grehan 		guest_msrs_init(vm, i);
250366f6083SPeter Grehan 	}
251366f6083SPeter Grehan 
252366f6083SPeter Grehan 	maxaddr = vmm_mem_maxaddr();
253366f6083SPeter Grehan 	vm->iommu = iommu_create_domain(maxaddr);
254366f6083SPeter Grehan 	vm_activate_cpu(vm, BSP);
255366f6083SPeter Grehan 
256366f6083SPeter Grehan 	return (vm);
257366f6083SPeter Grehan }
258366f6083SPeter Grehan 
259366f6083SPeter Grehan void
260366f6083SPeter Grehan vm_destroy(struct vm *vm)
261366f6083SPeter Grehan {
262366f6083SPeter Grehan 	int i;
263366f6083SPeter Grehan 
264366f6083SPeter Grehan 	ppt_unassign_all(vm);
265366f6083SPeter Grehan 
266366f6083SPeter Grehan 	for (i = 0; i < vm->num_mem_segs; i++)
267366f6083SPeter Grehan 		vmm_mem_free(vm->mem_segs[i].hpa, vm->mem_segs[i].len);
268366f6083SPeter Grehan 
269366f6083SPeter Grehan 	for (i = 0; i < VM_MAXCPU; i++)
270366f6083SPeter Grehan 		vcpu_cleanup(&vm->vcpu[i]);
271366f6083SPeter Grehan 
272366f6083SPeter Grehan 	iommu_destroy_domain(vm->iommu);
273366f6083SPeter Grehan 
274366f6083SPeter Grehan 	VMCLEANUP(vm->cookie);
275366f6083SPeter Grehan 
276366f6083SPeter Grehan 	free(vm, M_VM);
277366f6083SPeter Grehan }
278366f6083SPeter Grehan 
279366f6083SPeter Grehan const char *
280366f6083SPeter Grehan vm_name(struct vm *vm)
281366f6083SPeter Grehan {
282366f6083SPeter Grehan 	return (vm->name);
283366f6083SPeter Grehan }
284366f6083SPeter Grehan 
285366f6083SPeter Grehan int
286366f6083SPeter Grehan vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
287366f6083SPeter Grehan {
288366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
289366f6083SPeter Grehan 
290366f6083SPeter Grehan 	return (VMMMAP(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE,
291366f6083SPeter Grehan 		       VM_PROT_RW, spok));
292366f6083SPeter Grehan }
293366f6083SPeter Grehan 
294366f6083SPeter Grehan int
295366f6083SPeter Grehan vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len)
296366f6083SPeter Grehan {
297366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
298366f6083SPeter Grehan 
299366f6083SPeter Grehan 	return (VMMMAP(vm->cookie, gpa, 0, len, VM_MEMATTR_UNCACHEABLE,
300366f6083SPeter Grehan 		       VM_PROT_NONE, spok));
301366f6083SPeter Grehan }
302366f6083SPeter Grehan 
303366f6083SPeter Grehan int
304366f6083SPeter Grehan vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t *ret_hpa)
305366f6083SPeter Grehan {
306366f6083SPeter Grehan 	int error;
307366f6083SPeter Grehan 	vm_paddr_t hpa;
308366f6083SPeter Grehan 
309366f6083SPeter Grehan 	const boolean_t spok = TRUE;	/* superpage mappings are ok */
310366f6083SPeter Grehan 
311366f6083SPeter Grehan 	/*
312366f6083SPeter Grehan 	 * find the hpa if already it was already vm_malloc'd.
313366f6083SPeter Grehan 	 */
314366f6083SPeter Grehan 	hpa = vm_gpa2hpa(vm, gpa, len);
315366f6083SPeter Grehan 	if (hpa != ((vm_paddr_t)-1))
316366f6083SPeter Grehan 		goto out;
317366f6083SPeter Grehan 
318366f6083SPeter Grehan 	if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS)
319366f6083SPeter Grehan 		return (E2BIG);
320366f6083SPeter Grehan 
321366f6083SPeter Grehan 	hpa = vmm_mem_alloc(len);
322366f6083SPeter Grehan 	if (hpa == 0)
323366f6083SPeter Grehan 		return (ENOMEM);
324366f6083SPeter Grehan 
325366f6083SPeter Grehan 	error = VMMMAP(vm->cookie, gpa, hpa, len, VM_MEMATTR_WRITE_BACK,
326366f6083SPeter Grehan 		       VM_PROT_ALL, spok);
327366f6083SPeter Grehan 	if (error) {
328366f6083SPeter Grehan 		vmm_mem_free(hpa, len);
329366f6083SPeter Grehan 		return (error);
330366f6083SPeter Grehan 	}
331366f6083SPeter Grehan 
332366f6083SPeter Grehan 	iommu_create_mapping(vm->iommu, gpa, hpa, len);
333366f6083SPeter Grehan 
334366f6083SPeter Grehan 	vm->mem_segs[vm->num_mem_segs].gpa = gpa;
335366f6083SPeter Grehan 	vm->mem_segs[vm->num_mem_segs].hpa = hpa;
336366f6083SPeter Grehan 	vm->mem_segs[vm->num_mem_segs].len = len;
337366f6083SPeter Grehan 	vm->num_mem_segs++;
338366f6083SPeter Grehan out:
339366f6083SPeter Grehan 	*ret_hpa = hpa;
340366f6083SPeter Grehan 	return (0);
341366f6083SPeter Grehan }
342366f6083SPeter Grehan 
343366f6083SPeter Grehan vm_paddr_t
344366f6083SPeter Grehan vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len)
345366f6083SPeter Grehan {
346366f6083SPeter Grehan 	int i;
347366f6083SPeter Grehan 	vm_paddr_t gpabase, gpalimit, hpabase;
348366f6083SPeter Grehan 
349366f6083SPeter Grehan 	for (i = 0; i < vm->num_mem_segs; i++) {
350366f6083SPeter Grehan 		hpabase = vm->mem_segs[i].hpa;
351366f6083SPeter Grehan 		gpabase = vm->mem_segs[i].gpa;
352366f6083SPeter Grehan 		gpalimit = gpabase + vm->mem_segs[i].len;
353366f6083SPeter Grehan 		if (gpa >= gpabase && gpa + len <= gpalimit)
354366f6083SPeter Grehan 			return ((gpa - gpabase) + hpabase);
355366f6083SPeter Grehan 	}
356366f6083SPeter Grehan 	return ((vm_paddr_t)-1);
357366f6083SPeter Grehan }
358366f6083SPeter Grehan 
359366f6083SPeter Grehan int
360366f6083SPeter Grehan vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase,
361366f6083SPeter Grehan 		  struct vm_memory_segment *seg)
362366f6083SPeter Grehan {
363366f6083SPeter Grehan 	int i;
364366f6083SPeter Grehan 
365366f6083SPeter Grehan 	for (i = 0; i < vm->num_mem_segs; i++) {
366366f6083SPeter Grehan 		if (gpabase == vm->mem_segs[i].gpa) {
367366f6083SPeter Grehan 			*seg = vm->mem_segs[i];
368366f6083SPeter Grehan 			return (0);
369366f6083SPeter Grehan 		}
370366f6083SPeter Grehan 	}
371366f6083SPeter Grehan 	return (-1);
372366f6083SPeter Grehan }
373366f6083SPeter Grehan 
374366f6083SPeter Grehan int
375366f6083SPeter Grehan vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval)
376366f6083SPeter Grehan {
377366f6083SPeter Grehan 
378366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
379366f6083SPeter Grehan 		return (EINVAL);
380366f6083SPeter Grehan 
381366f6083SPeter Grehan 	if (reg >= VM_REG_LAST)
382366f6083SPeter Grehan 		return (EINVAL);
383366f6083SPeter Grehan 
384366f6083SPeter Grehan 	return (VMGETREG(vm->cookie, vcpu, reg, retval));
385366f6083SPeter Grehan }
386366f6083SPeter Grehan 
387366f6083SPeter Grehan int
388366f6083SPeter Grehan vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val)
389366f6083SPeter Grehan {
390366f6083SPeter Grehan 
391366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
392366f6083SPeter Grehan 		return (EINVAL);
393366f6083SPeter Grehan 
394366f6083SPeter Grehan 	if (reg >= VM_REG_LAST)
395366f6083SPeter Grehan 		return (EINVAL);
396366f6083SPeter Grehan 
397366f6083SPeter Grehan 	return (VMSETREG(vm->cookie, vcpu, reg, val));
398366f6083SPeter Grehan }
399366f6083SPeter Grehan 
400366f6083SPeter Grehan static boolean_t
401366f6083SPeter Grehan is_descriptor_table(int reg)
402366f6083SPeter Grehan {
403366f6083SPeter Grehan 
404366f6083SPeter Grehan 	switch (reg) {
405366f6083SPeter Grehan 	case VM_REG_GUEST_IDTR:
406366f6083SPeter Grehan 	case VM_REG_GUEST_GDTR:
407366f6083SPeter Grehan 		return (TRUE);
408366f6083SPeter Grehan 	default:
409366f6083SPeter Grehan 		return (FALSE);
410366f6083SPeter Grehan 	}
411366f6083SPeter Grehan }
412366f6083SPeter Grehan 
413366f6083SPeter Grehan static boolean_t
414366f6083SPeter Grehan is_segment_register(int reg)
415366f6083SPeter Grehan {
416366f6083SPeter Grehan 
417366f6083SPeter Grehan 	switch (reg) {
418366f6083SPeter Grehan 	case VM_REG_GUEST_ES:
419366f6083SPeter Grehan 	case VM_REG_GUEST_CS:
420366f6083SPeter Grehan 	case VM_REG_GUEST_SS:
421366f6083SPeter Grehan 	case VM_REG_GUEST_DS:
422366f6083SPeter Grehan 	case VM_REG_GUEST_FS:
423366f6083SPeter Grehan 	case VM_REG_GUEST_GS:
424366f6083SPeter Grehan 	case VM_REG_GUEST_TR:
425366f6083SPeter Grehan 	case VM_REG_GUEST_LDTR:
426366f6083SPeter Grehan 		return (TRUE);
427366f6083SPeter Grehan 	default:
428366f6083SPeter Grehan 		return (FALSE);
429366f6083SPeter Grehan 	}
430366f6083SPeter Grehan }
431366f6083SPeter Grehan 
432366f6083SPeter Grehan int
433366f6083SPeter Grehan vm_get_seg_desc(struct vm *vm, int vcpu, int reg,
434366f6083SPeter Grehan 		struct seg_desc *desc)
435366f6083SPeter Grehan {
436366f6083SPeter Grehan 
437366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
438366f6083SPeter Grehan 		return (EINVAL);
439366f6083SPeter Grehan 
440366f6083SPeter Grehan 	if (!is_segment_register(reg) && !is_descriptor_table(reg))
441366f6083SPeter Grehan 		return (EINVAL);
442366f6083SPeter Grehan 
443366f6083SPeter Grehan 	return (VMGETDESC(vm->cookie, vcpu, reg, desc));
444366f6083SPeter Grehan }
445366f6083SPeter Grehan 
446366f6083SPeter Grehan int
447366f6083SPeter Grehan vm_set_seg_desc(struct vm *vm, int vcpu, int reg,
448366f6083SPeter Grehan 		struct seg_desc *desc)
449366f6083SPeter Grehan {
450366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
451366f6083SPeter Grehan 		return (EINVAL);
452366f6083SPeter Grehan 
453366f6083SPeter Grehan 	if (!is_segment_register(reg) && !is_descriptor_table(reg))
454366f6083SPeter Grehan 		return (EINVAL);
455366f6083SPeter Grehan 
456366f6083SPeter Grehan 	return (VMSETDESC(vm->cookie, vcpu, reg, desc));
457366f6083SPeter Grehan }
458366f6083SPeter Grehan 
459366f6083SPeter Grehan int
460366f6083SPeter Grehan vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid)
461366f6083SPeter Grehan {
462366f6083SPeter Grehan 
463366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
464366f6083SPeter Grehan 		return (EINVAL);
465366f6083SPeter Grehan 
466366f6083SPeter Grehan 	*cpuid = VCPU_PINCPU(vm, vcpuid);
467366f6083SPeter Grehan 
468366f6083SPeter Grehan 	return (0);
469366f6083SPeter Grehan }
470366f6083SPeter Grehan 
471366f6083SPeter Grehan int
472366f6083SPeter Grehan vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid)
473366f6083SPeter Grehan {
474366f6083SPeter Grehan 	struct thread *td;
475366f6083SPeter Grehan 
476366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
477366f6083SPeter Grehan 		return (EINVAL);
478366f6083SPeter Grehan 
479366f6083SPeter Grehan 	td = curthread;		/* XXXSMP only safe when muxing vcpus */
480366f6083SPeter Grehan 
481366f6083SPeter Grehan 	/* unpin */
482366f6083SPeter Grehan 	if (host_cpuid < 0) {
483366f6083SPeter Grehan 		VCPU_UNPIN(vm, vcpuid);
484366f6083SPeter Grehan 		thread_lock(td);
485366f6083SPeter Grehan 		sched_unbind(td);
486366f6083SPeter Grehan 		thread_unlock(td);
487366f6083SPeter Grehan 		return (0);
488366f6083SPeter Grehan 	}
489366f6083SPeter Grehan 
490366f6083SPeter Grehan 	if (CPU_ABSENT(host_cpuid))
491366f6083SPeter Grehan 		return (EINVAL);
492366f6083SPeter Grehan 
493366f6083SPeter Grehan 	/*
494366f6083SPeter Grehan 	 * XXX we should check that 'host_cpuid' has not already been pinned
495366f6083SPeter Grehan 	 * by another vm.
496366f6083SPeter Grehan 	 */
497366f6083SPeter Grehan 	thread_lock(td);
498366f6083SPeter Grehan 	sched_bind(td, host_cpuid);
499366f6083SPeter Grehan 	thread_unlock(td);
500366f6083SPeter Grehan 	VCPU_PIN(vm, vcpuid, host_cpuid);
501366f6083SPeter Grehan 
502366f6083SPeter Grehan 	return (0);
503366f6083SPeter Grehan }
504366f6083SPeter Grehan 
505366f6083SPeter Grehan static void
506366f6083SPeter Grehan restore_guest_fpustate(struct vcpu *vcpu)
507366f6083SPeter Grehan {
508366f6083SPeter Grehan 	register_t s;
509366f6083SPeter Grehan 
510366f6083SPeter Grehan 	s = intr_disable();
511366f6083SPeter Grehan 	fpu_stop_emulating();
512366f6083SPeter Grehan 	fxrstor(&vcpu->savefpu);
513366f6083SPeter Grehan 	fpu_start_emulating();
514366f6083SPeter Grehan 	intr_restore(s);
515366f6083SPeter Grehan }
516366f6083SPeter Grehan 
517366f6083SPeter Grehan static void
518366f6083SPeter Grehan save_guest_fpustate(struct vcpu *vcpu)
519366f6083SPeter Grehan {
520366f6083SPeter Grehan 	register_t s;
521366f6083SPeter Grehan 
522366f6083SPeter Grehan 	s = intr_disable();
523366f6083SPeter Grehan 	fpu_stop_emulating();
524366f6083SPeter Grehan 	fxsave(&vcpu->savefpu);
525366f6083SPeter Grehan 	fpu_start_emulating();
526366f6083SPeter Grehan 	intr_restore(s);
527366f6083SPeter Grehan }
528366f6083SPeter Grehan 
529366f6083SPeter Grehan int
530366f6083SPeter Grehan vm_run(struct vm *vm, struct vm_run *vmrun)
531366f6083SPeter Grehan {
532366f6083SPeter Grehan 	int error, vcpuid;
533366f6083SPeter Grehan 	struct vcpu *vcpu;
534366f6083SPeter Grehan 	struct pcb *pcb;
535366f6083SPeter Grehan 	uint64_t tscval;
536366f6083SPeter Grehan 
537366f6083SPeter Grehan 	vcpuid = vmrun->cpuid;
538366f6083SPeter Grehan 
539366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
540366f6083SPeter Grehan 		return (EINVAL);
541366f6083SPeter Grehan 
542366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
543366f6083SPeter Grehan 
544366f6083SPeter Grehan 	critical_enter();
545366f6083SPeter Grehan 
546366f6083SPeter Grehan 	tscval = rdtsc();
547366f6083SPeter Grehan 
548366f6083SPeter Grehan 	pcb = PCPU_GET(curpcb);
549*34a6b2d6SJohn Baldwin 	set_pcb_flags(pcb, PCB_FULL_IRET);
550366f6083SPeter Grehan 
551366f6083SPeter Grehan 	vcpu->hostcpu = curcpu;
552366f6083SPeter Grehan 
553366f6083SPeter Grehan 	fpuexit(curthread);
554366f6083SPeter Grehan 	restore_guest_msrs(vm, vcpuid);
555366f6083SPeter Grehan 	restore_guest_fpustate(vcpu);
556366f6083SPeter Grehan 	error = VMRUN(vm->cookie, vcpuid, vmrun->rip, &vmrun->vm_exit);
557366f6083SPeter Grehan 	save_guest_fpustate(vcpu);
558366f6083SPeter Grehan 	restore_host_msrs(vm, vcpuid);
559366f6083SPeter Grehan 
560366f6083SPeter Grehan 	vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval);
561366f6083SPeter Grehan 
562366f6083SPeter Grehan 	critical_exit();
563366f6083SPeter Grehan 
564366f6083SPeter Grehan 	return (error);
565366f6083SPeter Grehan }
566366f6083SPeter Grehan 
567366f6083SPeter Grehan int
568366f6083SPeter Grehan vm_inject_event(struct vm *vm, int vcpuid, int type,
569366f6083SPeter Grehan 		int vector, uint32_t code, int code_valid)
570366f6083SPeter Grehan {
571366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
572366f6083SPeter Grehan 		return (EINVAL);
573366f6083SPeter Grehan 
574366f6083SPeter Grehan 	if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0)
575366f6083SPeter Grehan 		return (EINVAL);
576366f6083SPeter Grehan 
577366f6083SPeter Grehan 	if (vector < 0 || vector > 255)
578366f6083SPeter Grehan 		return (EINVAL);
579366f6083SPeter Grehan 
580366f6083SPeter Grehan 	return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid));
581366f6083SPeter Grehan }
582366f6083SPeter Grehan 
583366f6083SPeter Grehan int
584366f6083SPeter Grehan vm_inject_nmi(struct vm *vm, int vcpu)
585366f6083SPeter Grehan {
586366f6083SPeter Grehan 	int error;
587366f6083SPeter Grehan 
588366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
589366f6083SPeter Grehan 		return (EINVAL);
590366f6083SPeter Grehan 
591366f6083SPeter Grehan 	error = VMNMI(vm->cookie, vcpu);
592366f6083SPeter Grehan 	vm_interrupt_hostcpu(vm, vcpu);
593366f6083SPeter Grehan 	return (error);
594366f6083SPeter Grehan }
595366f6083SPeter Grehan 
596366f6083SPeter Grehan int
597366f6083SPeter Grehan vm_get_capability(struct vm *vm, int vcpu, int type, int *retval)
598366f6083SPeter Grehan {
599366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
600366f6083SPeter Grehan 		return (EINVAL);
601366f6083SPeter Grehan 
602366f6083SPeter Grehan 	if (type < 0 || type >= VM_CAP_MAX)
603366f6083SPeter Grehan 		return (EINVAL);
604366f6083SPeter Grehan 
605366f6083SPeter Grehan 	return (VMGETCAP(vm->cookie, vcpu, type, retval));
606366f6083SPeter Grehan }
607366f6083SPeter Grehan 
608366f6083SPeter Grehan int
609366f6083SPeter Grehan vm_set_capability(struct vm *vm, int vcpu, int type, int val)
610366f6083SPeter Grehan {
611366f6083SPeter Grehan 	if (vcpu < 0 || vcpu >= VM_MAXCPU)
612366f6083SPeter Grehan 		return (EINVAL);
613366f6083SPeter Grehan 
614366f6083SPeter Grehan 	if (type < 0 || type >= VM_CAP_MAX)
615366f6083SPeter Grehan 		return (EINVAL);
616366f6083SPeter Grehan 
617366f6083SPeter Grehan 	return (VMSETCAP(vm->cookie, vcpu, type, val));
618366f6083SPeter Grehan }
619366f6083SPeter Grehan 
620366f6083SPeter Grehan uint64_t *
621366f6083SPeter Grehan vm_guest_msrs(struct vm *vm, int cpu)
622366f6083SPeter Grehan {
623366f6083SPeter Grehan 	return (vm->vcpu[cpu].guest_msrs);
624366f6083SPeter Grehan }
625366f6083SPeter Grehan 
626366f6083SPeter Grehan struct vlapic *
627366f6083SPeter Grehan vm_lapic(struct vm *vm, int cpu)
628366f6083SPeter Grehan {
629366f6083SPeter Grehan 	return (vm->vcpu[cpu].vlapic);
630366f6083SPeter Grehan }
631366f6083SPeter Grehan 
632366f6083SPeter Grehan boolean_t
633366f6083SPeter Grehan vmm_is_pptdev(int bus, int slot, int func)
634366f6083SPeter Grehan {
635366f6083SPeter Grehan 	int found, b, s, f, n;
636366f6083SPeter Grehan 	char *val, *cp, *cp2;
637366f6083SPeter Grehan 
638366f6083SPeter Grehan 	/*
639366f6083SPeter Grehan 	 * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12"
640366f6083SPeter Grehan 	 */
641366f6083SPeter Grehan 	found = 0;
642366f6083SPeter Grehan 	cp = val = getenv("pptdevs");
643366f6083SPeter Grehan 	while (cp != NULL && *cp != '\0') {
644366f6083SPeter Grehan 		if ((cp2 = strchr(cp, ' ')) != NULL)
645366f6083SPeter Grehan 			*cp2 = '\0';
646366f6083SPeter Grehan 
647366f6083SPeter Grehan 		n = sscanf(cp, "%d/%d/%d", &b, &s, &f);
648366f6083SPeter Grehan 		if (n == 3 && bus == b && slot == s && func == f) {
649366f6083SPeter Grehan 			found = 1;
650366f6083SPeter Grehan 			break;
651366f6083SPeter Grehan 		}
652366f6083SPeter Grehan 
653366f6083SPeter Grehan 		if (cp2 != NULL)
654366f6083SPeter Grehan 			*cp2++ = ' ';
655366f6083SPeter Grehan 
656366f6083SPeter Grehan 		cp = cp2;
657366f6083SPeter Grehan 	}
658366f6083SPeter Grehan 	freeenv(val);
659366f6083SPeter Grehan 	return (found);
660366f6083SPeter Grehan }
661366f6083SPeter Grehan 
662366f6083SPeter Grehan void *
663366f6083SPeter Grehan vm_iommu_domain(struct vm *vm)
664366f6083SPeter Grehan {
665366f6083SPeter Grehan 
666366f6083SPeter Grehan 	return (vm->iommu);
667366f6083SPeter Grehan }
668366f6083SPeter Grehan 
669366f6083SPeter Grehan void
670366f6083SPeter Grehan vm_set_run_state(struct vm *vm, int vcpuid, int state)
671366f6083SPeter Grehan {
672366f6083SPeter Grehan 	struct vcpu *vcpu;
673366f6083SPeter Grehan 
674366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
675366f6083SPeter Grehan 		panic("vm_set_run_state: invalid vcpuid %d", vcpuid);
676366f6083SPeter Grehan 
677366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
678366f6083SPeter Grehan 
679366f6083SPeter Grehan 	if (state == VCPU_RUNNING) {
680366f6083SPeter Grehan 		if (vcpu->flags & VCPU_F_RUNNING) {
681366f6083SPeter Grehan 			panic("vm_set_run_state: %s[%d] is already running",
682366f6083SPeter Grehan 			      vm_name(vm), vcpuid);
683366f6083SPeter Grehan 		}
684366f6083SPeter Grehan 		vcpu->flags |= VCPU_F_RUNNING;
685366f6083SPeter Grehan 	} else {
686366f6083SPeter Grehan 		if ((vcpu->flags & VCPU_F_RUNNING) == 0) {
687366f6083SPeter Grehan 			panic("vm_set_run_state: %s[%d] is already stopped",
688366f6083SPeter Grehan 			      vm_name(vm), vcpuid);
689366f6083SPeter Grehan 		}
690366f6083SPeter Grehan 		vcpu->flags &= ~VCPU_F_RUNNING;
691366f6083SPeter Grehan 	}
692366f6083SPeter Grehan }
693366f6083SPeter Grehan 
694366f6083SPeter Grehan int
695366f6083SPeter Grehan vm_get_run_state(struct vm *vm, int vcpuid, int *cpuptr)
696366f6083SPeter Grehan {
697366f6083SPeter Grehan 	int retval, hostcpu;
698366f6083SPeter Grehan 	struct vcpu *vcpu;
699366f6083SPeter Grehan 
700366f6083SPeter Grehan 	if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
701366f6083SPeter Grehan 		panic("vm_get_run_state: invalid vcpuid %d", vcpuid);
702366f6083SPeter Grehan 
703366f6083SPeter Grehan 	vcpu = &vm->vcpu[vcpuid];
704366f6083SPeter Grehan 	if (vcpu->flags & VCPU_F_RUNNING) {
705366f6083SPeter Grehan 		retval = VCPU_RUNNING;
706366f6083SPeter Grehan 		hostcpu = vcpu->hostcpu;
707366f6083SPeter Grehan 	} else {
708366f6083SPeter Grehan 		retval = VCPU_STOPPED;
709366f6083SPeter Grehan 		hostcpu = -1;
710366f6083SPeter Grehan 	}
711366f6083SPeter Grehan 
712366f6083SPeter Grehan 	if (cpuptr)
713366f6083SPeter Grehan 		*cpuptr = hostcpu;
714366f6083SPeter Grehan 
715366f6083SPeter Grehan 	return (retval);
716366f6083SPeter Grehan }
717366f6083SPeter Grehan 
718366f6083SPeter Grehan void
719366f6083SPeter Grehan vm_activate_cpu(struct vm *vm, int vcpuid)
720366f6083SPeter Grehan {
721366f6083SPeter Grehan 
722366f6083SPeter Grehan 	if (vcpuid >= 0 && vcpuid < VM_MAXCPU)
723366f6083SPeter Grehan 		vm->active_cpus |= vcpu_mask(vcpuid);
724366f6083SPeter Grehan }
725366f6083SPeter Grehan 
726366f6083SPeter Grehan cpumask_t
727366f6083SPeter Grehan vm_active_cpus(struct vm *vm)
728366f6083SPeter Grehan {
729366f6083SPeter Grehan 
730366f6083SPeter Grehan 	return (vm->active_cpus);
731366f6083SPeter Grehan }
732366f6083SPeter Grehan 
733366f6083SPeter Grehan void *
734366f6083SPeter Grehan vcpu_stats(struct vm *vm, int vcpuid)
735366f6083SPeter Grehan {
736366f6083SPeter Grehan 
737366f6083SPeter Grehan 	return (vm->vcpu[vcpuid].stats);
738366f6083SPeter Grehan }
739