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$ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/sysctl.h> 37#include <sys/malloc.h> 38#include <sys/pcpu.h> 39#include <sys/lock.h> 40#include <sys/mutex.h> 41#include <sys/proc.h> 42#include <sys/sched.h> 43#include <sys/smp.h> 44#include <sys/systm.h> 45 46#include <vm/vm.h> 47 48#include <machine/vm.h> 49#include <machine/pcb.h> 50#include <machine/smp.h> 51#include <x86/apicreg.h> 52 53#include <machine/vmm.h> 54#include "vmm_mem.h" 55#include "vmm_util.h" 56#include <machine/vmm_dev.h> 57#include "vlapic.h" 58#include "vmm_msr.h" 59#include "vmm_ipi.h" 60#include "vmm_stat.h" 61 62#include "io/ppt.h" 63#include "io/iommu.h" 64 65struct vlapic; 66 67struct vcpu { 68 int flags; 69 enum vcpu_state state; 70 struct mtx mtx; 71 int pincpu; /* host cpuid this vcpu is bound to */ 72 int hostcpu; /* host cpuid this vcpu last ran on */ 73 uint64_t guest_msrs[VMM_MSR_NUM]; 74 struct vlapic *vlapic; 75 int vcpuid; 76 struct savefpu *guestfpu; /* guest fpu state */ 77 void *stats; 78 struct vm_exit exitinfo; 79 enum x2apic_state x2apic_state;
| 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$ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/sysctl.h> 37#include <sys/malloc.h> 38#include <sys/pcpu.h> 39#include <sys/lock.h> 40#include <sys/mutex.h> 41#include <sys/proc.h> 42#include <sys/sched.h> 43#include <sys/smp.h> 44#include <sys/systm.h> 45 46#include <vm/vm.h> 47 48#include <machine/vm.h> 49#include <machine/pcb.h> 50#include <machine/smp.h> 51#include <x86/apicreg.h> 52 53#include <machine/vmm.h> 54#include "vmm_mem.h" 55#include "vmm_util.h" 56#include <machine/vmm_dev.h> 57#include "vlapic.h" 58#include "vmm_msr.h" 59#include "vmm_ipi.h" 60#include "vmm_stat.h" 61 62#include "io/ppt.h" 63#include "io/iommu.h" 64 65struct vlapic; 66 67struct vcpu { 68 int flags; 69 enum vcpu_state state; 70 struct mtx mtx; 71 int pincpu; /* host cpuid this vcpu is bound to */ 72 int hostcpu; /* host cpuid this vcpu last ran on */ 73 uint64_t guest_msrs[VMM_MSR_NUM]; 74 struct vlapic *vlapic; 75 int vcpuid; 76 struct savefpu *guestfpu; /* guest fpu state */ 77 void *stats; 78 struct vm_exit exitinfo; 79 enum x2apic_state x2apic_state;
|
| 80 int nmi_pending;
|
80}; 81#define VCPU_F_PINNED 0x0001 82 83#define VCPU_PINCPU(vm, vcpuid) \ 84 ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1) 85 86#define VCPU_UNPIN(vm, vcpuid) (vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED) 87 88#define VCPU_PIN(vm, vcpuid, host_cpuid) \ 89do { \ 90 vm->vcpu[vcpuid].flags |= VCPU_F_PINNED; \ 91 vm->vcpu[vcpuid].pincpu = host_cpuid; \ 92} while(0) 93 94#define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_DEF) 95#define vcpu_lock(v) mtx_lock(&((v)->mtx)) 96#define vcpu_unlock(v) mtx_unlock(&((v)->mtx)) 97 98#define VM_MAX_MEMORY_SEGMENTS 2 99 100struct vm { 101 void *cookie; /* processor-specific data */ 102 void *iommu; /* iommu-specific data */ 103 struct vcpu vcpu[VM_MAXCPU]; 104 int num_mem_segs; 105 struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; 106 char name[VM_MAX_NAMELEN]; 107 108 /* 109 * Set of active vcpus. 110 * An active vcpu is one that has been started implicitly (BSP) or 111 * explicitly (AP) by sending it a startup ipi. 112 */ 113 cpuset_t active_cpus; 114}; 115 116static struct vmm_ops *ops; 117#define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 118#define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 119 120#define VMINIT(vm) (ops != NULL ? (*ops->vminit)(vm): NULL) 121#define VMRUN(vmi, vcpu, rip) \ 122 (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip) : ENXIO) 123#define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 124#define VMMMAP_SET(vmi, gpa, hpa, len, attr, prot, spm) \ 125 (ops != NULL ? \ 126 (*ops->vmmmap_set)(vmi, gpa, hpa, len, attr, prot, spm) : \ 127 ENXIO) 128#define VMMMAP_GET(vmi, gpa) \ 129 (ops != NULL ? (*ops->vmmmap_get)(vmi, gpa) : ENXIO) 130#define VMGETREG(vmi, vcpu, num, retval) \ 131 (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 132#define VMSETREG(vmi, vcpu, num, val) \ 133 (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 134#define VMGETDESC(vmi, vcpu, num, desc) \ 135 (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 136#define VMSETDESC(vmi, vcpu, num, desc) \ 137 (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 138#define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 139 (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO)
| 81}; 82#define VCPU_F_PINNED 0x0001 83 84#define VCPU_PINCPU(vm, vcpuid) \ 85 ((vm->vcpu[vcpuid].flags & VCPU_F_PINNED) ? vm->vcpu[vcpuid].pincpu : -1) 86 87#define VCPU_UNPIN(vm, vcpuid) (vm->vcpu[vcpuid].flags &= ~VCPU_F_PINNED) 88 89#define VCPU_PIN(vm, vcpuid, host_cpuid) \ 90do { \ 91 vm->vcpu[vcpuid].flags |= VCPU_F_PINNED; \ 92 vm->vcpu[vcpuid].pincpu = host_cpuid; \ 93} while(0) 94 95#define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_DEF) 96#define vcpu_lock(v) mtx_lock(&((v)->mtx)) 97#define vcpu_unlock(v) mtx_unlock(&((v)->mtx)) 98 99#define VM_MAX_MEMORY_SEGMENTS 2 100 101struct vm { 102 void *cookie; /* processor-specific data */ 103 void *iommu; /* iommu-specific data */ 104 struct vcpu vcpu[VM_MAXCPU]; 105 int num_mem_segs; 106 struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; 107 char name[VM_MAX_NAMELEN]; 108 109 /* 110 * Set of active vcpus. 111 * An active vcpu is one that has been started implicitly (BSP) or 112 * explicitly (AP) by sending it a startup ipi. 113 */ 114 cpuset_t active_cpus; 115}; 116 117static struct vmm_ops *ops; 118#define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) 119#define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) 120 121#define VMINIT(vm) (ops != NULL ? (*ops->vminit)(vm): NULL) 122#define VMRUN(vmi, vcpu, rip) \ 123 (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip) : ENXIO) 124#define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) 125#define VMMMAP_SET(vmi, gpa, hpa, len, attr, prot, spm) \ 126 (ops != NULL ? \ 127 (*ops->vmmmap_set)(vmi, gpa, hpa, len, attr, prot, spm) : \ 128 ENXIO) 129#define VMMMAP_GET(vmi, gpa) \ 130 (ops != NULL ? (*ops->vmmmap_get)(vmi, gpa) : ENXIO) 131#define VMGETREG(vmi, vcpu, num, retval) \ 132 (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) 133#define VMSETREG(vmi, vcpu, num, val) \ 134 (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) 135#define VMGETDESC(vmi, vcpu, num, desc) \ 136 (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) 137#define VMSETDESC(vmi, vcpu, num, desc) \ 138 (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) 139#define VMINJECT(vmi, vcpu, type, vec, ec, ecv) \ 140 (ops != NULL ? (*ops->vminject)(vmi, vcpu, type, vec, ec, ecv) : ENXIO)
|
140#define VMNMI(vmi, vcpu) \ 141 (ops != NULL ? (*ops->vmnmi)(vmi, vcpu) : ENXIO)
| |
142#define VMGETCAP(vmi, vcpu, num, retval) \ 143 (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 144#define VMSETCAP(vmi, vcpu, num, val) \ 145 (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 146 147#define fpu_start_emulating() start_emulating() 148#define fpu_stop_emulating() stop_emulating() 149 150static MALLOC_DEFINE(M_VM, "vm", "vm"); 151CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 152 153/* statistics */ 154static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 155 156static void 157vcpu_cleanup(struct vcpu *vcpu) 158{ 159 vlapic_cleanup(vcpu->vlapic); 160 vmm_stat_free(vcpu->stats); 161 fpu_save_area_free(vcpu->guestfpu); 162} 163 164static void 165vcpu_init(struct vm *vm, uint32_t vcpu_id) 166{ 167 struct vcpu *vcpu; 168 169 vcpu = &vm->vcpu[vcpu_id]; 170 171 vcpu_lock_init(vcpu); 172 vcpu->hostcpu = NOCPU; 173 vcpu->vcpuid = vcpu_id; 174 vcpu->vlapic = vlapic_init(vm, vcpu_id); 175 vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 176 vcpu->guestfpu = fpu_save_area_alloc(); 177 fpu_save_area_reset(vcpu->guestfpu); 178 vcpu->stats = vmm_stat_alloc(); 179} 180 181struct vm_exit * 182vm_exitinfo(struct vm *vm, int cpuid) 183{ 184 struct vcpu *vcpu; 185 186 if (cpuid < 0 || cpuid >= VM_MAXCPU) 187 panic("vm_exitinfo: invalid cpuid %d", cpuid); 188 189 vcpu = &vm->vcpu[cpuid]; 190 191 return (&vcpu->exitinfo); 192} 193 194static int 195vmm_init(void) 196{ 197 int error; 198 199 vmm_ipi_init(); 200 201 error = vmm_mem_init(); 202 if (error) 203 return (error); 204 205 if (vmm_is_intel()) 206 ops = &vmm_ops_intel; 207 else if (vmm_is_amd()) 208 ops = &vmm_ops_amd; 209 else 210 return (ENXIO); 211 212 vmm_msr_init(); 213 214 return (VMM_INIT()); 215} 216 217static int 218vmm_handler(module_t mod, int what, void *arg) 219{ 220 int error; 221 222 switch (what) { 223 case MOD_LOAD: 224 vmmdev_init(); 225 iommu_init(); 226 error = vmm_init(); 227 break; 228 case MOD_UNLOAD: 229 error = vmmdev_cleanup(); 230 if (error == 0) { 231 iommu_cleanup(); 232 vmm_ipi_cleanup(); 233 error = VMM_CLEANUP(); 234 } 235 break; 236 default: 237 error = 0; 238 break; 239 } 240 return (error); 241} 242 243static moduledata_t vmm_kmod = { 244 "vmm", 245 vmm_handler, 246 NULL 247}; 248 249/* 250 * Execute the module load handler after the pci passthru driver has had 251 * a chance to claim devices. We need this information at the time we do 252 * iommu initialization. 253 */ 254DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY); 255MODULE_VERSION(vmm, 1); 256 257SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 258 259struct vm * 260vm_create(const char *name) 261{ 262 int i; 263 struct vm *vm; 264 vm_paddr_t maxaddr; 265 266 const int BSP = 0; 267 268 if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 269 return (NULL); 270 271 vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 272 strcpy(vm->name, name); 273 vm->cookie = VMINIT(vm); 274 275 for (i = 0; i < VM_MAXCPU; i++) { 276 vcpu_init(vm, i); 277 guest_msrs_init(vm, i); 278 } 279 280 maxaddr = vmm_mem_maxaddr(); 281 vm->iommu = iommu_create_domain(maxaddr); 282 vm_activate_cpu(vm, BSP); 283 284 return (vm); 285} 286 287static void 288vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg) 289{ 290 size_t len; 291 vm_paddr_t hpa; 292 void *host_domain; 293 294 host_domain = iommu_host_domain(); 295 296 len = 0; 297 while (len < seg->len) { 298 hpa = vm_gpa2hpa(vm, seg->gpa + len, PAGE_SIZE); 299 if (hpa == (vm_paddr_t)-1) { 300 panic("vm_free_mem_segs: cannot free hpa " 301 "associated with gpa 0x%016lx", seg->gpa + len); 302 } 303 304 /* 305 * Remove the 'gpa' to 'hpa' mapping in VMs domain. 306 * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'. 307 */ 308 iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE); 309 iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE); 310 311 vmm_mem_free(hpa, PAGE_SIZE); 312 313 len += PAGE_SIZE; 314 } 315 316 /* 317 * Invalidate cached translations associated with 'vm->iommu' since 318 * we have now moved some pages from it. 319 */ 320 iommu_invalidate_tlb(vm->iommu); 321 322 bzero(seg, sizeof(struct vm_memory_segment)); 323} 324 325void 326vm_destroy(struct vm *vm) 327{ 328 int i; 329 330 ppt_unassign_all(vm); 331 332 for (i = 0; i < vm->num_mem_segs; i++) 333 vm_free_mem_seg(vm, &vm->mem_segs[i]); 334 335 vm->num_mem_segs = 0; 336 337 for (i = 0; i < VM_MAXCPU; i++) 338 vcpu_cleanup(&vm->vcpu[i]); 339 340 iommu_destroy_domain(vm->iommu); 341 342 VMCLEANUP(vm->cookie); 343 344 free(vm, M_VM); 345} 346 347const char * 348vm_name(struct vm *vm) 349{ 350 return (vm->name); 351} 352 353int 354vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 355{ 356 const boolean_t spok = TRUE; /* superpage mappings are ok */ 357 358 return (VMMMAP_SET(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE, 359 VM_PROT_RW, spok)); 360} 361 362int 363vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 364{ 365 const boolean_t spok = TRUE; /* superpage mappings are ok */ 366 367 return (VMMMAP_SET(vm->cookie, gpa, 0, len, 0, 368 VM_PROT_NONE, spok)); 369} 370 371/* 372 * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise 373 */ 374static boolean_t 375vm_gpa_available(struct vm *vm, vm_paddr_t gpa) 376{ 377 int i; 378 vm_paddr_t gpabase, gpalimit; 379 380 if (gpa & PAGE_MASK) 381 panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa); 382 383 for (i = 0; i < vm->num_mem_segs; i++) { 384 gpabase = vm->mem_segs[i].gpa; 385 gpalimit = gpabase + vm->mem_segs[i].len; 386 if (gpa >= gpabase && gpa < gpalimit) 387 return (FALSE); 388 } 389 390 return (TRUE); 391} 392 393int 394vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 395{ 396 int error, available, allocated; 397 struct vm_memory_segment *seg; 398 vm_paddr_t g, hpa; 399 void *host_domain; 400 401 const boolean_t spok = TRUE; /* superpage mappings are ok */ 402 403 if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 404 return (EINVAL); 405 406 available = allocated = 0; 407 g = gpa; 408 while (g < gpa + len) { 409 if (vm_gpa_available(vm, g)) 410 available++; 411 else 412 allocated++; 413 414 g += PAGE_SIZE; 415 } 416 417 /* 418 * If there are some allocated and some available pages in the address 419 * range then it is an error. 420 */ 421 if (allocated && available) 422 return (EINVAL); 423 424 /* 425 * If the entire address range being requested has already been 426 * allocated then there isn't anything more to do. 427 */ 428 if (allocated && available == 0) 429 return (0); 430 431 if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 432 return (E2BIG); 433 434 host_domain = iommu_host_domain(); 435 436 seg = &vm->mem_segs[vm->num_mem_segs]; 437 438 error = 0; 439 seg->gpa = gpa; 440 seg->len = 0; 441 while (seg->len < len) { 442 hpa = vmm_mem_alloc(PAGE_SIZE); 443 if (hpa == 0) { 444 error = ENOMEM; 445 break; 446 } 447 448 error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE, 449 VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok); 450 if (error) 451 break; 452 453 /* 454 * Remove the 1:1 mapping for 'hpa' from the 'host_domain'. 455 * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain. 456 */ 457 iommu_remove_mapping(host_domain, hpa, PAGE_SIZE); 458 iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE); 459 460 seg->len += PAGE_SIZE; 461 } 462 463 if (error) { 464 vm_free_mem_seg(vm, seg); 465 return (error); 466 } 467 468 /* 469 * Invalidate cached translations associated with 'host_domain' since 470 * we have now moved some pages from it. 471 */ 472 iommu_invalidate_tlb(host_domain); 473 474 vm->num_mem_segs++; 475 476 return (0); 477} 478 479vm_paddr_t 480vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len) 481{ 482 vm_paddr_t nextpage; 483 484 nextpage = rounddown(gpa + PAGE_SIZE, PAGE_SIZE); 485 if (len > nextpage - gpa) 486 panic("vm_gpa2hpa: invalid gpa/len: 0x%016lx/%lu", gpa, len); 487 488 return (VMMMAP_GET(vm->cookie, gpa)); 489} 490 491int 492vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 493 struct vm_memory_segment *seg) 494{ 495 int i; 496 497 for (i = 0; i < vm->num_mem_segs; i++) { 498 if (gpabase == vm->mem_segs[i].gpa) { 499 *seg = vm->mem_segs[i]; 500 return (0); 501 } 502 } 503 return (-1); 504} 505 506int 507vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 508{ 509 510 if (vcpu < 0 || vcpu >= VM_MAXCPU) 511 return (EINVAL); 512 513 if (reg >= VM_REG_LAST) 514 return (EINVAL); 515 516 return (VMGETREG(vm->cookie, vcpu, reg, retval)); 517} 518 519int 520vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 521{ 522 523 if (vcpu < 0 || vcpu >= VM_MAXCPU) 524 return (EINVAL); 525 526 if (reg >= VM_REG_LAST) 527 return (EINVAL); 528 529 return (VMSETREG(vm->cookie, vcpu, reg, val)); 530} 531 532static boolean_t 533is_descriptor_table(int reg) 534{ 535 536 switch (reg) { 537 case VM_REG_GUEST_IDTR: 538 case VM_REG_GUEST_GDTR: 539 return (TRUE); 540 default: 541 return (FALSE); 542 } 543} 544 545static boolean_t 546is_segment_register(int reg) 547{ 548 549 switch (reg) { 550 case VM_REG_GUEST_ES: 551 case VM_REG_GUEST_CS: 552 case VM_REG_GUEST_SS: 553 case VM_REG_GUEST_DS: 554 case VM_REG_GUEST_FS: 555 case VM_REG_GUEST_GS: 556 case VM_REG_GUEST_TR: 557 case VM_REG_GUEST_LDTR: 558 return (TRUE); 559 default: 560 return (FALSE); 561 } 562} 563 564int 565vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 566 struct seg_desc *desc) 567{ 568 569 if (vcpu < 0 || vcpu >= VM_MAXCPU) 570 return (EINVAL); 571 572 if (!is_segment_register(reg) && !is_descriptor_table(reg)) 573 return (EINVAL); 574 575 return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 576} 577 578int 579vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 580 struct seg_desc *desc) 581{ 582 if (vcpu < 0 || vcpu >= VM_MAXCPU) 583 return (EINVAL); 584 585 if (!is_segment_register(reg) && !is_descriptor_table(reg)) 586 return (EINVAL); 587 588 return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 589} 590 591int 592vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid) 593{ 594 595 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 596 return (EINVAL); 597 598 *cpuid = VCPU_PINCPU(vm, vcpuid); 599 600 return (0); 601} 602 603int 604vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid) 605{ 606 struct thread *td; 607 608 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 609 return (EINVAL); 610 611 td = curthread; /* XXXSMP only safe when muxing vcpus */ 612 613 /* unpin */ 614 if (host_cpuid < 0) { 615 VCPU_UNPIN(vm, vcpuid); 616 thread_lock(td); 617 sched_unbind(td); 618 thread_unlock(td); 619 return (0); 620 } 621 622 if (CPU_ABSENT(host_cpuid)) 623 return (EINVAL); 624 625 /* 626 * XXX we should check that 'host_cpuid' has not already been pinned 627 * by another vm. 628 */ 629 thread_lock(td); 630 sched_bind(td, host_cpuid); 631 thread_unlock(td); 632 VCPU_PIN(vm, vcpuid, host_cpuid); 633 634 return (0); 635} 636 637static void 638restore_guest_fpustate(struct vcpu *vcpu) 639{ 640 641 /* flush host state to the pcb */ 642 fpuexit(curthread); 643 fpu_stop_emulating(); 644 fpurestore(vcpu->guestfpu); 645} 646 647static void 648save_guest_fpustate(struct vcpu *vcpu) 649{ 650 651 fpusave(vcpu->guestfpu); 652 fpu_start_emulating(); 653} 654 655int 656vm_run(struct vm *vm, struct vm_run *vmrun) 657{ 658 int error, vcpuid; 659 struct vcpu *vcpu; 660 struct pcb *pcb; 661 uint64_t tscval; 662 663 vcpuid = vmrun->cpuid; 664 665 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 666 return (EINVAL); 667 668 vcpu = &vm->vcpu[vcpuid]; 669 670 critical_enter(); 671 672 tscval = rdtsc(); 673 674 pcb = PCPU_GET(curpcb); 675 set_pcb_flags(pcb, PCB_FULL_IRET); 676 677 restore_guest_msrs(vm, vcpuid); 678 restore_guest_fpustate(vcpu); 679 680 vcpu->hostcpu = curcpu; 681 error = VMRUN(vm->cookie, vcpuid, vmrun->rip); 682 vcpu->hostcpu = NOCPU; 683 684 save_guest_fpustate(vcpu); 685 restore_host_msrs(vm, vcpuid); 686 687 vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 688 689 /* copy the exit information */ 690 bcopy(&vcpu->exitinfo, &vmrun->vm_exit, sizeof(struct vm_exit)); 691 692 critical_exit(); 693 694 return (error); 695} 696 697int 698vm_inject_event(struct vm *vm, int vcpuid, int type, 699 int vector, uint32_t code, int code_valid) 700{ 701 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 702 return (EINVAL); 703 704 if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 705 return (EINVAL); 706 707 if (vector < 0 || vector > 255) 708 return (EINVAL); 709 710 return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 711} 712
| 141#define VMGETCAP(vmi, vcpu, num, retval) \ 142 (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) 143#define VMSETCAP(vmi, vcpu, num, val) \ 144 (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) 145 146#define fpu_start_emulating() start_emulating() 147#define fpu_stop_emulating() stop_emulating() 148 149static MALLOC_DEFINE(M_VM, "vm", "vm"); 150CTASSERT(VMM_MSR_NUM <= 64); /* msr_mask can keep track of up to 64 msrs */ 151 152/* statistics */ 153static VMM_STAT_DEFINE(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); 154 155static void 156vcpu_cleanup(struct vcpu *vcpu) 157{ 158 vlapic_cleanup(vcpu->vlapic); 159 vmm_stat_free(vcpu->stats); 160 fpu_save_area_free(vcpu->guestfpu); 161} 162 163static void 164vcpu_init(struct vm *vm, uint32_t vcpu_id) 165{ 166 struct vcpu *vcpu; 167 168 vcpu = &vm->vcpu[vcpu_id]; 169 170 vcpu_lock_init(vcpu); 171 vcpu->hostcpu = NOCPU; 172 vcpu->vcpuid = vcpu_id; 173 vcpu->vlapic = vlapic_init(vm, vcpu_id); 174 vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); 175 vcpu->guestfpu = fpu_save_area_alloc(); 176 fpu_save_area_reset(vcpu->guestfpu); 177 vcpu->stats = vmm_stat_alloc(); 178} 179 180struct vm_exit * 181vm_exitinfo(struct vm *vm, int cpuid) 182{ 183 struct vcpu *vcpu; 184 185 if (cpuid < 0 || cpuid >= VM_MAXCPU) 186 panic("vm_exitinfo: invalid cpuid %d", cpuid); 187 188 vcpu = &vm->vcpu[cpuid]; 189 190 return (&vcpu->exitinfo); 191} 192 193static int 194vmm_init(void) 195{ 196 int error; 197 198 vmm_ipi_init(); 199 200 error = vmm_mem_init(); 201 if (error) 202 return (error); 203 204 if (vmm_is_intel()) 205 ops = &vmm_ops_intel; 206 else if (vmm_is_amd()) 207 ops = &vmm_ops_amd; 208 else 209 return (ENXIO); 210 211 vmm_msr_init(); 212 213 return (VMM_INIT()); 214} 215 216static int 217vmm_handler(module_t mod, int what, void *arg) 218{ 219 int error; 220 221 switch (what) { 222 case MOD_LOAD: 223 vmmdev_init(); 224 iommu_init(); 225 error = vmm_init(); 226 break; 227 case MOD_UNLOAD: 228 error = vmmdev_cleanup(); 229 if (error == 0) { 230 iommu_cleanup(); 231 vmm_ipi_cleanup(); 232 error = VMM_CLEANUP(); 233 } 234 break; 235 default: 236 error = 0; 237 break; 238 } 239 return (error); 240} 241 242static moduledata_t vmm_kmod = { 243 "vmm", 244 vmm_handler, 245 NULL 246}; 247 248/* 249 * Execute the module load handler after the pci passthru driver has had 250 * a chance to claim devices. We need this information at the time we do 251 * iommu initialization. 252 */ 253DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_CONFIGURE + 1, SI_ORDER_ANY); 254MODULE_VERSION(vmm, 1); 255 256SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); 257 258struct vm * 259vm_create(const char *name) 260{ 261 int i; 262 struct vm *vm; 263 vm_paddr_t maxaddr; 264 265 const int BSP = 0; 266 267 if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) 268 return (NULL); 269 270 vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO); 271 strcpy(vm->name, name); 272 vm->cookie = VMINIT(vm); 273 274 for (i = 0; i < VM_MAXCPU; i++) { 275 vcpu_init(vm, i); 276 guest_msrs_init(vm, i); 277 } 278 279 maxaddr = vmm_mem_maxaddr(); 280 vm->iommu = iommu_create_domain(maxaddr); 281 vm_activate_cpu(vm, BSP); 282 283 return (vm); 284} 285 286static void 287vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg) 288{ 289 size_t len; 290 vm_paddr_t hpa; 291 void *host_domain; 292 293 host_domain = iommu_host_domain(); 294 295 len = 0; 296 while (len < seg->len) { 297 hpa = vm_gpa2hpa(vm, seg->gpa + len, PAGE_SIZE); 298 if (hpa == (vm_paddr_t)-1) { 299 panic("vm_free_mem_segs: cannot free hpa " 300 "associated with gpa 0x%016lx", seg->gpa + len); 301 } 302 303 /* 304 * Remove the 'gpa' to 'hpa' mapping in VMs domain. 305 * And resurrect the 1:1 mapping for 'hpa' in 'host_domain'. 306 */ 307 iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE); 308 iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE); 309 310 vmm_mem_free(hpa, PAGE_SIZE); 311 312 len += PAGE_SIZE; 313 } 314 315 /* 316 * Invalidate cached translations associated with 'vm->iommu' since 317 * we have now moved some pages from it. 318 */ 319 iommu_invalidate_tlb(vm->iommu); 320 321 bzero(seg, sizeof(struct vm_memory_segment)); 322} 323 324void 325vm_destroy(struct vm *vm) 326{ 327 int i; 328 329 ppt_unassign_all(vm); 330 331 for (i = 0; i < vm->num_mem_segs; i++) 332 vm_free_mem_seg(vm, &vm->mem_segs[i]); 333 334 vm->num_mem_segs = 0; 335 336 for (i = 0; i < VM_MAXCPU; i++) 337 vcpu_cleanup(&vm->vcpu[i]); 338 339 iommu_destroy_domain(vm->iommu); 340 341 VMCLEANUP(vm->cookie); 342 343 free(vm, M_VM); 344} 345 346const char * 347vm_name(struct vm *vm) 348{ 349 return (vm->name); 350} 351 352int 353vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) 354{ 355 const boolean_t spok = TRUE; /* superpage mappings are ok */ 356 357 return (VMMMAP_SET(vm->cookie, gpa, hpa, len, VM_MEMATTR_UNCACHEABLE, 358 VM_PROT_RW, spok)); 359} 360 361int 362vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len) 363{ 364 const boolean_t spok = TRUE; /* superpage mappings are ok */ 365 366 return (VMMMAP_SET(vm->cookie, gpa, 0, len, 0, 367 VM_PROT_NONE, spok)); 368} 369 370/* 371 * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise 372 */ 373static boolean_t 374vm_gpa_available(struct vm *vm, vm_paddr_t gpa) 375{ 376 int i; 377 vm_paddr_t gpabase, gpalimit; 378 379 if (gpa & PAGE_MASK) 380 panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa); 381 382 for (i = 0; i < vm->num_mem_segs; i++) { 383 gpabase = vm->mem_segs[i].gpa; 384 gpalimit = gpabase + vm->mem_segs[i].len; 385 if (gpa >= gpabase && gpa < gpalimit) 386 return (FALSE); 387 } 388 389 return (TRUE); 390} 391 392int 393vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) 394{ 395 int error, available, allocated; 396 struct vm_memory_segment *seg; 397 vm_paddr_t g, hpa; 398 void *host_domain; 399 400 const boolean_t spok = TRUE; /* superpage mappings are ok */ 401 402 if ((gpa & PAGE_MASK) || (len & PAGE_MASK) || len == 0) 403 return (EINVAL); 404 405 available = allocated = 0; 406 g = gpa; 407 while (g < gpa + len) { 408 if (vm_gpa_available(vm, g)) 409 available++; 410 else 411 allocated++; 412 413 g += PAGE_SIZE; 414 } 415 416 /* 417 * If there are some allocated and some available pages in the address 418 * range then it is an error. 419 */ 420 if (allocated && available) 421 return (EINVAL); 422 423 /* 424 * If the entire address range being requested has already been 425 * allocated then there isn't anything more to do. 426 */ 427 if (allocated && available == 0) 428 return (0); 429 430 if (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS) 431 return (E2BIG); 432 433 host_domain = iommu_host_domain(); 434 435 seg = &vm->mem_segs[vm->num_mem_segs]; 436 437 error = 0; 438 seg->gpa = gpa; 439 seg->len = 0; 440 while (seg->len < len) { 441 hpa = vmm_mem_alloc(PAGE_SIZE); 442 if (hpa == 0) { 443 error = ENOMEM; 444 break; 445 } 446 447 error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE, 448 VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok); 449 if (error) 450 break; 451 452 /* 453 * Remove the 1:1 mapping for 'hpa' from the 'host_domain'. 454 * Add mapping for 'gpa + seg->len' to 'hpa' in the VMs domain. 455 */ 456 iommu_remove_mapping(host_domain, hpa, PAGE_SIZE); 457 iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE); 458 459 seg->len += PAGE_SIZE; 460 } 461 462 if (error) { 463 vm_free_mem_seg(vm, seg); 464 return (error); 465 } 466 467 /* 468 * Invalidate cached translations associated with 'host_domain' since 469 * we have now moved some pages from it. 470 */ 471 iommu_invalidate_tlb(host_domain); 472 473 vm->num_mem_segs++; 474 475 return (0); 476} 477 478vm_paddr_t 479vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t len) 480{ 481 vm_paddr_t nextpage; 482 483 nextpage = rounddown(gpa + PAGE_SIZE, PAGE_SIZE); 484 if (len > nextpage - gpa) 485 panic("vm_gpa2hpa: invalid gpa/len: 0x%016lx/%lu", gpa, len); 486 487 return (VMMMAP_GET(vm->cookie, gpa)); 488} 489 490int 491vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, 492 struct vm_memory_segment *seg) 493{ 494 int i; 495 496 for (i = 0; i < vm->num_mem_segs; i++) { 497 if (gpabase == vm->mem_segs[i].gpa) { 498 *seg = vm->mem_segs[i]; 499 return (0); 500 } 501 } 502 return (-1); 503} 504 505int 506vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) 507{ 508 509 if (vcpu < 0 || vcpu >= VM_MAXCPU) 510 return (EINVAL); 511 512 if (reg >= VM_REG_LAST) 513 return (EINVAL); 514 515 return (VMGETREG(vm->cookie, vcpu, reg, retval)); 516} 517 518int 519vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val) 520{ 521 522 if (vcpu < 0 || vcpu >= VM_MAXCPU) 523 return (EINVAL); 524 525 if (reg >= VM_REG_LAST) 526 return (EINVAL); 527 528 return (VMSETREG(vm->cookie, vcpu, reg, val)); 529} 530 531static boolean_t 532is_descriptor_table(int reg) 533{ 534 535 switch (reg) { 536 case VM_REG_GUEST_IDTR: 537 case VM_REG_GUEST_GDTR: 538 return (TRUE); 539 default: 540 return (FALSE); 541 } 542} 543 544static boolean_t 545is_segment_register(int reg) 546{ 547 548 switch (reg) { 549 case VM_REG_GUEST_ES: 550 case VM_REG_GUEST_CS: 551 case VM_REG_GUEST_SS: 552 case VM_REG_GUEST_DS: 553 case VM_REG_GUEST_FS: 554 case VM_REG_GUEST_GS: 555 case VM_REG_GUEST_TR: 556 case VM_REG_GUEST_LDTR: 557 return (TRUE); 558 default: 559 return (FALSE); 560 } 561} 562 563int 564vm_get_seg_desc(struct vm *vm, int vcpu, int reg, 565 struct seg_desc *desc) 566{ 567 568 if (vcpu < 0 || vcpu >= VM_MAXCPU) 569 return (EINVAL); 570 571 if (!is_segment_register(reg) && !is_descriptor_table(reg)) 572 return (EINVAL); 573 574 return (VMGETDESC(vm->cookie, vcpu, reg, desc)); 575} 576 577int 578vm_set_seg_desc(struct vm *vm, int vcpu, int reg, 579 struct seg_desc *desc) 580{ 581 if (vcpu < 0 || vcpu >= VM_MAXCPU) 582 return (EINVAL); 583 584 if (!is_segment_register(reg) && !is_descriptor_table(reg)) 585 return (EINVAL); 586 587 return (VMSETDESC(vm->cookie, vcpu, reg, desc)); 588} 589 590int 591vm_get_pinning(struct vm *vm, int vcpuid, int *cpuid) 592{ 593 594 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 595 return (EINVAL); 596 597 *cpuid = VCPU_PINCPU(vm, vcpuid); 598 599 return (0); 600} 601 602int 603vm_set_pinning(struct vm *vm, int vcpuid, int host_cpuid) 604{ 605 struct thread *td; 606 607 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 608 return (EINVAL); 609 610 td = curthread; /* XXXSMP only safe when muxing vcpus */ 611 612 /* unpin */ 613 if (host_cpuid < 0) { 614 VCPU_UNPIN(vm, vcpuid); 615 thread_lock(td); 616 sched_unbind(td); 617 thread_unlock(td); 618 return (0); 619 } 620 621 if (CPU_ABSENT(host_cpuid)) 622 return (EINVAL); 623 624 /* 625 * XXX we should check that 'host_cpuid' has not already been pinned 626 * by another vm. 627 */ 628 thread_lock(td); 629 sched_bind(td, host_cpuid); 630 thread_unlock(td); 631 VCPU_PIN(vm, vcpuid, host_cpuid); 632 633 return (0); 634} 635 636static void 637restore_guest_fpustate(struct vcpu *vcpu) 638{ 639 640 /* flush host state to the pcb */ 641 fpuexit(curthread); 642 fpu_stop_emulating(); 643 fpurestore(vcpu->guestfpu); 644} 645 646static void 647save_guest_fpustate(struct vcpu *vcpu) 648{ 649 650 fpusave(vcpu->guestfpu); 651 fpu_start_emulating(); 652} 653 654int 655vm_run(struct vm *vm, struct vm_run *vmrun) 656{ 657 int error, vcpuid; 658 struct vcpu *vcpu; 659 struct pcb *pcb; 660 uint64_t tscval; 661 662 vcpuid = vmrun->cpuid; 663 664 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 665 return (EINVAL); 666 667 vcpu = &vm->vcpu[vcpuid]; 668 669 critical_enter(); 670 671 tscval = rdtsc(); 672 673 pcb = PCPU_GET(curpcb); 674 set_pcb_flags(pcb, PCB_FULL_IRET); 675 676 restore_guest_msrs(vm, vcpuid); 677 restore_guest_fpustate(vcpu); 678 679 vcpu->hostcpu = curcpu; 680 error = VMRUN(vm->cookie, vcpuid, vmrun->rip); 681 vcpu->hostcpu = NOCPU; 682 683 save_guest_fpustate(vcpu); 684 restore_host_msrs(vm, vcpuid); 685 686 vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); 687 688 /* copy the exit information */ 689 bcopy(&vcpu->exitinfo, &vmrun->vm_exit, sizeof(struct vm_exit)); 690 691 critical_exit(); 692 693 return (error); 694} 695 696int 697vm_inject_event(struct vm *vm, int vcpuid, int type, 698 int vector, uint32_t code, int code_valid) 699{ 700 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 701 return (EINVAL); 702 703 if ((type > VM_EVENT_NONE && type < VM_EVENT_MAX) == 0) 704 return (EINVAL); 705 706 if (vector < 0 || vector > 255) 707 return (EINVAL); 708 709 return (VMINJECT(vm->cookie, vcpuid, type, vector, code, code_valid)); 710} 711
|
| 712VMM_STAT_DEFINE(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); 713
|
713int
| 714int
|
714vm_inject_nmi(struct vm *vm, int vcpu)
| 715vm_inject_nmi(struct vm *vm, int vcpuid)
|
715{
| 716{
|
716 int error;
| 717 struct vcpu *vcpu;
|
717
| 718
|
718 if (vcpu < 0 || vcpu >= VM_MAXCPU)
| 719 if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
|
719 return (EINVAL); 720
| 720 return (EINVAL); 721
|
721 error = VMNMI(vm->cookie, vcpu); 722 vm_interrupt_hostcpu(vm, vcpu); 723 return (error);
| 722 vcpu = &vm->vcpu[vcpuid]; 723 724 vcpu->nmi_pending = 1; 725 vm_interrupt_hostcpu(vm, vcpuid); 726 return (0);
|
724} 725 726int
| 727} 728 729int
|
| 730vm_nmi_pending(struct vm *vm, int vcpuid) 731{ 732 struct vcpu *vcpu; 733 734 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 735 panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 736 737 vcpu = &vm->vcpu[vcpuid]; 738 739 return (vcpu->nmi_pending); 740} 741 742void 743vm_nmi_clear(struct vm *vm, int vcpuid) 744{ 745 struct vcpu *vcpu; 746 747 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 748 panic("vm_nmi_pending: invalid vcpuid %d", vcpuid); 749 750 vcpu = &vm->vcpu[vcpuid]; 751 752 if (vcpu->nmi_pending == 0) 753 panic("vm_nmi_clear: inconsistent nmi_pending state"); 754 755 vcpu->nmi_pending = 0; 756 vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1); 757} 758 759int
|
727vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 728{ 729 if (vcpu < 0 || vcpu >= VM_MAXCPU) 730 return (EINVAL); 731 732 if (type < 0 || type >= VM_CAP_MAX) 733 return (EINVAL); 734 735 return (VMGETCAP(vm->cookie, vcpu, type, retval)); 736} 737 738int 739vm_set_capability(struct vm *vm, int vcpu, int type, int val) 740{ 741 if (vcpu < 0 || vcpu >= VM_MAXCPU) 742 return (EINVAL); 743 744 if (type < 0 || type >= VM_CAP_MAX) 745 return (EINVAL); 746 747 return (VMSETCAP(vm->cookie, vcpu, type, val)); 748} 749 750uint64_t * 751vm_guest_msrs(struct vm *vm, int cpu) 752{ 753 return (vm->vcpu[cpu].guest_msrs); 754} 755 756struct vlapic * 757vm_lapic(struct vm *vm, int cpu) 758{ 759 return (vm->vcpu[cpu].vlapic); 760} 761 762boolean_t 763vmm_is_pptdev(int bus, int slot, int func) 764{ 765 int found, b, s, f, n; 766 char *val, *cp, *cp2; 767 768 /* 769 * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12" 770 */ 771 found = 0; 772 cp = val = getenv("pptdevs"); 773 while (cp != NULL && *cp != '\0') { 774 if ((cp2 = strchr(cp, ' ')) != NULL) 775 *cp2 = '\0'; 776 777 n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 778 if (n == 3 && bus == b && slot == s && func == f) { 779 found = 1; 780 break; 781 } 782 783 if (cp2 != NULL) 784 *cp2++ = ' '; 785 786 cp = cp2; 787 } 788 freeenv(val); 789 return (found); 790} 791 792void * 793vm_iommu_domain(struct vm *vm) 794{ 795 796 return (vm->iommu); 797} 798 799int 800vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state state) 801{ 802 int error; 803 struct vcpu *vcpu; 804 805 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 806 panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 807 808 vcpu = &vm->vcpu[vcpuid]; 809 810 vcpu_lock(vcpu); 811 812 /* 813 * The following state transitions are allowed: 814 * IDLE -> RUNNING -> IDLE 815 * IDLE -> CANNOT_RUN -> IDLE 816 */ 817 if ((vcpu->state == VCPU_IDLE && state != VCPU_IDLE) || 818 (vcpu->state != VCPU_IDLE && state == VCPU_IDLE)) { 819 error = 0; 820 vcpu->state = state; 821 } else { 822 error = EBUSY; 823 } 824 825 vcpu_unlock(vcpu); 826 827 return (error); 828} 829 830enum vcpu_state 831vcpu_get_state(struct vm *vm, int vcpuid) 832{ 833 struct vcpu *vcpu; 834 enum vcpu_state state; 835 836 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 837 panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 838 839 vcpu = &vm->vcpu[vcpuid]; 840 841 vcpu_lock(vcpu); 842 state = vcpu->state; 843 vcpu_unlock(vcpu); 844 845 return (state); 846} 847 848void 849vm_activate_cpu(struct vm *vm, int vcpuid) 850{ 851 852 if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 853 CPU_SET(vcpuid, &vm->active_cpus); 854} 855 856cpuset_t 857vm_active_cpus(struct vm *vm) 858{ 859 860 return (vm->active_cpus); 861} 862 863void * 864vcpu_stats(struct vm *vm, int vcpuid) 865{ 866 867 return (vm->vcpu[vcpuid].stats); 868} 869 870int 871vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 872{ 873 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 874 return (EINVAL); 875 876 *state = vm->vcpu[vcpuid].x2apic_state; 877 878 return (0); 879} 880 881int 882vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 883{ 884 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 885 return (EINVAL); 886 887 if (state < 0 || state >= X2APIC_STATE_LAST) 888 return (EINVAL); 889 890 vm->vcpu[vcpuid].x2apic_state = state; 891 892 vlapic_set_x2apic_state(vm, vcpuid, state); 893 894 return (0); 895} 896 897void 898vm_interrupt_hostcpu(struct vm *vm, int vcpuid) 899{ 900 int hostcpu; 901 struct vcpu *vcpu; 902 903 vcpu = &vm->vcpu[vcpuid]; 904 905 /* 906 * XXX racy but the worst case is that we'll send an unnecessary IPI 907 * to the 'hostcpu'. 908 * 909 * We cannot use vcpu_is_running() here because it acquires vcpu->mtx 910 * which is not allowed inside a critical section. 911 */ 912 hostcpu = vcpu->hostcpu; 913 if (hostcpu == NOCPU || hostcpu == curcpu) 914 return; 915 916 ipi_cpu(hostcpu, vmm_ipinum); 917}
| 760vm_get_capability(struct vm *vm, int vcpu, int type, int *retval) 761{ 762 if (vcpu < 0 || vcpu >= VM_MAXCPU) 763 return (EINVAL); 764 765 if (type < 0 || type >= VM_CAP_MAX) 766 return (EINVAL); 767 768 return (VMGETCAP(vm->cookie, vcpu, type, retval)); 769} 770 771int 772vm_set_capability(struct vm *vm, int vcpu, int type, int val) 773{ 774 if (vcpu < 0 || vcpu >= VM_MAXCPU) 775 return (EINVAL); 776 777 if (type < 0 || type >= VM_CAP_MAX) 778 return (EINVAL); 779 780 return (VMSETCAP(vm->cookie, vcpu, type, val)); 781} 782 783uint64_t * 784vm_guest_msrs(struct vm *vm, int cpu) 785{ 786 return (vm->vcpu[cpu].guest_msrs); 787} 788 789struct vlapic * 790vm_lapic(struct vm *vm, int cpu) 791{ 792 return (vm->vcpu[cpu].vlapic); 793} 794 795boolean_t 796vmm_is_pptdev(int bus, int slot, int func) 797{ 798 int found, b, s, f, n; 799 char *val, *cp, *cp2; 800 801 /* 802 * setenv pptdevs "1/2/3 4/5/6 7/8/9 10/11/12" 803 */ 804 found = 0; 805 cp = val = getenv("pptdevs"); 806 while (cp != NULL && *cp != '\0') { 807 if ((cp2 = strchr(cp, ' ')) != NULL) 808 *cp2 = '\0'; 809 810 n = sscanf(cp, "%d/%d/%d", &b, &s, &f); 811 if (n == 3 && bus == b && slot == s && func == f) { 812 found = 1; 813 break; 814 } 815 816 if (cp2 != NULL) 817 *cp2++ = ' '; 818 819 cp = cp2; 820 } 821 freeenv(val); 822 return (found); 823} 824 825void * 826vm_iommu_domain(struct vm *vm) 827{ 828 829 return (vm->iommu); 830} 831 832int 833vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state state) 834{ 835 int error; 836 struct vcpu *vcpu; 837 838 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 839 panic("vm_set_run_state: invalid vcpuid %d", vcpuid); 840 841 vcpu = &vm->vcpu[vcpuid]; 842 843 vcpu_lock(vcpu); 844 845 /* 846 * The following state transitions are allowed: 847 * IDLE -> RUNNING -> IDLE 848 * IDLE -> CANNOT_RUN -> IDLE 849 */ 850 if ((vcpu->state == VCPU_IDLE && state != VCPU_IDLE) || 851 (vcpu->state != VCPU_IDLE && state == VCPU_IDLE)) { 852 error = 0; 853 vcpu->state = state; 854 } else { 855 error = EBUSY; 856 } 857 858 vcpu_unlock(vcpu); 859 860 return (error); 861} 862 863enum vcpu_state 864vcpu_get_state(struct vm *vm, int vcpuid) 865{ 866 struct vcpu *vcpu; 867 enum vcpu_state state; 868 869 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 870 panic("vm_get_run_state: invalid vcpuid %d", vcpuid); 871 872 vcpu = &vm->vcpu[vcpuid]; 873 874 vcpu_lock(vcpu); 875 state = vcpu->state; 876 vcpu_unlock(vcpu); 877 878 return (state); 879} 880 881void 882vm_activate_cpu(struct vm *vm, int vcpuid) 883{ 884 885 if (vcpuid >= 0 && vcpuid < VM_MAXCPU) 886 CPU_SET(vcpuid, &vm->active_cpus); 887} 888 889cpuset_t 890vm_active_cpus(struct vm *vm) 891{ 892 893 return (vm->active_cpus); 894} 895 896void * 897vcpu_stats(struct vm *vm, int vcpuid) 898{ 899 900 return (vm->vcpu[vcpuid].stats); 901} 902 903int 904vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) 905{ 906 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 907 return (EINVAL); 908 909 *state = vm->vcpu[vcpuid].x2apic_state; 910 911 return (0); 912} 913 914int 915vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) 916{ 917 if (vcpuid < 0 || vcpuid >= VM_MAXCPU) 918 return (EINVAL); 919 920 if (state < 0 || state >= X2APIC_STATE_LAST) 921 return (EINVAL); 922 923 vm->vcpu[vcpuid].x2apic_state = state; 924 925 vlapic_set_x2apic_state(vm, vcpuid, state); 926 927 return (0); 928} 929 930void 931vm_interrupt_hostcpu(struct vm *vm, int vcpuid) 932{ 933 int hostcpu; 934 struct vcpu *vcpu; 935 936 vcpu = &vm->vcpu[vcpuid]; 937 938 /* 939 * XXX racy but the worst case is that we'll send an unnecessary IPI 940 * to the 'hostcpu'. 941 * 942 * We cannot use vcpu_is_running() here because it acquires vcpu->mtx 943 * which is not allowed inside a critical section. 944 */ 945 hostcpu = vcpu->hostcpu; 946 if (hostcpu == NOCPU || hostcpu == curcpu) 947 return; 948 949 ipi_cpu(hostcpu, vmm_ipinum); 950}
|