vmm_dev.c (250427) | vmm_dev.c (256072) |
---|---|
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 unchanged lines hidden (view full) --- 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 * | 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 unchanged lines hidden (view full) --- 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: head/sys/amd64/vmm/vmm_dev.c 250427 2013-05-10 02:59:49Z neel $ | 26 * $FreeBSD: head/sys/amd64/vmm/vmm_dev.c 256072 2013-10-05 21:22:35Z neel $ |
27 */ 28 29#include <sys/cdefs.h> | 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sys/amd64/vmm/vmm_dev.c 250427 2013-05-10 02:59:49Z neel $"); | 30__FBSDID("$FreeBSD: head/sys/amd64/vmm/vmm_dev.c 256072 2013-10-05 21:22:35Z neel $"); |
31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/queue.h> 35#include <sys/lock.h> 36#include <sys/mutex.h> 37#include <sys/malloc.h> 38#include <sys/conf.h> 39#include <sys/sysctl.h> 40#include <sys/libkern.h> 41#include <sys/ioccom.h> 42#include <sys/mman.h> 43#include <sys/uio.h> 44 45#include <vm/vm.h> 46#include <vm/pmap.h> | 31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/queue.h> 35#include <sys/lock.h> 36#include <sys/mutex.h> 37#include <sys/malloc.h> 38#include <sys/conf.h> 39#include <sys/sysctl.h> 40#include <sys/libkern.h> 41#include <sys/ioccom.h> 42#include <sys/mman.h> 43#include <sys/uio.h> 44 45#include <vm/vm.h> 46#include <vm/pmap.h> |
47#include <vm/vm_map.h> |
|
47 48#include <machine/pmap.h> 49#include <machine/vmparam.h> 50 51#include <machine/vmm.h> 52#include "vmm_lapic.h" 53#include "vmm_stat.h" 54#include "vmm_mem.h" --- 35 unchanged lines hidden (view full) --- 90{ 91 92 return (cdev->si_drv1); 93} 94 95static int 96vmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 97{ | 48 49#include <machine/pmap.h> 50#include <machine/vmparam.h> 51 52#include <machine/vmm.h> 53#include "vmm_lapic.h" 54#include "vmm_stat.h" 55#include "vmm_mem.h" --- 35 unchanged lines hidden (view full) --- 91{ 92 93 return (cdev->si_drv1); 94} 95 96static int 97vmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) 98{ |
98 int error, off, c; 99 vm_paddr_t hpa, gpa; | 99 int error, off, c, prot; 100 vm_paddr_t gpa; 101 void *hpa, *cookie; |
100 struct vmmdev_softc *sc; 101 102 static char zerobuf[PAGE_SIZE]; 103 104 error = 0; 105 mtx_lock(&vmmdev_mtx); 106 sc = vmmdev_lookup2(cdev); 107 if (sc == NULL) 108 error = ENXIO; 109 | 102 struct vmmdev_softc *sc; 103 104 static char zerobuf[PAGE_SIZE]; 105 106 error = 0; 107 mtx_lock(&vmmdev_mtx); 108 sc = vmmdev_lookup2(cdev); 109 if (sc == NULL) 110 error = ENXIO; 111 |
112 prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); |
|
110 while (uio->uio_resid > 0 && error == 0) { 111 gpa = uio->uio_offset; 112 off = gpa & PAGE_MASK; 113 c = min(uio->uio_resid, PAGE_SIZE - off); 114 115 /* 116 * The VM has a hole in its physical memory map. If we want to 117 * use 'dd' to inspect memory beyond the hole we need to 118 * provide bogus data for memory that lies in the hole. 119 * 120 * Since this device does not support lseek(2), dd(1) will 121 * read(2) blocks of data to simulate the lseek(2). 122 */ | 113 while (uio->uio_resid > 0 && error == 0) { 114 gpa = uio->uio_offset; 115 off = gpa & PAGE_MASK; 116 c = min(uio->uio_resid, PAGE_SIZE - off); 117 118 /* 119 * The VM has a hole in its physical memory map. If we want to 120 * use 'dd' to inspect memory beyond the hole we need to 121 * provide bogus data for memory that lies in the hole. 122 * 123 * Since this device does not support lseek(2), dd(1) will 124 * read(2) blocks of data to simulate the lseek(2). 125 */ |
123 hpa = vm_gpa2hpa(sc->vm, gpa, c); 124 if (hpa == (vm_paddr_t)-1) { | 126 hpa = vm_gpa_hold(sc->vm, gpa, c, prot, &cookie); 127 if (hpa == NULL) { |
125 if (uio->uio_rw == UIO_READ) 126 error = uiomove(zerobuf, c, uio); 127 else 128 error = EFAULT; | 128 if (uio->uio_rw == UIO_READ) 129 error = uiomove(zerobuf, c, uio); 130 else 131 error = EFAULT; |
129 } else 130 error = uiomove((void *)PHYS_TO_DMAP(hpa), c, uio); | 132 } else { 133 error = uiomove(hpa, c, uio); 134 vm_gpa_release(cookie); 135 } |
131 } 132 133 mtx_unlock(&vmmdev_mtx); 134 return (error); 135} 136 137static int 138vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 139 struct thread *td) 140{ 141 int error, vcpu, state_changed; | 136 } 137 138 mtx_unlock(&vmmdev_mtx); 139 return (error); 140} 141 142static int 143vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, 144 struct thread *td) 145{ 146 int error, vcpu, state_changed; |
142 enum vcpu_state new_state; | |
143 struct vmmdev_softc *sc; 144 struct vm_memory_segment *seg; 145 struct vm_register *vmreg; 146 struct vm_seg_desc* vmsegdesc; 147 struct vm_run *vmrun; 148 struct vm_event *vmevent; 149 struct vm_lapic_irq *vmirq; 150 struct vm_capability *vmcap; 151 struct vm_pptdev *pptdev; 152 struct vm_pptdev_mmio *pptmmio; 153 struct vm_pptdev_msi *pptmsi; 154 struct vm_pptdev_msix *pptmsix; 155 struct vm_nmi *vmnmi; 156 struct vm_stats *vmstats; 157 struct vm_stat_desc *statdesc; 158 struct vm_x2apic *x2apic; | 147 struct vmmdev_softc *sc; 148 struct vm_memory_segment *seg; 149 struct vm_register *vmreg; 150 struct vm_seg_desc* vmsegdesc; 151 struct vm_run *vmrun; 152 struct vm_event *vmevent; 153 struct vm_lapic_irq *vmirq; 154 struct vm_capability *vmcap; 155 struct vm_pptdev *pptdev; 156 struct vm_pptdev_mmio *pptmmio; 157 struct vm_pptdev_msi *pptmsi; 158 struct vm_pptdev_msix *pptmsix; 159 struct vm_nmi *vmnmi; 160 struct vm_stats *vmstats; 161 struct vm_stat_desc *statdesc; 162 struct vm_x2apic *x2apic; |
163 struct vm_gpa_pte *gpapte; |
|
159 160 sc = vmmdev_lookup2(cdev); 161 if (sc == NULL) 162 return (ENXIO); 163 164 vcpu = -1; 165 state_changed = 0; 166 --- 17 unchanged lines hidden (view full) --- 184 * Assumes that the first field of the ioctl data is the vcpu. 185 */ 186 vcpu = *(int *)data; 187 if (vcpu < 0 || vcpu >= VM_MAXCPU) { 188 error = EINVAL; 189 goto done; 190 } 191 | 164 165 sc = vmmdev_lookup2(cdev); 166 if (sc == NULL) 167 return (ENXIO); 168 169 vcpu = -1; 170 state_changed = 0; 171 --- 17 unchanged lines hidden (view full) --- 189 * Assumes that the first field of the ioctl data is the vcpu. 190 */ 191 vcpu = *(int *)data; 192 if (vcpu < 0 || vcpu >= VM_MAXCPU) { 193 error = EINVAL; 194 goto done; 195 } 196 |
192 if (cmd == VM_RUN) 193 new_state = VCPU_RUNNING; 194 else 195 new_state = VCPU_CANNOT_RUN; 196 197 error = vcpu_set_state(sc->vm, vcpu, new_state); | 197 error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN); |
198 if (error) 199 goto done; 200 201 state_changed = 1; 202 break; 203 204 case VM_MAP_PPTDEV_MMIO: 205 case VM_BIND_PPTDEV: 206 case VM_UNBIND_PPTDEV: 207 case VM_MAP_MEMORY: 208 /* 209 * ioctls that operate on the entire virtual machine must 210 * prevent all vcpus from running. 211 */ 212 error = 0; 213 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { | 198 if (error) 199 goto done; 200 201 state_changed = 1; 202 break; 203 204 case VM_MAP_PPTDEV_MMIO: 205 case VM_BIND_PPTDEV: 206 case VM_UNBIND_PPTDEV: 207 case VM_MAP_MEMORY: 208 /* 209 * ioctls that operate on the entire virtual machine must 210 * prevent all vcpus from running. 211 */ 212 error = 0; 213 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { |
214 error = vcpu_set_state(sc->vm, vcpu, VCPU_CANNOT_RUN); | 214 error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN); |
215 if (error) 216 break; 217 } 218 219 if (error) { 220 while (--vcpu >= 0) 221 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 222 goto done; --- 43 unchanged lines hidden (view full) --- 266 case VM_MAP_PPTDEV_MMIO: 267 pptmmio = (struct vm_pptdev_mmio *)data; 268 error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 269 pptmmio->func, pptmmio->gpa, pptmmio->len, 270 pptmmio->hpa); 271 break; 272 case VM_BIND_PPTDEV: 273 pptdev = (struct vm_pptdev *)data; | 215 if (error) 216 break; 217 } 218 219 if (error) { 220 while (--vcpu >= 0) 221 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 222 goto done; --- 43 unchanged lines hidden (view full) --- 266 case VM_MAP_PPTDEV_MMIO: 267 pptmmio = (struct vm_pptdev_mmio *)data; 268 error = ppt_map_mmio(sc->vm, pptmmio->bus, pptmmio->slot, 269 pptmmio->func, pptmmio->gpa, pptmmio->len, 270 pptmmio->hpa); 271 break; 272 case VM_BIND_PPTDEV: 273 pptdev = (struct vm_pptdev *)data; |
274 error = ppt_assign_device(sc->vm, pptdev->bus, pptdev->slot, 275 pptdev->func); | 274 error = vm_assign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 275 pptdev->func); |
276 break; 277 case VM_UNBIND_PPTDEV: 278 pptdev = (struct vm_pptdev *)data; | 276 break; 277 case VM_UNBIND_PPTDEV: 278 pptdev = (struct vm_pptdev *)data; |
279 error = ppt_unassign_device(sc->vm, pptdev->bus, pptdev->slot, 280 pptdev->func); | 279 error = vm_unassign_pptdev(sc->vm, pptdev->bus, pptdev->slot, 280 pptdev->func); |
281 break; 282 case VM_INJECT_EVENT: 283 vmevent = (struct vm_event *)data; 284 error = vm_inject_event(sc->vm, vmevent->cpuid, vmevent->type, 285 vmevent->vector, 286 vmevent->error_code, 287 vmevent->error_code_valid); 288 break; --- 54 unchanged lines hidden (view full) --- 343 error = vm_set_x2apic_state(sc->vm, 344 x2apic->cpuid, x2apic->state); 345 break; 346 case VM_GET_X2APIC_STATE: 347 x2apic = (struct vm_x2apic *)data; 348 error = vm_get_x2apic_state(sc->vm, 349 x2apic->cpuid, &x2apic->state); 350 break; | 281 break; 282 case VM_INJECT_EVENT: 283 vmevent = (struct vm_event *)data; 284 error = vm_inject_event(sc->vm, vmevent->cpuid, vmevent->type, 285 vmevent->vector, 286 vmevent->error_code, 287 vmevent->error_code_valid); 288 break; --- 54 unchanged lines hidden (view full) --- 343 error = vm_set_x2apic_state(sc->vm, 344 x2apic->cpuid, x2apic->state); 345 break; 346 case VM_GET_X2APIC_STATE: 347 x2apic = (struct vm_x2apic *)data; 348 error = vm_get_x2apic_state(sc->vm, 349 x2apic->cpuid, &x2apic->state); 350 break; |
351 case VM_GET_GPA_PMAP: 352 gpapte = (struct vm_gpa_pte *)data; 353 pmap_get_mapping(vmspace_pmap(vm_get_vmspace(sc->vm)), 354 gpapte->gpa, gpapte->pte, &gpapte->ptenum); 355 error = 0; 356 break; |
|
351 default: 352 error = ENOTTY; 353 break; 354 } 355 356 if (state_changed == 1) { 357 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 358 } else if (state_changed == 2) { 359 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) 360 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 361 } 362 363done: | 357 default: 358 error = ENOTTY; 359 break; 360 } 361 362 if (state_changed == 1) { 363 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 364 } else if (state_changed == 2) { 365 for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) 366 vcpu_set_state(sc->vm, vcpu, VCPU_IDLE); 367 } 368 369done: |
370 /* Make sure that no handler returns a bogus value like ERESTART */ 371 KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error)); |
|
364 return (error); 365} 366 367static int | 372 return (error); 373} 374 375static int |
368vmmdev_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr, 369 int nprot, vm_memattr_t *memattr) | 376vmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, 377 vm_size_t size, struct vm_object **object, int nprot) |
370{ 371 int error; 372 struct vmmdev_softc *sc; 373 | 378{ 379 int error; 380 struct vmmdev_softc *sc; 381 |
374 error = -1; | |
375 mtx_lock(&vmmdev_mtx); 376 377 sc = vmmdev_lookup2(cdev); | 382 mtx_lock(&vmmdev_mtx); 383 384 sc = vmmdev_lookup2(cdev); |
378 if (sc != NULL && (nprot & PROT_EXEC) == 0) { 379 *paddr = vm_gpa2hpa(sc->vm, (vm_paddr_t)offset, PAGE_SIZE); 380 if (*paddr != (vm_paddr_t)-1) 381 error = 0; 382 } | 385 if (sc != NULL && (nprot & PROT_EXEC) == 0) 386 error = vm_get_memobj(sc->vm, *offset, size, offset, object); 387 else 388 error = EINVAL; |
383 384 mtx_unlock(&vmmdev_mtx); 385 386 return (error); 387} 388 389static void 390vmmdev_destroy(struct vmmdev_softc *sc, boolean_t unlink) --- 50 unchanged lines hidden (view full) --- 441} 442SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 443 NULL, 0, sysctl_vmm_destroy, "A", NULL); 444 445static struct cdevsw vmmdevsw = { 446 .d_name = "vmmdev", 447 .d_version = D_VERSION, 448 .d_ioctl = vmmdev_ioctl, | 389 390 mtx_unlock(&vmmdev_mtx); 391 392 return (error); 393} 394 395static void 396vmmdev_destroy(struct vmmdev_softc *sc, boolean_t unlink) --- 50 unchanged lines hidden (view full) --- 447} 448SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy, CTLTYPE_STRING | CTLFLAG_RW, 449 NULL, 0, sysctl_vmm_destroy, "A", NULL); 450 451static struct cdevsw vmmdevsw = { 452 .d_name = "vmmdev", 453 .d_version = D_VERSION, 454 .d_ioctl = vmmdev_ioctl, |
449 .d_mmap = vmmdev_mmap, | 455 .d_mmap_single = vmmdev_mmap_single, |
450 .d_read = vmmdev_rw, 451 .d_write = vmmdev_rw, 452}; 453 454static int 455sysctl_vmm_create(SYSCTL_HANDLER_ARGS) 456{ 457 int error; --- 68 unchanged lines hidden --- | 456 .d_read = vmmdev_rw, 457 .d_write = vmmdev_rw, 458}; 459 460static int 461sysctl_vmm_create(SYSCTL_HANDLER_ARGS) 462{ 463 int error; --- 68 unchanged lines hidden --- |