vmm_dev.c revision 284899
1106159Sjulian/*-
2106159Sjulian * Copyright (c) 2011 NetApp, Inc.
3139823Simp * All rights reserved.
4139823Simp *
5139823Simp * Redistribution and use in source and binary forms, with or without
6106159Sjulian * modification, are permitted provided that the following conditions
7106159Sjulian * are met:
8106159Sjulian * 1. Redistributions of source code must retain the above copyright
9106159Sjulian *    notice, this list of conditions and the following disclaimer.
10106159Sjulian * 2. Redistributions in binary form must reproduce the above copyright
11106159Sjulian *    notice, this list of conditions and the following disclaimer in the
12106159Sjulian *    documentation and/or other materials provided with the distribution.
13106159Sjulian *
14106159Sjulian * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15106159Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16106159Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17106159Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18106159Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19106159Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20106159Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21106159Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22106159Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23106159Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24106159Sjulian * SUCH DAMAGE.
25106159Sjulian *
26106159Sjulian * $FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 284899 2015-06-28 01:21:55Z neel $
27106159Sjulian */
28106159Sjulian
29106159Sjulian#include <sys/cdefs.h>
30106159Sjulian__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/vmm_dev.c 284899 2015-06-28 01:21:55Z neel $");
31106159Sjulian
32106159Sjulian#include <sys/param.h>
33106159Sjulian#include <sys/kernel.h>
34106159Sjulian#include <sys/queue.h>
35106159Sjulian#include <sys/lock.h>
36106159Sjulian#include <sys/mutex.h>
37106159Sjulian#include <sys/malloc.h>
38106159Sjulian#include <sys/conf.h>
39139823Simp#include <sys/sysctl.h>
40106159Sjulian#include <sys/libkern.h>
41106159Sjulian#include <sys/ioccom.h>
42106159Sjulian#include <sys/mman.h>
43106159Sjulian#include <sys/uio.h>
44106159Sjulian
45106159Sjulian#include <vm/vm.h>
46106159Sjulian#include <vm/pmap.h>
47106159Sjulian#include <vm/vm_map.h>
48106159Sjulian
49106159Sjulian#include <machine/vmparam.h>
50106159Sjulian#include <machine/vmm.h>
51106159Sjulian#include <machine/vmm_instruction_emul.h>
52106159Sjulian#include <machine/vmm_dev.h>
53106159Sjulian
54106159Sjulian#include "vmm_lapic.h"
55106159Sjulian#include "vmm_stat.h"
56106159Sjulian#include "vmm_mem.h"
57106159Sjulian#include "io/ppt.h"
58106159Sjulian#include "io/vatpic.h"
59106159Sjulian#include "io/vioapic.h"
60106159Sjulian#include "io/vhpet.h"
61106159Sjulian#include "io/vrtc.h"
62106159Sjulian
63106159Sjulianstruct vmmdev_softc {
64106159Sjulian	struct vm	*vm;		/* vm instance cookie */
65106159Sjulian	struct cdev	*cdev;
66106159Sjulian	SLIST_ENTRY(vmmdev_softc) link;
67106159Sjulian	int		flags;
68106159Sjulian};
69106159Sjulian#define	VSC_LINKED		0x01
70106159Sjulian
71106159Sjulianstatic SLIST_HEAD(, vmmdev_softc) head;
72106159Sjulian
73106159Sjulianstatic struct mtx vmmdev_mtx;
74106159Sjulian
75106159Sjulianstatic MALLOC_DEFINE(M_VMMDEV, "vmmdev", "vmmdev");
76106159Sjulian
77106159SjulianSYSCTL_DECL(_hw_vmm);
78106159Sjulian
79106159Sjulianstatic struct vmmdev_softc *
80106159Sjulianvmmdev_lookup(const char *name)
81106159Sjulian{
82106159Sjulian	struct vmmdev_softc *sc;
83106159Sjulian
84106159Sjulian#ifdef notyet	/* XXX kernel is not compiled with invariants */
85106159Sjulian	mtx_assert(&vmmdev_mtx, MA_OWNED);
86106159Sjulian#endif
87106159Sjulian
88106159Sjulian	SLIST_FOREACH(sc, &head, link) {
89106159Sjulian		if (strcmp(name, vm_name(sc->vm)) == 0)
90106159Sjulian			break;
91106159Sjulian	}
92106159Sjulian
93106159Sjulian	return (sc);
94106159Sjulian}
95106159Sjulian
96106159Sjulianstatic struct vmmdev_softc *
97106159Sjulianvmmdev_lookup2(struct cdev *cdev)
98106159Sjulian{
99106159Sjulian
100106159Sjulian	return (cdev->si_drv1);
101106159Sjulian}
102106159Sjulian
103106159Sjulianstatic int
104106159Sjulianvmmdev_rw(struct cdev *cdev, struct uio *uio, int flags)
105152315Sru{
106106159Sjulian	int error, off, c, prot;
107106159Sjulian	vm_paddr_t gpa;
108106159Sjulian	void *hpa, *cookie;
109106159Sjulian	struct vmmdev_softc *sc;
110191148Skmacy
111106159Sjulian	static char zerobuf[PAGE_SIZE];
112106159Sjulian
113106159Sjulian	error = 0;
114106159Sjulian	sc = vmmdev_lookup2(cdev);
115106159Sjulian	if (sc == NULL)
116106159Sjulian		error = ENXIO;
117106159Sjulian
118106159Sjulian	prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ);
119106159Sjulian	while (uio->uio_resid > 0 && error == 0) {
120106159Sjulian		gpa = uio->uio_offset;
121106159Sjulian		off = gpa & PAGE_MASK;
122106159Sjulian		c = min(uio->uio_resid, PAGE_SIZE - off);
123106159Sjulian
124106159Sjulian		/*
125106159Sjulian		 * The VM has a hole in its physical memory map. If we want to
126106159Sjulian		 * use 'dd' to inspect memory beyond the hole we need to
127106159Sjulian		 * provide bogus data for memory that lies in the hole.
128106159Sjulian		 *
129106159Sjulian		 * Since this device does not support lseek(2), dd(1) will
130130808Swpaul		 * read(2) blocks of data to simulate the lseek(2).
131130808Swpaul		 */
132130808Swpaul		hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie);
133130808Swpaul		if (hpa == NULL) {
134130808Swpaul			if (uio->uio_rw == UIO_READ)
135130815Swpaul				error = uiomove(zerobuf, c, uio);
136130815Swpaul			else
137130808Swpaul				error = EFAULT;
138152243Sru		} else {
139106159Sjulian			error = uiomove(hpa, c, uio);
140106159Sjulian			vm_gpa_release(cookie);
141106159Sjulian		}
142106159Sjulian	}
143106159Sjulian	return (error);
144106159Sjulian}
145106159Sjulian
146106159Sjulianstatic int
147106159Sjulianvmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
148130815Swpaul	     struct thread *td)
149130815Swpaul{
150106159Sjulian	int error, vcpu, state_changed, size;
151106159Sjulian	cpuset_t *cpuset;
152106159Sjulian	struct vmmdev_softc *sc;
153169677Sdwmalone	struct vm_memory_segment *seg;
154106159Sjulian	struct vm_register *vmreg;
155106159Sjulian	struct vm_seg_desc *vmsegdesc;
156106159Sjulian	struct vm_run *vmrun;
157169677Sdwmalone	struct vm_exception *vmexc;
158169677Sdwmalone	struct vm_lapic_irq *vmirq;
159169677Sdwmalone	struct vm_lapic_msi *vmmsi;
160169677Sdwmalone	struct vm_ioapic_irq *ioapic_irq;
161169677Sdwmalone	struct vm_isa_irq *isa_irq;
162106159Sjulian	struct vm_isa_irq_trigger *isa_irq_trigger;
163106159Sjulian	struct vm_capability *vmcap;
164106159Sjulian	struct vm_pptdev *pptdev;
165106159Sjulian	struct vm_pptdev_mmio *pptmmio;
166130815Swpaul	struct vm_pptdev_msi *pptmsi;
167130815Swpaul	struct vm_pptdev_msix *pptmsix;
168249925Sglebius	struct vm_nmi *vmnmi;
169191148Skmacy	struct vm_stats *vmstats;
170106159Sjulian	struct vm_stat_desc *statdesc;
171106159Sjulian	struct vm_x2apic *x2apic;
172106159Sjulian	struct vm_gpa_pte *gpapte;
173106159Sjulian	struct vm_suspend *vmsuspend;
174106159Sjulian	struct vm_gla2gpa *gg;
175106159Sjulian	struct vm_activate_cpu *vac;
176106159Sjulian	struct vm_cpuset *vm_cpuset;
177106159Sjulian	struct vm_intinfo *vmii;
178147256Sbrooks	struct vm_rtc_time *rtctime;
179106159Sjulian	struct vm_rtc_data *rtcdata;
180106159Sjulian
181106159Sjulian	sc = vmmdev_lookup2(cdev);
182106159Sjulian	if (sc == NULL)
183106159Sjulian		return (ENXIO);
184106159Sjulian
185106159Sjulian	error = 0;
186106159Sjulian	vcpu = -1;
187106159Sjulian	state_changed = 0;
188106159Sjulian
189106159Sjulian	/*
190111565Swpaul	 * Some VMM ioctls can operate only on vcpus that are not running.
191106159Sjulian	 */
192106159Sjulian	switch (cmd) {
193106159Sjulian	case VM_RUN:
194106159Sjulian	case VM_GET_REGISTER:
195106159Sjulian	case VM_SET_REGISTER:
196106159Sjulian	case VM_GET_SEGMENT_DESCRIPTOR:
197106159Sjulian	case VM_SET_SEGMENT_DESCRIPTOR:
198106159Sjulian	case VM_INJECT_EXCEPTION:
199106159Sjulian	case VM_GET_CAPABILITY:
200106159Sjulian	case VM_SET_CAPABILITY:
201249925Sglebius	case VM_PPTDEV_MSI:
202106159Sjulian	case VM_PPTDEV_MSIX:
203106159Sjulian	case VM_SET_X2APIC_STATE:
204106159Sjulian	case VM_GLA2GPA:
205169677Sdwmalone	case VM_ACTIVATE_CPU:
206106159Sjulian	case VM_SET_INTINFO:
207106159Sjulian	case VM_GET_INTINFO:
208106159Sjulian	case VM_RESTART_INSTRUCTION:
209106159Sjulian		/*
210106159Sjulian		 * XXX fragile, handle with care
211106159Sjulian		 * Assumes that the first field of the ioctl data is the vcpu.
212141341Sru		 */
213106159Sjulian		vcpu = *(int *)data;
214106159Sjulian		if (vcpu < 0 || vcpu >= VM_MAXCPU) {
215106159Sjulian			error = EINVAL;
216106159Sjulian			goto done;
217106159Sjulian		}
218106159Sjulian
219106159Sjulian		error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true);
220106159Sjulian		if (error)
221106159Sjulian			goto done;
222106159Sjulian
223106159Sjulian		state_changed = 1;
224106159Sjulian		break;
225106159Sjulian
226106159Sjulian	case VM_MAP_PPTDEV_MMIO:
227106159Sjulian	case VM_BIND_PPTDEV:
228106159Sjulian	case VM_UNBIND_PPTDEV:
229106159Sjulian	case VM_MAP_MEMORY:
230106159Sjulian	case VM_REINIT:
231106159Sjulian		/*
232106159Sjulian		 * ioctls that operate on the entire virtual machine must
233106159Sjulian		 * prevent all vcpus from running.
234106159Sjulian		 */
235106159Sjulian		error = 0;
236106159Sjulian		for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) {
237106159Sjulian			error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true);
238106159Sjulian			if (error)
239106159Sjulian				break;
240106159Sjulian		}
241106159Sjulian
242106159Sjulian		if (error) {
243106159Sjulian			while (--vcpu >= 0)
244106159Sjulian				vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
245106159Sjulian			goto done;
246106159Sjulian		}
247106159Sjulian
248106159Sjulian		state_changed = 2;
249106159Sjulian		break;
250106159Sjulian
251106159Sjulian	default:
252129823Sjulian		break;
253129823Sjulian	}
254141341Sru
255129823Sjulian	switch(cmd) {
256129823Sjulian	case VM_RUN:
257129823Sjulian		vmrun = (struct vm_run *)data;
258129823Sjulian		error = vm_run(sc->vm, vmrun);
259106159Sjulian		break;
260106159Sjulian	case VM_SUSPEND:
261106159Sjulian		vmsuspend = (struct vm_suspend *)data;
262106159Sjulian		error = vm_suspend(sc->vm, vmsuspend->how);
263106159Sjulian		break;
264106159Sjulian	case VM_REINIT:
265106159Sjulian		error = vm_reinit(sc->vm);
266106159Sjulian		break;
267106159Sjulian	case VM_STAT_DESC: {
268106159Sjulian		statdesc = (struct vm_stat_desc *)data;
269106159Sjulian		error = vmm_stat_desc_copy(statdesc->index,
270132161Srwatson					statdesc->desc, sizeof(statdesc->desc));
271132161Srwatson		break;
272106159Sjulian	}
273106159Sjulian	case VM_STATS: {
274106159Sjulian		CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS);
275106159Sjulian		vmstats = (struct vm_stats *)data;
276131575Sstefanf		getmicrotime(&vmstats->tv);
277106159Sjulian		error = vmm_stat_copy(sc->vm, vmstats->cpuid,
278106159Sjulian				      &vmstats->num_entries, vmstats->statbuf);
279106159Sjulian		break;
280106159Sjulian	}
281132161Srwatson	case VM_PPTDEV_MSI:
282106159Sjulian		pptmsi = (struct vm_pptdev_msi *)data;
283106159Sjulian		error = ppt_setup_msi(sc->vm, pptmsi->vcpu,
284106159Sjulian				      pptmsi->bus, pptmsi->slot, pptmsi->func,
285106159Sjulian				      pptmsi->addr, pptmsi->msg,
286106159Sjulian				      pptmsi->numvec);
287106159Sjulian		break;
288184205Sdes	case VM_PPTDEV_MSIX:
289106159Sjulian		pptmsix = (struct vm_pptdev_msix *)data;
290132161Srwatson		error = ppt_setup_msix(sc->vm, pptmsix->vcpu,
291132161Srwatson				       pptmsix->bus, pptmsix->slot,
292106159Sjulian				       pptmsix->func, pptmsix->idx,
293132161Srwatson				       pptmsix->addr, pptmsix->msg,
294106159Sjulian				       pptmsix->vector_control);
295106159Sjulian		break;
296106159Sjulian	case VM_MAP_PPTDEV_MMIO:
297106159Sjulian		pptmmio = (struct vm_pptdev_mmio *)data;
298106159Sjulian		error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot,
299184205Sdes				     pptmmio->func, pptmmio->gpa, pptmmio->len,
300106159Sjulian				     pptmmio->hpa);
301106159Sjulian		break;
302106159Sjulian	case VM_BIND_PPTDEV:
303106159Sjulian		pptdev = (struct vm_pptdev *)data;
304106159Sjulian		error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
305148915Sobrien					 pptdev->func);
306106159Sjulian		break;
307106159Sjulian	case VM_UNBIND_PPTDEV:
308106159Sjulian		pptdev = (struct vm_pptdev *)data;
309132161Srwatson		error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot,
310106159Sjulian					   pptdev->func);
311106159Sjulian		break;
312106159Sjulian	case VM_INJECT_EXCEPTION:
313106159Sjulian		vmexc = (struct vm_exception *)data;
314106159Sjulian		error = vm_inject_exception(sc->vm, vmexc->cpuid,
315106159Sjulian		    vmexc->vector, vmexc->error_code_valid, vmexc->error_code,
316131575Sstefanf		    vmexc->restart_instruction);
317106159Sjulian		break;
318106159Sjulian	case VM_INJECT_NMI:
319106159Sjulian		vmnmi = (struct vm_nmi *)data;
320106159Sjulian		error = vm_inject_nmi(sc->vm, vmnmi->cpuid);
321106159Sjulian		break;
322106159Sjulian	case VM_LAPIC_IRQ:
323132161Srwatson		vmirq = (struct vm_lapic_irq *)data;
324106159Sjulian		error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector);
325148915Sobrien		break;
326106159Sjulian	case VM_LAPIC_LOCAL_IRQ:
327148915Sobrien		vmirq = (struct vm_lapic_irq *)data;
328106159Sjulian		error = lapic_set_local_intr(sc->vm, vmirq->cpuid,
329106159Sjulian		    vmirq->vector);
330106159Sjulian		break;
331106159Sjulian	case VM_LAPIC_MSI:
332106159Sjulian		vmmsi = (struct vm_lapic_msi *)data;
333106159Sjulian		error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg);
334106159Sjulian		break;
335106159Sjulian	case VM_IOAPIC_ASSERT_IRQ:
336106159Sjulian		ioapic_irq = (struct vm_ioapic_irq *)data;
337184205Sdes		error = vioapic_assert_irq(sc->vm, ioapic_irq->irq);
338106159Sjulian		break;
339106159Sjulian	case VM_IOAPIC_DEASSERT_IRQ:
340106159Sjulian		ioapic_irq = (struct vm_ioapic_irq *)data;
341132161Srwatson		error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq);
342106159Sjulian		break;
343106159Sjulian	case VM_IOAPIC_PULSE_IRQ:
344106159Sjulian		ioapic_irq = (struct vm_ioapic_irq *)data;
345106159Sjulian		error = vioapic_pulse_irq(sc->vm, ioapic_irq->irq);
346106159Sjulian		break;
347106159Sjulian	case VM_IOAPIC_PINCOUNT:
348106159Sjulian		*(int *)data = vioapic_pincount(sc->vm);
349106159Sjulian		break;
350106159Sjulian	case VM_ISA_ASSERT_IRQ:
351106159Sjulian		isa_irq = (struct vm_isa_irq *)data;
352106159Sjulian		error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq);
353106159Sjulian		if (error == 0 && isa_irq->ioapic_irq != -1)
354106159Sjulian			error = vioapic_assert_irq(sc->vm,
355106159Sjulian			    isa_irq->ioapic_irq);
356106159Sjulian		break;
357106159Sjulian	case VM_ISA_DEASSERT_IRQ:
358106159Sjulian		isa_irq = (struct vm_isa_irq *)data;
359147256Sbrooks		error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq);
360106159Sjulian		if (error == 0 && isa_irq->ioapic_irq != -1)
361152031Sru			error = vioapic_deassert_irq(sc->vm,
362152031Sru			    isa_irq->ioapic_irq);
363152031Sru		break;
364152031Sru	case VM_ISA_PULSE_IRQ:
365152031Sru		isa_irq = (struct vm_isa_irq *)data;
366152031Sru		error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq);
367152031Sru		if (error == 0 && isa_irq->ioapic_irq != -1)
368106159Sjulian			error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq);
369106159Sjulian		break;
370106159Sjulian	case VM_ISA_SET_IRQ_TRIGGER:
371106159Sjulian		isa_irq_trigger = (struct vm_isa_irq_trigger *)data;
372106159Sjulian		error = vatpic_set_irq_trigger(sc->vm,
373106159Sjulian		    isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger);
374106159Sjulian		break;
375106159Sjulian	case VM_MAP_MEMORY:
376106159Sjulian		seg = (struct vm_memory_segment *)data;
377106159Sjulian		error = vm_malloc(sc->vm, seg->gpa, seg->len);
378106159Sjulian		break;
379106159Sjulian	case VM_GET_MEMORY_SEG:
380106159Sjulian		seg = (struct vm_memory_segment *)data;
381106159Sjulian		seg->len = 0;
382106159Sjulian		(void)vm_gpabase2memseg(sc->vm, seg->gpa, seg);
383106159Sjulian		error = 0;
384106159Sjulian		break;
385106159Sjulian	case VM_GET_REGISTER:
386106159Sjulian		vmreg = (struct vm_register *)data;
387106159Sjulian		error = vm_get_register(sc->vm, vmreg->cpuid, vmreg->regnum,
388106159Sjulian					&vmreg->regval);
389106159Sjulian		break;
390106159Sjulian	case VM_SET_REGISTER:
391106159Sjulian		vmreg = (struct vm_register *)data;
392130815Swpaul		error = vm_set_register(sc->vm, vmreg->cpuid, vmreg->regnum,
393130815Swpaul					vmreg->regval);
394130815Swpaul		break;
395130815Swpaul	case VM_SET_SEGMENT_DESCRIPTOR:
396130815Swpaul		vmsegdesc = (struct vm_seg_desc *)data;
397130815Swpaul		error = vm_set_seg_desc(sc->vm, vmsegdesc->cpuid,
398130815Swpaul					vmsegdesc->regnum,
399130815Swpaul					&vmsegdesc->desc);
400130815Swpaul		break;
401130815Swpaul	case VM_GET_SEGMENT_DESCRIPTOR:
402130815Swpaul		vmsegdesc = (struct vm_seg_desc *)data;
403130815Swpaul		error = vm_get_seg_desc(sc->vm, vmsegdesc->cpuid,
404130815Swpaul					vmsegdesc->regnum,
405130815Swpaul					&vmsegdesc->desc);
406106159Sjulian		break;
407184214Sdes	case VM_GET_CAPABILITY:
408106159Sjulian		vmcap = (struct vm_capability *)data;
409106159Sjulian		error = vm_get_capability(sc->vm, vmcap->cpuid,
410106159Sjulian					  vmcap->captype,
411130808Swpaul					  &vmcap->capval);
412152243Sru		break;
413130808Swpaul	case VM_SET_CAPABILITY:
414130808Swpaul		vmcap = (struct vm_capability *)data;
415106159Sjulian		error = vm_set_capability(sc->vm, vmcap->cpuid,
416106159Sjulian					  vmcap->captype,
417106159Sjulian					  vmcap->capval);
418106159Sjulian		break;
419106159Sjulian	case VM_SET_X2APIC_STATE:
420152032Sru		x2apic = (struct vm_x2apic *)data;
421152315Sru		error = vm_set_x2apic_state(sc->vm,
422106159Sjulian					    x2apic->cpuid, x2apic->state);
423106159Sjulian		break;
424106159Sjulian	case VM_GET_X2APIC_STATE:
425106159Sjulian		x2apic = (struct vm_x2apic *)data;
426106159Sjulian		error = vm_get_x2apic_state(sc->vm,
427169677Sdwmalone					    x2apic->cpuid, &x2apic->state);
428169677Sdwmalone		break;
429169677Sdwmalone	case VM_GET_GPA_PMAP:
430106159Sjulian		gpapte = (struct vm_gpa_pte *)data;
431152315Sru		pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)),
432106159Sjulian				 gpapte->gpa, gpapte->pte, &gpapte->ptenum);
433106159Sjulian		error = 0;
434106159Sjulian		break;
435152315Sru	case VM_GET_HPET_CAPABILITIES:
436202588Sthompsa		error = vhpet_getcap((struct vm_hpet_cap *)data);
437106159Sjulian		break;
438111565Swpaul	case VM_GLA2GPA: {
439111565Swpaul		CTASSERT(PROT_READ == VM_PROT_READ);
440111565Swpaul		CTASSERT(PROT_WRITE == VM_PROT_WRITE);
441111565Swpaul		CTASSERT(PROT_EXEC == VM_PROT_EXECUTE);
442111565Swpaul		gg = (struct vm_gla2gpa *)data;
443111565Swpaul		error = vm_gla2gpa(sc->vm, gg->vcpuid, &gg->paging, gg->gla,
444130815Swpaul		    gg->prot, &gg->gpa);
445130815Swpaul		KASSERT(error == 0 || error == 1 || error == -1,
446130815Swpaul		    ("%s: vm_gla2gpa unknown error %d", __func__, error));
447130815Swpaul		if (error >= 0) {
448106159Sjulian			/*
449106159Sjulian			 * error = 0: the translation was successful
450152031Sru			 * error = 1: a fault was injected into the guest
451106159Sjulian			 */
452106159Sjulian			gg->fault = error;
453169677Sdwmalone			error = 0;
454169677Sdwmalone		} else {
455169677Sdwmalone			error = EFAULT;
456106159Sjulian		}
457106159Sjulian		break;
458106159Sjulian	}
459106159Sjulian	case VM_ACTIVATE_CPU:
460106159Sjulian		vac = (struct vm_activate_cpu *)data;
461106159Sjulian		error = vm_activate_cpu(sc->vm, vac->vcpuid);
462106159Sjulian		break;
463106159Sjulian	case VM_GET_CPUS:
464106159Sjulian		error = 0;
465106159Sjulian		vm_cpuset = (struct vm_cpuset *)data;
466106159Sjulian		size = vm_cpuset->cpusetsize;
467106159Sjulian		if (size < sizeof(cpuset_t) || size > CPU_MAXSIZE / NBBY) {
468106159Sjulian			error = ERANGE;
469106159Sjulian			break;
470147256Sbrooks		}
471106159Sjulian		cpuset = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
472152031Sru		if (vm_cpuset->which == VM_ACTIVE_CPUS)
473152031Sru			*cpuset = vm_active_cpus(sc->vm);
474152031Sru		else if (vm_cpuset->which == VM_SUSPENDED_CPUS)
475152031Sru			*cpuset = vm_suspended_cpus(sc->vm);
476152031Sru		else
477152031Sru			error = EINVAL;
478152031Sru		if (error == 0)
479106159Sjulian			error = copyout(cpuset, vm_cpuset->cpus, size);
480106159Sjulian		free(cpuset, M_TEMP);
481106159Sjulian		break;
482106159Sjulian	case VM_SET_INTINFO:
483106159Sjulian		vmii = (struct vm_intinfo *)data;
484106159Sjulian		error = vm_exit_intinfo(sc->vm, vmii->vcpuid, vmii->info1);
485106159Sjulian		break;
486106159Sjulian	case VM_GET_INTINFO:
487106159Sjulian		vmii = (struct vm_intinfo *)data;
488106159Sjulian		error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1,
489106159Sjulian		    &vmii->info2);
490106159Sjulian		break;
491106159Sjulian	case VM_RTC_WRITE:
492106159Sjulian		rtcdata = (struct vm_rtc_data *)data;
493106159Sjulian		error = vrtc_nvram_write(sc->vm, rtcdata->offset,
494106159Sjulian		    rtcdata->value);
495106159Sjulian		break;
496106159Sjulian	case VM_RTC_READ:
497106159Sjulian		rtcdata = (struct vm_rtc_data *)data;
498106159Sjulian		error = vrtc_nvram_read(sc->vm, rtcdata->offset,
499106159Sjulian		    &rtcdata->value);
500106159Sjulian		break;
501106159Sjulian	case VM_RTC_SETTIME:
502106159Sjulian		rtctime = (struct vm_rtc_time *)data;
503152032Sru		error = vrtc_set_time(sc->vm, rtctime->secs);
504106159Sjulian		break;
505111565Swpaul	case VM_RTC_GETTIME:
506111565Swpaul		error = 0;
507111565Swpaul		rtctime = (struct vm_rtc_time *)data;
508130808Swpaul		rtctime->secs = vrtc_get_time(sc->vm);
509130808Swpaul		break;
510152243Sru	case VM_RESTART_INSTRUCTION:
511130808Swpaul		error = vm_restart_instruction(sc->vm, vcpu);
512130808Swpaul		break;
513106159Sjulian	default:
514106159Sjulian		error = ENOTTY;
515184205Sdes		break;
516106159Sjulian	}
517106159Sjulian
518130815Swpaul	if (state_changed == 1) {
519130815Swpaul		vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
520130815Swpaul	} else if (state_changed == 2) {
521106159Sjulian		for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++)
522106159Sjulian			vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false);
523106159Sjulian	}
524169677Sdwmalone
525169677Sdwmalonedone:
526169677Sdwmalone	/* Make sure that no handler returns a bogus value like ERESTART */
527169677Sdwmalone	KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error));
528169677Sdwmalone	return (error);
529169677Sdwmalone}
530169677Sdwmalone
531169677Sdwmalonestatic int
532169677Sdwmalonevmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset,
533169677Sdwmalone		   vm_size_t size, struct vm_object **object, int nprot)
534169677Sdwmalone{
535169677Sdwmalone	int error;
536169677Sdwmalone	struct vmmdev_softc *sc;
537169677Sdwmalone
538169677Sdwmalone	sc = vmmdev_lookup2(cdev);
539169677Sdwmalone	if (sc != NULL && (nprot & PROT_EXEC) == 0)
540169677Sdwmalone		error = vm_get_memobj(sc->vm, *offset, size, offset, object);
541169677Sdwmalone	else
542169677Sdwmalone		error = EINVAL;
543169677Sdwmalone
544169677Sdwmalone	return (error);
545169677Sdwmalone}
546169677Sdwmalone
547169677Sdwmalonestatic void
548169677Sdwmalonevmmdev_destroy(void *arg)
549169677Sdwmalone{
550169677Sdwmalone
551169677Sdwmalone	struct vmmdev_softc *sc = arg;
552169677Sdwmalone
553169677Sdwmalone	if (sc->cdev != NULL)
554169677Sdwmalone		destroy_dev(sc->cdev);
555169677Sdwmalone
556169677Sdwmalone	if (sc->vm != NULL)
557169677Sdwmalone		vm_destroy(sc->vm);
558169677Sdwmalone
559169677Sdwmalone	if ((sc->flags & VSC_LINKED) != 0) {
560169677Sdwmalone		mtx_lock(&vmmdev_mtx);
561169677Sdwmalone		SLIST_REMOVE(&head, sc, vmmdev_softc, link);
562169677Sdwmalone		mtx_unlock(&vmmdev_mtx);
563169677Sdwmalone	}
564169677Sdwmalone
565169677Sdwmalone	free(sc, M_VMMDEV);
566169677Sdwmalone}
567169677Sdwmalone
568169677Sdwmalonestatic int
569169677Sdwmalonesysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
570169677Sdwmalone{
571169677Sdwmalone	int error;
572169677Sdwmalone	char buf[VM_MAX_NAMELEN];
573169677Sdwmalone	struct vmmdev_softc *sc;
574169677Sdwmalone	struct cdev *cdev;
575169677Sdwmalone
576169677Sdwmalone	strlcpy(buf, "beavis", sizeof(buf));
577169677Sdwmalone	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
578169677Sdwmalone	if (error != 0 || req->newptr == NULL)
579169677Sdwmalone		return (error);
580169677Sdwmalone
581169677Sdwmalone	mtx_lock(&vmmdev_mtx);
582169677Sdwmalone	sc = vmmdev_lookup(buf);
583169677Sdwmalone	if (sc == NULL || sc->cdev == NULL) {
584169677Sdwmalone		mtx_unlock(&vmmdev_mtx);
585106159Sjulian		return (EINVAL);
586106159Sjulian	}
587169677Sdwmalone
588106159Sjulian	/*
589106159Sjulian	 * The 'cdev' will be destroyed asynchronously when 'si_threadcount'
590106159Sjulian	 * goes down to 0 so we should not do it again in the callback.
591106159Sjulian	 */
592106159Sjulian	cdev = sc->cdev;
593106159Sjulian	sc->cdev = NULL;
594106159Sjulian	mtx_unlock(&vmmdev_mtx);
595106159Sjulian
596106159Sjulian	/*
597106159Sjulian	 * Schedule the 'cdev' to be destroyed:
598106159Sjulian	 *
599106159Sjulian	 * - any new operations on this 'cdev' will return an error (ENXIO).
600106159Sjulian	 *
601106159Sjulian	 * - when the 'si_threadcount' dwindles down to zero the 'cdev' will
602106159Sjulian	 *   be destroyed and the callback will be invoked in a taskqueue
603106159Sjulian	 *   context.
604106159Sjulian	 */
605106159Sjulian	destroy_dev_sched_cb(cdev, vmmdev_destroy, sc);
606106159Sjulian
607106159Sjulian	return (0);
608106159Sjulian}
609106159SjulianSYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW,
610106159Sjulian	    NULL, 0, sysctl_vmm_destroy, "A", NULL);
611106159Sjulian
612106159Sjulianstatic struct cdevsw vmmdevsw = {
613106159Sjulian	.d_name		= "vmmdev",
614106159Sjulian	.d_version	= D_VERSION,
615106159Sjulian	.d_ioctl	= vmmdev_ioctl,
616106159Sjulian	.d_mmap_single	= vmmdev_mmap_single,
617106159Sjulian	.d_read		= vmmdev_rw,
618149462Semax	.d_write	= vmmdev_rw,
619149462Semax};
620106159Sjulian
621106159Sjulianstatic int
622152031Srusysctl_vmm_create(SYSCTL_HANDLER_ARGS)
623106159Sjulian{
624106159Sjulian	int error;
625106159Sjulian	struct vm *vm;
626106159Sjulian	struct cdev *cdev;
627106159Sjulian	struct vmmdev_softc *sc, *sc2;
628106159Sjulian	char buf[VM_MAX_NAMELEN];
629106159Sjulian
630106159Sjulian	strlcpy(buf, "beavis", sizeof(buf));
631106159Sjulian	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
632106159Sjulian	if (error != 0 || req->newptr == NULL)
633106159Sjulian		return (error);
634106159Sjulian
635106159Sjulian	mtx_lock(&vmmdev_mtx);
636106159Sjulian	sc = vmmdev_lookup(buf);
637106159Sjulian	mtx_unlock(&vmmdev_mtx);
638106159Sjulian	if (sc != NULL)
639152030Sru		return (EEXIST);
640152030Sru
641152030Sru	error = vm_create(buf, &vm);
642106159Sjulian	if (error != 0)
643106159Sjulian		return (error);
644106159Sjulian
645106159Sjulian	sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
646106159Sjulian	sc->vm = vm;
647106159Sjulian
648106159Sjulian	/*
649106159Sjulian	 * Lookup the name again just in case somebody sneaked in when we
650106159Sjulian	 * dropped the lock.
651106159Sjulian	 */
652106159Sjulian	mtx_lock(&vmmdev_mtx);
653106159Sjulian	sc2 = vmmdev_lookup(buf);
654106159Sjulian	if (sc2 == NULL) {
655106159Sjulian		SLIST_INSERT_HEAD(&head, sc, link);
656106159Sjulian		sc->flags |= VSC_LINKED;
657106159Sjulian	}
658106159Sjulian	mtx_unlock(&vmmdev_mtx);
659106159Sjulian
660106159Sjulian	if (sc2 != NULL) {
661106159Sjulian		vmmdev_destroy(sc);
662106159Sjulian		return (EEXIST);
663106159Sjulian	}
664106159Sjulian
665106159Sjulian	error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmdevsw, NULL,
666152030Sru			   UID_ROOT, GID_WHEEL, 0600, "vmm/%s", buf);
667152030Sru	if (error != 0) {
668106159Sjulian		vmmdev_destroy(sc);
669106159Sjulian		return (error);
670106159Sjulian	}
671106159Sjulian
672106159Sjulian	mtx_lock(&vmmdev_mtx);
673106159Sjulian	sc->cdev = cdev;
674106159Sjulian	sc->cdev->si_drv1 = sc;
675106159Sjulian	mtx_unlock(&vmmdev_mtx);
676106159Sjulian
677106159Sjulian	return (0);
678106159Sjulian}
679106159SjulianSYSCTL_PROC(_hw_vmm, OID_AUTO, create, CTLTYPE_STRING | CTLFLAG_RW,
680106159Sjulian	    NULL, 0, sysctl_vmm_create, "A", NULL);
681106159Sjulian
682106159Sjulianvoid
683106159Sjulianvmmdev_init(void)
684106159Sjulian{
685106159Sjulian	mtx_init(&vmmdev_mtx, "vmm device mutex", NULL, MTX_DEF);
686106159Sjulian}
687106159Sjulian
688106159Sjulianint
689106159Sjulianvmmdev_cleanup(void)
690121816Sbrooks{
691106159Sjulian	int error;
692106159Sjulian
693106159Sjulian	if (SLIST_EMPTY(&head))
694130815Swpaul		error = 0;
695106159Sjulian	else
696106159Sjulian		error = EBUSY;
697106159Sjulian
698106159Sjulian	return (error);
699121816Sbrooks}
700106159Sjulian