Loading...
tests/unit/hypervisor/nested_vcpu_tests.c xnu-12377.101.15 /dev/null
--- xnu/xnu-12377.101.15/tests/unit/hypervisor/nested_vcpu_tests.c
+++ /dev/null
@@ -1,1726 +0,0 @@
-/*
- * Copyright (c) 2025 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@
- */
-
-#include <darwintest.h>
-#include "mocks/osfmk/unit_test_utils.h"
-#include "mocks/osfmk/mock_cpu.h"
-#include "mocks/osfmk/mock_hv.h"
-#include "mocks/osfmk/mock_vm.h"
-#include "mocks/osfmk/mock_vm_map.h"
-#include "mocks/osfmk/mock_mach_port.h"
-#include "mocks/osfmk/mock_hv_vcpu.h"
-
-#include <arm64/hv/hv_kern_types.h>
-#include <arm64/hv/hv_vm.h>
-#include <arm64/hv/hv_space.h>
-#include <arm64/hv/hv_vcpu.h>
-#include <arm64/hv_hvc.h>
-#include <kern/locks.h>
-#include <kern/thread.h>
-#include <mach/vm_param.h>
-#include <mach/vm_types.h>
-#include <mach/mach.h>
-#include <vm/vm_kern_xnu.h>
-
-#define UT_MODULE osfmk
-T_GLOBAL_META(
-	T_META_NAMESPACE("xnu.unit.nested_vcpu_tests"),
-	T_META_RADAR_COMPONENT_NAME("xnu"),
-	T_META_OWNER("vincenzo_scotti")
-	);
-
-bool hv_is_nested_vm_valid(hv_nested_vm_t *nvm);
-
-// Helper functions for test setup
-
-static const uint64_t nested_ro_context_ipa = 0x5000000;
-static const vm_prot_t nested_ro_context_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-static const bool paranested_initialized = true;
-
-
-static hv_nested_vcpu_t *
-setup_nested_vcpu(hv_vcpu_t *vcpu, uint64_t nested_vcpu_id)
-{
-	// Set up a nested vCPU at [0][0] that's ready to run
-	hv_nested_vcpu_t *nested_vcpu = &vcpu->vm->nested_vms[nested_vm_id]->vcpu_byid[nested_vcpu_id];
-	nested_vcpu->kif = calloc(1, sizeof(arm_guest_context_t));
-	T_QUIET; T_ASSERT_NOTNULL(nested_vcpu->kif, "Failed to allocate nested context");
-	nested_vcpu->state = NESTED_VCPU_IDLE;
-	nested_vcpu->nested_ro_context_ipa = nested_ro_context_ipa;
-	nested_vcpu->nested_ro_context_prot = nested_ro_context_prot;
-	nested_vcpu->generation = 1 + nested_vcpu_id;
-	return nested_vcpu;
-}
-
-// Mock hv_trap_vcpu_set_address_space to update the guest_map
-T_MOCK_SET_PERM_FUNC(hv_return_t, hv_trap_vcpu_set_address_space, (uint64_t asid))
-{
-	hv_vcpu_t *vcpu = hv_get_vcpu();
-	assert(vcpu != NULL);
-	if (asid == HV_VM_SPACE_DEFAULT) {
-		vcpu->host_context.guest_map = (vm_map_t)(uintptr_t)vcpu->vm->default_space;
-	} else {
-		T_EXPECT_EQ(asid, mock_nested_asid, "Check nested ASID");
-		vcpu->host_context.guest_map = mock_nested_guest_map;
-	}
-	return HV_SUCCESS;
-}
-
-// Test Cases
-
-T_DECL(vcpu_run_nested_guest_hvc_flow, "Root guest HVC request -> nested guest -> exit NONE -> root guest")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count = 0;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// Mock a nested guest taking a synchronous exception to be routed to the root guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_SYNC;
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Check nested run return value");
-			T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_SYNC, "Check nested vmexit reason");
-			T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-			vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 3, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(vcpu_run_error_entering_nested_space, "Test error while entering the nested guest space")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count = 0;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	// Mock hv_trap_vcpu_set_address_space to update the guest_map. Mock a failure when trying to
-	// activate the nested guest map.
-	T_MOCK_SET_CALLBACK(hv_trap_vcpu_set_address_space, hv_return_t, (uint64_t asid), {
-		if (asid == HV_VM_SPACE_DEFAULT) {
-		        vcpu->host_context.guest_map = (vm_map_t)(uintptr_t)vcpu->vm->default_space;
-		        return HV_SUCCESS;
-		}
-		T_EXPECT_EQ(asid, mock_nested_asid, "Check nested ASID");
-		return HV_ERROR;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_ERROR, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(vcpu_run_error_exiting_nested_space, "Test error while leaving the nested guest space")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count = 0;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	// Mock hv_trap_vcpu_set_address_space to update the guest_map. Mock a failure when trying to
-	// return to the root guest map.
-	T_MOCK_SET_CALLBACK(hv_trap_vcpu_set_address_space, hv_return_t, (uint64_t asid), {
-		if (asid == HV_VM_SPACE_DEFAULT) {
-		        return HV_ERROR;
-		}
-		T_EXPECT_EQ(asid, mock_nested_asid, "Check nested ASID");
-		vcpu->host_context.guest_map = mock_nested_guest_map;
-		return HV_SUCCESS;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_ERROR, "Should propagate failure to host userspace");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_error_remapping_context, "Test error while remapping nested context")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count = 0;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	T_MOCK_SET_RETVAL(mach_vm_remap_new_kernel, kern_return_t, KERN_NO_SPACE);
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_RESOURCES, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_error_wiring_context, "Test error while wiring nested context")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static bool remap_called;
-	static bool deallocate_called;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static uint64_t nested_context_ipa = 0x4000;
-	static uint64_t nested_context_remapped = 0x100000000;
-
-	T_MOCK_SET_CALLBACK(mach_vm_remap_new_kernel, kern_return_t, (
-		    vm_map_t                target_map,
-		    mach_vm_offset_ut      * address,
-		    mach_vm_size_ut         size,
-		    mach_vm_offset_ut       mask,
-		    vm_map_kernel_flags_t   vmk_flags,
-		    vm_map_t                src_map,
-		    mach_vm_offset_ut       memory_address,
-		    boolean_t               copy,
-		    vm_prot_ut             * cur_protection,
-		    vm_prot_ut             * max_protection,
-		    vm_inherit_ut           inheritance
-		    ), {
-		T_QUIET; T_ASSERT_FALSE(remap_called, "Check that we're not remapping twice");
-		T_QUIET; T_ASSERT_EQ_PTR(target_map, kernel_map, "Check remap target space");
-		T_QUIET; T_ASSERT_EQ_PTR(src_map, vcpu->vm->default_space, "Check remap source space");
-		T_QUIET; T_ASSERT_EQ(memory_address, nested_context_ipa, "Check remap source address");
-		remap_called = true;
-		*address = nested_context_remapped;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(mach_vm_deallocate_kernel, kern_return_t,
-	    (
-		    vm_map_t target,
-		    mach_vm_address_t address,
-		    mach_vm_size_t size
-	    ), {
-		T_QUIET; T_ASSERT_FALSE(deallocate_called, "Check that we're not deallocating twice");
-		T_QUIET; T_ASSERT_EQ_PTR(target, kernel_map, "Check remap target space");
-		T_QUIET; T_ASSERT_EQ(address, nested_context_remapped, "Check remapped context address");
-		T_QUIET; T_ASSERT_EQ((size_t)size, sizeof(arm_guest_context_t), "Check remapped context size");
-		deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_RETVAL(vm_map_wire_kernel, kern_return_t, KERN_NO_SPACE);
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_context_ipa);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_RESOURCES, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, 0);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(remap_called, "Check that we've remapped the nested context");
-	T_EXPECT_TRUE(deallocate_called, "Check that we've unmapped the nested context");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_error_ipa_lookup, "Test error while looking up IPA in guest map")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static bool remap_called;
-	static bool deallocate_called;
-	static bool wire_called;
-	static bool unwire_called;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static uint64_t nested_context_ipa = 0x4000;
-	static uint64_t nested_context_remapped = 0x100000000;
-
-	T_MOCK_SET_CALLBACK(mach_vm_remap_new_kernel, kern_return_t, (
-		    vm_map_t                target_map,
-		    mach_vm_offset_ut      * address,
-		    mach_vm_size_ut         size,
-		    mach_vm_offset_ut       mask,
-		    vm_map_kernel_flags_t   vmk_flags,
-		    vm_map_t                src_map,
-		    mach_vm_offset_ut       memory_address,
-		    boolean_t               copy,
-		    vm_prot_ut             * cur_protection,
-		    vm_prot_ut             * max_protection,
-		    vm_inherit_ut           inheritance
-		    ), {
-		T_QUIET; T_ASSERT_FALSE(remap_called, "Check that we're not remapping twice");
-		remap_called = true;
-		*address = nested_context_remapped;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(mach_vm_deallocate_kernel, kern_return_t,
-	    (
-		    vm_map_t target,
-		    mach_vm_address_t address,
-		    mach_vm_size_t size
-	    ), {
-		T_QUIET; T_ASSERT_FALSE(deallocate_called, "Check that we're not deallocating twice");
-		deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_wire_kernel, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    vm_prot_ut              prot_u,
-		    vm_tag_t                tag,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(wire_called, "Check that we're not wiring twice");
-		T_QUIET; T_ASSERT_EQ_PTR(map, kernel_map, "Check wire target space");
-		T_QUIET; T_ASSERT_EQ(start_u, nested_context_remapped, "Check wire context address");
-		T_QUIET; T_ASSERT_EQ(end_u, nested_context_remapped + sizeof(arm_guest_context_t), "Check wire context size");
-		wire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_unwire, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(unwire_called, "Check that we're not unwiring twice");
-		T_QUIET; T_ASSERT_EQ_PTR(map, kernel_map, "Check unwire target space");
-		T_QUIET; T_ASSERT_EQ(start_u, nested_context_remapped, "Check unwire context address");
-		T_QUIET; T_ASSERT_EQ(end_u, nested_context_remapped + sizeof(arm_guest_context_t), "Check unwire context size");
-		unwire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_find_entry_sh_locked, kern_return_t,
-	    (
-		    vm_map_find_lock_ctx_t  vml_ctx,
-		    vm_map_t               * map,
-		    vm_map_address_t        addr,
-		    vmrl_find_sh_flags_t    flags), {
-		return KERN_FAILURE;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_found_entry_sh_unlock, void,
-	    (
-		    vm_map_find_lock_ctx_t    vml_ctx,
-		    vm_map_t                 * map), {});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_context_ipa);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_ERROR, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, 0);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(remap_called, "Check that we've remapped the nested context");
-	T_EXPECT_TRUE(deallocate_called, "Check that we've unmapped the nested context");
-	T_EXPECT_TRUE(wire_called, "Check that we've wired the nested context");
-	T_EXPECT_TRUE(unwire_called, "Check that we've unwired the nested context");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_error_protecting_context, "Test error while protecting context in guest map")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static bool remap_called;
-	static bool deallocate_called;
-	static bool wire_called;
-	static bool unwire_called;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static uint64_t nested_context_ipa = 0x4000;
-	static uint64_t nested_context_remapped = 0x100000000;
-	static struct vm_map_entry fake_entry = {.protection = VM_PROT_READ};
-
-	T_MOCK_SET_CALLBACK(mach_vm_remap_new_kernel, kern_return_t, (
-		    vm_map_t                target_map,
-		    mach_vm_offset_ut      * address,
-		    mach_vm_size_ut         size,
-		    mach_vm_offset_ut       mask,
-		    vm_map_kernel_flags_t   vmk_flags,
-		    vm_map_t                src_map,
-		    mach_vm_offset_ut       memory_address,
-		    boolean_t               copy,
-		    vm_prot_ut             * cur_protection,
-		    vm_prot_ut             * max_protection,
-		    vm_inherit_ut           inheritance
-		    ), {
-		T_QUIET; T_ASSERT_FALSE(remap_called, "Check that we're not remapping twice");
-		remap_called = true;
-		*address = nested_context_remapped;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(mach_vm_deallocate_kernel, kern_return_t,
-	    (
-		    vm_map_t target,
-		    mach_vm_address_t address,
-		    mach_vm_size_t size
-	    ), {
-		T_QUIET; T_ASSERT_FALSE(deallocate_called, "Check that we're not deallocating twice");
-		deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_wire_kernel, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    vm_prot_ut              prot_u,
-		    vm_tag_t                tag,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(wire_called, "Check that we're not wiring twice");
-		wire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_unwire, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(unwire_called, "Check that we're not unwiring twice");
-		unwire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_find_entry_sh_locked, kern_return_t,
-	    (
-		    vm_map_find_lock_ctx_t  vml_ctx,
-		    vm_map_t               * map,
-		    vm_map_address_t        addr,
-		    vmrl_find_sh_flags_t    flags), {
-		vml_ctx->vmlc_vme = &fake_entry;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_found_entry_sh_unlock, void,
-	    (
-		    vm_map_find_lock_ctx_t    vml_ctx,
-		    vm_map_t                 * map), {});
-
-	T_MOCK_SET_RETVAL(mach_vm_protect, kern_return_t, KERN_NO_SPACE);
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_context_ipa);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_ERROR, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, 0);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(remap_called, "Check that we've remapped the nested context");
-	T_EXPECT_TRUE(deallocate_called, "Check that we've unmapped the nested context");
-	T_EXPECT_TRUE(wire_called, "Check that we've wired the nested context");
-	T_EXPECT_TRUE(unwire_called, "Check that we've unwired the nested context");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_error_no_vm, "Test nested vCPU initialization failure when there is no VM")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	__block int vmenter_count = 0;
-	__block uint64_t nested_context_ipa = 0x4000;
-	__block struct vm_map_entry fake_entry = {.protection = VM_PROT_READ};
-
-	T_MOCK_SET_RETVAL(vm_map_wire_kernel, kern_return_t, KERN_SUCCESS);
-	T_MOCK_SET_RETVAL(vm_map_unwire, kern_return_t, KERN_SUCCESS);
-	T_MOCK_SET_RETVAL(mach_vm_protect, kern_return_t, KERN_SUCCESS);
-	T_MOCK_SET_RETVAL(mach_vm_deallocate_kernel, kern_return_t, KERN_SUCCESS);
-
-	T_MOCK_SET_CALLBACK(mach_vm_remap_new_kernel, kern_return_t, (
-		    vm_map_t                target_map,
-		    mach_vm_offset_ut      * address,
-		    mach_vm_size_ut         size,
-		    mach_vm_offset_ut       mask,
-		    vm_map_kernel_flags_t   vmk_flags,
-		    vm_map_t                src_map,
-		    mach_vm_offset_ut       memory_address,
-		    boolean_t               copy,
-		    vm_prot_ut             * cur_protection,
-		    vm_prot_ut             * max_protection,
-		    vm_inherit_ut           inheritance
-		    ), {
-		arm_guest_context_t *nested_context = checked_alloc_align(sizeof(arm_guest_context_t), PAGE_SIZE);
-		T_QUIET; T_ASSERT_NOTNULL(nested_context, "Failed to allocate nested context");
-		*address = (mach_vm_offset_ut) nested_context;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_find_entry_sh_locked, kern_return_t,
-	    (
-		    vm_map_find_lock_ctx_t  vml_ctx,
-		    vm_map_t               * map,
-		    vm_map_address_t        addr,
-		    vmrl_find_sh_flags_t    flags), {
-		vml_ctx->vmlc_vme = &fake_entry;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_found_entry_sh_unlock, void,
-	    (
-		    vm_map_find_lock_ctx_t    vml_ctx,
-		    vm_map_t                 * map), {});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-		hv_nested_vm_t *nvm = vcpu->vm->nested_vms[nested_vm_id];
-		hv_nested_vcpu_t *nested_vcpu = &nvm->vcpu_byid[0];
-
-		switch (vmenter_count) {
-		case 1:
-			nvm->space = MACH_PORT_NULL;
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_context_ipa);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_DEVICE, "vCPU initialization should fail: no VM");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	// Intentionally skip setup_nested_vcpu and let the real code create the nested vCPU.
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_init_success, "Test nested vCPU initialization")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count = 0;
-	static bool remap_called;
-	static bool wire_called;
-	static bool protect_called;
-	static uint64_t nested_context_ipa = 0x4000;
-	static uint64_t nested_context_remapped = 0x100000000;
-	static struct vm_map_entry fake_entry = {.protection = VM_PROT_READ};
-
-	T_MOCK_SET_CALLBACK(mach_vm_remap_new_kernel, kern_return_t, (
-		    vm_map_t                target_map,
-		    mach_vm_offset_ut      * address,
-		    mach_vm_size_ut         size,
-		    mach_vm_offset_ut       mask,
-		    vm_map_kernel_flags_t   vmk_flags,
-		    vm_map_t                src_map,
-		    mach_vm_offset_ut       memory_address,
-		    boolean_t               copy,
-		    vm_prot_ut             * cur_protection,
-		    vm_prot_ut             * max_protection,
-		    vm_inherit_ut           inheritance
-		    ), {
-		T_QUIET; T_ASSERT_FALSE(remap_called, "Check that we're not remapping twice");
-		remap_called = true;
-		arm_guest_context_t *nested_context = aligned_alloc(PAGE_SIZE, sizeof(arm_guest_context_t));
-		T_QUIET; T_ASSERT_NOTNULL(nested_context, "Failed to allocate nested context");
-		memset(nested_context, 0, sizeof(arm_guest_context_t));
-		*address = (mach_vm_offset_ut) nested_context;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_wire_kernel, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    vm_prot_ut              prot_u,
-		    vm_tag_t                tag,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(wire_called, "Check that we're not wiring twice");
-		wire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_find_entry_sh_locked, kern_return_t,
-	    (
-		    vm_map_find_lock_ctx_t  vml_ctx,
-		    vm_map_t               * map,
-		    vm_map_address_t        addr,
-		    vmrl_find_sh_flags_t    flags), {
-		vml_ctx->vmlc_vme = &fake_entry;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_found_entry_sh_unlock, void,
-	    (
-		    vm_map_find_lock_ctx_t    vml_ctx,
-		    vm_map_t                 * map), {});
-
-	T_MOCK_SET_CALLBACK(mach_vm_protect, kern_return_t, (
-		    vm_map_t                map,
-		    mach_vm_address_ut      start_u,
-		    mach_vm_size_ut         size_u,
-		    boolean_t               set_maximum,
-		    vm_prot_ut              new_protection_u), {
-		T_QUIET; T_ASSERT_FALSE(protect_called, "Check that we're not protecting twice");
-		protect_called = true;
-		return KERN_SUCCESS;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-		hv_nested_vcpu_t *nested_vcpu = &vcpu->vm->nested_vms[nested_vm_id]->vcpu_byid[0];
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-			mock_nested_vcpu_init(vcpu->host_context.guest_context, nested_context_ipa);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "vCPU initialization should succeed");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	// Intentionally skip setup_nested_vcpu and let the real code create the nested vCPU.
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(remap_called, "Check that we've remapped the nested context");
-	T_EXPECT_TRUE(wire_called, "Check that we've wired the nested context");
-	T_EXPECT_TRUE(protect_called, "Check that we've protected the nested context");
-
-	hv_nested_vcpu_t *nested_vcpu = &vcpu->vm->nested_vms[nested_vm_id]->vcpu_byid[0];
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_destroy_error_protecting_context, "Test error while protecting context in guest map")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static bool unwire_called;
-	static bool deallocate_called;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	T_MOCK_SET_RETVAL(mach_vm_protect, kern_return_t, KERN_NO_SPACE);
-
-	T_MOCK_SET_CALLBACK(vm_map_unwire, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(unwire_called, "Check that we're not unwiring twice");
-		unwire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(mach_vm_deallocate_kernel, kern_return_t,
-	    (
-		    vm_map_t target,
-		    mach_vm_address_t address,
-		    mach_vm_size_t size
-	    ), {
-		T_QUIET; T_ASSERT_FALSE(deallocate_called, "Check that we're not deallocating twice");
-		T_QUIET; T_ASSERT_EQ_PTR(target, kernel_map, "Check deallocate target space");
-		T_QUIET; T_ASSERT_EQ(address, (uint64_t)nested_vcpu->kif, "Check deallocate address");
-		T_QUIET; T_ASSERT_EQ((size_t)size, sizeof(arm_guest_context_t), "Check deallocate size");
-		deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_destroy(vcpu->host_context.guest_context);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_ERROR, "Root guest should receive error");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(unwire_called, "Check that we've unwired the nested context");
-	T_EXPECT_TRUE(deallocate_called, "Check that we've unmapped the nested context");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_destroy_success, "Test nested vCPU destruction")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static bool protect_called;
-	static bool unwire_called;
-	static bool deallocate_called;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	T_MOCK_SET_CALLBACK(mach_vm_protect, kern_return_t, (
-		    vm_map_t                map,
-		    mach_vm_address_ut      start_u,
-		    mach_vm_size_ut         size_u,
-		    boolean_t               set_maximum,
-		    vm_prot_ut              new_protection_u), {
-		T_QUIET; T_ASSERT_FALSE(protect_called, "Check that we're not protecting twice");
-		T_QUIET; T_ASSERT_EQ_PTR(map, vcpu->host_context.guest_map, "Check protect target space");
-		T_QUIET; T_ASSERT_EQ(start_u, nested_ro_context_ipa, "Check protect start address");
-		T_QUIET; T_ASSERT_EQ(size_u, (uint64_t)sizeof(arm_guest_ro_context_t), "Check protect size");
-		T_QUIET; T_ASSERT_EQ(new_protection_u, nested_ro_context_prot, "Check protect permissions");
-		protect_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(vm_map_unwire, kern_return_t,
-	    (
-		    vm_map_t                map,
-		    vm_map_offset_ut        start_u,
-		    vm_map_offset_ut        end_u,
-		    boolean_t               user_wire), {
-		T_QUIET; T_ASSERT_FALSE(unwire_called, "Check that we're not unwiring twice");
-		unwire_called = true;
-		return KERN_SUCCESS;
-	});
-
-	T_MOCK_SET_CALLBACK(mach_vm_deallocate_kernel, kern_return_t,
-	    (
-		    vm_map_t target,
-		    mach_vm_address_t address,
-		    mach_vm_size_t size
-	    ), {
-		T_QUIET; T_ASSERT_FALSE(deallocate_called, "Check that we're not deallocating twice");
-		deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_destroy(vcpu->host_context.guest_context);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "vCPU destruction should succeed");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_TRUE(protect_called, "Check that we've unmapped the nested context");
-	T_EXPECT_TRUE(unwire_called, "Check that we've unwired the nested context");
-	T_EXPECT_TRUE(deallocate_called, "Check that we've unmapped the nested context");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_INVALID, "Nested vCPU should be invalid");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(root_vcpu_run_cancel_while_running_nested, "Test root vCPU cancellation while running nested vCPU")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// Mock a root vCPU cancellation from another thread.
-			os_atomic_store(&vcpu->vm->vcpu_byid[0].notified, true, relaxed);
-			// Mock reception of the IPI.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_FIQ;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-	T_EXPECT_FALSE(os_atomic_load(&vcpu->vm->vcpu_byid[0].notified, relaxed),
-	    "Check that the cancellation is no longer pending");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vcpu_run_cancel_before_running, "Test nested vCPU cancellation before vCPU is run")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run_cancel(vcpu->host_context.guest_context);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_TRUE(nested_vcpu->notified, "Check that the nested cancellation is pending");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Check nested run return value");
-			T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check nested vmexit reason");
-			T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-			vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 3, "Check number of vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-	T_EXPECT_FALSE(nested_vcpu->notified, "Check that the nested cancellation is no longer pending");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-hv_return_t
-hv_handle_nested_vcpu_run_cancel(hv_vcpu_t *vcpu, uint64_t nested_vm_id, uint64_t nested_vcpu_mask);
-
-T_DECL(nested_vcpu_run_cancel_while_running, "Test nested vCPU cancellation while vCPU is run")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-	static const uint64_t nested_vcpu_mask = 1ull << nested_vcpu_id;
-
-	// Mock completion of IPI signalling.
-	T_MOCK_SET_RETVAL(cpu_signal, kern_return_t, KERN_SUCCESS);
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// The cancellation would normally be requested by another root vCPU, but for simplicity
-			// let's just call straight into the underlying cancel implementation while the nested
-			// vCPU is running.
-			hv_handle_nested_vcpu_run_cancel(vcpu, 0, nested_vcpu_mask);
-			T_EXPECT_TRUE(nested_vcpu->notified, "Check that the nested cancellation is pending");
-			// Mock reception of the IPI.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_FIQ;
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Check nested run return value");
-			T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check nested vmexit reason");
-			T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-			vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 3, "Check number of vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-	T_EXPECT_FALSE(nested_vcpu->notified, "Check that the nested cancellation is no longer pending");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(concurrent_root_and_nested_cancellation, "Test concurrent root and nested cancellations")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	static int vmenter_count;
-	static hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-	static const uint64_t nested_vcpu_mask = 1ull << nested_vcpu_id;
-
-	// Mock completion of IPI signalling.
-	T_MOCK_SET_RETVAL(cpu_signal, kern_return_t, KERN_SUCCESS);
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// Mock arrival of two concurrent cancellations, one for the root vCPU and the other for
-			// the nested vCPU. We expect the former to be served first.
-			os_atomic_store(&vcpu->vm->vcpu_byid[0].notified, true, relaxed);
-			hv_handle_nested_vcpu_run_cancel(vcpu, 0, nested_vcpu_mask);
-			// Simulate an IPI (FIQ) arriving while running the nested guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_FIQ;
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Check nested run return value");
-			T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check nested vmexit reason");
-			T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-			vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			break;
-
-		case 4:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			// Mock a nested guest taking a synchronous exception to be routed to the root guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_SYNC;
-			break;
-
-		case 5:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Check nested run return value");
-			T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_SYNC, "Check nested vmexit reason");
-			T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-			vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 2, "Check number of vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-	T_EXPECT_FALSE(vcpu->vm->vcpu_byid[0].notified, "Check that the root cancellation is served");
-	T_EXPECT_FALSE(nested_vcpu->notified, "Check that the nested cancellation is served");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	result = hv_trap_vcpu_run(nested_vcpu_id);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 5, "Check number of vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-	T_EXPECT_FALSE(vcpu->vm->vcpu_byid[0].notified, "Check that the root cancellation is served");
-	T_EXPECT_FALSE(nested_vcpu->notified, "Check that the nested cancellation is served");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-static void
-root_vtimer_expiry_test(uint64_t cntv_ctl_el0, uint64_t timer_controls)
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	const uint64_t initial_host_hw_time = 10000;
-	const uint64_t guest_timer_offset = 1000;
-	const uint64_t guest_timer_deadline = 20050;
-	const uint64_t wait_interval = guest_timer_deadline - initial_host_hw_time + guest_timer_offset;
-	const uint64_t ticks_per_vmenter = 1000;
-	static_assert((wait_interval % ticks_per_vmenter) != 0,
-	    "wait_interval must not be a clean multiple of ticks_per_vmenter");
-	const unsigned vmenters_to_deadline = (wait_interval / ticks_per_vmenter) + 1;
-	const bool expect_root_timer_interrupt =
-	    (cntv_ctl_el0 & (CNTV_CTL_EL0_ENABLE | CNTV_CTL_EL0_IMASKED)) ==
-	    CNTV_CTL_EL0_ENABLE && (timer_controls & HV_TIMER_MASK) == 0;
-	// One vmenter to schedule the nested guest, another one when the nested guest is preempted.
-	const unsigned expected_root_vmenters = 2;
-	// After accounting for the initial vmenter to schedule the nested guest, use many vmenters as
-	// the timer allows, plus an additional one if the timer interrupt is disabled.
-	const unsigned expected_nested_vmenters =
-	    expect_root_timer_interrupt ? (vmenters_to_deadline - 1) : vmenters_to_deadline;
-	// HW model.
-	__block struct {
-		uint64_t cntvct_el0;
-		uint64_t guest_cntv_ctl_el0;
-	} hw = {
-		.cntvct_el0 = initial_host_hw_time
-	};
-
-	// Mock completion of IPI signalling.
-	T_MOCK_SET_RETVAL(cpu_signal, kern_return_t, KERN_SUCCESS);
-
-	/* BEGIN IGNORE CODESTYLE */
-	T_MOCK_SET_CALLBACK(testable_arm_rsr64, uint64_t, (const char *regname), {
-		if (!strcmp(regname, "ACNTVCT_EL0") || !strcmp(regname, "S3_4_C15_C10_6")
-			|| !strcmp(regname, "CNTVCTSS_EL0")) {
-			return hw.cntvct_el0;
-		}
-		if (!strcmp(regname, "CNTV_CTL_EL02")) {
-			return hw.guest_cntv_ctl_el0;
-		}
-		return 0;
-	});
-
-	T_MOCK_SET_CALLBACK(testable_arm_wsr64, void, (const char *regname, uint64_t value), {
-		if (!strcmp(regname, "CNTV_CTL_EL02")) {
-			hw.guest_cntv_ctl_el0 = value;
-		}
-	});
-	/* END IGNORE CODESTYLE */
-
-	vcpu->kif->ro.controls.virtual_timer_offset = guest_timer_offset;
-	vcpu->kif->rw.banked_sysregs.cntv_cval_el0 = guest_timer_deadline;
-	vcpu->kif->rw.banked_sysregs.cntv_ctl_el0 = cntv_ctl_el0;
-	vcpu->kif->rw.controls.timer = timer_controls;
-
-	__block int vmenter_count = 0;
-	__block hv_nested_vcpu_t *nested_vcpu = NULL;
-	static const uint64_t nested_vcpu_id = 0;
-	static const uint64_t nested_vcpu_mask = 1ull << nested_vcpu_id;
-	__block unsigned nested_vmenters = 0;
-	__block unsigned root_vmenters = 0;
-	// Mock hv_enter_guest to simulate different execution phases
-	/* BEGIN IGNORE CODESTYLE */
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		if (vmenter_count == 1 || vmenter_count == expected_nested_vmenters + 2) {
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			root_vmenters++;
-		} else {
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu);
-			nested_vmenters++;
-		}
-
-		const bool in_nested = vcpu->nested_vcpu != NULL;
-		if (in_nested) {
-			if (!expect_root_timer_interrupt && nested_vmenters == expected_nested_vmenters) {
-				// Mock a nested guest cancellation so that we return to the root guest.
-				hv_handle_nested_vcpu_run_cancel(vcpu, 0, nested_vcpu_mask);
-				vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			}
-			// Simulate an IPI (FIQ) arriving while running the nested guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_FIQ;
-		} else {
-			if (root_vmenters == 1) {
-				mock_nested_vcpu_run(vcpu->host_context.guest_context, nested_vcpu_id);
-			} else {
-				// If the timer interrupt is expected, host xnu should preempt the nested guest and
-				// set the exit reason to HOST_AST to give guest xnu a chance to serve its ASTs.
-				const uint32_t expected_reason = expect_root_timer_interrupt ?
-					ARM_VMEXIT_REASON_HOST_AST : ARM_VMEXIT_REASON_NONE;
-				T_EXPECT_EQ(nested_vcpu->kif->ro.exit.vmexit_reason, expected_reason, "Check vmexit reason");
-				T_EXPECT_EQ((uint64_t)nested_vcpu->kif->ro.exit.vmexit_reason,
-				    vcpu->host_context.guest_context->rw.regs.x[1], "Check nested vmexit consistency");
-				// Mock a root guest cancellation so that we return to host userspace.
-				vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			}
-		}
-
-		T_ASSERT_LE(nested_vmenters, expected_nested_vmenters, "Check current number of nested vmenters");
-		T_ASSERT_LE(root_vmenters, expected_root_vmenters, "Check current number of root vmenters");
-		hw.cntvct_el0 += ticks_per_vmenter;
-	});
-	/* END IGNORE CODESTYLE */
-
-	nested_vcpu = setup_nested_vcpu(vcpu, nested_vcpu_id);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(nested_vmenters, expected_nested_vmenters, "Check number of nested vmenters");
-	T_EXPECT_EQ(root_vmenters, expected_root_vmenters, "Check number of root vmenters");
-	T_EXPECT_EQ(vcpu->host_context.guest_context->ro.exit.vmexit_reason, ARM_VMEXIT_REASON_NONE, "Check vmexit reason");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(root_vtimer_expiry_interrupt, "Test root vCPU vtimer expiration interrupt")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_ENABLE, 0);
-}
-
-T_DECL(root_vtimer_expiry_hw_enabled_sw_masked, "Test root vCPU vtimer expiration with the SW interrupt masked")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_ENABLE, HV_TIMER_MASK);
-}
-
-T_DECL(root_vtimer_expiry_hw_masked_sw_enabled, "Test root vCPU vtimer expiration with the HW interrupt masked")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_ENABLE | CNTV_CTL_EL0_IMASKED, 0);
-}
-
-T_DECL(root_vtimer_expiry_hw_masked_sw_masked, "Test root vCPU vtimer expiration with the HW and SW interrupt masked")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_ENABLE | CNTV_CTL_EL0_IMASKED, HV_TIMER_MASK);
-}
-
-T_DECL(root_vtimer_expiry_hw_disabled_masked_sw_enabled,
-    "Test root vCPU vtimer expiration with the HW interrupt disabled and masked")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_IMASKED, 0);
-}
-
-T_DECL(root_vtimer_expiry_hw_disabled_masked_sw_masked,
-    "Test root vCPU vtimer expiration with the HW interrupt disabled and masked and SW interrupt masked")
-{
-	root_vtimer_expiry_test(CNTV_CTL_EL0_IMASKED, HV_TIMER_MASK);
-}
-
-T_DECL(root_vtimer_expiry_hw_disabled_sw_enabled, "Test root vCPU vtimer expiration with the interrupt disabled")
-{
-	root_vtimer_expiry_test(0, 0);
-}
-
-T_DECL(root_vtimer_expiry_hw_disabled_sw_masked,
-    "Test root vCPU vtimer expiration with the interrupt disabled and SW interrupt masked")
-{
-	root_vtimer_expiry_test(0, HV_TIMER_MASK);
-}
-
-T_DECL(tlb_flush_on_nested_vcpu_switch, "Test TLB flushing when different nested vCPUs are scheduled on the same pCPU")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	__block int vmenter_count = 0;
-	__block hv_nested_vcpu_t *nested_vcpu0;
-	__block hv_nested_vcpu_t *nested_vcpu1;
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu0->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(nested_vcpu1->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, 0);
-			break;
-
-		case 2:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu0);
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			// Mock a nested guest taking a synchronous exception to be routed to the root guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_SYNC;
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu0->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(nested_vcpu1->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, 0);
-			break;
-
-		case 4:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu0);
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			// Mock a nested guest taking a synchronous exception to be routed to the root guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_SYNC;
-			break;
-
-		case 5:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu0->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(nested_vcpu1->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			mock_nested_vcpu_run(vcpu->host_context.guest_context, 1);
-			break;
-
-		case 6:
-			assert_vcpu_in_nested_guest(vcpu, nested_vcpu1);
-			T_EXPECT_TRUE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			// Mock a nested guest taking a synchronous exception to be routed to the root guest.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_SYNC;
-			break;
-
-		case 7:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(nested_vcpu0->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_QUIET; T_ASSERT_EQ(nested_vcpu1->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-			T_EXPECT_FALSE(vcpu->host_context.flush_local_tlb, "Check pending TLB flush");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	nested_vcpu0 = setup_nested_vcpu(vcpu, 0);
-	nested_vcpu1 = setup_nested_vcpu(vcpu, 1);
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 7, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-	T_QUIET; T_ASSERT_EQ(nested_vcpu0->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-	T_QUIET; T_ASSERT_EQ(nested_vcpu1->state, NESTED_VCPU_IDLE, "Nested vCPU should be idle");
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vm_init, "Test nested VM init")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	__block int vmenter_count;
-	__block bool return_no_resources = false;
-
-	/* BEGIN IGNORE CODESTYLE */
-	T_MOCK_SET_CALLBACK(hv_space_create, hv_return_t, (hv_vm_t * vm, uint64_t min_ipa, uint64_t ipa_size, uint32_t granule, uint64_t * out_asid), {
-		if (return_no_resources) {
-			return HV_NO_RESOURCES;
-		} else {
-			*out_asid = mock_nested_asid;
-			return HV_SUCCESS;
-		}
-	});
-	/* END IGNORE CODESTYLE */
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-		hv_nested_vm_t *nested_vm = vcpu->vm->nested_vms[nested_vm_id];
-		const uint64_t min_ipa = 0x100000000;
-		const uint64_t ipa_size = 0x100000000;
-		const uint64_t granule = 16 * 1024;
-		const hv_vm_isa_t isa = _HV_VM_ISA_GENERIC;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, 0x1000000000000000ull /* invalid */, _HV_VM_ISA_GENERIC);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_BAD_ARGUMENT, "Error: invalid granule size");
-			T_QUIET; T_ASSERT_TRUE(!hv_is_nested_vm_valid(nested_vm), "Nested VM should be invalid");
-			return_no_resources = true;
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, granule, isa);
-			break;
-
-		case 3:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_RESOURCES, "Error: hv_space_create returns HV_NO_RESOURCES");
-			T_QUIET; T_ASSERT_TRUE(!hv_is_nested_vm_valid(nested_vm), "Nested VM should be invalid");
-			return_no_resources = false;
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, granule, isa);
-			break;
-
-		case 4:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Success creating first nested VM");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[1], nested_vm_id, "Returned nested VM ID == 0");
-			T_QUIET; T_ASSERT_TRUE(hv_is_nested_vm_valid(nested_vm), "Nested VM should be valid");
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, granule, isa);
-			break;
-
-		case 5:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Success creating second nested VM");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[1], nested_vm_id + 1, "Returned nested VM ID == 1");
-			T_QUIET; T_ASSERT_TRUE(hv_is_nested_vm_valid(vcpu->vm->nested_vms[nested_vm_id + 1]), "Nested VM should be valid");
-			// Simulate the scenario where all nested VM IDs are taken.
-			bitmap_full(&vcpu->vm->nested_vm_id_online_mask[0], HV_NESTED_VM_MAX);
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, granule, isa);
-			break;
-
-		case 6:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_RESOURCES, "Failure creating a nested VM: limit reached");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	vcpu->vm->nested_vms[nested_vm_id]->space = MACH_PORT_NULL; // Restore nested VM state back to INVALID
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 6, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-
-	free_mock_vcpu(vcpu);
-}
-
-T_DECL(nested_vm_destroy, "Test nested VM destroy")
-{
-	hv_vcpu_t *vcpu = create_mock_vcpu();
-
-	__block int vmenter_count;
-	__block bool port_deallocate_called = false;
-
-	T_MOCK_SET_CALLBACK(hv_space_create, hv_return_t, (hv_vm_t * vm, uint64_t min_ipa, uint64_t ipa_size, uint32_t granule, uint64_t * out_asid), {
-		*out_asid = mock_nested_asid;
-		return HV_SUCCESS;
-	})
-
-	T_MOCK_SET_CALLBACK(mach_port_deallocate, kern_return_t, (ipc_space_t space, mach_port_name_t name), {
-		T_QUIET; T_EXPECT_FALSE(port_deallocate_called, "Check that we're not deallocating port twice");
-		T_QUIET; T_EXPECT_EQ_PTR(space, current_space(), "Check port deallocate space");
-		T_QUIET; T_EXPECT_EQ(name, (mach_port_name_t)mock_nested_asid, "Check port name being deallocated");
-		port_deallocate_called = true;
-		return KERN_SUCCESS;
-	});
-
-	// Mock hv_enter_guest to simulate different execution phases
-	T_MOCK_SET_CALLBACK(hv_enter_guest, void, (arm_guest_context_t * guest_context, arm_host_context_t * host_context), {
-		vmenter_count++;
-		hv_nested_vm_t *nested_vm = vcpu->vm->nested_vms[nested_vm_id];
-		const uint64_t min_ipa = 0x100000000;
-		const uint64_t ipa_size = 0x100000000;
-		const uint64_t granule = 16 * 1024;
-		const hv_vm_isa_t isa = _HV_VM_ISA_GENERIC;
-
-		switch (vmenter_count) {
-		case 1:
-			assert_vcpu_in_root_guest(vcpu);
-			mock_nested_vm_destroy(vcpu->host_context.guest_context, HV_NESTED_VM_MAX);
-			break;
-
-		case 2:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_BAD_ARGUMENT, "Error: invalid nested VM ID");
-			T_QUIET; T_ASSERT_TRUE(!hv_is_nested_vm_valid(nested_vm), "Nested VM should be invalid");
-			mock_nested_vm_init(vcpu->host_context.guest_context, min_ipa, ipa_size, granule, isa);
-			break;
-
-		case 3:
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Successful creation");
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[1], nested_vm_id, "Returned nested VM ID == 0");
-			T_QUIET; T_ASSERT_TRUE(hv_is_nested_vm_valid(nested_vm), "Nested VM should be valid");
-			nested_vm->vcpu_byid[0].state = NESTED_VCPU_BUSY; // Fake presence of a VCPU
-			mock_nested_vm_destroy(vcpu->host_context.guest_context, nested_vm_id);
-			break;
-
-		case 4:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_BUSY, "Error: VCPU exists");
-			T_QUIET; T_ASSERT_TRUE(hv_is_nested_vm_valid(nested_vm), "Nested VM should be valid");
-			nested_vm->vcpu_byid[0].state = NESTED_VCPU_INVALID; // Revert VCPU state so we can test successful destruction
-			mock_nested_vm_destroy(vcpu->host_context.guest_context, nested_vm_id);
-			break;
-
-		case 5:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_SUCCESS, "Successful destruction!");
-			T_QUIET; T_EXPECT_TRUE(port_deallocate_called, "Check that port was deallocated");
-			T_QUIET; T_ASSERT_TRUE(!hv_is_nested_vm_valid(nested_vm), "Nested VM should be invalid");
-			mock_nested_vm_destroy(vcpu->host_context.guest_context, nested_vm_id);
-			break;
-
-		case 6:
-			assert_vcpu_in_root_guest(vcpu);
-			T_QUIET; T_ASSERT_EQ(vcpu->host_context.guest_context->rw.regs.x[0], (uint64_t)HV_NO_DEVICE, "Error: cannot destroy non-existent VM");
-			// Mock a root guest cancellation so that we return to host userspace.
-			vcpu->host_context.guest_context->ro.exit.vmexit_reason = ARM_VMEXIT_REASON_NONE;
-			break;
-
-		default:
-			T_FAIL("Unexpected number of vmenters: %d", vmenter_count);
-			break;
-		}
-	});
-
-	vcpu->vm->nested_vms[nested_vm_id]->space = MACH_PORT_NULL;  // Restore nested VM state back to INVALID
-
-	hv_return_t result = hv_trap_vcpu_run(0);
-
-	T_EXPECT_EQ(result, HV_SUCCESS, "Should succeed through the nested flow");
-	T_EXPECT_EQ(vmenter_count, 6, "Check number of vmenters");
-
-	assert_vcpu_in_root_guest(vcpu);
-
-	free_mock_vcpu(vcpu);
-}