-/* Retrieve a upl for an object underlying an address range in a map */
-
-kern_return_t
-vm_map_get_upl(
- vm_map_t map,
- vm_address_t offset,
- vm_size_t *upl_size,
- upl_t *upl,
- upl_page_info_array_t page_list,
- unsigned int *count,
- int *flags,
- int force_data_sync)
-{
- vm_map_entry_t entry;
- int caller_flags;
- int sync_cow_data = FALSE;
- vm_object_t local_object;
- vm_offset_t local_offset;
- vm_offset_t local_start;
- kern_return_t ret;
-
- caller_flags = *flags;
- if (!(caller_flags & UPL_COPYOUT_FROM)) {
- sync_cow_data = TRUE;
- }
- if(upl == NULL)
- return KERN_INVALID_ARGUMENT;
-
-
-REDISCOVER_ENTRY:
- vm_map_lock(map);
- if (vm_map_lookup_entry(map, offset, &entry)) {
- if (entry->object.vm_object == VM_OBJECT_NULL ||
- !entry->object.vm_object->phys_contiguous) {
- if((*upl_size/page_size) > MAX_UPL_TRANSFER) {
- *upl_size = MAX_UPL_TRANSFER * page_size;
- }
- }
- if((entry->vme_end - offset) < *upl_size) {
- *upl_size = entry->vme_end - offset;
- }
- if (caller_flags & UPL_QUERY_OBJECT_TYPE) {
- if (entry->object.vm_object == VM_OBJECT_NULL) {
- *flags = 0;
- } else if (entry->object.vm_object->private) {
- *flags = UPL_DEV_MEMORY;
- if (entry->object.vm_object->phys_contiguous) {
- *flags |= UPL_PHYS_CONTIG;
- }
- } else {
- *flags = 0;
- }
- vm_map_unlock(map);
- return KERN_SUCCESS;
- }
- /*
- * Create an object if necessary.
- */
- if (entry->object.vm_object == VM_OBJECT_NULL) {
- entry->object.vm_object = vm_object_allocate(
- (vm_size_t)(entry->vme_end - entry->vme_start));
- entry->offset = 0;
- }
- if (!(caller_flags & UPL_COPYOUT_FROM)) {
- if (!(entry->protection & VM_PROT_WRITE)) {
- vm_map_unlock(map);
- return KERN_PROTECTION_FAILURE;
- }
- if (entry->needs_copy) {
- vm_map_t local_map;
- vm_object_t object;
- vm_object_offset_t offset_hi;
- vm_object_offset_t offset_lo;
- vm_object_offset_t new_offset;
- vm_prot_t prot;
- boolean_t wired;
- vm_behavior_t behavior;
- vm_map_version_t version;
- vm_map_t pmap_map;
-
- local_map = map;
- vm_map_lock_write_to_read(map);
- if(vm_map_lookup_locked(&local_map,
- offset, VM_PROT_WRITE,
- &version, &object,
- &new_offset, &prot, &wired,
- &behavior, &offset_lo,
- &offset_hi, &pmap_map)) {
- vm_map_unlock(local_map);
- return KERN_FAILURE;
- }
- if (pmap_map != map) {
- vm_map_unlock(pmap_map);
- }
- vm_object_unlock(object);
- vm_map_unlock(local_map);
-
- goto REDISCOVER_ENTRY;
- }
- }
- if (entry->is_sub_map) {
- vm_map_t submap;
-
- submap = entry->object.sub_map;
- local_start = entry->vme_start;
- local_offset = entry->offset;
- vm_map_reference(submap);
- vm_map_unlock(map);
-
- ret = (vm_map_get_upl(submap,
- local_offset + (offset - local_start),
- upl_size, upl, page_list, count,
- flags, force_data_sync));
-
- vm_map_deallocate(submap);
- return ret;
- }
-
- if (sync_cow_data) {
- if (entry->object.vm_object->shadow
- || entry->object.vm_object->copy) {
- int flags;
-
- local_object = entry->object.vm_object;
- local_start = entry->vme_start;
- local_offset = entry->offset;
- vm_object_reference(local_object);
- vm_map_unlock(map);