xref: /xnu-12377.41.6/tests/vm/configurator_vm_wire.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * vm/configurator_vm_wire.c
31  *
32  * Test vm_wire with many different VM states.
33  */
34 
35 #include "configurator/vm_configurator_tests.h"
36 
37 T_GLOBAL_META(
38 	T_META_NAMESPACE("xnu.vm.configurator"),
39 	T_META_RADAR_COMPONENT_NAME("xnu"),
40 	T_META_RADAR_COMPONENT_VERSION("VM"),
41 	T_META_RUN_CONCURRENTLY(true),
42 	T_META_ALL_VALID_ARCHS(true),
43 	T_META_ASROOT(true)  /* root required for vm_wire on macOS */
44 	);
45 
46 /*
47  * Update checker state to mirror a successful call to
48  * vm_wire(PROT_NONE) a.k.a. unwire
49  */
50 static void
checker_perform_vm_unwire(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)51 checker_perform_vm_unwire(
52 	checker_list_t *checker_list,
53 	mach_vm_address_t start,
54 	mach_vm_size_t size)
55 {
56 	entry_checker_range_t limit = checker_list_find_and_clip(checker_list, start, size);
57 	FOREACH_CHECKER(checker, limit) {
58 		assert(checker->user_wired_count > 0);
59 		checker->user_wired_count--;
60 	}
61 	checker_list_simplify(checker_list, start, size);
62 }
63 
64 
65 /*
66  * Update checker state to mirror a successful call to
67  * vm_wire(PROT_NONE) a.k.a. unwire
68  * of a range that includes holes.
69  */
70 static kern_return_t
checker_perform_vm_unwire_with_holes(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)71 checker_perform_vm_unwire_with_holes(
72 	checker_list_t *checker_list,
73 	mach_vm_address_t start,
74 	mach_vm_size_t size)
75 {
76 	entry_checker_range_t limit = checker_list_find_range_including_holes(checker_list, start, size);
77 
78 	if (limit.head && limit.head->kind == Allocation &&
79 	    checker_contains_address(limit.head, start)) {
80 		/* range begins with an allocation - proceed normally */
81 	} else {
82 		/* range begins with a hole - do nothing, not even simplify */
83 		return KERN_INVALID_ADDRESS;
84 	}
85 
86 	FOREACH_CHECKER(checker, limit) {
87 		if (checker->kind == Allocation) {
88 			assert(checker->user_wired_count > 0);
89 			checker->user_wired_count--;
90 		}
91 	}
92 
93 	checker_list_simplify(checker_list, start, size);
94 	return KERN_SUCCESS;
95 }
96 
97 
98 /*
99  * Update checker state to mirrow a successful call to vm_wire.
100  */
101 static void
checker_perform_vm_wire(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,vm_prot_t wire_prot)102 checker_perform_vm_wire(
103 	checker_list_t *checker_list,
104 	mach_vm_address_t start,
105 	mach_vm_size_t size,
106 	vm_prot_t wire_prot)
107 {
108 	assert(wire_prot != VM_PROT_NONE);
109 
110 	entry_checker_range_t limit;
111 
112 	/*
113 	 * Resolve null objects.
114 	 * vm_wire does this before clipping
115 	 */
116 	limit = checker_list_find_range_including_holes(checker_list, start, size);
117 	FOREACH_CHECKER(checker, limit) {
118 		checker_resolve_null_vm_object(checker_list, checker);
119 	}
120 
121 	/*
122 	 * Perform clipping.
123 	 */
124 	limit = checker_list_find_range(checker_list, start, size);
125 	checker_clip_left(checker_list, limit.head, start);
126 	checker_clip_right(checker_list, limit.tail, start + size);
127 
128 	/*
129 	 * Fault and wire.
130 	 */
131 
132 	FOREACH_CHECKER(checker, limit) {
133 		checker->user_wired_count++;
134 		checker_fault_for_prot_not_cow(checker_list, checker, wire_prot);
135 	}
136 	checker_list_simplify(checker_list, start, size);
137 }
138 
139 
140 static void
checker_perform_failed_vm_wire(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,vm_prot_t wire_prot)141 checker_perform_failed_vm_wire(
142 	checker_list_t *checker_list,
143 	mach_vm_address_t start,
144 	mach_vm_size_t size,
145 	vm_prot_t wire_prot)
146 {
147 	assert(wire_prot != VM_PROT_NONE);
148 
149 	/*
150 	 * failed vm_wire clips entries and resolves null vm_objects
151 	 * one at a time until the entry that it couldn't change
152 	 *
153 	 * failed vm_wire doesn't simplify clipped entries on exit
154 	 *
155 	 * failed vm_wire is inconsistent about resident page counts
156 	 */
157 
158 	entry_checker_range_t limit =
159 	    checker_list_find_range_including_holes(checker_list, start, size);
160 	FOREACH_CHECKER(checker, limit) {
161 		if (checker->kind != Allocation) {
162 			/* stop at holes */
163 			break;
164 		}
165 
166 		/* wire of executable entry fails early */
167 		if (prot_contains_all(checker->protection, VM_PROT_EXECUTE)) {
168 			// (fixme jit, tpro)
169 			break;
170 		}
171 
172 		/* null vm_objects are resolved before clipping */
173 		checker_resolve_null_vm_object(checker_list, checker);
174 
175 		if (checker == limit.head) {
176 			checker_clip_left(checker_list, checker, start);
177 		}
178 		if (checker == limit.tail) {
179 			checker_clip_right(checker_list, checker, start + size);
180 		}
181 
182 		if (!prot_contains_all(checker->protection, wire_prot)) {
183 			/* stop at protection failures */
184 			break;
185 		}
186 
187 		if (checker != limit.tail && checker->next->kind != Allocation) {
188 			/* stop if the *next* entry is in range and is an illegal hole */
189 			break;
190 		}
191 
192 		/*
193 		 * failed vm_wire simplifies and faults in,
194 		 * except for the cases already short-circuited above
195 		 */
196 		checker_fault_for_prot_not_cow(checker_list, checker, wire_prot);
197 		checker_simplify_left(checker_list, checker);
198 	}
199 }
200 
201 
202 static test_result_t
successful_vm_wire_read_not_cow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)203 successful_vm_wire_read_not_cow(
204 	checker_list_t *checker_list,
205 	mach_vm_address_t start,
206 	mach_vm_size_t size)
207 {
208 	kern_return_t kr;
209 
210 	checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
211 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
212 	if (kr) {
213 		T_FAIL("mach_vm_wire failed (%s)", name_for_kr(kr));
214 		return TestFailed;
215 	}
216 
217 	if (verify_vm_state(checker_list, "after vm_wire") != TestSucceeded) {
218 		return TestFailed;
219 	}
220 
221 	checker_perform_vm_unwire(checker_list, start, size);
222 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_NONE);
223 	if (kr) {
224 		T_FAIL("mach_vm_wire(unwire) failed (%s)", name_for_kr(kr));
225 		return TestFailed;
226 	}
227 
228 	if (verify_vm_state(checker_list, "after vm_unwire") != TestSucceeded) {
229 		return TestFailed;
230 	}
231 
232 	return TestSucceeded;
233 }
234 
235 static test_result_t
failed_vm_wire_read_not_cow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)236 failed_vm_wire_read_not_cow(
237 	checker_list_t *checker_list,
238 	mach_vm_address_t start,
239 	mach_vm_size_t size)
240 {
241 	kern_return_t kr;
242 
243 	checker_perform_failed_vm_wire(checker_list, start, size, VM_PROT_READ);
244 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
245 	if (kr == KERN_SUCCESS) {
246 		T_FAIL("mach_vm_wire unexpectedly succeeded");
247 		return TestFailed;
248 	}
249 
250 	return verify_vm_state(checker_list, "after unsuccessful vm_wire");
251 }
252 
253 static test_result_t
wire_shared_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)254 wire_shared_entry(
255 	checker_list_t *checker_list,
256 	mach_vm_address_t start,
257 	mach_vm_size_t size)
258 {
259 	/* two entries each sharing the same object */
260 	vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
261 
262 	kern_return_t kr;
263 
264 	/*
265 	 * Wire the left entry. The right entry also faults in but
266 	 * stays at wire count zero.
267 	 */
268 	checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
269 	checker_fault_for_prot_not_cow(checker_list, right_checker, VM_PROT_READ);
270 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
271 	assert(kr == 0);
272 
273 	return verify_vm_state(checker_list, "after vm_wire shared");
274 }
275 
276 static test_result_t
wire_shared_entry_discontiguous(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)277 wire_shared_entry_discontiguous(
278 	checker_list_t *checker_list,
279 	mach_vm_address_t start,
280 	mach_vm_size_t size)
281 {
282 	/*
283 	 * two entries each sharing the same object
284 	 * but only partially overlap inside that object.
285 	 * Wiring the left entry does not affect the right entry,
286 	 * so this looks like an ordinary vm_wire test.
287 	 */
288 	return successful_vm_wire_read_not_cow(checker_list, start, size);
289 }
290 
291 static test_result_t
wire_shared_entry_partial(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)292 wire_shared_entry_partial(
293 	checker_list_t *checker_list,
294 	mach_vm_address_t start,
295 	mach_vm_size_t size)
296 {
297 	/*
298 	 * two entries each sharing the same object
299 	 * but only partially overlap inside that object
300 	 */
301 	vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
302 	mach_vm_address_t right_offset = DEFAULT_PARTIAL_ENTRY_SIZE;
303 
304 	kern_return_t kr;
305 
306 	/*
307 	 * Wire the left entry. The right entry stays at wire count zero
308 	 * and only the overlapping section faults in.
309 	 */
310 	checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
311 	right_checker->pages_resident = (uint32_t)((size - right_offset) / PAGE_SIZE);
312 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
313 	assert(kr == 0);
314 
315 	return verify_vm_state(checker_list, "after vm_wire shared partial");
316 }
317 
318 static void
checker_make_cow_private(checker_list_t * checker_list,vm_entry_checker_t * checker)319 checker_make_cow_private(
320 	checker_list_t *checker_list,
321 	vm_entry_checker_t *checker)
322 {
323 	if (checker->object->self_ref_count == 1) {
324 		/*
325 		 * COW but not shared with anything else.
326 		 * VM resolves COW by using the same object.
327 		 */
328 		checker->needs_copy = false;
329 		return;
330 	}
331 
332 	/* make new object */
333 	vm_object_checker_t *obj_checker = object_checker_clone(checker->object);
334 	checker_list_append_object(checker_list, obj_checker);
335 
336 	/* change object and entry to private */
337 	checker->needs_copy = false;
338 
339 	/* set new object (decreasing previous object's self_ref_count) */
340 	checker_set_object(checker, obj_checker);
341 }
342 
343 static test_result_t
wire_cow_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)344 wire_cow_entry(
345 	checker_list_t *checker_list,
346 	mach_vm_address_t start,
347 	mach_vm_size_t size)
348 {
349 	/* Wiring a COW entry resolves COW but has no effect on other copies. */
350 
351 	vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
352 	checker_make_cow_private(checker_list, left_checker);
353 
354 	return successful_vm_wire_read_not_cow(checker_list, start, size);
355 }
356 
357 static test_result_t
wire_cow_nocow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)358 wire_cow_nocow(
359 	checker_list_t *checker_list,
360 	mach_vm_address_t start,
361 	mach_vm_size_t size)
362 {
363 	vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
364 	checker_make_cow_private(checker_list, left_checker);
365 
366 	return successful_vm_wire_read_not_cow(checker_list, start, size);
367 }
368 
369 static test_result_t
wire_nocow_cow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)370 wire_nocow_cow(
371 	checker_list_t *checker_list,
372 	mach_vm_address_t start,
373 	mach_vm_size_t size)
374 {
375 	vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
376 	vm_entry_checker_t *right_checker = left_checker->next;
377 	checker_make_cow_private(checker_list, right_checker);
378 
379 	return successful_vm_wire_read_not_cow(checker_list, start, size);
380 }
381 
382 static test_result_t
wire_cow_unreadable(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)383 wire_cow_unreadable(
384 	checker_list_t *checker_list,
385 	mach_vm_address_t start,
386 	mach_vm_size_t size)
387 {
388 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
389 	checker_make_shadow_object(checker_list, checker);
390 	return failed_vm_wire_read_not_cow(checker_list, start, size);
391 }
392 
393 static test_result_t
wire_cow_unwriteable(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)394 wire_cow_unwriteable(
395 	checker_list_t *checker_list,
396 	mach_vm_address_t start,
397 	mach_vm_size_t size)
398 {
399 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
400 	checker_make_cow_private(checker_list, checker);
401 
402 	return successful_vm_wire_read_not_cow(checker_list, start, size);
403 }
404 
405 
406 /*
407  * Test vm_unwire with a range that includes holes.
408  * We wire each allocation separately, then unwire the entire range
409  * to test unwire's behavior across holes without reference to
410  * wire's behavior across holes.
411  */
412 static test_result_t
vm_unwire_holes(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)413 vm_unwire_holes(
414 	checker_list_t *checker_list,
415 	mach_vm_address_t start,
416 	mach_vm_size_t size)
417 {
418 	kern_return_t kr, expected_kr;
419 
420 	/*
421 	 * Wire each allocation separately,
422 	 * then unwire the entire range at once.
423 	 */
424 
425 	mach_vm_address_t end = start + size;
426 
427 	entry_checker_range_t limit =
428 	    checker_list_find_range_including_holes(checker_list, start, size);
429 
430 	FOREACH_CHECKER(checker, limit) {
431 		if (checker->kind == Allocation) {
432 			/*
433 			 * we manually "clip" our address range here
434 			 * because the real checker clipping must
435 			 * be done inside checker_perform_vm_wire()
436 			 * because wire's clip behavior is weird
437 			 */
438 			mach_vm_address_t clipped_address = max(start, checker->address);
439 			mach_vm_address_t clipped_end = min(checker_end_address(checker), end);
440 			mach_vm_size_t clipped_size = clipped_end - clipped_address;
441 			kr = mach_vm_wire(host_priv(), mach_task_self(),
442 			    clipped_address, clipped_size, VM_PROT_READ);
443 			assert(kr == 0);
444 			checker_perform_vm_wire(checker_list,
445 			    clipped_address, clipped_size, VM_PROT_READ);
446 		}
447 	}
448 
449 	if (verify_vm_state(checker_list, "before vm_unwire") != TestSucceeded) {
450 		return TestFailed;
451 	}
452 
453 	expected_kr = checker_perform_vm_unwire_with_holes(checker_list, start, size);
454 	kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_NONE);
455 	if (kr != expected_kr) {
456 		T_FAIL("mach_vm_wire(unwire) returned %d (%s), expected %d (%s)\n",
457 		    kr, name_for_kr(kr), expected_kr, name_for_kr(expected_kr));
458 		return TestFailed;
459 	}
460 
461 	if (verify_vm_state(checker_list, "after vm_unwire") != TestSucceeded) {
462 		return TestFailed;
463 	}
464 
465 	return TestSucceeded;
466 }
467 
468 T_DECL(vm_wire,
469     "run vm_wire with various vm configurations")
470 {
471 	vm_tests_t tests = {
472 		.single_entry_1 = successful_vm_wire_read_not_cow,
473 		.single_entry_2 = successful_vm_wire_read_not_cow,
474 		.single_entry_3 = successful_vm_wire_read_not_cow,
475 		.single_entry_4 = successful_vm_wire_read_not_cow,
476 
477 		.multiple_entries_1 = successful_vm_wire_read_not_cow,
478 		.multiple_entries_2 = successful_vm_wire_read_not_cow,
479 		.multiple_entries_3 = successful_vm_wire_read_not_cow,
480 		.multiple_entries_4 = successful_vm_wire_read_not_cow,
481 		.multiple_entries_5 = successful_vm_wire_read_not_cow,
482 		.multiple_entries_6 = successful_vm_wire_read_not_cow,
483 
484 		.some_holes_1 = failed_vm_wire_read_not_cow,
485 		.some_holes_2 = failed_vm_wire_read_not_cow,
486 		.some_holes_3 = failed_vm_wire_read_not_cow,
487 		.some_holes_4 = failed_vm_wire_read_not_cow,
488 		.some_holes_5 = failed_vm_wire_read_not_cow,
489 		.some_holes_6 = failed_vm_wire_read_not_cow,
490 		.some_holes_7 = failed_vm_wire_read_not_cow,
491 		.some_holes_8 = failed_vm_wire_read_not_cow,
492 		.some_holes_9 = failed_vm_wire_read_not_cow,
493 		.some_holes_10 = failed_vm_wire_read_not_cow,
494 		.some_holes_11 = failed_vm_wire_read_not_cow,
495 		.some_holes_12 = failed_vm_wire_read_not_cow,
496 
497 		.all_holes_1 = failed_vm_wire_read_not_cow,
498 		.all_holes_2 = failed_vm_wire_read_not_cow,
499 		.all_holes_3 = failed_vm_wire_read_not_cow,
500 		.all_holes_4 = failed_vm_wire_read_not_cow,
501 
502 		.null_entry        = successful_vm_wire_read_not_cow,
503 		.nonresident_entry = successful_vm_wire_read_not_cow,
504 		.resident_entry    = successful_vm_wire_read_not_cow,
505 
506 		.shared_entry               = wire_shared_entry,
507 		.shared_entry_discontiguous = wire_shared_entry_discontiguous,
508 		.shared_entry_partial       = wire_shared_entry_partial,
509 		.shared_entry_pairs         = successful_vm_wire_read_not_cow,
510 		.shared_entry_x1000         = successful_vm_wire_read_not_cow,
511 
512 		.cow_entry = wire_cow_entry,
513 		.cow_unreferenced = wire_cow_entry,
514 		.cow_nocow = wire_cow_nocow,
515 		.nocow_cow = wire_nocow_cow,
516 		.cow_unreadable = wire_cow_unreadable,
517 		.cow_unwriteable = wire_cow_unwriteable,
518 
519 		.permanent_entry = successful_vm_wire_read_not_cow,
520 		.permanent_before_permanent = successful_vm_wire_read_not_cow,
521 		.permanent_before_allocation = successful_vm_wire_read_not_cow,
522 		.permanent_before_allocation_2 = successful_vm_wire_read_not_cow,
523 		.permanent_before_hole = failed_vm_wire_read_not_cow,
524 		.permanent_after_allocation = successful_vm_wire_read_not_cow,
525 		.permanent_after_hole = failed_vm_wire_read_not_cow,
526 
527 		/* TODO: wire vs submaps */
528 		.single_submap_single_entry = test_is_unimplemented,
529 		.single_submap_single_entry_first_pages = test_is_unimplemented,
530 		.single_submap_single_entry_last_pages = test_is_unimplemented,
531 		.single_submap_single_entry_middle_pages = test_is_unimplemented,
532 		.single_submap_oversize_entry_at_start = test_is_unimplemented,
533 		.single_submap_oversize_entry_at_end = test_is_unimplemented,
534 		.single_submap_oversize_entry_at_both = test_is_unimplemented,
535 
536 		.submap_before_allocation = test_is_unimplemented,
537 		.submap_after_allocation = test_is_unimplemented,
538 		.submap_before_hole = test_is_unimplemented,
539 		.submap_after_hole = test_is_unimplemented,
540 		.submap_allocation_submap_one_entry = test_is_unimplemented,
541 		.submap_allocation_submap_two_entries = test_is_unimplemented,
542 		.submap_allocation_submap_three_entries = test_is_unimplemented,
543 
544 		.submap_before_allocation_ro = test_is_unimplemented,
545 		.submap_after_allocation_ro = test_is_unimplemented,
546 		.submap_before_hole_ro = test_is_unimplemented,
547 		.submap_after_hole_ro = test_is_unimplemented,
548 		.submap_allocation_submap_one_entry_ro = test_is_unimplemented,
549 		.submap_allocation_submap_two_entries_ro = test_is_unimplemented,
550 		.submap_allocation_submap_three_entries_ro = test_is_unimplemented,
551 
552 		.protection_single_000_000 = failed_vm_wire_read_not_cow,
553 		.protection_single_000_r00 = failed_vm_wire_read_not_cow,
554 		.protection_single_000_0w0 = failed_vm_wire_read_not_cow,
555 		.protection_single_000_rw0 = failed_vm_wire_read_not_cow,
556 		.protection_single_r00_r00 = successful_vm_wire_read_not_cow,
557 		.protection_single_r00_rw0 = successful_vm_wire_read_not_cow,
558 		.protection_single_0w0_0w0 = failed_vm_wire_read_not_cow,
559 		.protection_single_0w0_rw0 = failed_vm_wire_read_not_cow,
560 		.protection_single_rw0_rw0 = successful_vm_wire_read_not_cow,
561 
562 		.protection_pairs_000_000 = failed_vm_wire_read_not_cow,
563 		.protection_pairs_000_r00 = failed_vm_wire_read_not_cow,
564 		.protection_pairs_000_0w0 = failed_vm_wire_read_not_cow,
565 		.protection_pairs_000_rw0 = failed_vm_wire_read_not_cow,
566 		.protection_pairs_r00_000 = failed_vm_wire_read_not_cow,
567 		.protection_pairs_r00_r00 = successful_vm_wire_read_not_cow,
568 		.protection_pairs_r00_0w0 = failed_vm_wire_read_not_cow,
569 		.protection_pairs_r00_rw0 = successful_vm_wire_read_not_cow,
570 		.protection_pairs_0w0_000 = failed_vm_wire_read_not_cow,
571 		.protection_pairs_0w0_r00 = failed_vm_wire_read_not_cow,
572 		.protection_pairs_0w0_0w0 = failed_vm_wire_read_not_cow,
573 		.protection_pairs_0w0_rw0 = failed_vm_wire_read_not_cow,
574 		.protection_pairs_rw0_000 = failed_vm_wire_read_not_cow,
575 		.protection_pairs_rw0_r00 = successful_vm_wire_read_not_cow,
576 		.protection_pairs_rw0_0w0 = failed_vm_wire_read_not_cow,
577 		.protection_pairs_rw0_rw0 = successful_vm_wire_read_not_cow,
578 	};
579 
580 	run_vm_tests("vm_wire", __FILE__, &tests, argc, argv);
581 }
582 
583 
584 T_DECL(vm_unwire,
585     "run vm_unwire with various vm configurations")
586 {
587 	vm_tests_t tests = {
588 		.single_entry_1 = test_is_unimplemented,
589 		.single_entry_2 = test_is_unimplemented,
590 		.single_entry_3 = test_is_unimplemented,
591 		.single_entry_4 = test_is_unimplemented,
592 
593 		.multiple_entries_1 = test_is_unimplemented,
594 		.multiple_entries_2 = test_is_unimplemented,
595 		.multiple_entries_3 = test_is_unimplemented,
596 		.multiple_entries_4 = test_is_unimplemented,
597 		.multiple_entries_5 = test_is_unimplemented,
598 		.multiple_entries_6 = test_is_unimplemented,
599 
600 		.some_holes_1 = vm_unwire_holes,
601 		.some_holes_2 = vm_unwire_holes,
602 		.some_holes_3 = vm_unwire_holes,
603 		.some_holes_4 = vm_unwire_holes,
604 		.some_holes_5 = vm_unwire_holes,
605 		.some_holes_6 = vm_unwire_holes,
606 		.some_holes_7 = vm_unwire_holes,
607 		.some_holes_8 = vm_unwire_holes,
608 		.some_holes_9 = vm_unwire_holes,
609 		.some_holes_10 = vm_unwire_holes,
610 		.some_holes_11 = vm_unwire_holes,
611 		.some_holes_12 = vm_unwire_holes,
612 
613 		.all_holes_1 = vm_unwire_holes,
614 		.all_holes_2 = vm_unwire_holes,
615 		.all_holes_3 = vm_unwire_holes,
616 		.all_holes_4 = vm_unwire_holes,
617 
618 		.null_entry        = test_is_unimplemented,
619 		.nonresident_entry = test_is_unimplemented,
620 		.resident_entry    = test_is_unimplemented,
621 
622 		.shared_entry               = test_is_unimplemented,
623 		.shared_entry_discontiguous = test_is_unimplemented,
624 		.shared_entry_partial       = test_is_unimplemented,
625 		.shared_entry_pairs         = test_is_unimplemented,
626 		.shared_entry_x1000         = test_is_unimplemented,
627 
628 		.cow_entry = test_is_unimplemented,
629 		.cow_unreferenced = test_is_unimplemented,
630 		.cow_nocow = test_is_unimplemented,
631 		.nocow_cow = test_is_unimplemented,
632 		.cow_unreadable = test_is_unimplemented,
633 		.cow_unwriteable = test_is_unimplemented,
634 
635 		.permanent_entry = test_is_unimplemented,
636 		.permanent_before_permanent = test_is_unimplemented,
637 		.permanent_before_allocation = test_is_unimplemented,
638 		.permanent_before_allocation_2 = test_is_unimplemented,
639 		.permanent_before_hole = test_is_unimplemented,
640 		.permanent_after_allocation = test_is_unimplemented,
641 		.permanent_after_hole = test_is_unimplemented,
642 
643 		.single_submap_single_entry = test_is_unimplemented,
644 		.single_submap_single_entry_first_pages = test_is_unimplemented,
645 		.single_submap_single_entry_last_pages = test_is_unimplemented,
646 		.single_submap_single_entry_middle_pages = test_is_unimplemented,
647 		.single_submap_oversize_entry_at_start = test_is_unimplemented,
648 		.single_submap_oversize_entry_at_end = test_is_unimplemented,
649 		.single_submap_oversize_entry_at_both = test_is_unimplemented,
650 
651 		.submap_before_allocation = test_is_unimplemented,
652 		.submap_after_allocation = test_is_unimplemented,
653 		.submap_before_hole = test_is_unimplemented,
654 		.submap_after_hole = test_is_unimplemented,
655 		.submap_allocation_submap_one_entry = test_is_unimplemented,
656 		.submap_allocation_submap_two_entries = test_is_unimplemented,
657 		.submap_allocation_submap_three_entries = test_is_unimplemented,
658 
659 		.submap_before_allocation_ro = test_is_unimplemented,
660 		.submap_after_allocation_ro = test_is_unimplemented,
661 		.submap_before_hole_ro = test_is_unimplemented,
662 		.submap_after_hole_ro = test_is_unimplemented,
663 		.submap_allocation_submap_one_entry_ro = test_is_unimplemented,
664 		.submap_allocation_submap_two_entries_ro = test_is_unimplemented,
665 		.submap_allocation_submap_three_entries_ro = test_is_unimplemented,
666 
667 		.protection_single_000_000 = test_is_unimplemented,
668 		.protection_single_000_r00 = test_is_unimplemented,
669 		.protection_single_000_0w0 = test_is_unimplemented,
670 		.protection_single_000_rw0 = test_is_unimplemented,
671 		.protection_single_r00_r00 = test_is_unimplemented,
672 		.protection_single_r00_rw0 = test_is_unimplemented,
673 		.protection_single_0w0_0w0 = test_is_unimplemented,
674 		.protection_single_0w0_rw0 = test_is_unimplemented,
675 		.protection_single_rw0_rw0 = test_is_unimplemented,
676 
677 		.protection_pairs_000_000 = test_is_unimplemented,
678 		.protection_pairs_000_r00 = test_is_unimplemented,
679 		.protection_pairs_000_0w0 = test_is_unimplemented,
680 		.protection_pairs_000_rw0 = test_is_unimplemented,
681 		.protection_pairs_r00_000 = test_is_unimplemented,
682 		.protection_pairs_r00_r00 = test_is_unimplemented,
683 		.protection_pairs_r00_0w0 = test_is_unimplemented,
684 		.protection_pairs_r00_rw0 = test_is_unimplemented,
685 		.protection_pairs_0w0_000 = test_is_unimplemented,
686 		.protection_pairs_0w0_r00 = test_is_unimplemented,
687 		.protection_pairs_0w0_0w0 = test_is_unimplemented,
688 		.protection_pairs_0w0_rw0 = test_is_unimplemented,
689 		.protection_pairs_rw0_000 = test_is_unimplemented,
690 		.protection_pairs_rw0_r00 = test_is_unimplemented,
691 		.protection_pairs_rw0_0w0 = test_is_unimplemented,
692 		.protection_pairs_rw0_rw0 = test_is_unimplemented,
693 	};
694 
695 	run_vm_tests("vm_unwire", __FILE__, &tests, argc, argv);
696 }
697