/* * munlock system call handler * * munlock_args(const void *addr, size_t len) * * No requirements */ int sys_munlock(struct munlock_args *uap) { struct thread *td = curthread; struct proc *p = td->td_proc; vm_offset_t addr; vm_offset_t tmpaddr; vm_size_t size, pageoff; int error; addr = (vm_offset_t) uap->addr; size = uap->len; pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; size = (vm_size_t) round_page(size); tmpaddr = addr + size; if (tmpaddr < addr) /* wrap */ return (EINVAL); #ifndef pmap_wired_count error = priv_check(td, PRIV_ROOT); if (error) return (error); #endif error = vm_map_unwire(&p->p_vmspace->vm_map, addr, addr + size, TRUE); return (error == KERN_SUCCESS ? 0 : ENOMEM); }
int vsunlock( user_addr_t addr, user_size_t len, __unused int dirtied) { #if FIXME /* [ */ pmap_t pmap; vm_page_t pg; vm_map_offset_t vaddr; ppnum_t paddr; #endif /* FIXME ] */ kern_return_t kret; vm_map_t map; map = current_map(); #if FIXME /* [ */ if (dirtied) { pmap = get_task_pmap(current_task()); for (vaddr = vm_map_trunc_page(addr, PAGE_MASK); vaddr < vm_map_round_page(addr+len, PAGE_MASK); vaddr += PAGE_SIZE) { paddr = pmap_extract(pmap, vaddr); pg = PHYS_TO_VM_PAGE(paddr); vm_page_set_modified(pg); } } #endif /* FIXME ] */ #ifdef lint dirtied++; #endif /* lint */ kret = vm_map_unwire(map, vm_map_trunc_page(addr, vm_map_page_mask(map)), vm_map_round_page(addr+len, vm_map_page_mask(map)), FALSE); switch (kret) { case KERN_SUCCESS: return (0); case KERN_INVALID_ADDRESS: case KERN_NO_SPACE: return (ENOMEM); case KERN_PROTECTION_FAILURE: return (EACCES); default: return (EINVAL); } }
/* * mlock system call handler * * mlock_args(const void *addr, size_t len) * * No requirements */ int sys_mlock(struct mlock_args *uap) { vm_offset_t addr; vm_offset_t tmpaddr; vm_size_t size, pageoff; struct thread *td = curthread; struct proc *p = td->td_proc; int error; addr = (vm_offset_t) uap->addr; size = uap->len; pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; size = (vm_size_t) round_page(size); if (size < uap->len) /* wrap */ return(EINVAL); tmpaddr = addr + size; /* workaround gcc4 opt */ if (tmpaddr < addr) /* wrap */ return (EINVAL); if (atop(size) + vmstats.v_wire_count > vm_page_max_wired) return (EAGAIN); /* * We do not need to synchronize against other threads updating ucred; * they update p->ucred, which is synchronized into td_ucred ourselves. */ #ifdef pmap_wired_count if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) { return (ENOMEM); } #else error = priv_check_cred(td->td_ucred, PRIV_ROOT, 0); if (error) { return (error); } #endif error = vm_map_unwire(&p->p_vmspace->vm_map, addr, addr + size, FALSE); return (error == KERN_SUCCESS ? 0 : ENOMEM); }
static void vm_gpa_unwire(struct vm *vm) { int i, rv; struct mem_seg *seg; for (i = 0; i < vm->num_mem_segs; i++) { seg = &vm->mem_segs[i]; if (!seg->wired) continue; rv = vm_map_unwire(&vm->vmspace->vm_map, seg->gpa, seg->gpa + seg->len, VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); KASSERT(rv == KERN_SUCCESS, ("vm(%s) memory segment " "%#lx/%ld could not be unwired: %d", vm_name(vm), seg->gpa, seg->len, rv)); seg->wired = FALSE; } }
/* * Return an array of virtual pages that are mapped to a task. */ kern_return_t vm32_mapped_pages_info( __DEBUG_ONLY vm_map_t map, __DEBUG_ONLY page_address_array_t *pages, __DEBUG_ONLY mach_msg_type_number_t *pages_count) { #if !MACH_VM_DEBUG return KERN_FAILURE; #else pmap_t pmap; vm_size_t size, size_used; unsigned int actual, space; page_address_array_t list; vm_offset_t addr = 0; if (map == VM_MAP_NULL) return (KERN_INVALID_ARGUMENT); pmap = map->pmap; size = pmap_resident_count(pmap) * sizeof(vm_offset_t); size = vm_map_round_page(size, VM_MAP_PAGE_MASK(ipc_kernel_map)); for (;;) { (void) vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_IPC)); (void) vm_map_unwire( ipc_kernel_map, vm_map_trunc_page(addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(addr + size, VM_MAP_PAGE_MASK(ipc_kernel_map)), FALSE); list = (page_address_array_t) addr; space = (unsigned int) (size / sizeof(vm_offset_t)); actual = pmap_list_resident_pages(pmap, list, space); if (actual <= space) break; /* * Free memory if not enough */ (void) kmem_free(ipc_kernel_map, addr, size); /* * Try again, doubling the size */ size = vm_map_round_page(actual * sizeof(vm_offset_t), VM_MAP_PAGE_MASK(ipc_kernel_map)); } if (actual == 0) { *pages = 0; *pages_count = 0; (void) kmem_free(ipc_kernel_map, addr, size); } else { vm_size_t vmsize_used; *pages_count = actual; size_used = (actual * sizeof(vm_offset_t)); vmsize_used = vm_map_round_page(size_used, VM_MAP_PAGE_MASK(ipc_kernel_map)); (void) vm_map_wire( ipc_kernel_map, vm_map_trunc_page(addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(addr + size, VM_MAP_PAGE_MASK(ipc_kernel_map)), VM_PROT_READ|VM_PROT_WRITE, FALSE); (void) vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr, (vm_map_size_t)size_used, TRUE, (vm_map_copy_t *)pages); if (vmsize_used != size) { (void) kmem_free(ipc_kernel_map, addr + vmsize_used, size - vmsize_used); } } return (KERN_SUCCESS); #endif /* MACH_VM_DEBUG */ }
kern_return_t vm32_region_info_64( __DEBUG_ONLY vm_map_t map, __DEBUG_ONLY vm32_offset_t address, __DEBUG_ONLY vm_info_region_64_t *regionp, __DEBUG_ONLY vm_info_object_array_t *objectsp, __DEBUG_ONLY mach_msg_type_number_t *objectsCntp) { #if !MACH_VM_DEBUG return KERN_FAILURE; #else vm_map_copy_t copy; vm_offset_t addr = 0; /* memory for OOL data */ vm_size_t size; /* size of the memory */ unsigned int room; /* room for this many objects */ unsigned int used; /* actually this many objects */ vm_info_region_64_t region; kern_return_t kr; if (map == VM_MAP_NULL) return KERN_INVALID_TASK; size = 0; /* no memory allocated yet */ for (;;) { vm_map_t cmap; /* current map in traversal */ vm_map_t nmap; /* next map to look at */ vm_map_entry_t entry; vm_object_t object, cobject, nobject; /* nothing is locked */ vm_map_lock_read(map); for (cmap = map;; cmap = nmap) { /* cmap is read-locked */ if (!vm_map_lookup_entry(cmap, address, &entry)) { entry = entry->vme_next; if (entry == vm_map_to_entry(cmap)) { vm_map_unlock_read(cmap); if (size != 0) kmem_free(ipc_kernel_map, addr, size); return KERN_NO_SPACE; } } if (entry->is_sub_map) nmap = VME_SUBMAP(entry); else break; /* move down to the lower map */ vm_map_lock_read(nmap); vm_map_unlock_read(cmap); } /* cmap is read-locked; we have a real entry */ object = VME_OBJECT(entry); region.vir_start = (natural_t) entry->vme_start; region.vir_end = (natural_t) entry->vme_end; region.vir_object = (natural_t)(uintptr_t) object; region.vir_offset = VME_OFFSET(entry); region.vir_needs_copy = entry->needs_copy; region.vir_protection = entry->protection; region.vir_max_protection = entry->max_protection; region.vir_inheritance = entry->inheritance; region.vir_wired_count = entry->wired_count; region.vir_user_wired_count = entry->user_wired_count; used = 0; room = (unsigned int) (size / sizeof(vm_info_object_t)); if (object == VM_OBJECT_NULL) { vm_map_unlock_read(cmap); /* no memory needed */ break; } vm_object_lock(object); vm_map_unlock_read(cmap); for (cobject = object;; cobject = nobject) { /* cobject is locked */ if (used < room) { vm_info_object_t *vio = &((vm_info_object_t *) addr)[used]; vio->vio_object = (natural_t)(uintptr_t) cobject; vio->vio_size = (natural_t) cobject->vo_size; vio->vio_ref_count = cobject->ref_count; vio->vio_resident_page_count = cobject->resident_page_count; vio->vio_copy = (natural_t)(uintptr_t) cobject->copy; vio->vio_shadow = (natural_t)(uintptr_t) cobject->shadow; vio->vio_shadow_offset = (natural_t) cobject->vo_shadow_offset; vio->vio_paging_offset = (natural_t) cobject->paging_offset; vio->vio_copy_strategy = cobject->copy_strategy; vio->vio_last_alloc = (vm_offset_t) cobject->last_alloc; vio->vio_paging_in_progress = cobject->paging_in_progress + cobject->activity_in_progress; vio->vio_pager_created = cobject->pager_created; vio->vio_pager_initialized = cobject->pager_initialized; vio->vio_pager_ready = cobject->pager_ready; vio->vio_can_persist = cobject->can_persist; vio->vio_internal = cobject->internal; vio->vio_temporary = cobject->temporary; vio->vio_alive = cobject->alive; vio->vio_purgable = (cobject->purgable != VM_PURGABLE_DENY); vio->vio_purgable_volatile = (cobject->purgable == VM_PURGABLE_VOLATILE || cobject->purgable == VM_PURGABLE_EMPTY); } used++; nobject = cobject->shadow; if (nobject == VM_OBJECT_NULL) { vm_object_unlock(cobject); break; } vm_object_lock(nobject); vm_object_unlock(cobject); } /* nothing locked */ if (used <= room) break; /* must allocate more memory */ if (size != 0) kmem_free(ipc_kernel_map, addr, size); size = vm_map_round_page(2 * used * sizeof(vm_info_object_t), VM_MAP_PAGE_MASK(ipc_kernel_map)); kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_IPC)); if (kr != KERN_SUCCESS) return KERN_RESOURCE_SHORTAGE; kr = vm_map_wire( ipc_kernel_map, vm_map_trunc_page(addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(addr + size, VM_MAP_PAGE_MASK(ipc_kernel_map)), VM_PROT_READ|VM_PROT_WRITE, FALSE); assert(kr == KERN_SUCCESS); } /* free excess memory; make remaining memory pageable */ if (used == 0) { copy = VM_MAP_COPY_NULL; if (size != 0) kmem_free(ipc_kernel_map, addr, size); } else { vm_size_t size_used = (used * sizeof(vm_info_object_t)); vm_size_t vmsize_used = vm_map_round_page(size_used, VM_MAP_PAGE_MASK(ipc_kernel_map)); kr = vm_map_unwire( ipc_kernel_map, vm_map_trunc_page(addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(addr + size_used, VM_MAP_PAGE_MASK(ipc_kernel_map)), FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr, (vm_map_size_t)size_used, TRUE, ©); assert(kr == KERN_SUCCESS); if (size != vmsize_used) kmem_free(ipc_kernel_map, addr + vmsize_used, size - vmsize_used); } *regionp = region; *objectsp = (vm_info_object_array_t) copy; *objectsCntp = used; return KERN_SUCCESS; #endif /* MACH_VM_DEBUG */ }
/* * Internal version of mmap. * Currently used by mmap, exec, and sys5 shared memory. * Handle is either a vnode pointer or NULL for MAP_ANON. * * No requirements */ int vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, vm_prot_t maxprot, int flags, void *handle, vm_ooffset_t foff) { boolean_t fitit; vm_object_t object; vm_offset_t eaddr; vm_size_t esize; vm_size_t align; int (*uksmap)(cdev_t dev, vm_page_t fake); struct vnode *vp; struct thread *td = curthread; struct proc *p; int rv = KERN_SUCCESS; off_t objsize; int docow; int error; if (size == 0) return (0); objsize = round_page(size); if (objsize < size) return (EINVAL); size = objsize; lwkt_gettoken(&map->token); /* * XXX messy code, fixme * * NOTE: Overflow checks require discrete statements or GCC4 * will optimize it out. */ if ((p = curproc) != NULL && map == &p->p_vmspace->vm_map) { esize = map->size + size; /* workaround gcc4 opt */ if (esize < map->size || esize > p->p_rlimit[RLIMIT_VMEM].rlim_cur) { lwkt_reltoken(&map->token); return(ENOMEM); } } /* * We currently can only deal with page aligned file offsets. * The check is here rather than in the syscall because the * kernel calls this function internally for other mmaping * operations (such as in exec) and non-aligned offsets will * cause pmap inconsistencies...so we want to be sure to * disallow this in all cases. * * NOTE: Overflow checks require discrete statements or GCC4 * will optimize it out. */ if (foff & PAGE_MASK) { lwkt_reltoken(&map->token); return (EINVAL); } /* * Handle alignment. For large memory maps it is possible * that the MMU can optimize the page table so align anything * that is a multiple of SEG_SIZE to SEG_SIZE. * * Also align any large mapping (bigger than 16x SG_SIZE) to a * SEG_SIZE address boundary. */ if (flags & MAP_SIZEALIGN) { align = size; if ((align ^ (align - 1)) != (align << 1) - 1) { lwkt_reltoken(&map->token); return (EINVAL); } } else if ((flags & MAP_FIXED) == 0 && ((size & SEG_MASK) == 0 || size > SEG_SIZE * 16)) { align = SEG_SIZE; } else { align = PAGE_SIZE; } if ((flags & (MAP_FIXED | MAP_TRYFIXED)) == 0) { fitit = TRUE; *addr = round_page(*addr); } else { if (*addr != trunc_page(*addr)) { lwkt_reltoken(&map->token); return (EINVAL); } eaddr = *addr + size; if (eaddr < *addr) { lwkt_reltoken(&map->token); return (EINVAL); } fitit = FALSE; if ((flags & MAP_TRYFIXED) == 0) vm_map_remove(map, *addr, *addr + size); } uksmap = NULL; /* * Lookup/allocate object. */ if (flags & MAP_ANON) { /* * Unnamed anonymous regions always start at 0. */ if (handle) { /* * Default memory object */ object = default_pager_alloc(handle, objsize, prot, foff); if (object == NULL) { lwkt_reltoken(&map->token); return(ENOMEM); } docow = MAP_PREFAULT_PARTIAL; } else { /* * Implicit single instance of a default memory * object, so we don't need a VM object yet. */ foff = 0; object = NULL; docow = 0; } vp = NULL; } else { vp = (struct vnode *)handle; /* * Non-anonymous mappings of VCHR (aka not /dev/zero) * cannot specify MAP_STACK or MAP_VPAGETABLE. */ if (vp->v_type == VCHR) { if (flags & (MAP_STACK | MAP_VPAGETABLE)) { lwkt_reltoken(&map->token); return(EINVAL); } } if (vp->v_type == VCHR && vp->v_rdev->si_ops->d_uksmap) { /* * Device mappings without a VM object, typically * sharing permanently allocated kernel memory or * process-context-specific (per-process) data. * * Force them to be shared. */ uksmap = vp->v_rdev->si_ops->d_uksmap; object = NULL; docow = MAP_PREFAULT_PARTIAL; flags &= ~(MAP_PRIVATE|MAP_COPY); flags |= MAP_SHARED; } else if (vp->v_type == VCHR) { /* * Device mappings (device size unknown?). * Force them to be shared. */ error = dev_dmmap_single(vp->v_rdev, &foff, objsize, &object, prot, NULL); if (error == ENODEV) { handle = (void *)(intptr_t)vp->v_rdev; object = dev_pager_alloc(handle, objsize, prot, foff); if (object == NULL) { lwkt_reltoken(&map->token); return(EINVAL); } } else if (error) { lwkt_reltoken(&map->token); return(error); } docow = MAP_PREFAULT_PARTIAL; flags &= ~(MAP_PRIVATE|MAP_COPY); flags |= MAP_SHARED; } else { /* * Regular file mapping (typically). The attribute * check is for the link count test only. mmapable * vnodes must already have a VM object assigned. */ struct vattr vat; int error; error = VOP_GETATTR(vp, &vat); if (error) { lwkt_reltoken(&map->token); return (error); } docow = MAP_PREFAULT_PARTIAL; object = vnode_pager_reference(vp); if (object == NULL && vp->v_type == VREG) { lwkt_reltoken(&map->token); kprintf("Warning: cannot mmap vnode %p, no " "object\n", vp); return(EINVAL); } /* * If it is a regular file without any references * we do not need to sync it. */ if (vp->v_type == VREG && vat.va_nlink == 0) { flags |= MAP_NOSYNC; } } } /* * Deal with the adjusted flags */ if ((flags & (MAP_ANON|MAP_SHARED)) == 0) docow |= MAP_COPY_ON_WRITE; if (flags & MAP_NOSYNC) docow |= MAP_DISABLE_SYNCER; if (flags & MAP_NOCORE) docow |= MAP_DISABLE_COREDUMP; #if defined(VM_PROT_READ_IS_EXEC) if (prot & VM_PROT_READ) prot |= VM_PROT_EXECUTE; if (maxprot & VM_PROT_READ) maxprot |= VM_PROT_EXECUTE; #endif /* * This may place the area in its own page directory if (size) is * large enough, otherwise it typically returns its argument. * * (object can be NULL) */ if (fitit) { *addr = pmap_addr_hint(object, *addr, size); } /* * Stack mappings need special attention. * * Mappings that use virtual page tables will default to storing * the page table at offset 0. */ if (uksmap) { rv = vm_map_find(map, uksmap, vp->v_rdev, foff, addr, size, align, fitit, VM_MAPTYPE_UKSMAP, prot, maxprot, docow); } else if (flags & MAP_STACK) { rv = vm_map_stack(map, *addr, size, flags, prot, maxprot, docow); } else if (flags & MAP_VPAGETABLE) { rv = vm_map_find(map, object, NULL, foff, addr, size, align, fitit, VM_MAPTYPE_VPAGETABLE, prot, maxprot, docow); } else { rv = vm_map_find(map, object, NULL, foff, addr, size, align, fitit, VM_MAPTYPE_NORMAL, prot, maxprot, docow); } if (rv != KERN_SUCCESS) { /* * Lose the object reference. Will destroy the * object if it's an unnamed anonymous mapping * or named anonymous without other references. * * (NOTE: object can be NULL) */ vm_object_deallocate(object); goto out; } /* * Shared memory is also shared with children. */ if (flags & (MAP_SHARED|MAP_INHERIT)) { rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); if (rv != KERN_SUCCESS) { vm_map_remove(map, *addr, *addr + size); goto out; } } /* If a process has marked all future mappings for wiring, do so */ if ((rv == KERN_SUCCESS) && (map->flags & MAP_WIREFUTURE)) vm_map_unwire(map, *addr, *addr + size, FALSE); /* * Set the access time on the vnode */ if (vp != NULL) vn_mark_atime(vp, td); out: lwkt_reltoken(&map->token); switch (rv) { case KERN_SUCCESS: return (0); case KERN_INVALID_ADDRESS: case KERN_NO_SPACE: return (ENOMEM); case KERN_PROTECTION_FAILURE: return (EACCES); default: return (EINVAL); } }
DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem) { PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)pMem; int rc; switch (pMemFreeBSD->Core.enmType) { case RTR0MEMOBJTYPE_PAGE: case RTR0MEMOBJTYPE_LOW: case RTR0MEMOBJTYPE_CONT: rc = vm_map_remove(kernel_map, (vm_offset_t)pMemFreeBSD->Core.pv, (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb); AssertMsg(rc == KERN_SUCCESS, ("%#x", rc)); break; case RTR0MEMOBJTYPE_LOCK: { vm_map_t pMap = kernel_map; if (pMemFreeBSD->Core.u.Lock.R0Process != NIL_RTR0PROCESS) pMap = &((struct proc *)pMemFreeBSD->Core.u.Lock.R0Process)->p_vmspace->vm_map; rc = vm_map_unwire(pMap, (vm_offset_t)pMemFreeBSD->Core.pv, (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb, VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES); AssertMsg(rc == KERN_SUCCESS, ("%#x", rc)); break; } case RTR0MEMOBJTYPE_RES_VIRT: { vm_map_t pMap = kernel_map; if (pMemFreeBSD->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS) pMap = &((struct proc *)pMemFreeBSD->Core.u.ResVirt.R0Process)->p_vmspace->vm_map; rc = vm_map_remove(pMap, (vm_offset_t)pMemFreeBSD->Core.pv, (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb); AssertMsg(rc == KERN_SUCCESS, ("%#x", rc)); break; } case RTR0MEMOBJTYPE_MAPPING: { vm_map_t pMap = kernel_map; if (pMemFreeBSD->Core.u.Mapping.R0Process != NIL_RTR0PROCESS) pMap = &((struct proc *)pMemFreeBSD->Core.u.Mapping.R0Process)->p_vmspace->vm_map; rc = vm_map_remove(pMap, (vm_offset_t)pMemFreeBSD->Core.pv, (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb); AssertMsg(rc == KERN_SUCCESS, ("%#x", rc)); break; } case RTR0MEMOBJTYPE_PHYS: case RTR0MEMOBJTYPE_PHYS_NC: { #if __FreeBSD_version >= 1000030 VM_OBJECT_WLOCK(pMemFreeBSD->pObject); #else VM_OBJECT_LOCK(pMemFreeBSD->pObject); #endif vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0); vm_page_lock_queues(); for (vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0); pPage != NULL; pPage = vm_page_next(pPage)) { vm_page_unwire(pPage, 0); } vm_page_unlock_queues(); #if __FreeBSD_version >= 1000030 VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject); #else VM_OBJECT_UNLOCK(pMemFreeBSD->pObject); #endif vm_object_deallocate(pMemFreeBSD->pObject); break; } default: AssertMsgFailed(("enmType=%d\n", pMemFreeBSD->Core.enmType)); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
kern_return_t mach_port_space_info( ipc_space_t space, ipc_info_space_t *infop, ipc_info_name_array_t *tablep, mach_msg_type_number_t *tableCntp, __unused ipc_info_tree_name_array_t *treep, __unused mach_msg_type_number_t *treeCntp) { ipc_info_name_t *table_info; vm_offset_t table_addr; vm_size_t table_size, table_size_needed; ipc_entry_t table; ipc_entry_num_t tsize; mach_port_index_t index; kern_return_t kr; vm_map_copy_t copy; if (space == IS_NULL) return KERN_INVALID_TASK; #if !(DEVELOPMENT | DEBUG) const boolean_t dbg_ok = (mac_task_check_expose_task(kernel_task) == 0); #else const boolean_t dbg_ok = TRUE; #endif /* start with in-line memory */ table_size = 0; for (;;) { is_read_lock(space); if (!is_active(space)) { is_read_unlock(space); if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); return KERN_INVALID_TASK; } table_size_needed = vm_map_round_page((space->is_table_size * sizeof(ipc_info_name_t)), VM_MAP_PAGE_MASK(ipc_kernel_map)); if (table_size_needed == table_size) break; is_read_unlock(space); if (table_size != table_size_needed) { if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed, VM_KERN_MEMORY_IPC); if (kr != KERN_SUCCESS) { return KERN_RESOURCE_SHORTAGE; } table_size = table_size_needed; } } /* space is read-locked and active; we have enough wired memory */ /* get the overall space info */ infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD); infop->iis_table_size = space->is_table_size; infop->iis_table_next = space->is_table_next->its_size; /* walk the table for this space */ table = space->is_table; tsize = space->is_table_size; table_info = (ipc_info_name_array_t)table_addr; for (index = 0; index < tsize; index++) { ipc_info_name_t *iin = &table_info[index]; ipc_entry_t entry = &table[index]; ipc_entry_bits_t bits; bits = entry->ie_bits; iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); iin->iin_collision = 0; iin->iin_type = IE_BITS_TYPE(bits); if ((entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) != MACH_PORT_TYPE_NONE && entry->ie_request != IE_REQ_NONE) { __IGNORE_WCASTALIGN(ipc_port_t port = (ipc_port_t) entry->ie_object); assert(IP_VALID(port)); ip_lock(port); iin->iin_type |= ipc_port_request_type(port, iin->iin_name, entry->ie_request); ip_unlock(port); } iin->iin_urefs = IE_BITS_UREFS(bits); iin->iin_object = (dbg_ok) ? (natural_t)VM_KERNEL_ADDRPERM((uintptr_t)entry->ie_object) : 0; iin->iin_next = entry->ie_next; iin->iin_hash = entry->ie_index; } is_read_unlock(space); /* prepare the table out-of-line data for return */ if (table_size > 0) { vm_size_t used_table_size; used_table_size = infop->iis_table_size * sizeof(ipc_info_name_t); if (table_size > used_table_size) bzero((char *)&table_info[infop->iis_table_size], table_size - used_table_size); kr = vm_map_unwire( ipc_kernel_map, vm_map_trunc_page(table_addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(table_addr + table_size, VM_MAP_PAGE_MASK(ipc_kernel_map)), FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)table_addr, (vm_map_size_t)used_table_size, TRUE, ©); assert(kr == KERN_SUCCESS); *tablep = (ipc_info_name_t *)copy; *tableCntp = infop->iis_table_size; } else { *tablep = (ipc_info_name_t *)0; *tableCntp = 0; } /* splay tree is obsolete, no work to do... */ *treep = (ipc_info_tree_name_t *)0; *treeCntp = 0; return KERN_SUCCESS; }
/* * host_processor_info * * Return info about the processors on this host. It will return * the number of processors, and the specific type of info requested * in an OOL array. */ kern_return_t host_processor_info( host_t host, processor_flavor_t flavor, natural_t *out_pcount, processor_info_array_t *out_array, mach_msg_type_number_t *out_array_count) { kern_return_t result; processor_t processor; host_t thost; processor_info_t info; unsigned int icount, tcount; unsigned int pcount, i; vm_offset_t addr; vm_size_t size, needed; vm_map_copy_t copy; if (host == HOST_NULL) return (KERN_INVALID_ARGUMENT); result = processor_info_count(flavor, &icount); if (result != KERN_SUCCESS) return (result); pcount = processor_count; assert(pcount != 0); needed = pcount * icount * sizeof(natural_t); size = round_page(needed); result = kmem_alloc(ipc_kernel_map, &addr, size); if (result != KERN_SUCCESS) return (KERN_RESOURCE_SHORTAGE); info = (processor_info_t) addr; processor = processor_list; tcount = icount; result = processor_info(processor, flavor, &thost, info, &tcount); if (result != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr, size); return (result); } if (pcount > 1) { for (i = 1; i < pcount; i++) { simple_lock(&processor_list_lock); processor = processor->processor_list; simple_unlock(&processor_list_lock); info += icount; tcount = icount; result = processor_info(processor, flavor, &thost, info, &tcount); if (result != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr, size); return (result); } } } if (size != needed) bzero((char *) addr + needed, size - needed); result = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr), vm_map_round_page(addr + size), FALSE); assert(result == KERN_SUCCESS); result = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr, (vm_map_size_t)size, TRUE, ©); assert(result == KERN_SUCCESS); *out_pcount = pcount; *out_array = (processor_info_array_t) copy; *out_array_count = pcount * icount; return (KERN_SUCCESS); }
kern_return_t mach_port_space_info( ipc_space_t space, ipc_info_space_t *infop, ipc_info_name_array_t *tablep, mach_msg_type_number_t *tableCntp, ipc_info_tree_name_array_t *treep, mach_msg_type_number_t *treeCntp) { ipc_info_name_t *table_info; vm_offset_t table_addr; vm_size_t table_size, table_size_needed; ipc_info_tree_name_t *tree_info; vm_offset_t tree_addr; vm_size_t tree_size, tree_size_needed; ipc_tree_entry_t tentry; ipc_entry_t table; ipc_entry_num_t tsize; mach_port_index_t index; kern_return_t kr; vm_map_copy_t copy; if (space == IS_NULL) return KERN_INVALID_TASK; /* start with in-line memory */ table_size = 0; tree_size = 0; for (;;) { is_read_lock(space); if (!space->is_active) { is_read_unlock(space); if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); if (tree_size != 0) kmem_free(ipc_kernel_map, tree_addr, tree_size); return KERN_INVALID_TASK; } table_size_needed = round_page(space->is_table_size * sizeof(ipc_info_name_t)); tree_size_needed = round_page(space->is_tree_total * sizeof(ipc_info_tree_name_t)); if ((table_size_needed == table_size) && (tree_size_needed == tree_size)) break; is_read_unlock(space); if (table_size != table_size_needed) { if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed); if (kr != KERN_SUCCESS) { if (tree_size != 0) kmem_free(ipc_kernel_map, tree_addr, tree_size); return KERN_RESOURCE_SHORTAGE; } table_size = table_size_needed; } if (tree_size != tree_size_needed) { if (tree_size != 0) kmem_free(ipc_kernel_map, tree_addr, tree_size); kr = kmem_alloc(ipc_kernel_map, &tree_addr, tree_size_needed); if (kr != KERN_SUCCESS) { if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); return KERN_RESOURCE_SHORTAGE; } tree_size = tree_size_needed; } } /* space is read-locked and active; we have enough wired memory */ /* get the overall space info */ infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD); infop->iis_table_size = space->is_table_size; infop->iis_table_next = space->is_table_next->its_size; infop->iis_tree_size = space->is_tree_total; infop->iis_tree_small = space->is_tree_small; infop->iis_tree_hash = space->is_tree_hash; /* walk the table for this space */ table = space->is_table; tsize = space->is_table_size; table_info = (ipc_info_name_array_t)table_addr; for (index = 0; index < tsize; index++) { ipc_info_name_t *iin = &table_info[index]; ipc_entry_t entry = &table[index]; ipc_entry_bits_t bits; bits = entry->ie_bits; iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; iin->iin_type = IE_BITS_TYPE(bits); if (entry->ie_request) iin->iin_type |= MACH_PORT_TYPE_DNREQUEST; iin->iin_urefs = IE_BITS_UREFS(bits); iin->iin_object = (vm_offset_t) entry->ie_object; iin->iin_next = entry->ie_next; iin->iin_hash = entry->ie_index; } /* walk the splay tree for this space */ tree_info = (ipc_info_tree_name_array_t)tree_addr; for (tentry = ipc_splay_traverse_start(&space->is_tree), index = 0; tentry != ITE_NULL; tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { ipc_info_tree_name_t *iitn = &tree_info[index++]; ipc_info_name_t *iin = &iitn->iitn_name; ipc_entry_t entry = &tentry->ite_entry; ipc_entry_bits_t bits = entry->ie_bits; assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); iin->iin_name = tentry->ite_name; iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; iin->iin_type = IE_BITS_TYPE(bits); if (entry->ie_request) iin->iin_type |= MACH_PORT_TYPE_DNREQUEST; iin->iin_urefs = IE_BITS_UREFS(bits); iin->iin_object = (vm_offset_t) entry->ie_object; iin->iin_next = entry->ie_next; iin->iin_hash = entry->ie_index; if (tentry->ite_lchild == ITE_NULL) iitn->iitn_lchild = MACH_PORT_NULL; else iitn->iitn_lchild = tentry->ite_lchild->ite_name; if (tentry->ite_rchild == ITE_NULL) iitn->iitn_rchild = MACH_PORT_NULL; else iitn->iitn_rchild = tentry->ite_rchild->ite_name; } ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); /* prepare the table out-of-line data for return */ if (table_size > 0) { if (table_size > infop->iis_table_size * sizeof(ipc_info_name_t)) bzero((char *)&table_info[infop->iis_table_size], table_size - infop->iis_table_size * sizeof(ipc_info_name_t)); kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(table_addr), vm_map_round_page(table_addr + table_size), FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)table_addr, (vm_map_size_t)table_size, TRUE, ©); assert(kr == KERN_SUCCESS); *tablep = (ipc_info_name_t *)copy; *tableCntp = infop->iis_table_size; } else { *tablep = (ipc_info_name_t *)0; *tableCntp = 0; } /* prepare the tree out-of-line data for return */ if (tree_size > 0) { if (tree_size > infop->iis_tree_size * sizeof(ipc_info_tree_name_t)) bzero((char *)&tree_info[infop->iis_tree_size], tree_size - infop->iis_tree_size * sizeof(ipc_info_tree_name_t)); kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(tree_addr), vm_map_round_page(tree_addr + tree_size), FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)tree_addr, (vm_map_size_t)tree_size, TRUE, ©); assert(kr == KERN_SUCCESS); *treep = (ipc_info_tree_name_t *)copy; *treeCntp = infop->iis_tree_size; } else { *treep = (ipc_info_tree_name_t *)0; *treeCntp = 0; } return KERN_SUCCESS; }
kern_return_t mach_port_names( ipc_space_t space, mach_port_name_t **namesp, mach_msg_type_number_t *namesCnt, mach_port_type_t **typesp, mach_msg_type_number_t *typesCnt) { ipc_entry_bits_t *capability; ipc_tree_entry_t tentry; ipc_entry_t table; ipc_entry_num_t tsize; mach_port_index_t index; ipc_entry_num_t actual; /* this many names */ ipc_port_timestamp_t timestamp; /* logical time of this operation */ mach_port_name_t *names; mach_port_type_t *types; kern_return_t kr; vm_size_t size; /* size of allocated memory */ vm_offset_t addr1; /* allocated memory, for names */ vm_offset_t addr2; /* allocated memory, for types */ vm_map_copy_t memory1; /* copied-in memory, for names */ vm_map_copy_t memory2; /* copied-in memory, for types */ /* safe simplifying assumption */ assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t)); if (space == IS_NULL) return KERN_INVALID_TASK; size = 0; for (;;) { ipc_entry_num_t bound; vm_size_t size_needed; is_read_lock(space); if (!space->is_active) { is_read_unlock(space); if (size != 0) { kmem_free(ipc_kernel_map, addr1, size); kmem_free(ipc_kernel_map, addr2, size); } return KERN_INVALID_TASK; } /* upper bound on number of names in the space */ bound = space->is_table_size + space->is_tree_total; size_needed = round_page_32(bound * sizeof(mach_port_name_t)); if (size_needed <= size) break; is_read_unlock(space); if (size != 0) { kmem_free(ipc_kernel_map, addr1, size); kmem_free(ipc_kernel_map, addr2, size); } size = size_needed; kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE); if (kr != KERN_SUCCESS) return KERN_RESOURCE_SHORTAGE; kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE); if (kr != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr1, size); return KERN_RESOURCE_SHORTAGE; } /* can't fault while we hold locks */ kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size, VM_PROT_READ|VM_PROT_WRITE, FALSE); if (kr != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr1, size); kmem_free(ipc_kernel_map, addr2, size); return KERN_RESOURCE_SHORTAGE; } kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size, VM_PROT_READ|VM_PROT_WRITE, FALSE); if (kr != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr1, size); kmem_free(ipc_kernel_map, addr2, size); return KERN_RESOURCE_SHORTAGE; } } /* space is read-locked and active */ names = (mach_port_name_t *) addr1; types = (mach_port_type_t *) addr2; actual = 0; timestamp = ipc_port_timestamp(); table = space->is_table; tsize = space->is_table_size; for (index = 0; index < tsize; index++) { ipc_entry_t entry = &table[index]; ipc_entry_bits_t bits = entry->ie_bits; if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) { mach_port_name_t name; name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); mach_port_names_helper(timestamp, entry, name, names, types, &actual, space); } } for (tentry = ipc_splay_traverse_start(&space->is_tree); tentry != ITE_NULL; tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { ipc_entry_t entry = &tentry->ite_entry; mach_port_name_t name = tentry->ite_name; assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE); mach_port_names_helper(timestamp, entry, name, names, types, &actual, space); } ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual == 0) { memory1 = VM_MAP_COPY_NULL; memory2 = VM_MAP_COPY_NULL; if (size != 0) { kmem_free(ipc_kernel_map, addr1, size); kmem_free(ipc_kernel_map, addr2, size); } } else { vm_size_t size_used; vm_size_t vm_size_used; size_used = actual * sizeof(mach_port_name_t); vm_size_used = round_page_32(size_used); /* * Make used memory pageable and get it into * copied-in form. Free any unused memory. */ kr = vm_map_unwire(ipc_kernel_map, addr1, addr1 + vm_size_used, FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_unwire(ipc_kernel_map, addr2, addr2 + vm_size_used, FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, addr1, size_used, TRUE, &memory1); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, addr2, size_used, TRUE, &memory2); assert(kr == KERN_SUCCESS); if (vm_size_used != size) { kmem_free(ipc_kernel_map, addr1 + vm_size_used, size - vm_size_used); kmem_free(ipc_kernel_map, addr2 + vm_size_used, size - vm_size_used); } } *namesp = (mach_port_name_t *) memory1; *namesCnt = actual; *typesp = (mach_port_type_t *) memory2; *typesCnt = actual; return KERN_SUCCESS; }
kern_return_t mach_port_get_set_status( ipc_space_t space, mach_port_name_t name, mach_port_name_t **members, mach_msg_type_number_t *membersCnt) { ipc_entry_num_t actual; /* this many members */ ipc_entry_num_t maxnames; /* space for this many members */ kern_return_t kr; vm_size_t size; /* size of allocated memory */ vm_offset_t addr; /* allocated memory */ vm_map_copy_t memory; /* copied-in memory */ if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name)) return KERN_INVALID_RIGHT; size = PAGE_SIZE; /* initial guess */ for (;;) { ipc_tree_entry_t tentry; ipc_entry_t entry, table; ipc_entry_num_t tsize; mach_port_index_t index; mach_port_name_t *names; ipc_pset_t pset; kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE); if (kr != KERN_SUCCESS) return KERN_RESOURCE_SHORTAGE; /* can't fault while we hold locks */ kr = vm_map_wire(ipc_kernel_map, addr, addr + size, VM_PROT_READ|VM_PROT_WRITE, FALSE); assert(kr == KERN_SUCCESS); kr = ipc_right_lookup_read(space, name, &entry); if (kr != KERN_SUCCESS) { kmem_free(ipc_kernel_map, addr, size); return kr; } /* space is read-locked and active */ if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) { is_read_unlock(space); kmem_free(ipc_kernel_map, addr, size); return KERN_INVALID_RIGHT; } pset = (ipc_pset_t) entry->ie_object; assert(pset != IPS_NULL); /* the port set must be active */ names = (mach_port_name_t *) addr; maxnames = size / sizeof(mach_port_name_t); actual = 0; table = space->is_table; tsize = space->is_table_size; for (index = 0; index < tsize; index++) { ipc_entry_t ientry = &table[index]; if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) { ipc_port_t port = (ipc_port_t) ientry->ie_object; mach_port_gst_helper(pset, port, maxnames, names, &actual); } } for (tentry = ipc_splay_traverse_start(&space->is_tree); tentry != ITE_NULL; tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) { ipc_entry_bits_t bits = tentry->ite_bits; assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); if (bits & MACH_PORT_TYPE_RECEIVE) { ipc_port_t port = (ipc_port_t) tentry->ite_object; mach_port_gst_helper(pset, port, maxnames, names, &actual); } } ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual <= maxnames) break; /* didn't have enough memory; allocate more */ kmem_free(ipc_kernel_map, addr, size); size = round_page_32(actual * sizeof(mach_port_name_t)) + PAGE_SIZE; } if (actual == 0) { memory = VM_MAP_COPY_NULL; kmem_free(ipc_kernel_map, addr, size); } else { vm_size_t size_used; vm_size_t vm_size_used; size_used = actual * sizeof(mach_port_name_t); vm_size_used = round_page_32(size_used); /* * Make used memory pageable and get it into * copied-in form. Free any unused memory. */ kr = vm_map_unwire(ipc_kernel_map, addr, addr + vm_size_used, FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, addr, size_used, TRUE, &memory); assert(kr == KERN_SUCCESS); if (vm_size_used != size) kmem_free(ipc_kernel_map, addr + vm_size_used, size - vm_size_used); } *members = (mach_port_name_t *) memory; *membersCnt = actual; return KERN_SUCCESS; }