diff --git a/include/mach/mach4.defs b/include/mach/mach4.defs index 114edf4..4ecc0f5 100644 --- a/include/mach/mach4.defs +++ b/include/mach/mach4.defs @@ -110,3 +110,18 @@ routine memory_object_create_proxy( start : vm_offset_array_t; len : vm_offset_array_t; out proxy : mach_port_t); + + +/* + * Specify that the range of the virtual address space + * of the task must not cause page faults for + * the indicated accesses. + * + * [ To unwire the pages, specify VM_PROT_NONE. ] + */ +routine vm_task_wire( + task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + access : vm_prot_t); + diff --git a/vm/vm_map.c b/vm/vm_map.c index 6b13724..ae3ce21 100644 --- a/vm/vm_map.c +++ b/vm/vm_map.c @@ -208,6 +208,7 @@ void vm_map_setup( rbtree_init(&map->hdr.tree); map->size = 0; + map->user_wired = 0; map->ref_count = 1; map->pmap = pmap; map->min_offset = min; @@ -1409,7 +1410,10 @@ kern_return_t vm_map_pageable_common( if (user_wire) { if (--(entry->user_wired_count) == 0) + { + map->user_wired -= entry->vme_end - entry->vme_start; entry->wired_count--; + } } else { entry->wired_count--; @@ -1486,7 +1490,10 @@ kern_return_t vm_map_pageable_common( if (user_wire) { if ((entry->user_wired_count)++ == 0) + { + map->user_wired += entry->vme_end - entry->vme_start; entry->wired_count++; + } } else { entry->wired_count++; @@ -1512,6 +1519,7 @@ kern_return_t vm_map_pageable_common( (entry->vme_end > start)) { if (user_wire) { if (--(entry->user_wired_count) == 0) + map->user_wired -= entry->vme_end - entry->vme_start; entry->wired_count--; } else { @@ -1627,6 +1635,8 @@ void vm_map_entry_delete( if (entry->wired_count != 0) { vm_fault_unwire(map, entry); entry->wired_count = 0; + if (entry->user_wired_count) + map->user_wired -= entry->vme_end - entry->vme_start; entry->user_wired_count = 0; } @@ -2274,6 +2284,8 @@ start_pass_1: entry->offset = copy_entry->offset; entry->needs_copy = copy_entry->needs_copy; entry->wired_count = 0; + if (entry->user_wired_count) + dst_map->user_wired -= entry->vme_end - entry->vme_start; entry->user_wired_count = 0; vm_map_copy_entry_unlink(copy, copy_entry); @@ -2869,6 +2881,7 @@ create_object: if (must_wire) { entry->wired_count = 1; + dst_map->user_wired += entry->vme_end - entry->vme_start; entry->user_wired_count = 1; } else { entry->wired_count = 0; @@ -3954,6 +3967,8 @@ retry: assert(src_entry->wired_count > 0); src_entry->wired_count = 0; + if (src_entry->user_wired_count) + src_map->user_wired -= src_entry->vme_end - src_entry->vme_start; src_entry->user_wired_count = 0; unwire_end = src_entry->vme_end; pmap_pageable(vm_map_pmap(src_map), diff --git a/vm/vm_map.h b/vm/vm_map.h index fc7730a..9b31f90 100644 --- a/vm/vm_map.h +++ b/vm/vm_map.h @@ -170,6 +170,7 @@ struct vm_map { #define max_offset hdr.links.end /* end of range */ pmap_t pmap; /* Physical map */ vm_size_t size; /* virtual size */ + vm_size_t user_wired; /* wired by user size */ int ref_count; /* Reference count */ decl_simple_lock_data(, ref_lock) /* Lock for ref_count field */ vm_map_entry_t hint; /* hint for quick lookups */ diff --git a/vm/vm_user.c b/vm/vm_user.c index f7c87cc..e62dc42 100644 --- a/vm/vm_user.c +++ b/vm/vm_user.c @@ -431,3 +431,37 @@ kern_return_t vm_wire(host, map, start, size, access) round_page(start+size), access); } + +/* + * Specify that the range of the virtual address space + * of the target task must not cause page faults for + * the indicated accesses. + * + * [ To unwire the pages, specify VM_PROT_NONE. ] + */ +kern_return_t vm_task_wire(task, start, size, access) + vm_map_t task; + vm_offset_t start; + vm_size_t size; + vm_prot_t access; +{ + if (task == VM_MAP_NULL) + return KERN_INVALID_TASK; + + if (access & ~VM_PROT_ALL) + return KERN_INVALID_ARGUMENT; + + /*Check if range includes projected buffer; + user is not allowed direct manipulation in that case*/ + if (projected_buffer_in_range(task, start, start+size)) + return(KERN_INVALID_ARGUMENT); + + /* TODO: make it tunable */ + if (access != VM_PROT_NONE && task->user_wired + size > 65536) + return KERN_NO_ACCESS; + + return vm_map_pageable_user(task, + trunc_page(start), + round_page(start+size), + access); +}