Deleted Added
full compact
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 268935 2014-07-21 02:39:17Z jhb $
26 * $FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 268953 2014-07-21 19:08:02Z jhb $
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 268935 2014-07-21 02:39:17Z jhb $");
30__FBSDID("$FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 268953 2014-07-21 19:08:02Z 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{
186 int error;
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) {
198 *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
199 ctx->fd, gpa);
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 bzero(&isa_irq, sizeof(struct vm_isa_irq));
511 isa_irq.atpic_irq = atpic_irq;
512 isa_irq.ioapic_irq = ioapic_irq;
513
514 return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq));
515}
516
517int
518vm_inject_nmi(struct vmctx *ctx, int vcpu)
519{
520 struct vm_nmi vmnmi;
521
522 bzero(&vmnmi, sizeof(vmnmi));
523 vmnmi.cpuid = vcpu;
524
525 return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi));
526}
527
528static struct {
529 const char *name;
530 int type;
531} capstrmap[] = {
532 { "hlt_exit", VM_CAP_HALT_EXIT },
533 { "mtrap_exit", VM_CAP_MTRAP_EXIT },
534 { "pause_exit", VM_CAP_PAUSE_EXIT },
535 { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST },
536 { "enable_invpcid", VM_CAP_ENABLE_INVPCID },
537 { 0 }
538};
539
540int
541vm_capability_name2type(const char *capname)
542{
543 int i;
544
545 for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) {
546 if (strcmp(capstrmap[i].name, capname) == 0)
547 return (capstrmap[i].type);
548 }
549
550 return (-1);
551}
552
553const char *
554vm_capability_type2name(int type)
555{
556 int i;
557
558 for (i = 0; capstrmap[i].name != NULL; i++) {
559 if (capstrmap[i].type == type)
560 return (capstrmap[i].name);
561 }
562
563 return (NULL);
564}
565
566int
567vm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap,
568 int *retval)
569{
570 int error;
571 struct vm_capability vmcap;
572
573 bzero(&vmcap, sizeof(vmcap));
574 vmcap.cpuid = vcpu;
575 vmcap.captype = cap;
576
577 error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap);
578 *retval = vmcap.capval;
579 return (error);
580}
581
582int
583vm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val)
584{
585 struct vm_capability vmcap;
586
587 bzero(&vmcap, sizeof(vmcap));
588 vmcap.cpuid = vcpu;
589 vmcap.captype = cap;
590 vmcap.capval = val;
591
592 return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap));
593}
594
595int
596vm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
597{
598 struct vm_pptdev pptdev;
599
600 bzero(&pptdev, sizeof(pptdev));
601 pptdev.bus = bus;
602 pptdev.slot = slot;
603 pptdev.func = func;
604
605 return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev));
606}
607
608int
609vm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func)
610{
611 struct vm_pptdev pptdev;
612
613 bzero(&pptdev, sizeof(pptdev));
614 pptdev.bus = bus;
615 pptdev.slot = slot;
616 pptdev.func = func;
617
618 return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev));
619}
620
621int
622vm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
623 vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
624{
625 struct vm_pptdev_mmio pptmmio;
626
627 bzero(&pptmmio, sizeof(pptmmio));
628 pptmmio.bus = bus;
629 pptmmio.slot = slot;
630 pptmmio.func = func;
631 pptmmio.gpa = gpa;
632 pptmmio.len = len;
633 pptmmio.hpa = hpa;
634
635 return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio));
636}
637
638int
639vm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
640 uint64_t addr, uint64_t msg, int numvec)
641{
642 struct vm_pptdev_msi pptmsi;
643
644 bzero(&pptmsi, sizeof(pptmsi));
645 pptmsi.vcpu = vcpu;
646 pptmsi.bus = bus;
647 pptmsi.slot = slot;
648 pptmsi.func = func;
649 pptmsi.msg = msg;
650 pptmsi.addr = addr;
651 pptmsi.numvec = numvec;
652
653 return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi));
654}
655
656int
657vm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func,
658 int idx, uint64_t addr, uint64_t msg, uint32_t vector_control)
659{
660 struct vm_pptdev_msix pptmsix;
661
662 bzero(&pptmsix, sizeof(pptmsix));
663 pptmsix.vcpu = vcpu;
664 pptmsix.bus = bus;
665 pptmsix.slot = slot;
666 pptmsix.func = func;
667 pptmsix.idx = idx;
668 pptmsix.msg = msg;
669 pptmsix.addr = addr;
670 pptmsix.vector_control = vector_control;
671
672 return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix);
673}
674
675uint64_t *
676vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
677 int *ret_entries)
678{
679 int error;
680
681 static struct vm_stats vmstats;
682
683 vmstats.cpuid = vcpu;
684
685 error = ioctl(ctx->fd, VM_STATS, &vmstats);
686 if (error == 0) {
687 if (ret_entries)
688 *ret_entries = vmstats.num_entries;
689 if (ret_tv)
690 *ret_tv = vmstats.tv;
691 return (vmstats.statbuf);
692 } else
693 return (NULL);
694}
695
696const char *
697vm_get_stat_desc(struct vmctx *ctx, int index)
698{
699 static struct vm_stat_desc statdesc;
700
701 statdesc.index = index;
702 if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0)
703 return (statdesc.desc);
704 else
705 return (NULL);
706}
707
708int
709vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state)
710{
711 int error;
712 struct vm_x2apic x2apic;
713
714 bzero(&x2apic, sizeof(x2apic));
715 x2apic.cpuid = vcpu;
716
717 error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic);
718 *state = x2apic.state;
719 return (error);
720}
721
722int
723vm_set_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 x2apic.state = state;
731
732 error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic);
733
734 return (error);
735}
736
737/*
738 * From Intel Vol 3a:
739 * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT
740 */
741int
742vcpu_reset(struct vmctx *vmctx, int vcpu)
743{
744 int error;
745 uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx;
746 uint32_t desc_access, desc_limit;
747 uint16_t sel;
748
749 zero = 0;
750
751 rflags = 0x2;
752 error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
753 if (error)
754 goto done;
755
756 rip = 0xfff0;
757 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
758 goto done;
759
760 cr0 = CR0_NE;
761 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
762 goto done;
763
764 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0)
765 goto done;
766
767 cr4 = 0;
768 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
769 goto done;
770
771 /*
772 * CS: present, r/w, accessed, 16-bit, byte granularity, usable
773 */
774 desc_base = 0xffff0000;
775 desc_limit = 0xffff;
776 desc_access = 0x0093;
777 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
778 desc_base, desc_limit, desc_access);
779 if (error)
780 goto done;
781
782 sel = 0xf000;
783 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0)
784 goto done;
785
786 /*
787 * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity
788 */
789 desc_base = 0;
790 desc_limit = 0xffff;
791 desc_access = 0x0093;
792 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
793 desc_base, desc_limit, desc_access);
794 if (error)
795 goto done;
796
797 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
798 desc_base, desc_limit, desc_access);
799 if (error)
800 goto done;
801
802 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
803 desc_base, desc_limit, desc_access);
804 if (error)
805 goto done;
806
807 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
808 desc_base, desc_limit, desc_access);
809 if (error)
810 goto done;
811
812 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
813 desc_base, desc_limit, desc_access);
814 if (error)
815 goto done;
816
817 sel = 0;
818 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0)
819 goto done;
820 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0)
821 goto done;
822 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0)
823 goto done;
824 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0)
825 goto done;
826 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0)
827 goto done;
828
829 /* General purpose registers */
830 rdx = 0xf00;
831 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0)
832 goto done;
833 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0)
834 goto done;
835 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0)
836 goto done;
837 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0)
838 goto done;
839 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0)
840 goto done;
841 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0)
842 goto done;
843 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0)
844 goto done;
845 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0)
846 goto done;
847
848 /* GDTR, IDTR */
849 desc_base = 0;
850 desc_limit = 0xffff;
851 desc_access = 0;
852 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
853 desc_base, desc_limit, desc_access);
854 if (error != 0)
855 goto done;
856
857 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR,
858 desc_base, desc_limit, desc_access);
859 if (error != 0)
860 goto done;
861
862 /* TR */
863 desc_base = 0;
864 desc_limit = 0xffff;
865 desc_access = 0x0000008b;
866 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
867 if (error)
868 goto done;
869
870 sel = 0;
871 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0)
872 goto done;
873
874 /* LDTR */
875 desc_base = 0;
876 desc_limit = 0xffff;
877 desc_access = 0x00000082;
878 error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base,
879 desc_limit, desc_access);
880 if (error)
881 goto done;
882
883 sel = 0;
884 if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
885 goto done;
886
887 /* XXX cr2, debug registers */
888
889 error = 0;
890done:
891 return (error);
892}
893
894int
895vm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num)
896{
897 int error, i;
898 struct vm_gpa_pte gpapte;
899
900 bzero(&gpapte, sizeof(gpapte));
901 gpapte.gpa = gpa;
902
903 error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte);
904
905 if (error == 0) {
906 *num = gpapte.ptenum;
907 for (i = 0; i < gpapte.ptenum; i++)
908 pte[i] = gpapte.pte[i];
909 }
910
911 return (error);
912}
913
914int
915vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities)
916{
917 int error;
918 struct vm_hpet_cap cap;
919
920 bzero(&cap, sizeof(struct vm_hpet_cap));
921 error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap);
922 if (capabilities != NULL)
923 *capabilities = cap.capabilities;
924 return (error);
925}