vmmapi.c revision 284899
1117610Sdes/*- 2271947Sdes * Copyright (c) 2011 NetApp, Inc. 3117610Sdes * All rights reserved. 4271947Sdes * 5117610Sdes * Redistribution and use in source and binary forms, with or without 6174832Sdes * modification, are permitted provided that the following conditions 7117610Sdes * are met: 8228692Sdes * 1. Redistributions of source code must retain the above copyright 9255376Sdes * notice, this list of conditions and the following disclaimer. 10228692Sdes * 2. Redistributions in binary form must reproduce the above copyright 11228692Sdes * notice, this list of conditions and the following disclaimer in the 12117610Sdes * documentation and/or other materials provided with the distribution. 13117610Sdes * 14228692Sdes * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15228692Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16228692Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17117610Sdes * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18174832Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19174832Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20228692Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21117610Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22117610Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23228692Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24141098Sdes * SUCH DAMAGE. 25141098Sdes * 26174832Sdes * $FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 284899 2015-06-28 01:21:55Z neel $ 27174832Sdes */ 28228692Sdes 29228692Sdes#include <sys/cdefs.h> 30228692Sdes__FBSDID("$FreeBSD: stable/10/lib/libvmmapi/vmmapi.c 284899 2015-06-28 01:21:55Z neel $"); 31228692Sdes 32228692Sdes#include <sys/param.h> 33174832Sdes#include <sys/sysctl.h> 34117610Sdes#include <sys/ioctl.h> 35117610Sdes#include <sys/mman.h> 36174832Sdes#include <sys/_iovec.h> 37228692Sdes#include <sys/cpuset.h> 38228692Sdes 39228692Sdes#include <x86/segments.h> 40228692Sdes#include <machine/specialreg.h> 41228692Sdes#include <machine/param.h> 42228692Sdes 43228692Sdes#include <stdio.h> 44228692Sdes#include <stdlib.h> 45228692Sdes#include <assert.h> 46228692Sdes#include <string.h> 47228692Sdes#include <fcntl.h> 48228692Sdes#include <unistd.h> 49228692Sdes 50228692Sdes#include <libutil.h> 51228692Sdes 52228692Sdes#include <machine/vmm.h> 53228692Sdes#include <machine/vmm_dev.h> 54228692Sdes 55228692Sdes#include "vmmapi.h" 56228692Sdes 57174832Sdes#define MB (1024 * 1024UL) 58228692Sdes#define GB (1024 * 1024 * 1024UL) 59228692Sdes 60228692Sdesstruct vmctx { 61228692Sdes int fd; 62228692Sdes uint32_t lowmem_limit; 63228692Sdes enum vm_mmap_style vms; 64228692Sdes int memflags; 65228692Sdes size_t lowmem; 66228692Sdes char *lowmem_addr; 67228692Sdes size_t highmem; 68228692Sdes char *highmem_addr; 69228692Sdes char *name; 70174832Sdes}; 71228692Sdes 72228692Sdes#define CREATE(x) sysctlbyname("hw.vmm.create", NULL, NULL, (x), strlen((x))) 73174832Sdes#define DESTROY(x) sysctlbyname("hw.vmm.destroy", NULL, NULL, (x), strlen((x))) 74174832Sdes 75228692Sdesstatic int 76228692Sdesvm_device_open(const char *name) 77228692Sdes{ 78228692Sdes int fd, len; 79228692Sdes char *vmfile; 80228692Sdes 81228692Sdes len = strlen("/dev/vmm/") + strlen(name) + 1; 82117610Sdes vmfile = malloc(len); 83117610Sdes assert(vmfile != NULL); 84117610Sdes snprintf(vmfile, len, "/dev/vmm/%s", name); 85174832Sdes 86174832Sdes /* Open the device file */ 87174832Sdes fd = open(vmfile, O_RDWR, 0); 88174832Sdes 89174832Sdes free(vmfile); 90174832Sdes return (fd); 91174832Sdes} 92174832Sdes 93228692Sdesint 94228692Sdesvm_create(const char *name) 95174832Sdes{ 96174832Sdes 97174832Sdes return (CREATE((char *)name)); 98174832Sdes} 99174832Sdes 100174832Sdesstruct vmctx * 101228692Sdesvm_open(const char *name) 102228692Sdes{ 103174832Sdes struct vmctx *vm; 104174832Sdes 105174832Sdes vm = malloc(sizeof(struct vmctx) + strlen(name) + 1); 106174832Sdes assert(vm != NULL); 107174832Sdes 108174832Sdes vm->fd = -1; 109174832Sdes vm->memflags = 0; 110174832Sdes vm->lowmem_limit = 3 * GB; 111174832Sdes vm->name = (char *)(vm + 1); 112174832Sdes strcpy(vm->name, name); 113228692Sdes 114228692Sdes if ((vm->fd = vm_device_open(vm->name)) < 0) 115174832Sdes goto err; 116174832Sdes 117228692Sdes return (vm); 118228692Sdeserr: 119228692Sdes vm_destroy(vm); 120228692Sdes return (NULL); 121228692Sdes} 122228692Sdes 123228692Sdesvoid 124174832Sdesvm_destroy(struct vmctx *vm) 125141098Sdes{ 126141098Sdes assert(vm != NULL); 127141098Sdes 128117610Sdes if (vm->fd >= 0) 129141098Sdes close(vm->fd); 130228692Sdes DESTROY(vm->name); 131228692Sdes 132228692Sdes free(vm); 133228692Sdes} 134141098Sdes 135174832Sdesint 136228692Sdesvm_parse_memsize(const char *optarg, size_t *ret_memsize) 137141098Sdes{ 138255376Sdes char *endptr; 139255376Sdes size_t optval; 140255376Sdes int error; 141255376Sdes 142255376Sdes optval = strtoul(optarg, &endptr, 0); 143255376Sdes if (*optarg != '\0' && *endptr == '\0') { 144255376Sdes /* 145255376Sdes * For the sake of backward compatibility if the memory size 146255376Sdes * specified on the command line is less than a megabyte then 147255376Sdes * it is interpreted as being in units of MB. 148255376Sdes */ 149255376Sdes if (optval < MB) 150255376Sdes optval *= MB; 151255376Sdes *ret_memsize = optval; 152255376Sdes error = 0; 153255376Sdes } else 154255376Sdes error = expand_number(optarg, ret_memsize); 155255376Sdes 156255376Sdes return (error); 157255376Sdes} 158255376Sdes 159255376Sdesint 160255376Sdesvm_get_memory_seg(struct vmctx *ctx, vm_paddr_t gpa, size_t *ret_len, 161255376Sdes int *wired) 162255376Sdes{ 163174832Sdes int error; 164228692Sdes struct vm_memory_segment seg; 165228692Sdes 166228692Sdes bzero(&seg, sizeof(seg)); 167228692Sdes seg.gpa = gpa; 168228692Sdes error = ioctl(ctx->fd, VM_GET_MEMORY_SEG, &seg); 169228692Sdes *ret_len = seg.len; 170228692Sdes if (wired != NULL) 171174832Sdes *wired = seg.wired; 172228692Sdes return (error); 173228692Sdes} 174228692Sdes 175228692Sdesuint32_t 176228692Sdesvm_get_lowmem_limit(struct vmctx *ctx) 177228692Sdes{ 178117610Sdes 179228692Sdes return (ctx->lowmem_limit); 180228692Sdes} 181228692Sdes 182228692Sdesvoid 183228692Sdesvm_set_lowmem_limit(struct vmctx *ctx, uint32_t limit) 184228692Sdes{ 185117610Sdes 186174832Sdes ctx->lowmem_limit = limit; 187228692Sdes} 188228692Sdes 189228692Sdesvoid 190228692Sdesvm_set_memflags(struct vmctx *ctx, int flags) 191228692Sdes{ 192117610Sdes 193174832Sdes ctx->memflags = flags; 194228692Sdes} 195174832Sdes 196255376Sdesstatic int 197255376Sdessetup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char **addr) 198228692Sdes{ 199228692Sdes int error, mmap_flags; 200228692Sdes struct vm_memory_segment seg; 201228692Sdes 202228692Sdes /* 203174832Sdes * Create and optionally map 'len' bytes of memory at guest 204228692Sdes * physical address 'gpa' 205228692Sdes */ 206228692Sdes bzero(&seg, sizeof(seg)); 207228692Sdes seg.gpa = gpa; 208228692Sdes seg.len = len; 209228692Sdes error = ioctl(ctx->fd, VM_MAP_MEMORY, &seg); 210228692Sdes if (error == 0 && addr != NULL) { 211228692Sdes mmap_flags = MAP_SHARED; 212228692Sdes if ((ctx->memflags & VM_MEM_F_INCORE) == 0) 213174832Sdes mmap_flags |= MAP_NOCORE; 214228692Sdes *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, mmap_flags, 215174832Sdes ctx->fd, gpa); 216228692Sdes } 217174832Sdes return (error); 218174832Sdes} 219228692Sdes 220228692Sdesint 221117610Sdesvm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) 222117610Sdes{ 223117610Sdes char **addr; 224117610Sdes int error; 225228692Sdes 226228692Sdes /* XXX VM_MMAP_SPARSE not implemented yet */ 227117610Sdes assert(vms == VM_MMAP_NONE || vms == VM_MMAP_ALL); 228174832Sdes ctx->vms = vms; 229228692Sdes 230228692Sdes /* 231228692Sdes * If 'memsize' cannot fit entirely in the 'lowmem' segment then 232228692Sdes * create another 'highmem' segment above 4GB for the remainder. 233228692Sdes */ 234228692Sdes if (memsize > ctx->lowmem_limit) { 235228692Sdes ctx->lowmem = ctx->lowmem_limit; 236228692Sdes ctx->highmem = memsize - ctx->lowmem; 237228692Sdes } else { 238174832Sdes ctx->lowmem = memsize; 239174832Sdes ctx->highmem = 0; 240228692Sdes } 241174832Sdes 242228692Sdes if (ctx->lowmem > 0) { 243228692Sdes addr = (vms == VM_MMAP_ALL) ? &ctx->lowmem_addr : NULL; 244228692Sdes error = setup_memory_segment(ctx, 0, ctx->lowmem, addr); 245228692Sdes if (error) 246174832Sdes return (error); 247174832Sdes } 248174832Sdes 249228692Sdes if (ctx->highmem > 0) { 250255376Sdes addr = (vms == VM_MMAP_ALL) ? &ctx->highmem_addr : NULL; 251255376Sdes error = setup_memory_segment(ctx, 4*GB, ctx->highmem, addr); 252255376Sdes if (error) 253255376Sdes return (error); 254255376Sdes } 255255376Sdes 256255376Sdes return (0); 257255376Sdes} 258255376Sdes 259255376Sdesvoid * 260255376Sdesvm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) 261255376Sdes{ 262255376Sdes 263255376Sdes /* XXX VM_MMAP_SPARSE not implemented yet */ 264255376Sdes assert(ctx->vms == VM_MMAP_ALL); 265255376Sdes 266255376Sdes if (gaddr < ctx->lowmem && gaddr + len <= ctx->lowmem) 267255376Sdes return ((void *)(ctx->lowmem_addr + gaddr)); 268255376Sdes 269174832Sdes if (gaddr >= 4*GB) { 270174832Sdes gaddr -= 4*GB; 271228692Sdes if (gaddr < ctx->highmem && gaddr + len <= ctx->highmem) 272228692Sdes return ((void *)(ctx->highmem_addr + gaddr)); 273228692Sdes } 274228692Sdes 275228692Sdes return (NULL); 276228692Sdes} 277228692Sdes 278228692Sdessize_t 279228692Sdesvm_get_lowmem_size(struct vmctx *ctx) 280228692Sdes{ 281228692Sdes 282228692Sdes return (ctx->lowmem); 283228692Sdes} 284174832Sdes 285174832Sdessize_t 286174832Sdesvm_get_highmem_size(struct vmctx *ctx) 287228692Sdes{ 288228692Sdes 289228692Sdes return (ctx->highmem); 290228692Sdes} 291228692Sdes 292174832Sdesint 293228692Sdesvm_set_desc(struct vmctx *ctx, int vcpu, int reg, 294228692Sdes uint64_t base, uint32_t limit, uint32_t access) 295228692Sdes{ 296228692Sdes int error; 297228692Sdes struct vm_seg_desc vmsegdesc; 298228692Sdes 299228692Sdes bzero(&vmsegdesc, sizeof(vmsegdesc)); 300228692Sdes vmsegdesc.cpuid = vcpu; 301228692Sdes vmsegdesc.regnum = reg; 302228692Sdes vmsegdesc.desc.base = base; 303228692Sdes vmsegdesc.desc.limit = limit; 304174832Sdes vmsegdesc.desc.access = access; 305228692Sdes 306228692Sdes error = ioctl(ctx->fd, VM_SET_SEGMENT_DESCRIPTOR, &vmsegdesc); 307228692Sdes return (error); 308228692Sdes} 309228692Sdes 310228692Sdesint 311228692Sdesvm_get_desc(struct vmctx *ctx, int vcpu, int reg, 312174832Sdes uint64_t *base, uint32_t *limit, uint32_t *access) 313228692Sdes{ 314228692Sdes int error; 315228692Sdes struct vm_seg_desc vmsegdesc; 316228692Sdes 317228692Sdes bzero(&vmsegdesc, sizeof(vmsegdesc)); 318228692Sdes vmsegdesc.cpuid = vcpu; 319228692Sdes vmsegdesc.regnum = reg; 320228692Sdes 321228692Sdes error = ioctl(ctx->fd, VM_GET_SEGMENT_DESCRIPTOR, &vmsegdesc); 322174832Sdes if (error == 0) { 323228692Sdes *base = vmsegdesc.desc.base; 324228692Sdes *limit = vmsegdesc.desc.limit; 325228692Sdes *access = vmsegdesc.desc.access; 326228692Sdes } 327228692Sdes return (error); 328174832Sdes} 329228692Sdes 330228692Sdesint 331228692Sdesvm_get_seg_desc(struct vmctx *ctx, int vcpu, int reg, struct seg_desc *seg_desc) 332228692Sdes{ 333228692Sdes int error; 334228692Sdes 335228692Sdes error = vm_get_desc(ctx, vcpu, reg, &seg_desc->base, &seg_desc->limit, 336228692Sdes &seg_desc->access); 337228692Sdes return (error); 338228692Sdes} 339228692Sdes 340228692Sdesint 341228692Sdesvm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val) 342228692Sdes{ 343228692Sdes int error; 344228692Sdes struct vm_register vmreg; 345228692Sdes 346228692Sdes bzero(&vmreg, sizeof(vmreg)); 347228692Sdes vmreg.cpuid = vcpu; 348228692Sdes vmreg.regnum = reg; 349228692Sdes vmreg.regval = val; 350228692Sdes 351228692Sdes error = ioctl(ctx->fd, VM_SET_REGISTER, &vmreg); 352228692Sdes return (error); 353228692Sdes} 354228692Sdes 355228692Sdesint 356228692Sdesvm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *ret_val) 357228692Sdes{ 358228692Sdes int error; 359228692Sdes struct vm_register vmreg; 360228692Sdes 361228692Sdes bzero(&vmreg, sizeof(vmreg)); 362228692Sdes vmreg.cpuid = vcpu; 363228692Sdes vmreg.regnum = reg; 364228692Sdes 365228692Sdes error = ioctl(ctx->fd, VM_GET_REGISTER, &vmreg); 366228692Sdes *ret_val = vmreg.regval; 367117610Sdes return (error); 368174832Sdes} 369228692Sdes 370255376Sdesint 371255376Sdesvm_run(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit) 372255376Sdes{ 373255376Sdes int error; 374255376Sdes struct vm_run vmrun; 375255376Sdes 376255376Sdes bzero(&vmrun, sizeof(vmrun)); 377255376Sdes vmrun.cpuid = vcpu; 378228692Sdes 379228692Sdes error = ioctl(ctx->fd, VM_RUN, &vmrun); 380228692Sdes bcopy(&vmrun.vm_exit, vmexit, sizeof(struct vm_exit)); 381228692Sdes return (error); 382228692Sdes} 383228692Sdes 384228692Sdesint 385228692Sdesvm_suspend(struct vmctx *ctx, enum vm_suspend_how how) 386228692Sdes{ 387228692Sdes struct vm_suspend vmsuspend; 388228692Sdes 389228692Sdes bzero(&vmsuspend, sizeof(vmsuspend)); 390228692Sdes vmsuspend.how = how; 391228692Sdes return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); 392228692Sdes} 393228692Sdes 394228692Sdesint 395174832Sdesvm_reinit(struct vmctx *ctx) 396228692Sdes{ 397228692Sdes 398228692Sdes return (ioctl(ctx->fd, VM_REINIT, 0)); 399228692Sdes} 400228692Sdes 401228692Sdesint 402228692Sdesvm_inject_exception(struct vmctx *ctx, int vcpu, int vector, int errcode_valid, 403228692Sdes uint32_t errcode, int restart_instruction) 404228692Sdes{ 405228692Sdes struct vm_exception exc; 406228692Sdes 407228692Sdes exc.cpuid = vcpu; 408228692Sdes exc.vector = vector; 409228692Sdes exc.error_code = errcode; 410228692Sdes exc.error_code_valid = errcode_valid; 411228692Sdes exc.restart_instruction = restart_instruction; 412174832Sdes 413174832Sdes return (ioctl(ctx->fd, VM_INJECT_EXCEPTION, &exc)); 414228692Sdes} 415228692Sdes 416228692Sdesint 417228692Sdesvm_apicid2vcpu(struct vmctx *ctx, int apicid) 418228692Sdes{ 419228692Sdes /* 420228692Sdes * The apic id associated with the 'vcpu' has the same numerical value 421228692Sdes * as the 'vcpu' itself. 422228692Sdes */ 423228692Sdes return (apicid); 424228692Sdes} 425228692Sdes 426228692Sdesint 427228692Sdesvm_lapic_irq(struct vmctx *ctx, int vcpu, int vector) 428228692Sdes{ 429174832Sdes struct vm_lapic_irq vmirq; 430228692Sdes 431228692Sdes bzero(&vmirq, sizeof(vmirq)); 432228692Sdes vmirq.cpuid = vcpu; 433174832Sdes vmirq.vector = vector; 434228692Sdes 435174832Sdes return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq)); 436174832Sdes} 437228692Sdes 438228692Sdesint 439174832Sdesvm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector) 440228692Sdes{ 441174832Sdes struct vm_lapic_irq vmirq; 442174832Sdes 443228692Sdes bzero(&vmirq, sizeof(vmirq)); 444228692Sdes vmirq.cpuid = vcpu; 445174832Sdes vmirq.vector = vector; 446228692Sdes 447174832Sdes return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq)); 448174832Sdes} 449228692Sdes 450228692Sdesint 451228692Sdesvm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg) 452228692Sdes{ 453228692Sdes struct vm_lapic_msi vmmsi; 454228692Sdes 455228692Sdes bzero(&vmmsi, sizeof(vmmsi)); 456228692Sdes vmmsi.addr = addr; 457228692Sdes vmmsi.msg = msg; 458228692Sdes 459228692Sdes return (ioctl(ctx->fd, VM_LAPIC_MSI, &vmmsi)); 460228692Sdes} 461228692Sdes 462228692Sdesint 463228692Sdesvm_ioapic_assert_irq(struct vmctx *ctx, int irq) 464228692Sdes{ 465228692Sdes struct vm_ioapic_irq ioapic_irq; 466228692Sdes 467174832Sdes bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 468228692Sdes ioapic_irq.irq = irq; 469228692Sdes 470228692Sdes return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq)); 471228692Sdes} 472228692Sdes 473228692Sdesint 474174832Sdesvm_ioapic_deassert_irq(struct vmctx *ctx, int irq) 475174832Sdes{ 476228692Sdes struct vm_ioapic_irq ioapic_irq; 477228692Sdes 478228692Sdes bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 479228692Sdes ioapic_irq.irq = irq; 480228692Sdes 481174832Sdes return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq)); 482174832Sdes} 483174832Sdes 484174832Sdesint 485117610Sdesvm_ioapic_pulse_irq(struct vmctx *ctx, int irq) 486174832Sdes{ 487174832Sdes struct vm_ioapic_irq ioapic_irq; 488174832Sdes 489174832Sdes bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); 490117610Sdes ioapic_irq.irq = irq; 491174832Sdes 492174832Sdes return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq)); 493117610Sdes} 494174832Sdes 495117610Sdesint 496174832Sdesvm_ioapic_pincount(struct vmctx *ctx, int *pincount) 497228692Sdes{ 498117610Sdes 499255376Sdes return (ioctl(ctx->fd, VM_IOAPIC_PINCOUNT, pincount)); 500255376Sdes} 501255376Sdes 502255376Sdesint 503117610Sdesvm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 504117610Sdes{ 505174832Sdes struct vm_isa_irq isa_irq; 506174832Sdes 507117610Sdes bzero(&isa_irq, sizeof(struct vm_isa_irq)); 508117610Sdes isa_irq.atpic_irq = atpic_irq; 509117610Sdes isa_irq.ioapic_irq = ioapic_irq; 510117610Sdes 511174832Sdes return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq)); 512228692Sdes} 513174832Sdes 514228692Sdesint 515174832Sdesvm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 516228692Sdes{ 517228692Sdes struct vm_isa_irq isa_irq; 518228692Sdes 519174832Sdes bzero(&isa_irq, sizeof(struct vm_isa_irq)); 520174832Sdes isa_irq.atpic_irq = atpic_irq; 521174832Sdes isa_irq.ioapic_irq = ioapic_irq; 522117610Sdes 523117610Sdes return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq)); 524117610Sdes} 525174832Sdes 526174832Sdesint 527174832Sdesvm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq) 528174832Sdes{ 529228692Sdes struct vm_isa_irq isa_irq; 530174832Sdes 531228692Sdes bzero(&isa_irq, sizeof(struct vm_isa_irq)); 532228692Sdes isa_irq.atpic_irq = atpic_irq; 533228692Sdes isa_irq.ioapic_irq = ioapic_irq; 534228692Sdes 535228692Sdes return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq)); 536228692Sdes} 537255376Sdes 538228692Sdesint 539255376Sdesvm_isa_set_irq_trigger(struct vmctx *ctx, int atpic_irq, 540228692Sdes enum vm_intr_trigger trigger) 541228692Sdes{ 542228692Sdes struct vm_isa_irq_trigger isa_irq_trigger; 543255376Sdes 544228692Sdes bzero(&isa_irq_trigger, sizeof(struct vm_isa_irq_trigger)); 545117610Sdes isa_irq_trigger.atpic_irq = atpic_irq; 546255376Sdes isa_irq_trigger.trigger = trigger; 547117610Sdes 548174832Sdes return (ioctl(ctx->fd, VM_ISA_SET_IRQ_TRIGGER, &isa_irq_trigger)); 549174832Sdes} 550117610Sdes 551141098Sdesint 552228692Sdesvm_inject_nmi(struct vmctx *ctx, int vcpu) 553141098Sdes{ 554141098Sdes struct vm_nmi vmnmi; 555141098Sdes 556141098Sdes bzero(&vmnmi, sizeof(vmnmi)); 557141098Sdes vmnmi.cpuid = vcpu; 558255376Sdes 559255376Sdes return (ioctl(ctx->fd, VM_INJECT_NMI, &vmnmi)); 560117610Sdes} 561117610Sdes 562141098Sdesstatic struct { 563117610Sdes const char *name; 564117610Sdes int type; 565141098Sdes} capstrmap[] = { 566117610Sdes { "hlt_exit", VM_CAP_HALT_EXIT }, 567141098Sdes { "mtrap_exit", VM_CAP_MTRAP_EXIT }, 568141098Sdes { "pause_exit", VM_CAP_PAUSE_EXIT }, 569141098Sdes { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST }, 570228692Sdes { "enable_invpcid", VM_CAP_ENABLE_INVPCID }, 571228692Sdes { 0 } 572141098Sdes}; 573117610Sdes 574228692Sdesint 575117610Sdesvm_capability_name2type(const char *capname) 576117610Sdes{ 577117610Sdes int i; 578117610Sdes 579117610Sdes for (i = 0; capstrmap[i].name != NULL && capname != NULL; i++) { 580117610Sdes if (strcmp(capstrmap[i].name, capname) == 0) 581117610Sdes return (capstrmap[i].type); 582174832Sdes } 583141098Sdes 584174832Sdes return (-1); 585117610Sdes} 586117610Sdes 587117610Sdesconst char * 588117610Sdesvm_capability_type2name(int type) 589117610Sdes{ 590117610Sdes int i; 591117610Sdes 592117610Sdes for (i = 0; capstrmap[i].name != NULL; i++) { 593271947Sdes if (capstrmap[i].type == type) 594271947Sdes return (capstrmap[i].name); 595174832Sdes } 596255376Sdes 597117610Sdes return (NULL); 598255376Sdes} 599117610Sdes 600117610Sdesint 601117610Sdesvm_get_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, 602174832Sdes int *retval) 603117610Sdes{ 604117610Sdes int error; 605174832Sdes struct vm_capability vmcap; 606117610Sdes 607117610Sdes bzero(&vmcap, sizeof(vmcap)); 608174832Sdes vmcap.cpuid = vcpu; 609117610Sdes vmcap.captype = cap; 610117610Sdes 611117610Sdes error = ioctl(ctx->fd, VM_GET_CAPABILITY, &vmcap); 612174832Sdes *retval = vmcap.capval; 613117610Sdes return (error); 614117610Sdes} 615117610Sdes 616174832Sdesint 617174832Sdesvm_set_capability(struct vmctx *ctx, int vcpu, enum vm_cap_type cap, int val) 618117610Sdes{ 619117610Sdes struct vm_capability vmcap; 620117610Sdes 621117610Sdes bzero(&vmcap, sizeof(vmcap)); 622174832Sdes vmcap.cpuid = vcpu; 623117610Sdes vmcap.captype = cap; 624117610Sdes vmcap.capval = val; 625174832Sdes 626117610Sdes return (ioctl(ctx->fd, VM_SET_CAPABILITY, &vmcap)); 627117610Sdes} 628174832Sdes 629174832Sdesint 630174832Sdesvm_assign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 631174832Sdes{ 632117610Sdes struct vm_pptdev pptdev; 633117610Sdes 634117610Sdes bzero(&pptdev, sizeof(pptdev)); 635228692Sdes pptdev.bus = bus; 636228692Sdes pptdev.slot = slot; 637228692Sdes pptdev.func = func; 638228692Sdes 639255376Sdes return (ioctl(ctx->fd, VM_BIND_PPTDEV, &pptdev)); 640228692Sdes} 641228692Sdes 642228692Sdesint 643228692Sdesvm_unassign_pptdev(struct vmctx *ctx, int bus, int slot, int func) 644228692Sdes{ 645228692Sdes struct vm_pptdev pptdev; 646228692Sdes 647228692Sdes bzero(&pptdev, sizeof(pptdev)); 648228692Sdes pptdev.bus = bus; 649228692Sdes pptdev.slot = slot; 650255376Sdes pptdev.func = func; 651255376Sdes 652228692Sdes return (ioctl(ctx->fd, VM_UNBIND_PPTDEV, &pptdev)); 653228692Sdes} 654228692Sdes 655228692Sdesint 656228692Sdesvm_map_pptdev_mmio(struct vmctx *ctx, int bus, int slot, int func, 657228692Sdes vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 658228692Sdes{ 659228692Sdes struct vm_pptdev_mmio pptmmio; 660228692Sdes 661228692Sdes bzero(&pptmmio, sizeof(pptmmio)); 662228692Sdes pptmmio.bus = bus; 663228692Sdes pptmmio.slot = slot; 664228692Sdes pptmmio.func = func; 665228692Sdes pptmmio.gpa = gpa; 666228692Sdes pptmmio.len = len; 667228692Sdes pptmmio.hpa = hpa; 668228692Sdes 669228692Sdes return (ioctl(ctx->fd, VM_MAP_PPTDEV_MMIO, &pptmmio)); 670228692Sdes} 671228692Sdes 672228692Sdesint 673228692Sdesvm_setup_pptdev_msi(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 674228692Sdes uint64_t addr, uint64_t msg, int numvec) 675228692Sdes{ 676228692Sdes struct vm_pptdev_msi pptmsi; 677228692Sdes 678228692Sdes bzero(&pptmsi, sizeof(pptmsi)); 679174832Sdes pptmsi.vcpu = vcpu; 680228692Sdes pptmsi.bus = bus; 681228692Sdes pptmsi.slot = slot; 682228692Sdes pptmsi.func = func; 683228692Sdes pptmsi.msg = msg; 684228692Sdes pptmsi.addr = addr; 685228692Sdes pptmsi.numvec = numvec; 686228692Sdes 687255376Sdes return (ioctl(ctx->fd, VM_PPTDEV_MSI, &pptmsi)); 688228692Sdes} 689228692Sdes 690228692Sdesint 691228692Sdesvm_setup_pptdev_msix(struct vmctx *ctx, int vcpu, int bus, int slot, int func, 692228692Sdes int idx, uint64_t addr, uint64_t msg, uint32_t vector_control) 693228692Sdes{ 694228692Sdes struct vm_pptdev_msix pptmsix; 695228692Sdes 696228692Sdes bzero(&pptmsix, sizeof(pptmsix)); 697228692Sdes pptmsix.vcpu = vcpu; 698228692Sdes pptmsix.bus = bus; 699228692Sdes pptmsix.slot = slot; 700174832Sdes pptmsix.func = func; 701255376Sdes pptmsix.idx = idx; 702255376Sdes pptmsix.msg = msg; 703255376Sdes pptmsix.addr = addr; 704255376Sdes pptmsix.vector_control = vector_control; 705228692Sdes 706228692Sdes return ioctl(ctx->fd, VM_PPTDEV_MSIX, &pptmsix); 707228692Sdes} 708228692Sdes 709228692Sdesuint64_t * 710228692Sdesvm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, 711228692Sdes int *ret_entries) 712228692Sdes{ 713228692Sdes int error; 714174832Sdes 715228692Sdes static struct vm_stats vmstats; 716228692Sdes 717228692Sdes vmstats.cpuid = vcpu; 718228692Sdes 719228692Sdes error = ioctl(ctx->fd, VM_STATS, &vmstats); 720228692Sdes if (error == 0) { 721228692Sdes if (ret_entries) 722228692Sdes *ret_entries = vmstats.num_entries; 723228692Sdes if (ret_tv) 724228692Sdes *ret_tv = vmstats.tv; 725228692Sdes return (vmstats.statbuf); 726228692Sdes } else 727174832Sdes return (NULL); 728228692Sdes} 729228692Sdes 730228692Sdesconst char * 731228692Sdesvm_get_stat_desc(struct vmctx *ctx, int index) 732228692Sdes{ 733228692Sdes static struct vm_stat_desc statdesc; 734228692Sdes 735228692Sdes statdesc.index = index; 736228692Sdes if (ioctl(ctx->fd, VM_STAT_DESC, &statdesc) == 0) 737228692Sdes return (statdesc.desc); 738228692Sdes else 739228692Sdes return (NULL); 740228692Sdes} 741228692Sdes 742228692Sdesint 743228692Sdesvm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state) 744228692Sdes{ 745228692Sdes int error; 746228692Sdes struct vm_x2apic x2apic; 747228692Sdes 748228692Sdes bzero(&x2apic, sizeof(x2apic)); 749228692Sdes x2apic.cpuid = vcpu; 750228692Sdes 751228692Sdes error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic); 752228692Sdes *state = x2apic.state; 753228692Sdes return (error); 754228692Sdes} 755228692Sdes 756228692Sdesint 757228692Sdesvm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state) 758228692Sdes{ 759228692Sdes int error; 760228692Sdes struct vm_x2apic x2apic; 761228692Sdes 762228692Sdes bzero(&x2apic, sizeof(x2apic)); 763228692Sdes x2apic.cpuid = vcpu; 764228692Sdes x2apic.state = state; 765228692Sdes 766141098Sdes error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic); 767228692Sdes 768228692Sdes return (error); 769255376Sdes} 770228692Sdes 771228692Sdes/* 772228692Sdes * From Intel Vol 3a: 773228692Sdes * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT 774228692Sdes */ 775228692Sdesint 776228692Sdesvcpu_reset(struct vmctx *vmctx, int vcpu) 777228692Sdes{ 778228692Sdes int error; 779228692Sdes uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx; 780228692Sdes uint32_t desc_access, desc_limit; 781228692Sdes uint16_t sel; 782228692Sdes 783228692Sdes zero = 0; 784228692Sdes 785228692Sdes rflags = 0x2; 786228692Sdes error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags); 787228692Sdes if (error) 788228692Sdes goto done; 789174832Sdes 790174832Sdes rip = 0xfff0; 791174832Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0) 792174832Sdes goto done; 793174832Sdes 794174832Sdes cr0 = CR0_NE; 795174832Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0) 796174832Sdes goto done; 797228692Sdes 798117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0) 799174832Sdes goto done; 800117610Sdes 801117610Sdes cr4 = 0; 802117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0) 803228692Sdes goto done; 804228692Sdes 805117610Sdes /* 806117610Sdes * CS: present, r/w, accessed, 16-bit, byte granularity, usable 807117610Sdes */ 808117610Sdes desc_base = 0xffff0000; 809117610Sdes desc_limit = 0xffff; 810117610Sdes desc_access = 0x0093; 811117610Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS, 812117610Sdes desc_base, desc_limit, desc_access); 813117610Sdes if (error) 814117610Sdes goto done; 815117610Sdes 816117610Sdes sel = 0xf000; 817117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0) 818117610Sdes goto done; 819117610Sdes 820117610Sdes /* 821117610Sdes * SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity 822117610Sdes */ 823117610Sdes desc_base = 0; 824117610Sdes desc_limit = 0xffff; 825117610Sdes desc_access = 0x0093; 826117610Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS, 827174832Sdes desc_base, desc_limit, desc_access); 828117610Sdes if (error) 829117610Sdes goto done; 830117610Sdes 831174832Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS, 832174832Sdes desc_base, desc_limit, desc_access); 833117610Sdes if (error) 834117610Sdes goto done; 835117610Sdes 836117610Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES, 837117610Sdes desc_base, desc_limit, desc_access); 838174832Sdes if (error) 839174832Sdes goto done; 840174832Sdes 841174832Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS, 842174832Sdes desc_base, desc_limit, desc_access); 843174832Sdes if (error) 844174832Sdes goto done; 845174832Sdes 846174832Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS, 847117610Sdes desc_base, desc_limit, desc_access); 848117610Sdes if (error) 849174832Sdes goto done; 850117610Sdes 851117610Sdes sel = 0; 852117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0) 853117610Sdes goto done; 854174832Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0) 855117610Sdes goto done; 856117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0) 857117610Sdes goto done; 858117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0) 859174832Sdes goto done; 860228692Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0) 861228692Sdes goto done; 862228692Sdes 863174832Sdes /* General purpose registers */ 864117610Sdes rdx = 0xf00; 865117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0) 866117610Sdes goto done; 867174832Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0) 868174832Sdes goto done; 869174832Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0) 870117610Sdes goto done; 871117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0) 872117610Sdes goto done; 873117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0) 874117610Sdes goto done; 875117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0) 876117610Sdes goto done; 877117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0) 878117610Sdes goto done; 879117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0) 880117610Sdes goto done; 881117610Sdes 882117610Sdes /* GDTR, IDTR */ 883117610Sdes desc_base = 0; 884117610Sdes desc_limit = 0xffff; 885117610Sdes desc_access = 0; 886117610Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, 887117610Sdes desc_base, desc_limit, desc_access); 888117610Sdes if (error != 0) 889117610Sdes goto done; 890117610Sdes 891174832Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR, 892117610Sdes desc_base, desc_limit, desc_access); 893174832Sdes if (error != 0) 894117610Sdes goto done; 895117610Sdes 896174832Sdes /* TR */ 897174832Sdes desc_base = 0; 898174832Sdes desc_limit = 0xffff; 899174832Sdes desc_access = 0x0000008b; 900174832Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access); 901174832Sdes if (error) 902174832Sdes goto done; 903117610Sdes 904228692Sdes sel = 0; 905117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0) 906228692Sdes goto done; 907228692Sdes 908228692Sdes /* LDTR */ 909228692Sdes desc_base = 0; 910228692Sdes desc_limit = 0xffff; 911228692Sdes desc_access = 0x00000082; 912228692Sdes error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base, 913228692Sdes desc_limit, desc_access); 914228692Sdes if (error) 915228692Sdes goto done; 916228692Sdes 917228692Sdes sel = 0; 918117610Sdes if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0) 919174832Sdes goto done; 920174832Sdes 921174832Sdes /* XXX cr2, debug registers */ 922174832Sdes 923174832Sdes error = 0; 924174832Sdesdone: 925174832Sdes return (error); 926174832Sdes} 927174832Sdes 928174832Sdesint 929117610Sdesvm_get_gpa_pmap(struct vmctx *ctx, uint64_t gpa, uint64_t *pte, int *num) 930228692Sdes{ 931117610Sdes int error, i; 932228692Sdes struct vm_gpa_pte gpapte; 933228692Sdes 934228692Sdes bzero(&gpapte, sizeof(gpapte)); 935228692Sdes gpapte.gpa = gpa; 936228692Sdes 937228692Sdes error = ioctl(ctx->fd, VM_GET_GPA_PMAP, &gpapte); 938228692Sdes 939228692Sdes if (error == 0) { 940228692Sdes *num = gpapte.ptenum; 941228692Sdes for (i = 0; i < gpapte.ptenum; i++) 942228692Sdes pte[i] = gpapte.pte[i]; 943228692Sdes } 944117610Sdes 945117610Sdes return (error); 946117610Sdes} 947117610Sdes 948117610Sdesint 949117610Sdesvm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) 950117610Sdes{ 951117610Sdes int error; 952117610Sdes struct vm_hpet_cap cap; 953117610Sdes 954117610Sdes bzero(&cap, sizeof(struct vm_hpet_cap)); 955117610Sdes error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap); 956117610Sdes if (capabilities != NULL) 957117610Sdes *capabilities = cap.capabilities; 958117610Sdes return (error); 959117610Sdes} 960117610Sdes 961117610Sdesstatic int 962117610Sdesgla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 963117610Sdes uint64_t gla, int prot, int *fault, uint64_t *gpa) 964117610Sdes{ 965117610Sdes struct vm_gla2gpa gg; 966117610Sdes int error; 967117610Sdes 968117610Sdes bzero(&gg, sizeof(struct vm_gla2gpa)); 969117610Sdes gg.vcpuid = vcpu; 970174832Sdes gg.prot = prot; 971174832Sdes gg.gla = gla; 972174832Sdes gg.paging = *paging; 973174832Sdes 974174832Sdes error = ioctl(ctx->fd, VM_GLA2GPA, &gg); 975174832Sdes if (error == 0) { 976117610Sdes *fault = gg.fault; 977117610Sdes *gpa = gg.gpa; 978117610Sdes } 979117610Sdes return (error); 980117610Sdes} 981117610Sdes 982117610Sdesint 983117610Sdesvm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 984117610Sdes uint64_t gla, int prot, uint64_t *gpa) 985117610Sdes{ 986117610Sdes int error, fault; 987117610Sdes 988117610Sdes error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, gpa); 989117610Sdes if (fault) 990117610Sdes error = fault; 991117610Sdes return (error); 992117610Sdes} 993117610Sdes 994117610Sdes#ifndef min 995117610Sdes#define min(a,b) (((a) < (b)) ? (a) : (b)) 996117610Sdes#endif 997117610Sdes 998117610Sdesint 999117610Sdesvm_copy_setup(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, 1000174832Sdes uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt) 1001174832Sdes{ 1002174832Sdes void *va; 1003174832Sdes uint64_t gpa; 1004174832Sdes int error, fault, i, n, off; 1005117610Sdes 1006174832Sdes for (i = 0; i < iovcnt; i++) { 1007117610Sdes iov[i].iov_base = 0; 1008117610Sdes iov[i].iov_len = 0; 1009174832Sdes } 1010117610Sdes 1011117610Sdes while (len) { 1012117610Sdes assert(iovcnt > 0); 1013117610Sdes error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, &gpa); 1014117610Sdes if (error) 1015117610Sdes return (-1); 1016117610Sdes if (fault) 1017117610Sdes return (1); 1018117610Sdes 1019117610Sdes off = gpa & PAGE_MASK; 1020117610Sdes n = min(len, PAGE_SIZE - off); 1021117610Sdes 1022117610Sdes va = vm_map_gpa(ctx, gpa, n); 1023117610Sdes if (va == NULL) 1024117610Sdes return (-1); 1025117610Sdes 1026117610Sdes iov->iov_base = va; 1027117610Sdes iov->iov_len = n; 1028117610Sdes iov++; 1029117610Sdes iovcnt--; 1030117610Sdes 1031117610Sdes gla += n; 1032117610Sdes len -= n; 1033117610Sdes } 1034117610Sdes return (0); 1035117610Sdes} 1036117610Sdes 1037117610Sdesvoid 1038117610Sdesvm_copy_teardown(struct vmctx *ctx, int vcpu, struct iovec *iov, int iovcnt) 1039117610Sdes{ 1040117610Sdes 1041117610Sdes return; 1042117610Sdes} 1043117610Sdes 1044117610Sdesvoid 1045117610Sdesvm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) 1046117610Sdes{ 1047117610Sdes const char *src; 1048117610Sdes char *dst; 1049117610Sdes size_t n; 1050117610Sdes 1051117610Sdes dst = vp; 1052117610Sdes while (len) { 1053117610Sdes assert(iov->iov_len); 1054117610Sdes n = min(len, iov->iov_len); 1055117610Sdes src = iov->iov_base; 1056117610Sdes bcopy(src, dst, n); 1057117610Sdes 1058117610Sdes iov++; 1059117610Sdes dst += n; 1060117610Sdes len -= n; 1061117610Sdes } 1062117610Sdes} 1063117610Sdes 1064117610Sdesvoid 1065117610Sdesvm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, 1066117610Sdes size_t len) 1067117610Sdes{ 1068117610Sdes const char *src; 1069117610Sdes char *dst; 1070117610Sdes size_t n; 1071117610Sdes 1072117610Sdes src = vp; 1073117610Sdes while (len) { 1074174832Sdes assert(iov->iov_len); 1075174832Sdes n = min(len, iov->iov_len); 1076174832Sdes dst = iov->iov_base; 1077174832Sdes bcopy(src, dst, n); 1078174832Sdes 1079174832Sdes iov++; 1080174832Sdes src += n; 1081174832Sdes len -= n; 1082174832Sdes } 1083174832Sdes} 1084117610Sdes 1085117610Sdesstatic int 1086117610Sdesvm_get_cpus(struct vmctx *ctx, int which, cpuset_t *cpus) 1087117610Sdes{ 1088117610Sdes struct vm_cpuset vm_cpuset; 1089117610Sdes int error; 1090117610Sdes 1091117610Sdes bzero(&vm_cpuset, sizeof(struct vm_cpuset)); 1092117610Sdes vm_cpuset.which = which; 1093117610Sdes vm_cpuset.cpusetsize = sizeof(cpuset_t); 1094117610Sdes vm_cpuset.cpus = cpus; 1095117610Sdes 1096117610Sdes error = ioctl(ctx->fd, VM_GET_CPUS, &vm_cpuset); 1097117610Sdes return (error); 1098117610Sdes} 1099117610Sdes 1100117610Sdesint 1101117610Sdesvm_active_cpus(struct vmctx *ctx, cpuset_t *cpus) 1102117610Sdes{ 1103117610Sdes 1104117610Sdes return (vm_get_cpus(ctx, VM_ACTIVE_CPUS, cpus)); 1105117610Sdes} 1106117610Sdes 1107117610Sdesint 1108117610Sdesvm_suspended_cpus(struct vmctx *ctx, cpuset_t *cpus) 1109117610Sdes{ 1110117610Sdes 1111117610Sdes return (vm_get_cpus(ctx, VM_SUSPENDED_CPUS, cpus)); 1112117610Sdes} 1113117610Sdes 1114117610Sdesint 1115117610Sdesvm_activate_cpu(struct vmctx *ctx, int vcpu) 1116117610Sdes{ 1117117610Sdes struct vm_activate_cpu ac; 1118117610Sdes int error; 1119117610Sdes 1120117610Sdes bzero(&ac, sizeof(struct vm_activate_cpu)); 1121117610Sdes ac.vcpuid = vcpu; 1122117610Sdes error = ioctl(ctx->fd, VM_ACTIVATE_CPU, &ac); 1123117610Sdes return (error); 1124117610Sdes} 1125117610Sdes 1126117610Sdesint 1127117610Sdesvm_get_intinfo(struct vmctx *ctx, int vcpu, uint64_t *info1, uint64_t *info2) 1128117610Sdes{ 1129117610Sdes struct vm_intinfo vmii; 1130117610Sdes int error; 1131117610Sdes 1132117610Sdes bzero(&vmii, sizeof(struct vm_intinfo)); 1133117610Sdes vmii.vcpuid = vcpu; 1134228692Sdes error = ioctl(ctx->fd, VM_GET_INTINFO, &vmii); 1135117610Sdes if (error == 0) { 1136228692Sdes *info1 = vmii.info1; 1137228692Sdes *info2 = vmii.info2; 1138228692Sdes } 1139228692Sdes return (error); 1140228692Sdes} 1141228692Sdes 1142228692Sdesint 1143228692Sdesvm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t info1) 1144228692Sdes{ 1145228692Sdes struct vm_intinfo vmii; 1146228692Sdes int error; 1147228692Sdes 1148117610Sdes bzero(&vmii, sizeof(struct vm_intinfo)); 1149117610Sdes vmii.vcpuid = vcpu; 1150228692Sdes vmii.info1 = info1; 1151117610Sdes error = ioctl(ctx->fd, VM_SET_INTINFO, &vmii); 1152228692Sdes return (error); 1153228692Sdes} 1154228692Sdes 1155228692Sdesint 1156228692Sdesvm_rtc_write(struct vmctx *ctx, int offset, uint8_t value) 1157228692Sdes{ 1158228692Sdes struct vm_rtc_data rtcdata; 1159228692Sdes int error; 1160228692Sdes 1161228692Sdes bzero(&rtcdata, sizeof(struct vm_rtc_data)); 1162228692Sdes rtcdata.offset = offset; 1163228692Sdes rtcdata.value = value; 1164117610Sdes error = ioctl(ctx->fd, VM_RTC_WRITE, &rtcdata); 1165117610Sdes return (error); 1166117610Sdes} 1167117610Sdes 1168117610Sdesint 1169117610Sdesvm_rtc_read(struct vmctx *ctx, int offset, uint8_t *retval) 1170117610Sdes{ 1171117610Sdes struct vm_rtc_data rtcdata; 1172117610Sdes int error; 1173117610Sdes 1174117610Sdes bzero(&rtcdata, sizeof(struct vm_rtc_data)); 1175117610Sdes rtcdata.offset = offset; 1176117610Sdes error = ioctl(ctx->fd, VM_RTC_READ, &rtcdata); 1177117610Sdes if (error == 0) 1178117610Sdes *retval = rtcdata.value; 1179117610Sdes return (error); 1180117610Sdes} 1181117610Sdes 1182117610Sdesint 1183228692Sdesvm_rtc_settime(struct vmctx *ctx, time_t secs) 1184228692Sdes{ 1185117610Sdes struct vm_rtc_time rtctime; 1186117610Sdes int error; 1187117610Sdes 1188117610Sdes bzero(&rtctime, sizeof(struct vm_rtc_time)); 1189117610Sdes rtctime.secs = secs; 1190228692Sdes error = ioctl(ctx->fd, VM_RTC_SETTIME, &rtctime); 1191228692Sdes return (error); 1192228692Sdes} 1193228692Sdes 1194174832Sdesint 1195117610Sdesvm_rtc_gettime(struct vmctx *ctx, time_t *secs) 1196117610Sdes{ 1197117610Sdes struct vm_rtc_time rtctime; 1198117610Sdes int error; 1199228692Sdes 1200117610Sdes bzero(&rtctime, sizeof(struct vm_rtc_time)); 1201228692Sdes error = ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime); 1202228692Sdes if (error == 0) 1203117610Sdes *secs = rtctime.secs; 1204117610Sdes return (error); 1205117610Sdes} 1206117610Sdes 1207117610Sdesint 1208117610Sdesvm_restart_instruction(void *arg, int vcpu) 1209117610Sdes{ 1210228692Sdes struct vmctx *ctx = arg; 1211117610Sdes 1212117610Sdes return (ioctl(ctx->fd, VM_RESTART_INSTRUCTION, &vcpu)); 1213228692Sdes} 1214228692Sdes