xref: /freebsd/sys/amd64/vmm/vmm_dev_machdep.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2011 NetApp, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "opt_bhyve_snapshot.h"
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/conf.h>
34 #include <sys/libkern.h>
35 #include <sys/ioccom.h>
36 #include <sys/mman.h>
37 #include <sys/uio.h>
38 #include <sys/proc.h>
39 
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42 #include <vm/vm_map.h>
43 
44 #include <machine/vmparam.h>
45 #include <machine/vmm.h>
46 #include <machine/vmm_instruction_emul.h>
47 #include <machine/vmm_snapshot.h>
48 #include <x86/apicreg.h>
49 
50 #include <dev/vmm/vmm_dev.h>
51 #include <dev/vmm/vmm_stat.h>
52 
53 #include "vmm_lapic.h"
54 #include "vmm_mem.h"
55 #include "io/ppt.h"
56 #include "io/vatpic.h"
57 #include "io/vioapic.h"
58 #include "io/vhpet.h"
59 #include "io/vrtc.h"
60 
61 #ifdef COMPAT_FREEBSD13
62 struct vm_stats_13 {
63 	int		cpuid;				/* in */
64 	int		num_entries;			/* out */
65 	struct timeval	tv;
66 	uint64_t	statbuf[MAX_VM_STATS];
67 };
68 
69 #define	VM_STATS_13	_IOWR('v', IOCNUM_VM_STATS, struct vm_stats_13)
70 
71 struct vm_snapshot_meta_13 {
72 	void *ctx;			/* unused */
73 	void *dev_data;
74 	const char *dev_name;      /* identify userspace devices */
75 	enum snapshot_req dev_req; /* identify kernel structs */
76 
77 	struct vm_snapshot_buffer buffer;
78 
79 	enum vm_snapshot_op op;
80 };
81 
82 #define VM_SNAPSHOT_REQ_13 \
83 	_IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta_13)
84 
85 struct vm_exit_ipi_13 {
86 	uint32_t	mode;
87 	uint8_t		vector;
88 	__BITSET_DEFINE(, 256) dmask;
89 };
90 
91 struct vm_exit_13 {
92 	uint32_t	exitcode;
93 	int32_t		inst_length;
94 	uint64_t	rip;
95 	uint64_t	u[120 / sizeof(uint64_t)];
96 };
97 
98 struct vm_run_13 {
99 	int		cpuid;
100 	struct vm_exit_13 vm_exit;
101 };
102 
103 #define	VM_RUN_13 \
104 	_IOWR('v', IOCNUM_RUN, struct vm_run_13)
105 
106 #endif /* COMPAT_FREEBSD13 */
107 
108 const struct vmmdev_ioctl vmmdev_machdep_ioctls[] = {
109 	VMMDEV_IOCTL(VM_RUN, VMMDEV_IOCTL_LOCK_ONE_VCPU),
110 #ifdef COMPAT_FREEBSD13
111 	VMMDEV_IOCTL(VM_RUN_13, VMMDEV_IOCTL_LOCK_ONE_VCPU),
112 #endif
113 	VMMDEV_IOCTL(VM_GET_SEGMENT_DESCRIPTOR, VMMDEV_IOCTL_LOCK_ONE_VCPU),
114 	VMMDEV_IOCTL(VM_SET_SEGMENT_DESCRIPTOR, VMMDEV_IOCTL_LOCK_ONE_VCPU),
115 	VMMDEV_IOCTL(VM_INJECT_EXCEPTION, VMMDEV_IOCTL_LOCK_ONE_VCPU),
116 	VMMDEV_IOCTL(VM_SET_X2APIC_STATE, VMMDEV_IOCTL_LOCK_ONE_VCPU),
117 	VMMDEV_IOCTL(VM_GLA2GPA, VMMDEV_IOCTL_LOCK_ONE_VCPU),
118 	VMMDEV_IOCTL(VM_GLA2GPA_NOFAULT, VMMDEV_IOCTL_LOCK_ONE_VCPU),
119 	VMMDEV_IOCTL(VM_SET_INTINFO, VMMDEV_IOCTL_LOCK_ONE_VCPU),
120 	VMMDEV_IOCTL(VM_GET_INTINFO, VMMDEV_IOCTL_LOCK_ONE_VCPU),
121 	VMMDEV_IOCTL(VM_RESTART_INSTRUCTION, VMMDEV_IOCTL_LOCK_ONE_VCPU),
122 	VMMDEV_IOCTL(VM_GET_KERNEMU_DEV, VMMDEV_IOCTL_LOCK_ONE_VCPU),
123 	VMMDEV_IOCTL(VM_SET_KERNEMU_DEV, VMMDEV_IOCTL_LOCK_ONE_VCPU),
124 
125 	VMMDEV_IOCTL(VM_BIND_PPTDEV,
126 	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
127 	VMMDEV_IOCTL(VM_UNBIND_PPTDEV,
128 	    VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
129 
130 	VMMDEV_IOCTL(VM_MAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS),
131 	VMMDEV_IOCTL(VM_UNMAP_PPTDEV_MMIO, VMMDEV_IOCTL_LOCK_ALL_VCPUS),
132 #ifdef BHYVE_SNAPSHOT
133 #ifdef COMPAT_FREEBSD13
134 	VMMDEV_IOCTL(VM_SNAPSHOT_REQ_13, VMMDEV_IOCTL_LOCK_ALL_VCPUS),
135 #endif
136 	VMMDEV_IOCTL(VM_SNAPSHOT_REQ, VMMDEV_IOCTL_LOCK_ALL_VCPUS),
137 	VMMDEV_IOCTL(VM_RESTORE_TIME, VMMDEV_IOCTL_LOCK_ALL_VCPUS),
138 #endif
139 
140 #ifdef COMPAT_FREEBSD13
141 	VMMDEV_IOCTL(VM_STATS_13, VMMDEV_IOCTL_LOCK_ONE_VCPU),
142 #endif
143 	VMMDEV_IOCTL(VM_INJECT_NMI, VMMDEV_IOCTL_LOCK_ONE_VCPU),
144 	VMMDEV_IOCTL(VM_LAPIC_IRQ, VMMDEV_IOCTL_LOCK_ONE_VCPU),
145 	VMMDEV_IOCTL(VM_GET_X2APIC_STATE, VMMDEV_IOCTL_LOCK_ONE_VCPU),
146 
147 	VMMDEV_IOCTL(VM_LAPIC_LOCAL_IRQ, VMMDEV_IOCTL_MAYBE_ALLOC_VCPU),
148 
149 	VMMDEV_IOCTL(VM_PPTDEV_MSI, 0),
150 	VMMDEV_IOCTL(VM_PPTDEV_MSIX, 0),
151 	VMMDEV_IOCTL(VM_PPTDEV_DISABLE_MSIX, 0),
152 	VMMDEV_IOCTL(VM_LAPIC_MSI, 0),
153 	VMMDEV_IOCTL(VM_IOAPIC_ASSERT_IRQ, 0),
154 	VMMDEV_IOCTL(VM_IOAPIC_DEASSERT_IRQ, 0),
155 	VMMDEV_IOCTL(VM_IOAPIC_PULSE_IRQ, 0),
156 	VMMDEV_IOCTL(VM_IOAPIC_PINCOUNT, 0),
157 	VMMDEV_IOCTL(VM_ISA_ASSERT_IRQ, 0),
158 	VMMDEV_IOCTL(VM_ISA_DEASSERT_IRQ, 0),
159 	VMMDEV_IOCTL(VM_ISA_PULSE_IRQ, 0),
160 	VMMDEV_IOCTL(VM_ISA_SET_IRQ_TRIGGER, 0),
161 	VMMDEV_IOCTL(VM_GET_GPA_PMAP, 0),
162 	VMMDEV_IOCTL(VM_GET_HPET_CAPABILITIES, 0),
163 	VMMDEV_IOCTL(VM_RTC_READ, 0),
164 	VMMDEV_IOCTL(VM_RTC_WRITE, 0),
165 	VMMDEV_IOCTL(VM_RTC_GETTIME, 0),
166 	VMMDEV_IOCTL(VM_RTC_SETTIME, 0),
167 };
168 const size_t vmmdev_machdep_ioctl_count = nitems(vmmdev_machdep_ioctls);
169 
170 int
171 vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd, caddr_t data,
172     int fflag, struct thread *td)
173 {
174 	struct vm_seg_desc *vmsegdesc;
175 	struct vm_run *vmrun;
176 #ifdef COMPAT_FREEBSD13
177 	struct vm_run_13 *vmrun_13;
178 #endif
179 	struct vm_exception *vmexc;
180 	struct vm_lapic_irq *vmirq;
181 	struct vm_lapic_msi *vmmsi;
182 	struct vm_ioapic_irq *ioapic_irq;
183 	struct vm_isa_irq *isa_irq;
184 	struct vm_isa_irq_trigger *isa_irq_trigger;
185 	struct vm_pptdev *pptdev;
186 	struct vm_pptdev_mmio *pptmmio;
187 	struct vm_pptdev_msi *pptmsi;
188 	struct vm_pptdev_msix *pptmsix;
189 	struct vm_x2apic *x2apic;
190 	struct vm_gpa_pte *gpapte;
191 	struct vm_gla2gpa *gg;
192 	struct vm_intinfo *vmii;
193 	struct vm_rtc_time *rtctime;
194 	struct vm_rtc_data *rtcdata;
195 	struct vm_readwrite_kernemu_device *kernemu;
196 #ifdef BHYVE_SNAPSHOT
197 	struct vm_snapshot_meta *snapshot_meta;
198 #ifdef COMPAT_FREEBSD13
199 	struct vm_snapshot_meta_13 *snapshot_13;
200 #endif
201 #endif
202 	int error;
203 
204 	error = 0;
205 	switch (cmd) {
206 	case VM_RUN: {
207 		struct vm_exit *vme;
208 
209 		vmrun = (struct vm_run *)data;
210 		vme = vm_exitinfo(vcpu);
211 
212 		error = vm_run(vcpu);
213 		if (error != 0)
214 			break;
215 
216 		error = copyout(vme, vmrun->vm_exit, sizeof(*vme));
217 		if (error != 0)
218 			break;
219 		if (vme->exitcode == VM_EXITCODE_IPI) {
220 			error = copyout(vm_exitinfo_cpuset(vcpu),
221 			    vmrun->cpuset,
222 			    min(vmrun->cpusetsize, sizeof(cpuset_t)));
223 			if (error != 0)
224 				break;
225 			if (sizeof(cpuset_t) < vmrun->cpusetsize) {
226 				uint8_t *p;
227 
228 				p = (uint8_t *)vmrun->cpuset +
229 				    sizeof(cpuset_t);
230 				while (p < (uint8_t *)vmrun->cpuset +
231 				    vmrun->cpusetsize) {
232 					if (subyte(p++, 0) != 0) {
233 						error = EFAULT;
234 						break;
235 					}
236 				}
237 			}
238 		}
239 		break;
240 	}
241 #ifdef COMPAT_FREEBSD13
242 	case VM_RUN_13: {
243 		struct vm_exit *vme;
244 		struct vm_exit_13 *vme_13;
245 
246 		vmrun_13 = (struct vm_run_13 *)data;
247 		vme_13 = &vmrun_13->vm_exit;
248 		vme = vm_exitinfo(vcpu);
249 
250 		error = vm_run(vcpu);
251 		if (error == 0) {
252 			vme_13->exitcode = vme->exitcode;
253 			vme_13->inst_length = vme->inst_length;
254 			vme_13->rip = vme->rip;
255 			memcpy(vme_13->u, &vme->u, sizeof(vme_13->u));
256 			if (vme->exitcode == VM_EXITCODE_IPI) {
257 				struct vm_exit_ipi_13 *ipi;
258 				cpuset_t *dmask;
259 				int cpu;
260 
261 				dmask = vm_exitinfo_cpuset(vcpu);
262 				ipi = (struct vm_exit_ipi_13 *)&vme_13->u[0];
263 				BIT_ZERO(256, &ipi->dmask);
264 				CPU_FOREACH_ISSET(cpu, dmask) {
265 					if (cpu >= 256)
266 						break;
267 					BIT_SET(256, cpu, &ipi->dmask);
268 				}
269 			}
270 		}
271 		break;
272 	}
273 	case VM_STATS_13: {
274 		struct vm_stats_13 *vmstats_13;
275 
276 		vmstats_13 = (struct vm_stats_13 *)data;
277 		getmicrotime(&vmstats_13->tv);
278 		error = vmm_stat_copy(vcpu, 0, nitems(vmstats_13->statbuf),
279 		    &vmstats_13->num_entries, vmstats_13->statbuf);
280 		break;
281 	}
282 #endif
283 	case VM_PPTDEV_MSI:
284 		pptmsi = (struct vm_pptdev_msi *)data;
285 		error = ppt_setup_msi(vm,
286 				      pptmsi->bus, pptmsi->slot, pptmsi->func,
287 				      pptmsi->addr, pptmsi->msg,
288 				      pptmsi->numvec);
289 		break;
290 	case VM_PPTDEV_MSIX:
291 		pptmsix = (struct vm_pptdev_msix *)data;
292 		error = ppt_setup_msix(vm,
293 				       pptmsix->bus, pptmsix->slot,
294 				       pptmsix->func, pptmsix->idx,
295 				       pptmsix->addr, pptmsix->msg,
296 				       pptmsix->vector_control);
297 		break;
298 	case VM_PPTDEV_DISABLE_MSIX:
299 		pptdev = (struct vm_pptdev *)data;
300 		error = ppt_disable_msix(vm, pptdev->bus, pptdev->slot,
301 					 pptdev->func);
302 		break;
303 	case VM_MAP_PPTDEV_MMIO:
304 		pptmmio = (struct vm_pptdev_mmio *)data;
305 		error = ppt_map_mmio(vm, pptmmio->bus, pptmmio->slot,
306 				     pptmmio->func, pptmmio->gpa, pptmmio->len,
307 				     pptmmio->hpa);
308 		break;
309 	case VM_UNMAP_PPTDEV_MMIO:
310 		pptmmio = (struct vm_pptdev_mmio *)data;
311 		error = ppt_unmap_mmio(vm, pptmmio->bus, pptmmio->slot,
312 				       pptmmio->func, pptmmio->gpa, pptmmio->len);
313 		break;
314 	case VM_BIND_PPTDEV:
315 		pptdev = (struct vm_pptdev *)data;
316 		error = vm_assign_pptdev(vm, pptdev->bus, pptdev->slot,
317 					 pptdev->func);
318 		break;
319 	case VM_UNBIND_PPTDEV:
320 		pptdev = (struct vm_pptdev *)data;
321 		error = vm_unassign_pptdev(vm, pptdev->bus, pptdev->slot,
322 					   pptdev->func);
323 		break;
324 	case VM_INJECT_EXCEPTION:
325 		vmexc = (struct vm_exception *)data;
326 		error = vm_inject_exception(vcpu,
327 		    vmexc->vector, vmexc->error_code_valid, vmexc->error_code,
328 		    vmexc->restart_instruction);
329 		break;
330 	case VM_INJECT_NMI:
331 		error = vm_inject_nmi(vcpu);
332 		break;
333 	case VM_LAPIC_IRQ:
334 		vmirq = (struct vm_lapic_irq *)data;
335 		error = lapic_intr_edge(vcpu, vmirq->vector);
336 		break;
337 	case VM_LAPIC_LOCAL_IRQ:
338 		vmirq = (struct vm_lapic_irq *)data;
339 		error = lapic_set_local_intr(vm, vcpu, vmirq->vector);
340 		break;
341 	case VM_LAPIC_MSI:
342 		vmmsi = (struct vm_lapic_msi *)data;
343 		error = lapic_intr_msi(vm, vmmsi->addr, vmmsi->msg);
344 		break;
345 	case VM_IOAPIC_ASSERT_IRQ:
346 		ioapic_irq = (struct vm_ioapic_irq *)data;
347 		error = vioapic_assert_irq(vm, ioapic_irq->irq);
348 		break;
349 	case VM_IOAPIC_DEASSERT_IRQ:
350 		ioapic_irq = (struct vm_ioapic_irq *)data;
351 		error = vioapic_deassert_irq(vm, ioapic_irq->irq);
352 		break;
353 	case VM_IOAPIC_PULSE_IRQ:
354 		ioapic_irq = (struct vm_ioapic_irq *)data;
355 		error = vioapic_pulse_irq(vm, ioapic_irq->irq);
356 		break;
357 	case VM_IOAPIC_PINCOUNT:
358 		*(int *)data = vioapic_pincount(vm);
359 		break;
360 	case VM_SET_KERNEMU_DEV:
361 	case VM_GET_KERNEMU_DEV: {
362 		mem_region_write_t mwrite;
363 		mem_region_read_t mread;
364 		int size;
365 		bool arg;
366 
367 		kernemu = (void *)data;
368 
369 		if (kernemu->access_width > 0)
370 			size = (1u << kernemu->access_width);
371 		else
372 			size = 1;
373 
374 		if (kernemu->gpa >= DEFAULT_APIC_BASE &&
375 		    kernemu->gpa < DEFAULT_APIC_BASE + PAGE_SIZE) {
376 			mread = lapic_mmio_read;
377 			mwrite = lapic_mmio_write;
378 		} else if (kernemu->gpa >= VIOAPIC_BASE &&
379 		    kernemu->gpa < VIOAPIC_BASE + VIOAPIC_SIZE) {
380 			mread = vioapic_mmio_read;
381 			mwrite = vioapic_mmio_write;
382 		} else if (kernemu->gpa >= VHPET_BASE &&
383 		    kernemu->gpa < VHPET_BASE + VHPET_SIZE) {
384 			mread = vhpet_mmio_read;
385 			mwrite = vhpet_mmio_write;
386 		} else {
387 			error = EINVAL;
388 			break;
389 		}
390 
391 		if (cmd == VM_SET_KERNEMU_DEV)
392 			error = mwrite(vcpu, kernemu->gpa,
393 			    kernemu->value, size, &arg);
394 		else
395 			error = mread(vcpu, kernemu->gpa,
396 			    &kernemu->value, size, &arg);
397 		break;
398 		}
399 	case VM_ISA_ASSERT_IRQ:
400 		isa_irq = (struct vm_isa_irq *)data;
401 		error = vatpic_assert_irq(vm, isa_irq->atpic_irq);
402 		if (error == 0 && isa_irq->ioapic_irq != -1)
403 			error = vioapic_assert_irq(vm, isa_irq->ioapic_irq);
404 		break;
405 	case VM_ISA_DEASSERT_IRQ:
406 		isa_irq = (struct vm_isa_irq *)data;
407 		error = vatpic_deassert_irq(vm, isa_irq->atpic_irq);
408 		if (error == 0 && isa_irq->ioapic_irq != -1)
409 			error = vioapic_deassert_irq(vm, isa_irq->ioapic_irq);
410 		break;
411 	case VM_ISA_PULSE_IRQ:
412 		isa_irq = (struct vm_isa_irq *)data;
413 		error = vatpic_pulse_irq(vm, isa_irq->atpic_irq);
414 		if (error == 0 && isa_irq->ioapic_irq != -1)
415 			error = vioapic_pulse_irq(vm, isa_irq->ioapic_irq);
416 		break;
417 	case VM_ISA_SET_IRQ_TRIGGER:
418 		isa_irq_trigger = (struct vm_isa_irq_trigger *)data;
419 		error = vatpic_set_irq_trigger(vm,
420 		    isa_irq_trigger->atpic_irq, isa_irq_trigger->trigger);
421 		break;
422 	case VM_SET_SEGMENT_DESCRIPTOR:
423 		vmsegdesc = (struct vm_seg_desc *)data;
424 		error = vm_set_seg_desc(vcpu,
425 					vmsegdesc->regnum,
426 					&vmsegdesc->desc);
427 		break;
428 	case VM_GET_SEGMENT_DESCRIPTOR:
429 		vmsegdesc = (struct vm_seg_desc *)data;
430 		error = vm_get_seg_desc(vcpu,
431 					vmsegdesc->regnum,
432 					&vmsegdesc->desc);
433 		break;
434 	case VM_SET_X2APIC_STATE:
435 		x2apic = (struct vm_x2apic *)data;
436 		error = vm_set_x2apic_state(vcpu, x2apic->state);
437 		break;
438 	case VM_GET_X2APIC_STATE:
439 		x2apic = (struct vm_x2apic *)data;
440 		error = vm_get_x2apic_state(vcpu, &x2apic->state);
441 		break;
442 	case VM_GET_GPA_PMAP:
443 		gpapte = (struct vm_gpa_pte *)data;
444 		pmap_get_mapping(vmspace_pmap(vm_get_vmspace(vm)),
445 				 gpapte->gpa, gpapte->pte, &gpapte->ptenum);
446 		error = 0;
447 		break;
448 	case VM_GET_HPET_CAPABILITIES:
449 		error = vhpet_getcap((struct vm_hpet_cap *)data);
450 		break;
451 	case VM_GLA2GPA: {
452 		CTASSERT(PROT_READ == VM_PROT_READ);
453 		CTASSERT(PROT_WRITE == VM_PROT_WRITE);
454 		CTASSERT(PROT_EXEC == VM_PROT_EXECUTE);
455 		gg = (struct vm_gla2gpa *)data;
456 		error = vm_gla2gpa(vcpu, &gg->paging, gg->gla,
457 		    gg->prot, &gg->gpa, &gg->fault);
458 		KASSERT(error == 0 || error == EFAULT,
459 		    ("%s: vm_gla2gpa unknown error %d", __func__, error));
460 		break;
461 	}
462 	case VM_GLA2GPA_NOFAULT:
463 		gg = (struct vm_gla2gpa *)data;
464 		error = vm_gla2gpa_nofault(vcpu, &gg->paging, gg->gla,
465 		    gg->prot, &gg->gpa, &gg->fault);
466 		KASSERT(error == 0 || error == EFAULT,
467 		    ("%s: vm_gla2gpa unknown error %d", __func__, error));
468 		break;
469 	case VM_SET_INTINFO:
470 		vmii = (struct vm_intinfo *)data;
471 		error = vm_exit_intinfo(vcpu, vmii->info1);
472 		break;
473 	case VM_GET_INTINFO:
474 		vmii = (struct vm_intinfo *)data;
475 		error = vm_get_intinfo(vcpu, &vmii->info1, &vmii->info2);
476 		break;
477 	case VM_RTC_WRITE:
478 		rtcdata = (struct vm_rtc_data *)data;
479 		error = vrtc_nvram_write(vm, rtcdata->offset,
480 		    rtcdata->value);
481 		break;
482 	case VM_RTC_READ:
483 		rtcdata = (struct vm_rtc_data *)data;
484 		error = vrtc_nvram_read(vm, rtcdata->offset,
485 		    &rtcdata->value);
486 		break;
487 	case VM_RTC_SETTIME:
488 		rtctime = (struct vm_rtc_time *)data;
489 		error = vrtc_set_time(vm, rtctime->secs);
490 		break;
491 	case VM_RTC_GETTIME:
492 		error = 0;
493 		rtctime = (struct vm_rtc_time *)data;
494 		rtctime->secs = vrtc_get_time(vm);
495 		break;
496 	case VM_RESTART_INSTRUCTION:
497 		error = vm_restart_instruction(vcpu);
498 		break;
499 #ifdef BHYVE_SNAPSHOT
500 	case VM_SNAPSHOT_REQ:
501 		snapshot_meta = (struct vm_snapshot_meta *)data;
502 		error = vm_snapshot_req(vm, snapshot_meta);
503 		break;
504 #ifdef COMPAT_FREEBSD13
505 	case VM_SNAPSHOT_REQ_13:
506 		/*
507 		 * The old structure just has an additional pointer at
508 		 * the start that is ignored.
509 		 */
510 		snapshot_13 = (struct vm_snapshot_meta_13 *)data;
511 		snapshot_meta =
512 		    (struct vm_snapshot_meta *)&snapshot_13->dev_data;
513 		error = vm_snapshot_req(vm, snapshot_meta);
514 		break;
515 #endif
516 	case VM_RESTORE_TIME:
517 		error = vm_restore_time(vm);
518 		break;
519 #endif
520 	default:
521 		error = ENOTTY;
522 		break;
523 	}
524 
525 	return (error);
526 }
527