-/*
- * kmem_io_map_copyout:
- *
- * Establish temporary mapping in designated map for the memory
- * passed in. Memory format must be a page_list vm_map_copy.
- */
-
-kern_return_t
-kmem_io_map_copyout(
- vm_map_t map,
- vm_offset_t *addr, /* actual addr of data */
- vm_size_t *alloc_size, /* size allocated */
- vm_map_copy_t copy,
- vm_size_t min_size, /* Do at least this much */
- vm_prot_t prot) /* Protection of mapping */
-{
- vm_offset_t myaddr, offset;
- vm_size_t mysize, copy_size;
- kern_return_t ret;
- register
- vm_page_t *page_list;
- vm_map_copy_t new_copy;
- register
- int i;
-
- assert(copy->type == VM_MAP_COPY_PAGE_LIST);
- assert(min_size != 0);
-
- /*
- * Figure out the size in vm pages.
- */
- min_size += (vm_size_t)(copy->offset - trunc_page_64(copy->offset));
- min_size = round_page(min_size);
- mysize = (vm_size_t)(round_page_64(
- copy->offset + (vm_object_offset_t)copy->size) -
- trunc_page_64(copy->offset));
-
- /*
- * If total size is larger than one page list and
- * we don't have to do more than one page list, then
- * only do one page list.
- *
- * XXX Could be much smarter about this ... like trimming length
- * XXX if we need more than one page list but not all of them.
- */
-
- copy_size = ptoa(copy->cpy_npages);
- if (mysize > copy_size && copy_size > min_size)
- mysize = copy_size;
-
- /*
- * Allocate some address space in the map (must be kernel
- * space).
- */
- myaddr = vm_map_min(map);
- ret = vm_map_enter(map, &myaddr, mysize,
- (vm_offset_t) 0, TRUE,
- VM_OBJECT_NULL, (vm_object_offset_t) 0, FALSE,
- prot, prot, VM_INHERIT_DEFAULT);
-
- if (ret != KERN_SUCCESS)
- return(ret);
-
- /*
- * Tell the pmap module that this will be wired, and
- * enter the mappings.
- */
- pmap_pageable(vm_map_pmap(map), myaddr, myaddr + mysize, TRUE);
-
- *addr = myaddr + (vm_offset_t)
- (copy->offset - trunc_page_64(copy->offset));
- *alloc_size = mysize;
-
- offset = myaddr;
- page_list = ©->cpy_page_list[0];
- while (TRUE) {
- for ( i = 0; i < copy->cpy_npages; i++, offset+=PAGE_SIZE_64) {
- PMAP_ENTER(vm_map_pmap(map),
- (vm_offset_t)offset, *page_list,
- prot, TRUE);
- page_list++;
- }
-
- if (offset == (myaddr + mysize))
- break;
-
- /*
- * Onward to the next page_list. The extend_cont
- * leaves the current page list's pages alone;
- * they'll be cleaned up at discard. Reset this
- * copy's continuation to discard the next one.
- */
- vm_map_copy_invoke_extend_cont(copy, &new_copy, &ret);
-
- if (ret != KERN_SUCCESS) {
- kmem_io_map_deallocate(map, myaddr, mysize);
- return(ret);
- }
- copy->cpy_cont = vm_map_copy_discard_cont;
- copy->cpy_cont_args = (vm_map_copyin_args_t) new_copy;
- assert(new_copy != VM_MAP_COPY_NULL);
- assert(new_copy->type == VM_MAP_COPY_PAGE_LIST);
- copy = new_copy;
- page_list = ©->cpy_page_list[0];
- }
-
- return(ret);
-}
-
-/*
- * kmem_io_map_deallocate:
- *
- * Get rid of the mapping established by kmem_io_map_copyout.
- * Assumes that addr and size have been rounded to page boundaries.
- */
-
-void
-kmem_io_map_deallocate(
- vm_map_t map,
- vm_offset_t addr,
- vm_size_t size)
-{
-
- register vm_offset_t va, end;
-
- end = round_page(addr + size);
- for (va = trunc_page(addr); va < end; va += PAGE_SIZE)
- pmap_change_wiring(vm_map_pmap(map), va, FALSE);
-
- /*
- * Remove the mappings. The pmap_remove is needed.
- */
-
- pmap_remove(vm_map_pmap(map), addr, addr + size);
- vm_map_remove(map, addr, addr + size, VM_MAP_REMOVE_KUNWIRE);
-}
-