Changeset View
Standalone View
sys/amd64/vmm/vmm_dev.c
Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | vmm_priv_check(struct ucred *ucred) | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vcpu_lock_one(struct vmmdev_softc *sc, int vcpu) | vcpu_lock_one(struct vmmdev_softc *sc, int vcpu) | ||||
{ | { | ||||
int error; | int error; | ||||
if (vcpu < 0 || vcpu >= VM_MAXCPU) | if (vcpu < 0 || vcpu >= vm_get_maxcpus(sc->vm)) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); | error = vcpu_set_state(sc->vm, vcpu, VCPU_FROZEN, true); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
vcpu_unlock_one(struct vmmdev_softc *sc, int vcpu) | vcpu_unlock_one(struct vmmdev_softc *sc, int vcpu) | ||||
Show All 9 Lines | vcpu_unlock_one(struct vmmdev_softc *sc, int vcpu) | ||||
vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); | vcpu_set_state(sc->vm, vcpu, VCPU_IDLE, false); | ||||
} | } | ||||
static int | static int | ||||
vcpu_lock_all(struct vmmdev_softc *sc) | vcpu_lock_all(struct vmmdev_softc *sc) | ||||
{ | { | ||||
int error, vcpu; | int error, vcpu; | ||||
for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) { | for (vcpu = 0; vcpu < vm_get_maxcpus(sc->vm); vcpu++) { | ||||
pmooney_pfmooney.com: Cache the max here? | |||||
error = vcpu_lock_one(sc, vcpu); | error = vcpu_lock_one(sc, vcpu); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
} | } | ||||
if (error) { | if (error) { | ||||
while (--vcpu >= 0) | while (--vcpu >= 0) | ||||
vcpu_unlock_one(sc, vcpu); | vcpu_unlock_one(sc, vcpu); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
vcpu_unlock_all(struct vmmdev_softc *sc) | vcpu_unlock_all(struct vmmdev_softc *sc) | ||||
{ | { | ||||
int vcpu; | int vcpu; | ||||
for (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) | for (vcpu = 0; vcpu < vm_get_maxcpus(sc->vm); vcpu++) | ||||
Done Inline ActionsCache the max? pmooney_pfmooney.com: Cache the max? | |||||
Done Inline ActionsI would hope the compiler would do that already without me having to explicitly code code this as Also doesn't this go away when we upstream the better locking implementation you have already done? rgrimes: I would hope the compiler would do that already without me having to explicitly code code this… | |||||
Not Done Inline ActionsThere would be some caching needed in vcpu_lock_all(), which would become part of the "write lock acquisition" path. It would be safe for the unlock path, since maxcpu would be effectively fixed while you held the write lock. pmooney_pfmooney.com: There would be some caching needed in vcpu_lock_all(), which would become part of the "write… | |||||
Not Done Inline ActionsYou can tell the compiler that the return value is always the same for a given input by marking the function prototype with '__pure2' or some such in which case the compiler would cache the return value and only call it once. What you have is fine though. jhb: You can tell the compiler that the return value is always the same for a given input by marking… | |||||
vcpu_unlock_one(sc, vcpu); | vcpu_unlock_one(sc, vcpu); | ||||
} | } | ||||
static struct vmmdev_softc * | static struct vmmdev_softc * | ||||
vmmdev_lookup(const char *name) | vmmdev_lookup(const char *name) | ||||
{ | { | ||||
struct vmmdev_softc *sc; | struct vmmdev_softc *sc; | ||||
Show All 30 Lines | vmmdev_rw(struct cdev *cdev, struct uio *uio, int flags) | ||||
sc = vmmdev_lookup2(cdev); | sc = vmmdev_lookup2(cdev); | ||||
if (sc == NULL) | if (sc == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* | /* | ||||
* Get a read lock on the guest memory map by freezing any vcpu. | * Get a read lock on the guest memory map by freezing any vcpu. | ||||
*/ | */ | ||||
error = vcpu_lock_one(sc, VM_MAXCPU - 1); | error = vcpu_lock_one(sc, vm_get_maxcpus(sc->vm) - 1); | ||||
Done Inline ActionsCache the max - 1 once, instead of recalculating it all over the function? pmooney_pfmooney.com: Cache the `max - 1` once, instead of recalculating it all over the function? | |||||
Done Inline ActionsWill do rgrimes: Will do | |||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); | prot = (uio->uio_rw == UIO_WRITE ? VM_PROT_WRITE : VM_PROT_READ); | ||||
maxaddr = vmm_sysmem_maxaddr(sc->vm); | maxaddr = vmm_sysmem_maxaddr(sc->vm); | ||||
while (uio->uio_resid > 0 && error == 0) { | while (uio->uio_resid > 0 && error == 0) { | ||||
gpa = uio->uio_offset; | gpa = uio->uio_offset; | ||||
off = gpa & PAGE_MASK; | off = gpa & PAGE_MASK; | ||||
c = min(uio->uio_resid, PAGE_SIZE - off); | c = min(uio->uio_resid, PAGE_SIZE - off); | ||||
/* | /* | ||||
* The VM has a hole in its physical memory map. If we want to | * The VM has a hole in its physical memory map. If we want to | ||||
* use 'dd' to inspect memory beyond the hole we need to | * use 'dd' to inspect memory beyond the hole we need to | ||||
* provide bogus data for memory that lies in the hole. | * provide bogus data for memory that lies in the hole. | ||||
* | * | ||||
* Since this device does not support lseek(2), dd(1) will | * Since this device does not support lseek(2), dd(1) will | ||||
* read(2) blocks of data to simulate the lseek(2). | * read(2) blocks of data to simulate the lseek(2). | ||||
*/ | */ | ||||
hpa = vm_gpa_hold(sc->vm, VM_MAXCPU - 1, gpa, c, prot, &cookie); | hpa = vm_gpa_hold(sc->vm, vm_get_maxcpus(sc->vm) - 1, gpa, c, prot, &cookie); | ||||
if (hpa == NULL) { | if (hpa == NULL) { | ||||
if (uio->uio_rw == UIO_READ && gpa < maxaddr) | if (uio->uio_rw == UIO_READ && gpa < maxaddr) | ||||
error = uiomove(__DECONST(void *, zero_region), | error = uiomove(__DECONST(void *, zero_region), | ||||
c, uio); | c, uio); | ||||
else | else | ||||
error = EFAULT; | error = EFAULT; | ||||
} else { | } else { | ||||
error = uiomove(hpa, c, uio); | error = uiomove(hpa, c, uio); | ||||
vm_gpa_release(cookie); | vm_gpa_release(cookie); | ||||
} | } | ||||
} | } | ||||
vcpu_unlock_one(sc, VM_MAXCPU - 1); | vcpu_unlock_one(sc, vm_get_maxcpus(sc->vm) - 1); | ||||
return (error); | return (error); | ||||
} | } | ||||
CTASSERT(sizeof(((struct vm_memseg *)0)->name) >= SPECNAMELEN + 1); | CTASSERT(sizeof(((struct vm_memseg *)0)->name) >= SPECNAMELEN + 1); | ||||
static int | static int | ||||
get_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg) | get_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | case VM_REINIT: | ||||
break; | break; | ||||
case VM_GET_MEMSEG: | case VM_GET_MEMSEG: | ||||
case VM_MMAP_GETNEXT: | case VM_MMAP_GETNEXT: | ||||
/* | /* | ||||
* Lock a vcpu to make sure that the memory map cannot be | * Lock a vcpu to make sure that the memory map cannot be | ||||
* modified while it is being inspected. | * modified while it is being inspected. | ||||
*/ | */ | ||||
vcpu = VM_MAXCPU - 1; | vcpu = vm_get_maxcpus(sc->vm) - 1; | ||||
error = vcpu_lock_one(sc, vcpu); | error = vcpu_lock_one(sc, vcpu); | ||||
if (error) | if (error) | ||||
goto done; | goto done; | ||||
state_changed = 1; | state_changed = 1; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | vmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t mapsize, | ||||
if (sc == NULL) { | if (sc == NULL) { | ||||
/* virtual machine is in the process of being created */ | /* virtual machine is in the process of being created */ | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* | /* | ||||
* Get a read lock on the guest memory map by freezing any vcpu. | * Get a read lock on the guest memory map by freezing any vcpu. | ||||
*/ | */ | ||||
error = vcpu_lock_one(sc, VM_MAXCPU - 1); | error = vcpu_lock_one(sc, vm_get_maxcpus(sc->vm) - 1); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
gpa = 0; | gpa = 0; | ||||
found = 0; | found = 0; | ||||
while (!found) { | while (!found) { | ||||
error = vm_mmap_getnext(sc->vm, &gpa, &segid, &segoff, &len, | error = vm_mmap_getnext(sc->vm, &gpa, &segid, &segoff, &len, | ||||
NULL, NULL); | NULL, NULL); | ||||
Show All 12 Lines | KASSERT(error == 0 && *objp != NULL, | ||||
("%s: invalid memory segment %d", __func__, segid)); | ("%s: invalid memory segment %d", __func__, segid)); | ||||
if (sysmem) { | if (sysmem) { | ||||
vm_object_reference(*objp); | vm_object_reference(*objp); | ||||
*offset = segoff + (first - gpa); | *offset = segoff + (first - gpa); | ||||
} else { | } else { | ||||
error = EINVAL; | error = EINVAL; | ||||
} | } | ||||
} | } | ||||
vcpu_unlock_one(sc, VM_MAXCPU - 1); | vcpu_unlock_one(sc, vm_get_maxcpus(sc->vm) - 1); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
vmmdev_destroy(void *arg) | vmmdev_destroy(void *arg) | ||||
{ | { | ||||
struct vmmdev_softc *sc = arg; | struct vmmdev_softc *sc = arg; | ||||
struct devmem_softc *dsc; | struct devmem_softc *dsc; | ||||
▲ Show 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | if (dsc == NULL) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
first = *offset; | first = *offset; | ||||
last = *offset + len; | last = *offset + len; | ||||
if ((nprot & PROT_EXEC) || first < 0 || first >= last) | if ((nprot & PROT_EXEC) || first < 0 || first >= last) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = vcpu_lock_one(dsc->sc, VM_MAXCPU - 1); | error = vcpu_lock_one(dsc->sc, vm_get_maxcpus(dsc->sc->vm) - 1); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = vm_get_memseg(dsc->sc->vm, dsc->segid, &seglen, &sysmem, objp); | error = vm_get_memseg(dsc->sc->vm, dsc->segid, &seglen, &sysmem, objp); | ||||
KASSERT(error == 0 && !sysmem && *objp != NULL, | KASSERT(error == 0 && !sysmem && *objp != NULL, | ||||
("%s: invalid devmem segment %d", __func__, dsc->segid)); | ("%s: invalid devmem segment %d", __func__, dsc->segid)); | ||||
vcpu_unlock_one(dsc->sc, VM_MAXCPU - 1); | vcpu_unlock_one(dsc->sc, vm_get_maxcpus(dsc->sc->vm) - 1); | ||||
if (seglen >= last) { | if (seglen >= last) { | ||||
vm_object_reference(*objp); | vm_object_reference(*objp); | ||||
return (0); | return (0); | ||||
} else { | } else { | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 54 Lines • Show Last 20 Lines |
Cache the max here?