vmmapi.c revision 268972
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 268972 2014-07-22 03:14:37Z jhb $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 268972 2014-07-22 03:14:37Z jhb $");
31
32#include <sys/types.h>
33#include <sys/sysctl.h>
34#include <sys/ioctl.h>
35#include <sys/mman.h>
36
37#include <machine/specialreg.h>
38
39#include <stdio.h>
40#include <stdlib.h>
41#include <assert.h>
42#include <string.h>
43#include <fcntl.h>
44#include <unistd.h>
45
46#include <libutil.h>
47
48#include <machine/vmm.h>
49#include <machine/vmm_dev.h>
50
51#include "vmmapi.h"
52
53#define	MB	(1024 * 1024UL)
54#define	GB	(1024 * 1024 * 1024UL)
55
56struct vmctx {
57	int	fd;
58	uint32_t lowmem_limit;
59	enum vm_mmap_style vms;
60	int	memflags;
61	size_t	lowmem;
62	char	*lowmem_addr;
63	size_t	highmem;
64	char	*highmem_addr;
65	char	*name;
66};
67
68#define	CREATE(x)  sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x)))
69#define	DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x)))
70
71static int
72vm_device_open(const char *name)
73{
74        int fd, len;
75        char *vmfile;
76
77	len = strlen("/dev/vmm/") + strlen(name) + 1;
78	vmfile = malloc(len);
79	assert(vmfile != NULL);
80	snprintf(vmfile, len, "/dev/vmm/%s", name);
81
82        /* Open the device file */
83        fd = open(vmfile, O_RDWR, 0);
84
85	free(vmfile);
86        return (fd);
87}
88
89int
90vm_create(const char *name)
91{
92
93	return (CREATE((char *)name));
94}
95
96struct vmctx *
97vm_open(const char *name)
98{
99	struct vmctx *vm;
100
101	vm = malloc(sizeof(struct vmctx) + strlen(name) + 1);
102	assert(vm != NULL);
103
104	vm->fd = -1;
105	vm->memflags = 0;
106	vm->lowmem_limit = 3 * GB;
107	vm->name = (char *)(vm + 1);
108	strcpy(vm->name, name);
109
110	if ((vm->fd = vm_device_open(vm->name)) < 0)
111		goto err;
112
113	return (vm);
114err:
115	vm_destroy(vm);
116	return (NULL);
117}
118
119void
120vm_destroy(struct vmctx *vm)
121{
122	assert(vm != NULL);
123
124	if (vm->fd >= 0)
125		close(vm->fd);
126	DESTROY(vm->name);
127
128	free(vm);
129}
130
131int
132vm_parse_memsize(const char *optarg, size_t *ret_memsize)
133{
134	char *endptr;
135	size_t optval;
136	int error;
137
138	optval = strtoul(optarg, &endptr, 0);
139	if (*optarg != '\0' && *endptr == '\0') {
140		/*
141		 * For the sake of backward compatibility if the memory size
142		 * specified on the command line is less than a megabyte then
143		 * it is interpreted as being in units of MB.
144		 */
145		if (optval < MB)
146			optval *= MB;
147		*ret_memsize = optval;
148		error = 0;
149	} else
150		error = expand_number(optarg, ret_memsize);
151
152	return (error);
153}
154
155int
156vm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa, size_t *ret_len,
157		  int *wired)
158{
159	int error;
160	struct vm_memory_segment seg;
161
162	bzero(&seg, sizeof(seg));
163	seg.gpa = gpa;
164	error = ioctl(ctx->fd, VM_GET_MEMORY_SEG, &seg);
165	*ret_len = seg.len;
166	if (wired != NULL)
167		*wired = seg.wired;
168	return (error);
169}
170
171uint32_t
172vm_get_lowmem_limit(struct vmctx *ctx)
173{
174
175	return (ctx->lowmem_limit);
176}
177
178void
179vm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit)
180{
181
182	ctx->lowmem_limit = limit;
183}
184
185void
186vm_set_memflags(struct vmctx *ctx, int flags)
187{
188
189	ctx->memflags = flags;
190}
191
192static int
193setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char **addr)
194{
195	int error, mmap_flags;
196	struct vm_memory_segment seg;
197
198	/*
199	 * Create and optionally map 'len' bytes of memory at guest
200	 * physical address 'gpa'
201	 */
202	bzero(&seg, sizeof(seg));
203	seg.gpa = gpa;
204	seg.len = len;
205	error = ioctl(ctx->fd, VM_MAP_MEMORY, &seg);
206	if (error == 0 && addr != NULL) {
207		mmap_flags = MAP_SHARED;
208		if ((ctx->memflags & VM_MEM_F_INCORE) == 0)
209			mmap_flags |= MAP_NOCORE;
210		*addr = mmap(NULL, len, PROT_READ | PROT_WRITE, mmap_flags,
211		    ctx->fd, gpa);
212	}
213	return (error);
214}
215
216int
217vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
218{
219	char **addr;
220	int error;
221
222	/* XXX VM_MMAP_SPARSE not implemented yet */
223	assert(vms == VM_MMAP_NONE || vms == VM_MMAP_ALL);
224	ctx->vms = vms;
225
226	/*
227	 * If 'memsize' cannot fit entirely in the 'lowmem' segment then
228	 * create another 'highmem' segment above 4GB for the remainder.
229	 */
230	if (memsize > ctx->lowmem_limit) {
231		ctx->lowmem = ctx->lowmem_limit;
232		ctx->highmem = memsize - ctx->lowmem;
233	} else {
234		ctx->lowmem = memsize;
235		ctx->highmem = 0;
236	}
237
238	if (ctx->lowmem > 0) {
239		addr = (vms == VM_MMAP_ALL) ? &ctx->lowmem_addr : NULL;
240		error = setup_memory_segment(ctx, 0, ctx->lowmem, addr);
241		if (error)
242			return (error);
243	}
244
245	if (ctx->highmem > 0) {
246		addr = (vms == VM_MMAP_ALL) ? &ctx->highmem_addr : NULL;
247		error = setup_memory_segment(ctx, 4*GB, ctx->highmem, addr);
248		if (error)
249			return (error);
250	}
251
252	return (0);
253}
254
255void *
256vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len)
257{
258
259	/* XXX VM_MMAP_SPARSE not implemented yet */
260	assert(ctx->vms == VM_MMAP_ALL);
261
262	if (gaddr < ctx->lowmem && gaddr + len <= ctx->lowmem)
263		return ((void *)(ctx->lowmem_addr + gaddr));
264
265	if (gaddr >= 4*GB) {
266		gaddr -= 4*GB;
267		if (gaddr < ctx->highmem && gaddr + len <= ctx->highmem)
268			return ((void *)(ctx->highmem_addr + gaddr));
269	}
270
271	return (NULL);
272}
273
274int
275vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
276	    uint64_t base, uint32_t limit, uint32_t access)
277{
278	int error;
279	struct vm_seg_desc vmsegdesc;
280
281	bzero(&vmsegdesc, sizeof(vmsegdesc));
282	vmsegdesc.cpuid = vcpu;
283	vmsegdesc.regnum = reg;
284	vmsegdesc.desc.base = base;
285	vmsegdesc.desc.limit = limit;
286	vmsegdesc.desc.access = access;
287
288	error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc);
289	return (error);
290}
291
292int
293vm_get_desc(struct vmctx *ctx, int vcpu, int reg,
294	    uint64_t *base, uint32_t *limit, uint32_t *access)
295{
296	int error;
297	struct vm_seg_desc vmsegdesc;
298
299	bzero(&vmsegdesc, sizeof(vmsegdesc));
300	vmsegdesc.cpuid = vcpu;
301	vmsegdesc.regnum = reg;
302
303	error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc);
304	if (error == 0) {
305		*base = vmsegdesc.desc.base;
306		*limit = vmsegdesc.desc.limit;
307		*access = vmsegdesc.desc.access;
308	}
309	return (error);
310}
311
312int
313vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val)
314{
315	int error;
316	struct vm_register vmreg;
317
318	bzero(&vmreg, sizeof(vmreg));
319	vmreg.cpuid = vcpu;
320	vmreg.regnum = reg;
321	vmreg.regval = val;
322
323	error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg);
324	return (error);
325}
326
327int
328vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val)
329{
330	int error;
331	struct vm_register vmreg;
332
333	bzero(&vmreg, sizeof(vmreg));
334	vmreg.cpuid = vcpu;
335	vmreg.regnum = reg;
336
337	error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg);
338	*ret_val = vmreg.regval;
339	return (error);
340}
341
342int
343vm_run(struct vmctx *ctx, int vcpu, uint64_t rip, struct vm_exit *vmexit)
344{
345	int error;
346	struct vm_run vmrun;
347
348	bzero(&vmrun, sizeof(vmrun));
349	vmrun.cpuid = vcpu;
350	vmrun.rip = rip;
351
352	error = ioctl(ctx->fd, VM_RUN, &vmrun);
353	bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit));
354	return (error);
355}
356
357int
358vm_suspend(struct vmctx *ctx, enum vm_suspend_how how)
359{
360	struct vm_suspend vmsuspend;
361
362	bzero(&vmsuspend, sizeof(vmsuspend));
363	vmsuspend.how = how;
364	return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend));
365}
366
367static int
368vm_inject_exception_real(struct vmctx *ctx, int vcpu, int vector,
369    int error_code, int error_code_valid)
370{
371	struct vm_exception exc;
372
373	bzero(&exc, sizeof(exc));
374	exc.cpuid = vcpu;
375	exc.vector = vector;
376	exc.error_code = error_code;
377	exc.error_code_valid = error_code_valid;
378
379	return (ioctl(ctx->fd, VM_INJECT_EXCEPTION, &exc));
380}
381
382int
383vm_inject_exception(struct vmctx *ctx, int vcpu, int vector)
384{
385
386	return (vm_inject_exception_real(ctx, vcpu, vector, 0, 0));
387}
388
389int
390vm_inject_exception2(struct vmctx *ctx, int vcpu, int vector, int errcode)
391{
392
393	return (vm_inject_exception_real(ctx, vcpu, vector, errcode, 1));
394}
395
396int
397vm_apicid2vcpu(struct vmctx *ctx, int apicid)
398{
399	/*
400	 * The apic id associated with the 'vcpu' has the same numerical value
401	 * as the 'vcpu' itself.
402	 */
403	return (apicid);
404}
405
406int
407vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector)
408{
409	struct vm_lapic_irq vmirq;
410
411	bzero(&vmirq, sizeof(vmirq));
412	vmirq.cpuid = vcpu;
413	vmirq.vector = vector;
414
415	return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq));
416}
417
418int
419vm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector)
420{
421	struct vm_lapic_irq vmirq;
422
423	bzero(&vmirq, sizeof(vmirq));
424	vmirq.cpuid = vcpu;
425	vmirq.vector = vector;
426
427	return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq));
428}
429
430int
431vm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg)
432{
433	struct vm_lapic_msi vmmsi;
434
435	bzero(&vmmsi, sizeof(vmmsi));
436	vmmsi.addr = addr;
437	vmmsi.msg = msg;
438
439	return (ioctl(ctx->fd, VM_LAPIC_MSI, &vmmsi));
440}
441
442int
443vm_ioapic_assert_irq(struct vmctx *ctx, int irq)
444{
445	struct vm_ioapic_irq ioapic_irq;
446
447	bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq));
448	ioapic_irq.irq = irq;
449
450	return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq));
451}
452
453int
454vm_ioapic_deassert_irq(struct vmctx *ctx, int irq)
455{
456	struct vm_ioapic_irq ioapic_irq;
457
458	bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq));
459	ioapic_irq.irq = irq;
460
461	return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq));
462}
463
464int
465vm_ioapic_pulse_irq(struct vmctx *ctx, int irq)
466{
467	struct vm_ioapic_irq ioapic_irq;
468
469	bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq));
470	ioapic_irq.irq = irq;
471
472	return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq));
473}
474
475int
476vm_ioapic_pincount(struct vmctx *ctx, int *pincount)
477{
478
479	return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount));
480}
481
482int
483vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
484{
485	struct vm_isa_irq isa_irq;
486
487	bzero(&isa_irq, sizeof(struct vm_isa_irq));
488	isa_irq.atpic_irq = atpic_irq;
489	isa_irq.ioapic_irq = ioapic_irq;
490
491	return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq));
492}
493
494int
495vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
496{
497	struct vm_isa_irq isa_irq;
498
499	bzero(&isa_irq, sizeof(struct vm_isa_irq));
500	isa_irq.atpic_irq = atpic_irq;
501	isa_irq.ioapic_irq = ioapic_irq;
502
503	return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq));
504}
505
506int
507vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
508{
509	struct vm_isa_irq isa_irq;
510
511	bzero(&isa_irq, sizeof(struct vm_isa_irq));
512	isa_irq.atpic_irq = atpic_irq;
513	isa_irq.ioapic_irq = ioapic_irq;
514
515	return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq));
516}
517
518int
519vm_isa_set_irq_trigger(struct vmctx *ctx, int atpic_irq,
520    enum vm_intr_trigger trigger)
521{
522	struct vm_isa_irq_trigger isa_irq_trigger;
523
524	bzero(&isa_irq_trigger, sizeof(struct vm_isa_irq_trigger));
525	isa_irq_trigger.atpic_irq = atpic_irq;
526	isa_irq_trigger.trigger = trigger;
527
528	return (ioctl(ctx->fd, VM_ISA_SET_IRQ_TRIGGER, &isa_irq_trigger));
529}
530
531int
532vm_inject_nmi(struct vmctx *ctx, int vcpu)
533{
534	struct vm_nmi vmnmi;
535
536	bzero(&vmnmi, sizeof(vmnmi));
537	vmnmi.cpuid = vcpu;
538
539	return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi));
540}
541
542static struct {
543	const char	*name;
544	int		type;
545} capstrmap[] = {
546	{ "hlt_exit",		VM_CAP_HALT_EXIT },
547	{ "mtrap_exit",		VM_CAP_MTRAP_EXIT },
548	{ "pause_exit",		VM_CAP_PAUSE_EXIT },
549	{ "unrestricted_guest",	VM_CAP_UNRESTRICTED_GUEST },
550	{ "enable_invpcid",	VM_CAP_ENABLE_INVPCID },
551	{ 0 }
552};
553
554int
555vm_capability_name2type(const char *capname)
556{
557	int i;
558
559	for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) {
560		if (strcmp(capstrmap[i].name, capname) == 0)
561			return (capstrmap[i].type);
562	}
563
564	return (-1);
565}
566
567const char *
568vm_capability_type2name(int type)
569{
570	int i;
571
572	for (i = 0; capstrmap[i].name != NULL; i++) {
573		if (capstrmap[i].type == type)
574			return (capstrmap[i].name);
575	}
576
577	return (NULL);
578}
579
580int
581vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap,
582		  int *retval)
583{
584	int error;
585	struct vm_capability vmcap;
586
587	bzero(&vmcap, sizeof(vmcap));
588	vmcap.cpuid = vcpu;
589	vmcap.captype = cap;
590
591	error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap);
592	*retval = vmcap.capval;
593	return (error);
594}
595
596int
597vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val)
598{
599	struct vm_capability vmcap;
600
601	bzero(&vmcap, sizeof(vmcap));
602	vmcap.cpuid = vcpu;
603	vmcap.captype = cap;
604	vmcap.capval = val;
605
606	return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap));
607}
608
609int
610vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
611{
612	struct vm_pptdev pptdev;
613
614	bzero(&pptdev, sizeof(pptdev));
615	pptdev.bus = bus;
616	pptdev.slot = slot;
617	pptdev.func = func;
618
619	return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev));
620}
621
622int
623vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
624{
625	struct vm_pptdev pptdev;
626
627	bzero(&pptdev, sizeof(pptdev));
628	pptdev.bus = bus;
629	pptdev.slot = slot;
630	pptdev.func = func;
631
632	return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev));
633}
634
635int
636vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
637		   vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
638{
639	struct vm_pptdev_mmio pptmmio;
640
641	bzero(&pptmmio, sizeof(pptmmio));
642	pptmmio.bus = bus;
643	pptmmio.slot = slot;
644	pptmmio.func = func;
645	pptmmio.gpa = gpa;
646	pptmmio.len = len;
647	pptmmio.hpa = hpa;
648
649	return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio));
650}
651
652int
653vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
654    uint64_t addr, uint64_t msg, int numvec)
655{
656	struct vm_pptdev_msi pptmsi;
657
658	bzero(&pptmsi, sizeof(pptmsi));
659	pptmsi.vcpu = vcpu;
660	pptmsi.bus = bus;
661	pptmsi.slot = slot;
662	pptmsi.func = func;
663	pptmsi.msg = msg;
664	pptmsi.addr = addr;
665	pptmsi.numvec = numvec;
666
667	return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi));
668}
669
670int
671vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
672    int idx, uint64_t addr, uint64_t msg, uint32_t vector_control)
673{
674	struct vm_pptdev_msix pptmsix;
675
676	bzero(&pptmsix, sizeof(pptmsix));
677	pptmsix.vcpu = vcpu;
678	pptmsix.bus = bus;
679	pptmsix.slot = slot;
680	pptmsix.func = func;
681	pptmsix.idx = idx;
682	pptmsix.msg = msg;
683	pptmsix.addr = addr;
684	pptmsix.vector_control = vector_control;
685
686	return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix);
687}
688
689uint64_t *
690vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
691	     int *ret_entries)
692{
693	int error;
694
695	static struct vm_stats vmstats;
696
697	vmstats.cpuid = vcpu;
698
699	error = ioctl(ctx->fd, VM_STATS, &vmstats);
700	if (error == 0) {
701		if (ret_entries)
702			*ret_entries = vmstats.num_entries;
703		if (ret_tv)
704			*ret_tv = vmstats.tv;
705		return (vmstats.statbuf);
706	} else
707		return (NULL);
708}
709
710const char *
711vm_get_stat_desc(struct vmctx *ctx, int index)
712{
713	static struct vm_stat_desc statdesc;
714
715	statdesc.index = index;
716	if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0)
717		return (statdesc.desc);
718	else
719		return (NULL);
720}
721
722int
723vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state)
724{
725	int error;
726	struct vm_x2apic x2apic;
727
728	bzero(&x2apic, sizeof(x2apic));
729	x2apic.cpuid = vcpu;
730
731	error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic);
732	*state = x2apic.state;
733	return (error);
734}
735
736int
737vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state)
738{
739	int error;
740	struct vm_x2apic x2apic;
741
742	bzero(&x2apic, sizeof(x2apic));
743	x2apic.cpuid = vcpu;
744	x2apic.state = state;
745
746	error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic);
747
748	return (error);
749}
750
751/*
752 * From Intel Vol 3a:
753 * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT
754 */
755int
756vcpu_reset(struct vmctx *vmctx, int vcpu)
757{
758	int error;
759	uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx;
760	uint32_t desc_access, desc_limit;
761	uint16_t sel;
762
763	zero = 0;
764
765	rflags = 0x2;
766	error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
767	if (error)
768		goto done;
769
770	rip = 0xfff0;
771	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
772		goto done;
773
774	cr0 = CR0_NE;
775	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
776		goto done;
777
778	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0)
779		goto done;
780
781	cr4 = 0;
782	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
783		goto done;
784
785	/*
786	 * CS: present, r/w, accessed, 16-bit, byte granularity, usable
787	 */
788	desc_base = 0xffff0000;
789	desc_limit = 0xffff;
790	desc_access = 0x0093;
791	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
792			    desc_base, desc_limit, desc_access);
793	if (error)
794		goto done;
795
796	sel = 0xf000;
797	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0)
798		goto done;
799
800	/*
801	 * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity
802	 */
803	desc_base = 0;
804	desc_limit = 0xffff;
805	desc_access = 0x0093;
806	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
807			    desc_base, desc_limit, desc_access);
808	if (error)
809		goto done;
810
811	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
812			    desc_base, desc_limit, desc_access);
813	if (error)
814		goto done;
815
816	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
817			    desc_base, desc_limit, desc_access);
818	if (error)
819		goto done;
820
821	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
822			    desc_base, desc_limit, desc_access);
823	if (error)
824		goto done;
825
826	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
827			    desc_base, desc_limit, desc_access);
828	if (error)
829		goto done;
830
831	sel = 0;
832	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0)
833		goto done;
834	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0)
835		goto done;
836	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0)
837		goto done;
838	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0)
839		goto done;
840	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0)
841		goto done;
842
843	/* General purpose registers */
844	rdx = 0xf00;
845	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0)
846		goto done;
847	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0)
848		goto done;
849	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0)
850		goto done;
851	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0)
852		goto done;
853	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0)
854		goto done;
855	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0)
856		goto done;
857	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0)
858		goto done;
859	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0)
860		goto done;
861
862	/* GDTR, IDTR */
863	desc_base = 0;
864	desc_limit = 0xffff;
865	desc_access = 0;
866	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
867			    desc_base, desc_limit, desc_access);
868	if (error != 0)
869		goto done;
870
871	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR,
872			    desc_base, desc_limit, desc_access);
873	if (error != 0)
874		goto done;
875
876	/* TR */
877	desc_base = 0;
878	desc_limit = 0xffff;
879	desc_access = 0x0000008b;
880	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
881	if (error)
882		goto done;
883
884	sel = 0;
885	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0)
886		goto done;
887
888	/* LDTR */
889	desc_base = 0;
890	desc_limit = 0xffff;
891	desc_access = 0x00000082;
892	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base,
893			    desc_limit, desc_access);
894	if (error)
895		goto done;
896
897	sel = 0;
898	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
899		goto done;
900
901	/* XXX cr2, debug registers */
902
903	error = 0;
904done:
905	return (error);
906}
907
908int
909vm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num)
910{
911	int error, i;
912	struct vm_gpa_pte gpapte;
913
914	bzero(&gpapte, sizeof(gpapte));
915	gpapte.gpa = gpa;
916
917	error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte);
918
919	if (error == 0) {
920		*num = gpapte.ptenum;
921		for (i = 0; i < gpapte.ptenum; i++)
922			pte[i] = gpapte.pte[i];
923	}
924
925	return (error);
926}
927
928int
929vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities)
930{
931	int error;
932	struct vm_hpet_cap cap;
933
934	bzero(&cap, sizeof(struct vm_hpet_cap));
935	error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap);
936	if (capabilities != NULL)
937		*capabilities = cap.capabilities;
938	return (error);
939}
940