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