Index: include/vmm.h =================================================================== --- include/vmm.h (revision 251767) +++ include/vmm.h (working copy) @@ -40,6 +40,8 @@ struct vm_run; struct vlapic; +struct vm_object; + enum x2apic_state; typedef int (*vmm_init_func_t)(void); @@ -96,6 +98,8 @@ vm_paddr_t vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t size); int vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase, struct vm_memory_segment *seg); +int vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, + vm_offset_t *offset, struct vm_object **object); int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval); int vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val); int vm_get_seg_desc(struct vm *vm, int vcpu, int reg, Index: vmm/vmm.c =================================================================== --- vmm/vmm.c (revision 251767) +++ vmm/vmm.c (working copy) @@ -39,11 +39,14 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -85,6 +88,11 @@ #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) +struct mem_seg { + vm_paddr_t gpa; + size_t len; + vm_object_t object; +}; #define VM_MAX_MEMORY_SEGMENTS 2 struct vm { @@ -92,7 +100,7 @@ void *iommu; /* iommu-specific data */ struct vcpu vcpu[VM_MAXCPU]; int num_mem_segs; - struct vm_memory_segment mem_segs[VM_MAX_MEMORY_SEGMENTS]; + struct mem_seg mem_segs[VM_MAX_MEMORY_SEGMENTS]; char name[VM_MAX_NAMELEN]; /* @@ -291,7 +299,7 @@ } static void -vm_free_mem_seg(struct vm *vm, struct vm_memory_segment *seg) +vm_free_mem_seg(struct vm *vm, struct mem_seg *seg) { size_t len; vm_paddr_t hpa; @@ -314,18 +322,19 @@ iommu_remove_mapping(vm->iommu, seg->gpa + len, PAGE_SIZE); iommu_create_mapping(host_domain, hpa, hpa, PAGE_SIZE); - vmm_mem_free(hpa, PAGE_SIZE); - len += PAGE_SIZE; } + if (seg->object != NULL) + vmm_mem_free(seg->object); + /* * Invalidate cached translations associated with 'vm->iommu' since * we have now moved some pages from it. */ iommu_invalidate_tlb(vm->iommu); - bzero(seg, sizeof(struct vm_memory_segment)); + bzero(seg, sizeof(struct mem_seg)); } void @@ -400,8 +409,10 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len) { int error, available, allocated; - struct vm_memory_segment *seg; + struct mem_seg *seg; vm_paddr_t g, hpa; + vm_pindex_t pindex; + vm_page_t m; void *host_domain; const boolean_t spok = TRUE; /* superpage mappings are ok */ @@ -441,16 +452,29 @@ seg = &vm->mem_segs[vm->num_mem_segs]; - error = 0; + seg->object = vmm_mem_alloc(len); + if (seg->object == NULL) { + error = ENOMEM; + goto done; + } + + pindex = 0; seg->gpa = gpa; - seg->len = 0; while (seg->len < len) { - hpa = vmm_mem_alloc(PAGE_SIZE); - if (hpa == 0) { - error = ENOMEM; - break; + VM_OBJECT_WLOCK(seg->object); + + m = vm_page_lookup(seg->object, pindex); + if (m == NULL) + panic("vm_malloc: no page at pindex %lu", pindex); + + if (m->wire_count <= 0) { + panic("vm_malloc: page at pindex %lu not wired", + pindex); } + hpa = VM_PAGE_TO_PHYS(m); + VM_OBJECT_WUNLOCK(seg->object); + error = VMMMAP_SET(vm->cookie, gpa + seg->len, hpa, PAGE_SIZE, VM_MEMATTR_WRITE_BACK, VM_PROT_ALL, spok); if (error) @@ -463,9 +487,11 @@ iommu_remove_mapping(host_domain, hpa, PAGE_SIZE); iommu_create_mapping(vm->iommu, gpa + seg->len, hpa, PAGE_SIZE); + pindex++; seg->len += PAGE_SIZE; } +done: if (error) { vm_free_mem_seg(vm, seg); return (error); @@ -502,7 +528,8 @@ for (i = 0; i < vm->num_mem_segs; i++) { if (gpabase == vm->mem_segs[i].gpa) { - *seg = vm->mem_segs[i]; + seg->gpa = vm->mem_segs[i].gpa; + seg->len = vm->mem_segs[i].len; return (0); } } @@ -510,6 +537,32 @@ } int +vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len, + vm_offset_t *offset, struct vm_object **object) +{ + int i; + vm_paddr_t seg_gpa; + size_t seg_len; + + for (i = 0; i < vm->num_mem_segs; i++) { + if (vm->mem_segs[i].object == NULL) + continue; + + seg_gpa = vm->mem_segs[i].gpa; + seg_len = vm->mem_segs[i].len; + + if (gpa >= seg_gpa && gpa < seg_gpa + seg_len) { + *offset = gpa - vm->mem_segs[i].gpa; + *object = vm->mem_segs[i].object; + vm_object_reference(*object); + return (0); /* found it! */ + } + } + + return (EINVAL); +} + +int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval) { Index: vmm/vmm_dev.c =================================================================== --- vmm/vmm_dev.c (revision 251767) +++ vmm/vmm_dev.c (working copy) @@ -365,21 +365,19 @@ } static int -vmmdev_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr, - int nprot, vm_memattr_t *memattr) +vmmdev_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, + vm_size_t size, struct vm_object **object, int nprot) { int error; struct vmmdev_softc *sc; - error = -1; mtx_lock(&vmmdev_mtx); sc = vmmdev_lookup2(cdev); - if (sc != NULL && (nprot & PROT_EXEC) == 0) { - *paddr = vm_gpa2hpa(sc->vm, (vm_paddr_t)offset, PAGE_SIZE); - if (*paddr != (vm_paddr_t)-1) - error = 0; - } + if (sc != NULL && (nprot & PROT_EXEC) == 0) + error = vm_get_memobj(sc->vm, *offset, size, offset, object); + else + error = EINVAL; mtx_unlock(&vmmdev_mtx); @@ -446,7 +444,7 @@ .d_name = "vmmdev", .d_version = D_VERSION, .d_ioctl = vmmdev_ioctl, - .d_mmap = vmmdev_mmap, + .d_mmap_single = vmmdev_mmap_single, .d_read = vmmdev_rw, .d_write = vmmdev_rw, }; Index: vmm/vmm_mem.c =================================================================== --- vmm/vmm_mem.c (revision 251767) +++ vmm/vmm_mem.c (working copy) @@ -30,15 +30,16 @@ __FBSDID("$FreeBSD$"); #include +#include #include +#include #include -#include +#include #include -#include -#include #include #include +#include #include #include #include @@ -71,60 +72,76 @@ return (0); } -vm_paddr_t +vm_object_t vmm_mem_alloc(size_t size) { - int flags; vm_page_t m; + vm_object_t obj; vm_paddr_t pa; + boolean_t populated; + vm_pindex_t pindex, start, end; - if (size != PAGE_SIZE) + if (size & PAGE_MASK) panic("vmm_mem_alloc: invalid allocation size %lu", size); - flags = VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | - VM_ALLOC_ZERO; + start = 0; + end = OFF_TO_IDX(size); - while (1) { - /* - * XXX need policy to determine when to back off the allocation - */ - m = vm_page_alloc(NULL, 0, flags); - if (m == NULL) - VM_WAIT; - else - break; - } + obj = vm_object_allocate(OBJT_PHYS, end); + if (obj != NULL) { + VM_OBJECT_WLOCK(obj); + if ((populated = vm_object_populate(obj, start, end))) { + for (pindex = start; pindex < end; pindex++) { + m = vm_page_lookup(obj, pindex); + if (m == NULL) + panic("no page at pindex %lu", pindex); - pa = VM_PAGE_TO_PHYS(m); - - if ((m->flags & PG_ZERO) == 0) - pagezero((void *)PHYS_TO_DMAP(pa)); - m->valid = VM_PAGE_BITS_ALL; + pa = VM_PAGE_TO_PHYS(m); - update_pages_allocated(1); + vm_page_lock(m); + vm_page_wire(m); + if ((m->flags & PG_ZERO) == 0) + pagezero((void *)PHYS_TO_DMAP(pa)); + vm_page_unlock(m); - return (pa); + m->valid = VM_PAGE_BITS_ALL; + } + update_pages_allocated(end - start); + } + VM_OBJECT_WUNLOCK(obj); + + if (!populated) { + vm_object_deallocate(obj); + obj = NULL; + } + } + return (obj); } void -vmm_mem_free(vm_paddr_t base, size_t length) +vmm_mem_free(vm_object_t obj) { vm_page_t m; + vm_paddr_t pa; + vm_pindex_t pindex; - if (base & PAGE_MASK) { - panic("vmm_mem_free: base 0x%0lx must be aligned on a " - "0x%0x boundary\n", base, PAGE_SIZE); - } + VM_OBJECT_WLOCK(obj); + for (pindex = 0; pindex < obj->size; pindex++) { + m = vm_page_lookup(obj, pindex); + if (m == NULL) + panic("vmm_mem_free: no page at pindex %lu", pindex); - if (length != PAGE_SIZE) - panic("vmm_mem_free: invalid length %lu", length); + pa = VM_PAGE_TO_PHYS(m); - m = PHYS_TO_VM_PAGE(base); - m->wire_count--; - vm_page_free(m); - atomic_subtract_int(&cnt.v_wire_count, 1); - - update_pages_allocated(-1); + vm_page_lock(m); + vm_page_unwire(m, 0); + pagezero((void *)PHYS_TO_DMAP(pa)); + vm_page_free_zero(m); + vm_page_unlock(m); + update_pages_allocated(-1); + } + VM_OBJECT_WUNLOCK(obj); + vm_object_deallocate(obj); } vm_paddr_t Index: vmm/vmm_mem.h =================================================================== --- vmm/vmm_mem.h (revision 251767) +++ vmm/vmm_mem.h (working copy) @@ -29,9 +29,11 @@ #ifndef _VMM_MEM_H_ #define _VMM_MEM_H_ +struct vm_object; + int vmm_mem_init(void); -vm_paddr_t vmm_mem_alloc(size_t size); -void vmm_mem_free(vm_paddr_t start, size_t size); +struct vm_object *vmm_mem_alloc(size_t size); +void vmm_mem_free(struct vm_object *obj); vm_paddr_t vmm_mem_maxaddr(void); #endif