1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26221828Sgrehan * $FreeBSD: releng/10.1/lib/libvmmapi/vmmapi.c 309636 2016-12-06 18:49:59Z glebius $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD: releng/10.1/lib/libvmmapi/vmmapi.c 309636 2016-12-06 18:49:59Z glebius $"); 31221828Sgrehan 32270070Sgrehan#include <sys/param.h> 33221828Sgrehan#include <sys/sysctl.h> 34221828Sgrehan#include <sys/ioctl.h> 35221828Sgrehan#include <sys/mman.h> 36268976Sjhb#include <sys/_iovec.h> 37270070Sgrehan#include <sys/cpuset.h> 38221828Sgrehan 39270159Sgrehan#include <x86/segments.h> 40221828Sgrehan#include <machine/specialreg.h> 41268976Sjhb#include <machine/param.h> 42221828Sgrehan 43221828Sgrehan#include <stdio.h> 44221828Sgrehan#include <stdlib.h> 45221828Sgrehan#include <assert.h> 46221828Sgrehan#include <string.h> 47221828Sgrehan#include <fcntl.h> 48221828Sgrehan#include <unistd.h> 49221828Sgrehan 50256176Sneel#include <libutil.h> 51256176Sneel 52221828Sgrehan#include <machine/vmm.h> 53221828Sgrehan#include <machine/vmm_dev.h> 54221828Sgrehan 55221828Sgrehan#include "vmmapi.h" 56221828Sgrehan 57256176Sneel#define MB (1024 * 1024UL) 58248477Sneel#define GB (1024 * 1024 * 1024UL) 59248477Sneel 60221828Sgrehanstruct vmctx { 61221828Sgrehan int fd; 62248477Sneel uint32_t lowmem_limit; 63248477Sneel enum vm_mmap_style vms; 64268953Sjhb int memflags; 65248477Sneel size_t lowmem; 66248477Sneel char *lowmem_addr; 67248477Sneel size_t highmem; 68248477Sneel char *highmem_addr; 69221828Sgrehan char *name; 70221828Sgrehan}; 71221828Sgrehan 72221828Sgrehan#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) 73221828Sgrehan#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) 74221828Sgrehan 75221828Sgrehanstatic int 76221828Sgrehanvm_device_open(const char *name) 77221828Sgrehan{ 78221828Sgrehan int fd, len; 79221828Sgrehan char *vmfile; 80221828Sgrehan 81221828Sgrehan len = strlen("/dev/vmm/") + strlen(name) + 1; 82221828Sgrehan vmfile = malloc(len); 83221828Sgrehan assert(vmfile != NULL); 84221828Sgrehan snprintf(vmfile, len, "/dev/vmm/%s", name); 85221828Sgrehan 86221828Sgrehan /* Open the device file */ 87221828Sgrehan fd = open(vmfile, O_RDWR, 0); 88221828Sgrehan 89221828Sgrehan free(vmfile); 90221828Sgrehan return (fd); 91221828Sgrehan} 92221828Sgrehan 93221828Sgrehanint 94221828Sgrehanvm_create(const char *name) 95221828Sgrehan{ 96221828Sgrehan 97221828Sgrehan return (CREATE((char *)name)); 98221828Sgrehan} 99221828Sgrehan 100221828Sgrehanstruct vmctx * 101221828Sgrehanvm_open(const char *name) 102221828Sgrehan{ 103221828Sgrehan struct vmctx *vm; 104221828Sgrehan 105221828Sgrehan vm = malloc(sizeof(struct vmctx) + strlen(name) + 1); 106221828Sgrehan assert(vm != NULL); 107221828Sgrehan 108221828Sgrehan vm->fd = -1; 109268953Sjhb vm->memflags = 0; 110248477Sneel vm->lowmem_limit = 3 * GB; 111221828Sgrehan vm->name = (char *)(vm + 1); 112221828Sgrehan strcpy(vm->name, name); 113221828Sgrehan 114221828Sgrehan if ((vm->fd = vm_device_open(vm->name)) < 0) 115221828Sgrehan goto err; 116221828Sgrehan 117221828Sgrehan return (vm); 118221828Sgrehanerr: 119221828Sgrehan vm_destroy(vm); 120221828Sgrehan return (NULL); 121221828Sgrehan} 122221828Sgrehan 123221828Sgrehanvoid 124221828Sgrehanvm_destroy(struct vmctx *vm) 125221828Sgrehan{ 126221828Sgrehan assert(vm != NULL); 127221828Sgrehan 128221828Sgrehan if (vm->fd >= 0) 129221828Sgrehan close(vm->fd); 130241178Sneel DESTROY(vm->name); 131241178Sneel 132221828Sgrehan free(vm); 133221828Sgrehan} 134221828Sgrehan 135221828Sgrehanint 136256176Sneelvm_parse_memsize(const char *optarg, size_t *ret_memsize) 137256176Sneel{ 138256176Sneel char *endptr; 139256176Sneel size_t optval; 140256176Sneel int error; 141256176Sneel 142256176Sneel optval = strtoul(optarg, &endptr, 0); 143256176Sneel if (*optarg != '\0' && *endptr == '\0') { 144256176Sneel /* 145256176Sneel * For the sake of backward compatibility if the memory size 146256176Sneel * specified on the command line is less than a megabyte then 147256176Sneel * it is interpreted as being in units of MB. 148256176Sneel */ 149256176Sneel if (optval < MB) 150256176Sneel optval *= MB; 151256176Sneel *ret_memsize = optval; 152256176Sneel error = 0; 153256176Sneel } else 154256176Sneel error = expand_number(optarg, ret_memsize); 155256176Sneel 156256176Sneel return (error); 157256176Sneel} 158256176Sneel 159256176Sneelint 160256072Sneelvm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa, size_t *ret_len, 161256072Sneel int *wired) 162221828Sgrehan{ 163221828Sgrehan int error; 164221828Sgrehan struct vm_memory_segment seg; 165221828Sgrehan 166221828Sgrehan bzero(&seg, sizeof(seg)); 167221828Sgrehan seg.gpa = gpa; 168221828Sgrehan error = ioctl(ctx->fd, VM_GET_MEMORY_SEG, &seg); 169221828Sgrehan *ret_len = seg.len; 170256072Sneel if (wired != NULL) 171256072Sneel *wired = seg.wired; 172221828Sgrehan return (error); 173221828Sgrehan} 174221828Sgrehan 175248477Sneeluint32_t 176248477Sneelvm_get_lowmem_limit(struct vmctx *ctx) 177221828Sgrehan{ 178248477Sneel 179248477Sneel return (ctx->lowmem_limit); 180248477Sneel} 181248477Sneel 182248477Sneelvoid 183248477Sneelvm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit) 184248477Sneel{ 185248477Sneel 186248477Sneel ctx->lowmem_limit = limit; 187248477Sneel} 188248477Sneel 189268953Sjhbvoid 190268953Sjhbvm_set_memflags(struct vmctx *ctx, int flags) 191268953Sjhb{ 192268953Sjhb 193268953Sjhb ctx->memflags = flags; 194268953Sjhb} 195268953Sjhb 196248477Sneelstatic int 197248477Sneelsetup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char **addr) 198248477Sneel{ 199268953Sjhb int error, mmap_flags; 200221828Sgrehan struct vm_memory_segment seg; 201221828Sgrehan 202221828Sgrehan /* 203221828Sgrehan * Create and optionally map 'len' bytes of memory at guest 204221828Sgrehan * physical address 'gpa' 205221828Sgrehan */ 206221828Sgrehan bzero(&seg, sizeof(seg)); 207221828Sgrehan seg.gpa = gpa; 208221828Sgrehan seg.len = len; 209221828Sgrehan error = ioctl(ctx->fd, VM_MAP_MEMORY, &seg); 210248477Sneel if (error == 0 && addr != NULL) { 211268953Sjhb mmap_flags = MAP_SHARED; 212268953Sjhb if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 213268953Sjhb mmap_flags |= MAP_NOCORE; 214268953Sjhb *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, mmap_flags, 215268953Sjhb ctx->fd, gpa); 216221828Sgrehan } 217221828Sgrehan return (error); 218221828Sgrehan} 219221828Sgrehan 220248477Sneelint 221248477Sneelvm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) 222221828Sgrehan{ 223248477Sneel char **addr; 224248477Sneel int error; 225221828Sgrehan 226248477Sneel /* XXX VM_MMAP_SPARSE not implemented yet */ 227248477Sneel assert(vms == VM_MMAP_NONE || vms == VM_MMAP_ALL); 228248477Sneel ctx->vms = vms; 229248477Sneel 230248477Sneel /* 231248477Sneel * If 'memsize' cannot fit entirely in the 'lowmem' segment then 232248477Sneel * create another 'highmem' segment above 4GB for the remainder. 233248477Sneel */ 234248477Sneel if (memsize > ctx->lowmem_limit) { 235248477Sneel ctx->lowmem = ctx->lowmem_limit; 236248477Sneel ctx->highmem = memsize - ctx->lowmem; 237248477Sneel } else { 238248477Sneel ctx->lowmem = memsize; 239248477Sneel ctx->highmem = 0; 240248477Sneel } 241248477Sneel 242248477Sneel if (ctx->lowmem > 0) { 243248477Sneel addr = (vms == VM_MMAP_ALL) ? &ctx->lowmem_addr : NULL; 244248477Sneel error = setup_memory_segment(ctx, 0, ctx->lowmem, addr); 245248477Sneel if (error) 246248477Sneel return (error); 247248477Sneel } 248248477Sneel 249248477Sneel if (ctx->highmem > 0) { 250248477Sneel addr = (vms == VM_MMAP_ALL) ? &ctx->highmem_addr : NULL; 251248477Sneel error = setup_memory_segment(ctx, 4*GB, ctx->highmem, addr); 252248477Sneel if (error) 253248477Sneel return (error); 254248477Sneel } 255248477Sneel 256248477Sneel return (0); 257221828Sgrehan} 258221828Sgrehan 259248477Sneelvoid * 260248477Sneelvm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) 261248477Sneel{ 262248477Sneel 263248477Sneel /* XXX VM_MMAP_SPARSE not implemented yet */ 264248477Sneel assert(ctx->vms == VM_MMAP_ALL); 265248477Sneel 266309636Sglebius if (gaddr < ctx->lowmem && len <= ctx->lowmem && 267309636Sglebius gaddr + len <= ctx->lowmem) 268248477Sneel return ((void *)(ctx->lowmem_addr + gaddr)); 269248477Sneel 270248477Sneel if (gaddr >= 4*GB) { 271248477Sneel gaddr -= 4*GB; 272309636Sglebius if (gaddr < ctx->highmem && len <= ctx->highmem && 273309636Sglebius gaddr + len <= ctx->highmem) 274248477Sneel return ((void *)(ctx->highmem_addr + gaddr)); 275248477Sneel } 276248477Sneel 277248477Sneel return (NULL); 278248477Sneel} 279248477Sneel 280270074Sgrehansize_t 281270074Sgrehanvm_get_lowmem_size(struct vmctx *ctx) 282270074Sgrehan{ 283270074Sgrehan 284270074Sgrehan return (ctx->lowmem); 285270074Sgrehan} 286270074Sgrehan 287270074Sgrehansize_t 288270074Sgrehanvm_get_highmem_size(struct vmctx *ctx) 289270074Sgrehan{ 290270074Sgrehan 291270074Sgrehan return (ctx->highmem); 292270074Sgrehan} 293270074Sgrehan 294221828Sgrehanint 295221828Sgrehanvm_set_desc(struct vmctx *ctx, int vcpu, int reg, 296221828Sgrehan uint64_t base, uint32_t limit, uint32_t access) 297221828Sgrehan{ 298221828Sgrehan int error; 299221828Sgrehan struct vm_seg_desc vmsegdesc; 300221828Sgrehan 301221828Sgrehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 302221828Sgrehan vmsegdesc.cpuid = vcpu; 303221828Sgrehan vmsegdesc.regnum = reg; 304221828Sgrehan vmsegdesc.desc.base = base; 305221828Sgrehan vmsegdesc.desc.limit = limit; 306221828Sgrehan vmsegdesc.desc.access = access; 307221828Sgrehan 308221828Sgrehan error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc); 309221828Sgrehan return (error); 310221828Sgrehan} 311221828Sgrehan 312221828Sgrehanint 313221828Sgrehanvm_get_desc(struct vmctx *ctx, int vcpu, int reg, 314221828Sgrehan uint64_t *base, uint32_t *limit, uint32_t *access) 315221828Sgrehan{ 316221828Sgrehan int error; 317221828Sgrehan struct vm_seg_desc vmsegdesc; 318221828Sgrehan 319221828Sgrehan bzero(&vmsegdesc, sizeof(vmsegdesc)); 320221828Sgrehan vmsegdesc.cpuid = vcpu; 321221828Sgrehan vmsegdesc.regnum = reg; 322221828Sgrehan 323221828Sgrehan error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc); 324221828Sgrehan if (error == 0) { 325221828Sgrehan *base = vmsegdesc.desc.base; 326221828Sgrehan *limit = vmsegdesc.desc.limit; 327221828Sgrehan *access = vmsegdesc.desc.access; 328221828Sgrehan } 329221828Sgrehan return (error); 330221828Sgrehan} 331221828Sgrehan 332221828Sgrehanint 333270159Sgrehanvm_get_seg_desc(struct vmctx *ctx, int vcpu, int reg, struct seg_desc *seg_desc) 334270159Sgrehan{ 335270159Sgrehan int error; 336270159Sgrehan 337270159Sgrehan error = vm_get_desc(ctx, vcpu, reg, &seg_desc->base, &seg_desc->limit, 338270159Sgrehan &seg_desc->access); 339270159Sgrehan return (error); 340270159Sgrehan} 341270159Sgrehan 342270159Sgrehanint 343221828Sgrehanvm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val) 344221828Sgrehan{ 345221828Sgrehan int error; 346221828Sgrehan struct vm_register vmreg; 347221828Sgrehan 348221828Sgrehan bzero(&vmreg, sizeof(vmreg)); 349221828Sgrehan vmreg.cpuid = vcpu; 350221828Sgrehan vmreg.regnum = reg; 351221828Sgrehan vmreg.regval = val; 352221828Sgrehan 353221828Sgrehan error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg); 354221828Sgrehan return (error); 355221828Sgrehan} 356221828Sgrehan 357221828Sgrehanint 358221828Sgrehanvm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val) 359221828Sgrehan{ 360221828Sgrehan int error; 361221828Sgrehan struct vm_register vmreg; 362221828Sgrehan 363221828Sgrehan bzero(&vmreg, sizeof(vmreg)); 364221828Sgrehan vmreg.cpuid = vcpu; 365221828Sgrehan vmreg.regnum = reg; 366221828Sgrehan 367221828Sgrehan error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg); 368221828Sgrehan *ret_val = vmreg.regval; 369221828Sgrehan return (error); 370221828Sgrehan} 371221828Sgrehan 372221828Sgrehanint 373221828Sgrehanvm_run(struct vmctx *ctx, int vcpu, uint64_t rip, struct vm_exit *vmexit) 374221828Sgrehan{ 375221828Sgrehan int error; 376221828Sgrehan struct vm_run vmrun; 377221828Sgrehan 378221828Sgrehan bzero(&vmrun, sizeof(vmrun)); 379221828Sgrehan vmrun.cpuid = vcpu; 380221828Sgrehan vmrun.rip = rip; 381221828Sgrehan 382221828Sgrehan error = ioctl(ctx->fd, VM_RUN, &vmrun); 383221828Sgrehan bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit)); 384221828Sgrehan return (error); 385221828Sgrehan} 386221828Sgrehan 387268935Sjhbint 388268935Sjhbvm_suspend(struct vmctx *ctx, enum vm_suspend_how how) 389268935Sjhb{ 390268935Sjhb struct vm_suspend vmsuspend; 391268935Sjhb 392268935Sjhb bzero(&vmsuspend, sizeof(vmsuspend)); 393268935Sjhb vmsuspend.how = how; 394268935Sjhb return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); 395268935Sjhb} 396268935Sjhb 397270071Sgrehanint 398270071Sgrehanvm_reinit(struct vmctx *ctx) 399270071Sgrehan{ 400270071Sgrehan 401270071Sgrehan return (ioctl(ctx->fd, VM_REINIT, 0)); 402270071Sgrehan} 403270071Sgrehan 404221828Sgrehanstatic int 405267427Sjhbvm_inject_exception_real(struct vmctx *ctx, int vcpu, int vector, 406267427Sjhb int error_code, int error_code_valid) 407221828Sgrehan{ 408267427Sjhb struct vm_exception exc; 409221828Sgrehan 410267427Sjhb bzero(&exc, sizeof(exc)); 411267427Sjhb exc.cpuid = vcpu; 412267427Sjhb exc.vector = vector; 413267427Sjhb exc.error_code = error_code; 414267427Sjhb exc.error_code_valid = error_code_valid; 415221828Sgrehan 416267427Sjhb return (ioctl(ctx->fd, VM_INJECT_EXCEPTION, &exc)); 417221828Sgrehan} 418221828Sgrehan 419221828Sgrehanint 420267427Sjhbvm_inject_exception(struct vmctx *ctx, int vcpu, int vector) 421221828Sgrehan{ 422221828Sgrehan 423267427Sjhb return (vm_inject_exception_real(ctx, vcpu, vector, 0, 0)); 424221828Sgrehan} 425221828Sgrehan 426221828Sgrehanint 427267427Sjhbvm_inject_exception2(struct vmctx *ctx, int vcpu, int vector, int errcode) 428221828Sgrehan{ 429221828Sgrehan 430267427Sjhb return (vm_inject_exception_real(ctx, vcpu, vector, errcode, 1)); 431221828Sgrehan} 432221828Sgrehan 433221828Sgrehanint 434239026Sneelvm_apicid2vcpu(struct vmctx *ctx, int apicid) 435239026Sneel{ 436239026Sneel /* 437239026Sneel * The apic id associated with the 'vcpu' has the same numerical value 438239026Sneel * as the 'vcpu' itself. 439239026Sneel */ 440239026Sneel return (apicid); 441239026Sneel} 442239026Sneel 443239026Sneelint 444221828Sgrehanvm_lapic_irq(struct vmctx *ctx, int vcpu, int vector) 445221828Sgrehan{ 446221828Sgrehan struct vm_lapic_irq vmirq; 447221828Sgrehan 448221828Sgrehan bzero(&vmirq, sizeof(vmirq)); 449221828Sgrehan vmirq.cpuid = vcpu; 450221828Sgrehan vmirq.vector = vector; 451221828Sgrehan 452221828Sgrehan return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq)); 453221828Sgrehan} 454221828Sgrehan 455221828Sgrehanint 456262350Sjhbvm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector) 457262350Sjhb{ 458262350Sjhb struct vm_lapic_irq vmirq; 459262350Sjhb 460262350Sjhb bzero(&vmirq, sizeof(vmirq)); 461262350Sjhb vmirq.cpuid = vcpu; 462262350Sjhb vmirq.vector = vector; 463262350Sjhb 464262350Sjhb return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq)); 465262350Sjhb} 466262350Sjhb 467262350Sjhbint 468262350Sjhbvm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg) 469262350Sjhb{ 470262350Sjhb struct vm_lapic_msi vmmsi; 471262350Sjhb 472262350Sjhb bzero(&vmmsi, sizeof(vmmsi)); 473262350Sjhb vmmsi.addr = addr; 474262350Sjhb vmmsi.msg = msg; 475262350Sjhb 476262350Sjhb return (ioctl(ctx->fd, VM_LAPIC_MSI, &vmmsi)); 477262350Sjhb} 478262350Sjhb 479262350Sjhbint 480261088Sjhbvm_ioapic_assert_irq(struct vmctx *ctx, int irq) 481261088Sjhb{ 482261088Sjhb struct vm_ioapic_irq ioapic_irq; 483261088Sjhb 484261088Sjhb bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 485261088Sjhb ioapic_irq.irq = irq; 486261088Sjhb 487261088Sjhb return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq)); 488261088Sjhb} 489261088Sjhb 490261088Sjhbint 491261088Sjhbvm_ioapic_deassert_irq(struct vmctx *ctx, int irq) 492261088Sjhb{ 493261088Sjhb struct vm_ioapic_irq ioapic_irq; 494261088Sjhb 495261088Sjhb bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 496261088Sjhb ioapic_irq.irq = irq; 497261088Sjhb 498261088Sjhb return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq)); 499261088Sjhb} 500261088Sjhb 501261088Sjhbint 502261088Sjhbvm_ioapic_pulse_irq(struct vmctx *ctx, int irq) 503261088Sjhb{ 504261088Sjhb struct vm_ioapic_irq ioapic_irq; 505261088Sjhb 506261088Sjhb bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 507261088Sjhb ioapic_irq.irq = irq; 508261088Sjhb 509261088Sjhb return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq)); 510261088Sjhb} 511261088Sjhb 512261088Sjhbint 513267393Sjhbvm_ioapic_pincount(struct vmctx *ctx, int *pincount) 514267393Sjhb{ 515267393Sjhb 516267393Sjhb return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount)); 517267393Sjhb} 518267393Sjhb 519267393Sjhbint 520268891Sjhbvm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 521268891Sjhb{ 522268891Sjhb struct vm_isa_irq isa_irq; 523268891Sjhb 524268891Sjhb bzero(&isa_irq, sizeof(struct vm_isa_irq)); 525268891Sjhb isa_irq.atpic_irq = atpic_irq; 526268891Sjhb isa_irq.ioapic_irq = ioapic_irq; 527268891Sjhb 528268891Sjhb return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq)); 529268891Sjhb} 530268891Sjhb 531268891Sjhbint 532268891Sjhbvm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 533268891Sjhb{ 534268891Sjhb struct vm_isa_irq isa_irq; 535268891Sjhb 536268891Sjhb bzero(&isa_irq, sizeof(struct vm_isa_irq)); 537268891Sjhb isa_irq.atpic_irq = atpic_irq; 538268891Sjhb isa_irq.ioapic_irq = ioapic_irq; 539268891Sjhb 540268891Sjhb return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq)); 541268891Sjhb} 542268891Sjhb 543268891Sjhbint 544268891Sjhbvm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 545268891Sjhb{ 546268891Sjhb struct vm_isa_irq isa_irq; 547268972Sjhb 548268891Sjhb bzero(&isa_irq, sizeof(struct vm_isa_irq)); 549268891Sjhb isa_irq.atpic_irq = atpic_irq; 550268891Sjhb isa_irq.ioapic_irq = ioapic_irq; 551268891Sjhb 552268891Sjhb return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq)); 553268891Sjhb} 554268891Sjhb 555268891Sjhbint 556268972Sjhbvm_isa_set_irq_trigger(struct vmctx *ctx, int atpic_irq, 557268972Sjhb enum vm_intr_trigger trigger) 558268972Sjhb{ 559268972Sjhb struct vm_isa_irq_trigger isa_irq_trigger; 560268972Sjhb 561268972Sjhb bzero(&isa_irq_trigger, sizeof(struct vm_isa_irq_trigger)); 562268972Sjhb isa_irq_trigger.atpic_irq = atpic_irq; 563268972Sjhb isa_irq_trigger.trigger = trigger; 564268972Sjhb 565268972Sjhb return (ioctl(ctx->fd, VM_ISA_SET_IRQ_TRIGGER, &isa_irq_trigger)); 566268972Sjhb} 567268972Sjhb 568268972Sjhbint 569221828Sgrehanvm_inject_nmi(struct vmctx *ctx, int vcpu) 570221828Sgrehan{ 571221828Sgrehan struct vm_nmi vmnmi; 572221828Sgrehan 573221828Sgrehan bzero(&vmnmi, sizeof(vmnmi)); 574221828Sgrehan vmnmi.cpuid = vcpu; 575221828Sgrehan 576221828Sgrehan return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi)); 577221828Sgrehan} 578221828Sgrehan 579241486Sneelstatic struct { 580241486Sneel const char *name; 581241486Sneel int type; 582241486Sneel} capstrmap[] = { 583241486Sneel { "hlt_exit", VM_CAP_HALT_EXIT }, 584241486Sneel { "mtrap_exit", VM_CAP_MTRAP_EXIT }, 585241486Sneel { "pause_exit", VM_CAP_PAUSE_EXIT }, 586241486Sneel { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST }, 587256869Sneel { "enable_invpcid", VM_CAP_ENABLE_INVPCID }, 588241486Sneel { 0 } 589241486Sneel}; 590241486Sneel 591221828Sgrehanint 592221828Sgrehanvm_capability_name2type(const char *capname) 593221828Sgrehan{ 594221828Sgrehan int i; 595221828Sgrehan 596221828Sgrehan for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) { 597221828Sgrehan if (strcmp(capstrmap[i].name, capname) == 0) 598221828Sgrehan return (capstrmap[i].type); 599221828Sgrehan } 600221828Sgrehan 601221828Sgrehan return (-1); 602221828Sgrehan} 603221828Sgrehan 604241486Sneelconst char * 605241486Sneelvm_capability_type2name(int type) 606241486Sneel{ 607241486Sneel int i; 608241486Sneel 609241486Sneel for (i = 0; capstrmap[i].name != NULL; i++) { 610241486Sneel if (capstrmap[i].type == type) 611241486Sneel return (capstrmap[i].name); 612241486Sneel } 613241486Sneel 614241486Sneel return (NULL); 615241486Sneel} 616241486Sneel 617221828Sgrehanint 618221828Sgrehanvm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, 619221828Sgrehan int *retval) 620221828Sgrehan{ 621221828Sgrehan int error; 622221828Sgrehan struct vm_capability vmcap; 623221828Sgrehan 624221828Sgrehan bzero(&vmcap, sizeof(vmcap)); 625221828Sgrehan vmcap.cpuid = vcpu; 626221828Sgrehan vmcap.captype = cap; 627221828Sgrehan 628221828Sgrehan error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap); 629221828Sgrehan *retval = vmcap.capval; 630221828Sgrehan return (error); 631221828Sgrehan} 632221828Sgrehan 633221828Sgrehanint 634221828Sgrehanvm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val) 635221828Sgrehan{ 636221828Sgrehan struct vm_capability vmcap; 637221828Sgrehan 638221828Sgrehan bzero(&vmcap, sizeof(vmcap)); 639221828Sgrehan vmcap.cpuid = vcpu; 640221828Sgrehan vmcap.captype = cap; 641221828Sgrehan vmcap.capval = val; 642221828Sgrehan 643221828Sgrehan return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap)); 644221828Sgrehan} 645221828Sgrehan 646221828Sgrehanint 647221828Sgrehanvm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 648221828Sgrehan{ 649221828Sgrehan struct vm_pptdev pptdev; 650221828Sgrehan 651221828Sgrehan bzero(&pptdev, sizeof(pptdev)); 652221828Sgrehan pptdev.bus = bus; 653221828Sgrehan pptdev.slot = slot; 654221828Sgrehan pptdev.func = func; 655221828Sgrehan 656221828Sgrehan return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev)); 657221828Sgrehan} 658221828Sgrehan 659221828Sgrehanint 660221828Sgrehanvm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 661221828Sgrehan{ 662221828Sgrehan struct vm_pptdev pptdev; 663221828Sgrehan 664221828Sgrehan bzero(&pptdev, sizeof(pptdev)); 665221828Sgrehan pptdev.bus = bus; 666221828Sgrehan pptdev.slot = slot; 667221828Sgrehan pptdev.func = func; 668221828Sgrehan 669221828Sgrehan return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev)); 670221828Sgrehan} 671221828Sgrehan 672221828Sgrehanint 673221828Sgrehanvm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, 674221828Sgrehan vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 675221828Sgrehan{ 676221828Sgrehan struct vm_pptdev_mmio pptmmio; 677221828Sgrehan 678221828Sgrehan bzero(&pptmmio, sizeof(pptmmio)); 679221828Sgrehan pptmmio.bus = bus; 680221828Sgrehan pptmmio.slot = slot; 681221828Sgrehan pptmmio.func = func; 682221828Sgrehan pptmmio.gpa = gpa; 683221828Sgrehan pptmmio.len = len; 684221828Sgrehan pptmmio.hpa = hpa; 685221828Sgrehan 686221828Sgrehan return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); 687221828Sgrehan} 688221828Sgrehan 689221828Sgrehanint 690262350Sjhbvm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 691262350Sjhb uint64_t addr, uint64_t msg, int numvec) 692221828Sgrehan{ 693221828Sgrehan struct vm_pptdev_msi pptmsi; 694221828Sgrehan 695221828Sgrehan bzero(&pptmsi, sizeof(pptmsi)); 696221828Sgrehan pptmsi.vcpu = vcpu; 697221828Sgrehan pptmsi.bus = bus; 698221828Sgrehan pptmsi.slot = slot; 699221828Sgrehan pptmsi.func = func; 700262350Sjhb pptmsi.msg = msg; 701262350Sjhb pptmsi.addr = addr; 702221828Sgrehan pptmsi.numvec = numvec; 703221828Sgrehan 704221828Sgrehan return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi)); 705221828Sgrehan} 706221828Sgrehan 707234761Sgrehanint 708262350Sjhbvm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 709262350Sjhb int idx, uint64_t addr, uint64_t msg, uint32_t vector_control) 710234761Sgrehan{ 711234761Sgrehan struct vm_pptdev_msix pptmsix; 712234761Sgrehan 713234761Sgrehan bzero(&pptmsix, sizeof(pptmsix)); 714234761Sgrehan pptmsix.vcpu = vcpu; 715234761Sgrehan pptmsix.bus = bus; 716234761Sgrehan pptmsix.slot = slot; 717234761Sgrehan pptmsix.func = func; 718234761Sgrehan pptmsix.idx = idx; 719234761Sgrehan pptmsix.msg = msg; 720234761Sgrehan pptmsix.addr = addr; 721234761Sgrehan pptmsix.vector_control = vector_control; 722234761Sgrehan 723234761Sgrehan return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix); 724234761Sgrehan} 725234761Sgrehan 726221828Sgrehanuint64_t * 727221828Sgrehanvm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, 728221828Sgrehan int *ret_entries) 729221828Sgrehan{ 730221828Sgrehan int error; 731221828Sgrehan 732221828Sgrehan static struct vm_stats vmstats; 733221828Sgrehan 734221828Sgrehan vmstats.cpuid = vcpu; 735221828Sgrehan 736221828Sgrehan error = ioctl(ctx->fd, VM_STATS, &vmstats); 737221828Sgrehan if (error == 0) { 738221828Sgrehan if (ret_entries) 739221828Sgrehan *ret_entries = vmstats.num_entries; 740221828Sgrehan if (ret_tv) 741221828Sgrehan *ret_tv = vmstats.tv; 742221828Sgrehan return (vmstats.statbuf); 743221828Sgrehan } else 744221828Sgrehan return (NULL); 745221828Sgrehan} 746221828Sgrehan 747221828Sgrehanconst char * 748221828Sgrehanvm_get_stat_desc(struct vmctx *ctx, int index) 749221828Sgrehan{ 750221828Sgrehan static struct vm_stat_desc statdesc; 751221828Sgrehan 752221828Sgrehan statdesc.index = index; 753221828Sgrehan if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0) 754221828Sgrehan return (statdesc.desc); 755221828Sgrehan else 756221828Sgrehan return (NULL); 757221828Sgrehan} 758221828Sgrehan 759240922Sneelint 760240922Sneelvm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state) 761240922Sneel{ 762240922Sneel int error; 763240922Sneel struct vm_x2apic x2apic; 764240922Sneel 765240922Sneel bzero(&x2apic, sizeof(x2apic)); 766240922Sneel x2apic.cpuid = vcpu; 767240922Sneel 768240922Sneel error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic); 769240922Sneel *state = x2apic.state; 770240922Sneel return (error); 771240922Sneel} 772240922Sneel 773240922Sneelint 774240922Sneelvm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state) 775240922Sneel{ 776240922Sneel int error; 777240922Sneel struct vm_x2apic x2apic; 778240922Sneel 779240922Sneel bzero(&x2apic, sizeof(x2apic)); 780240922Sneel x2apic.cpuid = vcpu; 781240922Sneel x2apic.state = state; 782240922Sneel 783240922Sneel error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic); 784240922Sneel 785240922Sneel return (error); 786240922Sneel} 787240922Sneel 788221828Sgrehan/* 789221828Sgrehan * From Intel Vol 3a: 790221828Sgrehan * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT 791221828Sgrehan */ 792221828Sgrehanint 793221828Sgrehanvcpu_reset(struct vmctx *vmctx, int vcpu) 794221828Sgrehan{ 795221828Sgrehan int error; 796221828Sgrehan uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx; 797221828Sgrehan uint32_t desc_access, desc_limit; 798221828Sgrehan uint16_t sel; 799221828Sgrehan 800221828Sgrehan zero = 0; 801221828Sgrehan 802221828Sgrehan rflags = 0x2; 803221828Sgrehan error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags); 804221828Sgrehan if (error) 805221828Sgrehan goto done; 806221828Sgrehan 807221828Sgrehan rip = 0xfff0; 808221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0) 809221828Sgrehan goto done; 810221828Sgrehan 811221828Sgrehan cr0 = CR0_NE; 812221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0) 813221828Sgrehan goto done; 814221828Sgrehan 815221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0) 816221828Sgrehan goto done; 817221828Sgrehan 818239025Sneel cr4 = 0; 819221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0) 820221828Sgrehan goto done; 821221828Sgrehan 822221828Sgrehan /* 823221828Sgrehan * CS: present, r/w, accessed, 16-bit, byte granularity, usable 824221828Sgrehan */ 825221828Sgrehan desc_base = 0xffff0000; 826221828Sgrehan desc_limit = 0xffff; 827221828Sgrehan desc_access = 0x0093; 828221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS, 829221828Sgrehan desc_base, desc_limit, desc_access); 830221828Sgrehan if (error) 831221828Sgrehan goto done; 832221828Sgrehan 833221828Sgrehan sel = 0xf000; 834221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0) 835221828Sgrehan goto done; 836221828Sgrehan 837221828Sgrehan /* 838221828Sgrehan * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity 839221828Sgrehan */ 840221828Sgrehan desc_base = 0; 841221828Sgrehan desc_limit = 0xffff; 842221828Sgrehan desc_access = 0x0093; 843221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS, 844221828Sgrehan desc_base, desc_limit, desc_access); 845221828Sgrehan if (error) 846221828Sgrehan goto done; 847221828Sgrehan 848221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS, 849221828Sgrehan desc_base, desc_limit, desc_access); 850221828Sgrehan if (error) 851221828Sgrehan goto done; 852221828Sgrehan 853221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES, 854221828Sgrehan desc_base, desc_limit, desc_access); 855221828Sgrehan if (error) 856221828Sgrehan goto done; 857221828Sgrehan 858221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS, 859221828Sgrehan desc_base, desc_limit, desc_access); 860221828Sgrehan if (error) 861221828Sgrehan goto done; 862221828Sgrehan 863221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS, 864221828Sgrehan desc_base, desc_limit, desc_access); 865221828Sgrehan if (error) 866221828Sgrehan goto done; 867221828Sgrehan 868221828Sgrehan sel = 0; 869221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0) 870221828Sgrehan goto done; 871221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0) 872221828Sgrehan goto done; 873221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0) 874221828Sgrehan goto done; 875221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0) 876221828Sgrehan goto done; 877221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0) 878221828Sgrehan goto done; 879221828Sgrehan 880221828Sgrehan /* General purpose registers */ 881221828Sgrehan rdx = 0xf00; 882221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0) 883221828Sgrehan goto done; 884221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0) 885221828Sgrehan goto done; 886221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0) 887221828Sgrehan goto done; 888221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0) 889221828Sgrehan goto done; 890221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0) 891221828Sgrehan goto done; 892221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0) 893221828Sgrehan goto done; 894221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0) 895221828Sgrehan goto done; 896221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0) 897221828Sgrehan goto done; 898221828Sgrehan 899221828Sgrehan /* GDTR, IDTR */ 900221828Sgrehan desc_base = 0; 901221828Sgrehan desc_limit = 0xffff; 902221828Sgrehan desc_access = 0; 903221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, 904221828Sgrehan desc_base, desc_limit, desc_access); 905221828Sgrehan if (error != 0) 906221828Sgrehan goto done; 907221828Sgrehan 908221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR, 909221828Sgrehan desc_base, desc_limit, desc_access); 910221828Sgrehan if (error != 0) 911221828Sgrehan goto done; 912221828Sgrehan 913221828Sgrehan /* TR */ 914221828Sgrehan desc_base = 0; 915221828Sgrehan desc_limit = 0xffff; 916221828Sgrehan desc_access = 0x0000008b; 917221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access); 918221828Sgrehan if (error) 919221828Sgrehan goto done; 920221828Sgrehan 921221828Sgrehan sel = 0; 922221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0) 923221828Sgrehan goto done; 924221828Sgrehan 925221828Sgrehan /* LDTR */ 926221828Sgrehan desc_base = 0; 927221828Sgrehan desc_limit = 0xffff; 928221828Sgrehan desc_access = 0x00000082; 929221828Sgrehan error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base, 930221828Sgrehan desc_limit, desc_access); 931221828Sgrehan if (error) 932221828Sgrehan goto done; 933221828Sgrehan 934221828Sgrehan sel = 0; 935221828Sgrehan if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0) 936221828Sgrehan goto done; 937221828Sgrehan 938221828Sgrehan /* XXX cr2, debug registers */ 939221828Sgrehan 940221828Sgrehan error = 0; 941221828Sgrehandone: 942221828Sgrehan return (error); 943221828Sgrehan} 944256072Sneel 945256072Sneelint 946256072Sneelvm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num) 947256072Sneel{ 948256072Sneel int error, i; 949256072Sneel struct vm_gpa_pte gpapte; 950256072Sneel 951256072Sneel bzero(&gpapte, sizeof(gpapte)); 952256072Sneel gpapte.gpa = gpa; 953256072Sneel 954256072Sneel error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte); 955256072Sneel 956256072Sneel if (error == 0) { 957256072Sneel *num = gpapte.ptenum; 958256072Sneel for (i = 0; i < gpapte.ptenum; i++) 959256072Sneel pte[i] = gpapte.pte[i]; 960256072Sneel } 961256072Sneel 962256072Sneel return (error); 963256072Sneel} 964261088Sjhb 965261088Sjhbint 966261088Sjhbvm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) 967261088Sjhb{ 968261088Sjhb int error; 969261088Sjhb struct vm_hpet_cap cap; 970261088Sjhb 971261088Sjhb bzero(&cap, sizeof(struct vm_hpet_cap)); 972261088Sjhb error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap); 973261088Sjhb if (capabilities != NULL) 974261088Sjhb *capabilities = cap.capabilities; 975261088Sjhb return (error); 976261088Sjhb} 977268976Sjhb 978268976Sjhbstatic int 979268976Sjhbgla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 980268976Sjhb uint64_t gla, int prot, int *fault, uint64_t *gpa) 981268976Sjhb{ 982268976Sjhb struct vm_gla2gpa gg; 983268976Sjhb int error; 984268976Sjhb 985268976Sjhb bzero(&gg, sizeof(struct vm_gla2gpa)); 986268976Sjhb gg.vcpuid = vcpu; 987268976Sjhb gg.prot = prot; 988268976Sjhb gg.gla = gla; 989268976Sjhb gg.paging = *paging; 990268976Sjhb 991268976Sjhb error = ioctl(ctx->fd, VM_GLA2GPA, &gg); 992268976Sjhb if (error == 0) { 993268976Sjhb *fault = gg.fault; 994268976Sjhb *gpa = gg.gpa; 995268976Sjhb } 996268976Sjhb return (error); 997268976Sjhb} 998268976Sjhb 999268976Sjhb#ifndef min 1000268976Sjhb#define min(a,b) (((a) < (b)) ? (a) : (b)) 1001268976Sjhb#endif 1002268976Sjhb 1003268976Sjhbint 1004270159Sgrehanvm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 1005268976Sjhb uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt) 1006268976Sjhb{ 1007268976Sjhb uint64_t gpa; 1008268976Sjhb int error, fault, i, n, off; 1009268976Sjhb 1010268976Sjhb for (i = 0; i < iovcnt; i++) { 1011268976Sjhb iov[i].iov_base = 0; 1012268976Sjhb iov[i].iov_len = 0; 1013268976Sjhb } 1014268976Sjhb 1015268976Sjhb while (len) { 1016268976Sjhb assert(iovcnt > 0); 1017268976Sjhb error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, &gpa); 1018268976Sjhb if (error) 1019268976Sjhb return (-1); 1020268976Sjhb if (fault) 1021268976Sjhb return (1); 1022268976Sjhb 1023268976Sjhb off = gpa & PAGE_MASK; 1024268976Sjhb n = min(len, PAGE_SIZE - off); 1025268976Sjhb 1026268976Sjhb iov->iov_base = (void *)gpa; 1027268976Sjhb iov->iov_len = n; 1028268976Sjhb iov++; 1029268976Sjhb iovcnt--; 1030268976Sjhb 1031268976Sjhb gla += n; 1032268976Sjhb len -= n; 1033268976Sjhb } 1034268976Sjhb return (0); 1035268976Sjhb} 1036268976Sjhb 1037268976Sjhbvoid 1038268976Sjhbvm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) 1039268976Sjhb{ 1040268976Sjhb const char *src; 1041268976Sjhb char *dst; 1042268976Sjhb uint64_t gpa; 1043268976Sjhb size_t n; 1044268976Sjhb 1045268976Sjhb dst = vp; 1046268976Sjhb while (len) { 1047268976Sjhb assert(iov->iov_len); 1048268976Sjhb gpa = (uint64_t)iov->iov_base; 1049268976Sjhb n = min(len, iov->iov_len); 1050268976Sjhb src = vm_map_gpa(ctx, gpa, n); 1051268976Sjhb bcopy(src, dst, n); 1052268976Sjhb 1053268976Sjhb iov++; 1054268976Sjhb dst += n; 1055268976Sjhb len -= n; 1056268976Sjhb } 1057268976Sjhb} 1058268976Sjhb 1059268976Sjhbvoid 1060268976Sjhbvm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, 1061268976Sjhb size_t len) 1062268976Sjhb{ 1063268976Sjhb const char *src; 1064268976Sjhb char *dst; 1065268976Sjhb uint64_t gpa; 1066268976Sjhb size_t n; 1067268976Sjhb 1068268976Sjhb src = vp; 1069268976Sjhb while (len) { 1070268976Sjhb assert(iov->iov_len); 1071268976Sjhb gpa = (uint64_t)iov->iov_base; 1072268976Sjhb n = min(len, iov->iov_len); 1073268976Sjhb dst = vm_map_gpa(ctx, gpa, n); 1074268976Sjhb bcopy(src, dst, n); 1075268976Sjhb 1076268976Sjhb iov++; 1077268976Sjhb src += n; 1078268976Sjhb len -= n; 1079268976Sjhb } 1080268976Sjhb} 1081270070Sgrehan 1082270070Sgrehanstatic int 1083270070Sgrehanvm_get_cpus(struct vmctx *ctx, int which, cpuset_t *cpus) 1084270070Sgrehan{ 1085270070Sgrehan struct vm_cpuset vm_cpuset; 1086270070Sgrehan int error; 1087270070Sgrehan 1088270070Sgrehan bzero(&vm_cpuset, sizeof(struct vm_cpuset)); 1089270070Sgrehan vm_cpuset.which = which; 1090270070Sgrehan vm_cpuset.cpusetsize = sizeof(cpuset_t); 1091270070Sgrehan vm_cpuset.cpus = cpus; 1092270070Sgrehan 1093270070Sgrehan error = ioctl(ctx->fd, VM_GET_CPUS, &vm_cpuset); 1094270070Sgrehan return (error); 1095270070Sgrehan} 1096270070Sgrehan 1097270070Sgrehanint 1098270070Sgrehanvm_active_cpus(struct vmctx *ctx, cpuset_t *cpus) 1099270070Sgrehan{ 1100270070Sgrehan 1101270070Sgrehan return (vm_get_cpus(ctx, VM_ACTIVE_CPUS, cpus)); 1102270070Sgrehan} 1103270070Sgrehan 1104270070Sgrehanint 1105270070Sgrehanvm_suspended_cpus(struct vmctx *ctx, cpuset_t *cpus) 1106270070Sgrehan{ 1107270070Sgrehan 1108270070Sgrehan return (vm_get_cpus(ctx, VM_SUSPENDED_CPUS, cpus)); 1109270070Sgrehan} 1110270070Sgrehan 1111270070Sgrehanint 1112270070Sgrehanvm_activate_cpu(struct vmctx *ctx, int vcpu) 1113270070Sgrehan{ 1114270070Sgrehan struct vm_activate_cpu ac; 1115270070Sgrehan int error; 1116270070Sgrehan 1117270070Sgrehan bzero(&ac, sizeof(struct vm_activate_cpu)); 1118270070Sgrehan ac.vcpuid = vcpu; 1119270070Sgrehan error = ioctl(ctx->fd, VM_ACTIVATE_CPU, &ac); 1120270070Sgrehan return (error); 1121270070Sgrehan} 1122270159Sgrehan 1123270159Sgrehanint 1124270159Sgrehanvm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *info1, uint64_t *info2) 1125270159Sgrehan{ 1126270159Sgrehan struct vm_intinfo vmii; 1127270159Sgrehan int error; 1128270159Sgrehan 1129270159Sgrehan bzero(&vmii, sizeof(struct vm_intinfo)); 1130270159Sgrehan vmii.vcpuid = vcpu; 1131270159Sgrehan error = ioctl(ctx->fd, VM_GET_INTINFO, &vmii); 1132270159Sgrehan if (error == 0) { 1133270159Sgrehan *info1 = vmii.info1; 1134270159Sgrehan *info2 = vmii.info2; 1135270159Sgrehan } 1136270159Sgrehan return (error); 1137270159Sgrehan} 1138270159Sgrehan 1139270159Sgrehanint 1140270159Sgrehanvm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t info1) 1141270159Sgrehan{ 1142270159Sgrehan struct vm_intinfo vmii; 1143270159Sgrehan int error; 1144270159Sgrehan 1145270159Sgrehan bzero(&vmii, sizeof(struct vm_intinfo)); 1146270159Sgrehan vmii.vcpuid = vcpu; 1147270159Sgrehan vmii.info1 = info1; 1148270159Sgrehan error = ioctl(ctx->fd, VM_SET_INTINFO, &vmii); 1149270159Sgrehan return (error); 1150270159Sgrehan} 1151