This is xnu-12377.1.9. See this file in:
/*
* Copyright (c) 2024 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* vm/configurator_vm_wire.c
*
* Test vm_wire with many different VM states.
*/
#include "configurator/vm_configurator_tests.h"
T_GLOBAL_META(
T_META_NAMESPACE("xnu.vm.configurator"),
T_META_RADAR_COMPONENT_NAME("xnu"),
T_META_RADAR_COMPONENT_VERSION("VM"),
T_META_RUN_CONCURRENTLY(true),
T_META_ALL_VALID_ARCHS(true),
T_META_ASROOT(true) /* root required for vm_wire on macOS */
);
/*
* Update checker state to mirror a successful call to
* vm_wire(PROT_NONE) a.k.a. unwire
*/
static void
checker_perform_vm_unwire(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
entry_checker_range_t limit = checker_list_find_and_clip(checker_list, start, size);
FOREACH_CHECKER(checker, limit) {
assert(checker->user_wired_count > 0);
checker->user_wired_count--;
}
checker_list_simplify(checker_list, start, size);
}
/*
* Update checker state to mirror a successful call to
* vm_wire(PROT_NONE) a.k.a. unwire
* of a range that includes holes.
*/
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)
{
entry_checker_range_t limit = checker_list_find_range_including_holes(checker_list, start, size);
if (limit.head && limit.head->kind == Allocation &&
checker_contains_address(limit.head, start)) {
/* range begins with an allocation - proceed normally */
} else {
/* range begins with a hole - do nothing, not even simplify */
return KERN_INVALID_ADDRESS;
}
FOREACH_CHECKER(checker, limit) {
if (checker->kind == Allocation) {
assert(checker->user_wired_count > 0);
checker->user_wired_count--;
}
}
checker_list_simplify(checker_list, start, size);
return KERN_SUCCESS;
}
/*
* Update checker state to mirrow a successful call to vm_wire.
*/
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)
{
assert(wire_prot != VM_PROT_NONE);
entry_checker_range_t limit;
/*
* Resolve null objects.
* vm_wire does this before clipping
*/
limit = checker_list_find_range_including_holes(checker_list, start, size);
FOREACH_CHECKER(checker, limit) {
checker_resolve_null_vm_object(checker_list, checker);
}
/*
* Perform clipping.
*/
limit = checker_list_find_range(checker_list, start, size);
checker_clip_left(checker_list, limit.head, start);
checker_clip_right(checker_list, limit.tail, start + size);
/*
* Fault and wire.
*/
FOREACH_CHECKER(checker, limit) {
checker->user_wired_count++;
checker_fault_for_prot_not_cow(checker_list, checker, wire_prot);
}
checker_list_simplify(checker_list, start, size);
}
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)
{
assert(wire_prot != VM_PROT_NONE);
/*
* failed vm_wire clips entries and resolves null vm_objects
* one at a time until the entry that it couldn't change
*
* failed vm_wire doesn't simplify clipped entries on exit
*
* failed vm_wire is inconsistent about resident page counts
*/
entry_checker_range_t limit =
checker_list_find_range_including_holes(checker_list, start, size);
FOREACH_CHECKER(checker, limit) {
if (checker->kind != Allocation) {
/* stop at holes */
break;
}
/* wire of executable entry fails early */
if (prot_contains_all(checker->protection, VM_PROT_EXECUTE)) {
// (fixme jit, tpro)
break;
}
/* null vm_objects are resolved before clipping */
checker_resolve_null_vm_object(checker_list, checker);
if (checker == limit.head) {
checker_clip_left(checker_list, checker, start);
}
if (checker == limit.tail) {
checker_clip_right(checker_list, checker, start + size);
}
if (!prot_contains_all(checker->protection, wire_prot)) {
/* stop at protection failures */
break;
}
if (checker != limit.tail && checker->next->kind != Allocation) {
/* stop if the *next* entry is in range and is an illegal hole */
break;
}
/*
* failed vm_wire simplifies and faults in,
* except for the cases already short-circuited above
*/
checker_fault_for_prot_not_cow(checker_list, checker, wire_prot);
checker_simplify_left(checker_list, checker);
}
}
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)
{
kern_return_t kr;
checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
if (kr) {
T_FAIL("mach_vm_wire failed (%s)", name_for_kr(kr));
return TestFailed;
}
if (verify_vm_state(checker_list, "after vm_wire") != TestSucceeded) {
return TestFailed;
}
checker_perform_vm_unwire(checker_list, start, size);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_NONE);
if (kr) {
T_FAIL("mach_vm_wire(unwire) failed (%s)", name_for_kr(kr));
return TestFailed;
}
if (verify_vm_state(checker_list, "after vm_unwire") != TestSucceeded) {
return TestFailed;
}
return TestSucceeded;
}
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)
{
kern_return_t kr;
checker_perform_failed_vm_wire(checker_list, start, size, VM_PROT_READ);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
if (kr == KERN_SUCCESS) {
T_FAIL("mach_vm_wire unexpectedly succeeded");
return TestFailed;
}
return verify_vm_state(checker_list, "after unsuccessful vm_wire");
}
static test_result_t
wire_shared_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* two entries each sharing the same object */
vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
kern_return_t kr;
/*
* Wire the left entry. The right entry also faults in but
* stays at wire count zero.
*/
checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
checker_fault_for_prot_not_cow(checker_list, right_checker, VM_PROT_READ);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
assert(kr == 0);
return verify_vm_state(checker_list, "after vm_wire shared");
}
static test_result_t
wire_shared_entry_discontiguous(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two entries each sharing the same object
* but only partially overlap inside that object.
* Wiring the left entry does not affect the right entry,
* so this looks like an ordinary vm_wire test.
*/
return successful_vm_wire_read_not_cow(checker_list, start, size);
}
static test_result_t
wire_shared_entry_partial(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two entries each sharing the same object
* but only partially overlap inside that object
*/
vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
mach_vm_address_t right_offset = DEFAULT_PARTIAL_ENTRY_SIZE;
kern_return_t kr;
/*
* Wire the left entry. The right entry stays at wire count zero
* and only the overlapping section faults in.
*/
checker_perform_vm_wire(checker_list, start, size, VM_PROT_READ);
right_checker->pages_resident = (uint32_t)((size - right_offset) / PAGE_SIZE);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_READ);
assert(kr == 0);
return verify_vm_state(checker_list, "after vm_wire shared partial");
}
static void
checker_make_cow_private(
checker_list_t *checker_list,
vm_entry_checker_t *checker)
{
if (checker->object->self_ref_count == 1) {
/*
* COW but not shared with anything else.
* VM resolves COW by using the same object.
*/
checker->needs_copy = false;
return;
}
/* make new object */
vm_object_checker_t *obj_checker = object_checker_clone(checker->object);
checker_list_append_object(checker_list, obj_checker);
/* change object and entry to private */
checker->needs_copy = false;
/* set new object (decreasing previous object's self_ref_count) */
checker_set_object(checker, obj_checker);
}
static test_result_t
wire_cow_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* Wiring a COW entry resolves COW but has no effect on other copies. */
vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
checker_make_cow_private(checker_list, left_checker);
return successful_vm_wire_read_not_cow(checker_list, start, size);
}
static test_result_t
wire_cow_nocow(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
checker_make_cow_private(checker_list, left_checker);
return successful_vm_wire_read_not_cow(checker_list, start, size);
}
static test_result_t
wire_nocow_cow(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
vm_entry_checker_t *right_checker = left_checker->next;
checker_make_cow_private(checker_list, right_checker);
return successful_vm_wire_read_not_cow(checker_list, start, size);
}
static test_result_t
wire_cow_unreadable(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
checker_make_shadow_object(checker_list, checker);
return failed_vm_wire_read_not_cow(checker_list, start, size);
}
static test_result_t
wire_cow_unwriteable(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
checker_make_cow_private(checker_list, checker);
return successful_vm_wire_read_not_cow(checker_list, start, size);
}
/*
* Test vm_unwire with a range that includes holes.
* We wire each allocation separately, then unwire the entire range
* to test unwire's behavior across holes without reference to
* wire's behavior across holes.
*/
static test_result_t
vm_unwire_holes(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
kern_return_t kr, expected_kr;
/*
* Wire each allocation separately,
* then unwire the entire range at once.
*/
mach_vm_address_t end = start + size;
entry_checker_range_t limit =
checker_list_find_range_including_holes(checker_list, start, size);
FOREACH_CHECKER(checker, limit) {
if (checker->kind == Allocation) {
/*
* we manually "clip" our address range here
* because the real checker clipping must
* be done inside checker_perform_vm_wire()
* because wire's clip behavior is weird
*/
mach_vm_address_t clipped_address = max(start, checker->address);
mach_vm_address_t clipped_end = min(checker_end_address(checker), end);
mach_vm_size_t clipped_size = clipped_end - clipped_address;
kr = mach_vm_wire(host_priv(), mach_task_self(),
clipped_address, clipped_size, VM_PROT_READ);
assert(kr == 0);
checker_perform_vm_wire(checker_list,
clipped_address, clipped_size, VM_PROT_READ);
}
}
if (verify_vm_state(checker_list, "before vm_unwire") != TestSucceeded) {
return TestFailed;
}
expected_kr = checker_perform_vm_unwire_with_holes(checker_list, start, size);
kr = mach_vm_wire(host_priv(), mach_task_self(), start, size, VM_PROT_NONE);
if (kr != expected_kr) {
T_FAIL("mach_vm_wire(unwire) returned %d (%s), expected %d (%s)\n",
kr, name_for_kr(kr), expected_kr, name_for_kr(expected_kr));
return TestFailed;
}
if (verify_vm_state(checker_list, "after vm_unwire") != TestSucceeded) {
return TestFailed;
}
return TestSucceeded;
}
T_DECL(vm_wire,
"run vm_wire with various vm configurations")
{
vm_tests_t tests = {
.single_entry_1 = successful_vm_wire_read_not_cow,
.single_entry_2 = successful_vm_wire_read_not_cow,
.single_entry_3 = successful_vm_wire_read_not_cow,
.single_entry_4 = successful_vm_wire_read_not_cow,
.multiple_entries_1 = successful_vm_wire_read_not_cow,
.multiple_entries_2 = successful_vm_wire_read_not_cow,
.multiple_entries_3 = successful_vm_wire_read_not_cow,
.multiple_entries_4 = successful_vm_wire_read_not_cow,
.multiple_entries_5 = successful_vm_wire_read_not_cow,
.multiple_entries_6 = successful_vm_wire_read_not_cow,
.some_holes_1 = failed_vm_wire_read_not_cow,
.some_holes_2 = failed_vm_wire_read_not_cow,
.some_holes_3 = failed_vm_wire_read_not_cow,
.some_holes_4 = failed_vm_wire_read_not_cow,
.some_holes_5 = failed_vm_wire_read_not_cow,
.some_holes_6 = failed_vm_wire_read_not_cow,
.some_holes_7 = failed_vm_wire_read_not_cow,
.some_holes_8 = failed_vm_wire_read_not_cow,
.some_holes_9 = failed_vm_wire_read_not_cow,
.some_holes_10 = failed_vm_wire_read_not_cow,
.some_holes_11 = failed_vm_wire_read_not_cow,
.some_holes_12 = failed_vm_wire_read_not_cow,
.all_holes_1 = failed_vm_wire_read_not_cow,
.all_holes_2 = failed_vm_wire_read_not_cow,
.all_holes_3 = failed_vm_wire_read_not_cow,
.all_holes_4 = failed_vm_wire_read_not_cow,
.null_entry = successful_vm_wire_read_not_cow,
.nonresident_entry = successful_vm_wire_read_not_cow,
.resident_entry = successful_vm_wire_read_not_cow,
.shared_entry = wire_shared_entry,
.shared_entry_discontiguous = wire_shared_entry_discontiguous,
.shared_entry_partial = wire_shared_entry_partial,
.shared_entry_pairs = successful_vm_wire_read_not_cow,
.shared_entry_x1000 = successful_vm_wire_read_not_cow,
.cow_entry = wire_cow_entry,
.cow_unreferenced = wire_cow_entry,
.cow_nocow = wire_cow_nocow,
.nocow_cow = wire_nocow_cow,
.cow_unreadable = wire_cow_unreadable,
.cow_unwriteable = wire_cow_unwriteable,
.permanent_entry = successful_vm_wire_read_not_cow,
.permanent_before_permanent = successful_vm_wire_read_not_cow,
.permanent_before_allocation = successful_vm_wire_read_not_cow,
.permanent_before_allocation_2 = successful_vm_wire_read_not_cow,
.permanent_before_hole = failed_vm_wire_read_not_cow,
.permanent_after_allocation = successful_vm_wire_read_not_cow,
.permanent_after_hole = failed_vm_wire_read_not_cow,
/* TODO: wire vs submaps */
.single_submap_single_entry = test_is_unimplemented,
.single_submap_single_entry_first_pages = test_is_unimplemented,
.single_submap_single_entry_last_pages = test_is_unimplemented,
.single_submap_single_entry_middle_pages = test_is_unimplemented,
.single_submap_oversize_entry_at_start = test_is_unimplemented,
.single_submap_oversize_entry_at_end = test_is_unimplemented,
.single_submap_oversize_entry_at_both = test_is_unimplemented,
.submap_before_allocation = test_is_unimplemented,
.submap_after_allocation = test_is_unimplemented,
.submap_before_hole = test_is_unimplemented,
.submap_after_hole = test_is_unimplemented,
.submap_allocation_submap_one_entry = test_is_unimplemented,
.submap_allocation_submap_two_entries = test_is_unimplemented,
.submap_allocation_submap_three_entries = test_is_unimplemented,
.submap_before_allocation_ro = test_is_unimplemented,
.submap_after_allocation_ro = test_is_unimplemented,
.submap_before_hole_ro = test_is_unimplemented,
.submap_after_hole_ro = test_is_unimplemented,
.submap_allocation_submap_one_entry_ro = test_is_unimplemented,
.submap_allocation_submap_two_entries_ro = test_is_unimplemented,
.submap_allocation_submap_three_entries_ro = test_is_unimplemented,
.protection_single_000_000 = failed_vm_wire_read_not_cow,
.protection_single_000_r00 = failed_vm_wire_read_not_cow,
.protection_single_000_0w0 = failed_vm_wire_read_not_cow,
.protection_single_000_rw0 = failed_vm_wire_read_not_cow,
.protection_single_r00_r00 = successful_vm_wire_read_not_cow,
.protection_single_r00_rw0 = successful_vm_wire_read_not_cow,
.protection_single_0w0_0w0 = failed_vm_wire_read_not_cow,
.protection_single_0w0_rw0 = failed_vm_wire_read_not_cow,
.protection_single_rw0_rw0 = successful_vm_wire_read_not_cow,
.protection_pairs_000_000 = failed_vm_wire_read_not_cow,
.protection_pairs_000_r00 = failed_vm_wire_read_not_cow,
.protection_pairs_000_0w0 = failed_vm_wire_read_not_cow,
.protection_pairs_000_rw0 = failed_vm_wire_read_not_cow,
.protection_pairs_r00_000 = failed_vm_wire_read_not_cow,
.protection_pairs_r00_r00 = successful_vm_wire_read_not_cow,
.protection_pairs_r00_0w0 = failed_vm_wire_read_not_cow,
.protection_pairs_r00_rw0 = successful_vm_wire_read_not_cow,
.protection_pairs_0w0_000 = failed_vm_wire_read_not_cow,
.protection_pairs_0w0_r00 = failed_vm_wire_read_not_cow,
.protection_pairs_0w0_0w0 = failed_vm_wire_read_not_cow,
.protection_pairs_0w0_rw0 = failed_vm_wire_read_not_cow,
.protection_pairs_rw0_000 = failed_vm_wire_read_not_cow,
.protection_pairs_rw0_r00 = successful_vm_wire_read_not_cow,
.protection_pairs_rw0_0w0 = failed_vm_wire_read_not_cow,
.protection_pairs_rw0_rw0 = successful_vm_wire_read_not_cow,
};
run_vm_tests("vm_wire", __FILE__, &tests, argc, argv);
}
T_DECL(vm_unwire,
"run vm_unwire with various vm configurations")
{
vm_tests_t tests = {
.single_entry_1 = test_is_unimplemented,
.single_entry_2 = test_is_unimplemented,
.single_entry_3 = test_is_unimplemented,
.single_entry_4 = test_is_unimplemented,
.multiple_entries_1 = test_is_unimplemented,
.multiple_entries_2 = test_is_unimplemented,
.multiple_entries_3 = test_is_unimplemented,
.multiple_entries_4 = test_is_unimplemented,
.multiple_entries_5 = test_is_unimplemented,
.multiple_entries_6 = test_is_unimplemented,
.some_holes_1 = vm_unwire_holes,
.some_holes_2 = vm_unwire_holes,
.some_holes_3 = vm_unwire_holes,
.some_holes_4 = vm_unwire_holes,
.some_holes_5 = vm_unwire_holes,
.some_holes_6 = vm_unwire_holes,
.some_holes_7 = vm_unwire_holes,
.some_holes_8 = vm_unwire_holes,
.some_holes_9 = vm_unwire_holes,
.some_holes_10 = vm_unwire_holes,
.some_holes_11 = vm_unwire_holes,
.some_holes_12 = vm_unwire_holes,
.all_holes_1 = vm_unwire_holes,
.all_holes_2 = vm_unwire_holes,
.all_holes_3 = vm_unwire_holes,
.all_holes_4 = vm_unwire_holes,
.null_entry = test_is_unimplemented,
.nonresident_entry = test_is_unimplemented,
.resident_entry = test_is_unimplemented,
.shared_entry = test_is_unimplemented,
.shared_entry_discontiguous = test_is_unimplemented,
.shared_entry_partial = test_is_unimplemented,
.shared_entry_pairs = test_is_unimplemented,
.shared_entry_x1000 = test_is_unimplemented,
.cow_entry = test_is_unimplemented,
.cow_unreferenced = test_is_unimplemented,
.cow_nocow = test_is_unimplemented,
.nocow_cow = test_is_unimplemented,
.cow_unreadable = test_is_unimplemented,
.cow_unwriteable = test_is_unimplemented,
.permanent_entry = test_is_unimplemented,
.permanent_before_permanent = test_is_unimplemented,
.permanent_before_allocation = test_is_unimplemented,
.permanent_before_allocation_2 = test_is_unimplemented,
.permanent_before_hole = test_is_unimplemented,
.permanent_after_allocation = test_is_unimplemented,
.permanent_after_hole = test_is_unimplemented,
.single_submap_single_entry = test_is_unimplemented,
.single_submap_single_entry_first_pages = test_is_unimplemented,
.single_submap_single_entry_last_pages = test_is_unimplemented,
.single_submap_single_entry_middle_pages = test_is_unimplemented,
.single_submap_oversize_entry_at_start = test_is_unimplemented,
.single_submap_oversize_entry_at_end = test_is_unimplemented,
.single_submap_oversize_entry_at_both = test_is_unimplemented,
.submap_before_allocation = test_is_unimplemented,
.submap_after_allocation = test_is_unimplemented,
.submap_before_hole = test_is_unimplemented,
.submap_after_hole = test_is_unimplemented,
.submap_allocation_submap_one_entry = test_is_unimplemented,
.submap_allocation_submap_two_entries = test_is_unimplemented,
.submap_allocation_submap_three_entries = test_is_unimplemented,
.submap_before_allocation_ro = test_is_unimplemented,
.submap_after_allocation_ro = test_is_unimplemented,
.submap_before_hole_ro = test_is_unimplemented,
.submap_after_hole_ro = test_is_unimplemented,
.submap_allocation_submap_one_entry_ro = test_is_unimplemented,
.submap_allocation_submap_two_entries_ro = test_is_unimplemented,
.submap_allocation_submap_three_entries_ro = test_is_unimplemented,
.protection_single_000_000 = test_is_unimplemented,
.protection_single_000_r00 = test_is_unimplemented,
.protection_single_000_0w0 = test_is_unimplemented,
.protection_single_000_rw0 = test_is_unimplemented,
.protection_single_r00_r00 = test_is_unimplemented,
.protection_single_r00_rw0 = test_is_unimplemented,
.protection_single_0w0_0w0 = test_is_unimplemented,
.protection_single_0w0_rw0 = test_is_unimplemented,
.protection_single_rw0_rw0 = test_is_unimplemented,
.protection_pairs_000_000 = test_is_unimplemented,
.protection_pairs_000_r00 = test_is_unimplemented,
.protection_pairs_000_0w0 = test_is_unimplemented,
.protection_pairs_000_rw0 = test_is_unimplemented,
.protection_pairs_r00_000 = test_is_unimplemented,
.protection_pairs_r00_r00 = test_is_unimplemented,
.protection_pairs_r00_0w0 = test_is_unimplemented,
.protection_pairs_r00_rw0 = test_is_unimplemented,
.protection_pairs_0w0_000 = test_is_unimplemented,
.protection_pairs_0w0_r00 = test_is_unimplemented,
.protection_pairs_0w0_0w0 = test_is_unimplemented,
.protection_pairs_0w0_rw0 = test_is_unimplemented,
.protection_pairs_rw0_000 = test_is_unimplemented,
.protection_pairs_rw0_r00 = test_is_unimplemented,
.protection_pairs_rw0_0w0 = test_is_unimplemented,
.protection_pairs_rw0_rw0 = test_is_unimplemented,
};
run_vm_tests("vm_unwire", __FILE__, &tests, argc, argv);
}