diff --git a/tools/testing/selftests/kvm/lib/ucall.c b/tools/testing/selftests/kvm/lib/ucall.c
index 694bc2eaa63e9..a2ab38be2f479 100644
--- a/tools/testing/selftests/kvm/lib/ucall.c
+++ b/tools/testing/selftests/kvm/lib/ucall.c
@@ -35,6 +35,7 @@ void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg)
 
 	if (type == UCALL_MMIO) {
 		vm_paddr_t gpa, start, end, step, offset;
+		unsigned bits;
 		bool ret;
 
 		if (arg) {
@@ -45,23 +46,30 @@ void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg)
 		}
 
 		/*
-		 * Find an address within the allowed virtual address space,
-		 * that does _not_ have a KVM memory region associated with it.
-		 * Identity mapping an address like this allows the guest to
+		 * Find an address within the allowed physical and virtual address
+		 * spaces, that does _not_ have a KVM memory region associated with
+		 * it. Identity mapping an address like this allows the guest to
 		 * access it, but as KVM doesn't know what to do with it, it
 		 * will assume it's something userspace handles and exit with
 		 * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64.
-		 * Here we start with a guess that the addresses around two
-		 * thirds of the VA space are unmapped and then work both down
-		 * and up from there in 1/12 VA space sized steps.
+		 * Here we start with a guess that the addresses around 5/8th
+		 * of the allowed space are unmapped and then work both down and
+		 * up from there in 1/16th allowed space sized steps.
+		 *
+		 * Note, we need to use VA-bits - 1 when calculating the allowed
+		 * virtual address space for an identity mapping because the upper
+		 * half of the virtual address space is the two's complement of the
+		 * lower and won't match physical addresses.
 		 */
-		start = 1ul << (vm->va_bits * 2 / 3);
-		end = 1ul << vm->va_bits;
-		step = 1ul << (vm->va_bits / 12);
+		bits = vm->va_bits - 1;
+		bits = vm->pa_bits < bits ? vm->pa_bits : bits;
+		end = 1ul << bits;
+		start = end * 5 / 8;
+		step = end / 16;
 		for (offset = 0; offset < end - start; offset += step) {
-			if (ucall_mmio_init(vm, (gpa - offset) & ~(vm->page_size - 1)))
+			if (ucall_mmio_init(vm, start - offset))
 				return;
-			if (ucall_mmio_init(vm, (gpa + offset) & ~(vm->page_size - 1)))
+			if (ucall_mmio_init(vm, start + offset))
 				return;
 		}
 		TEST_ASSERT(false, "Can't find a ucall mmio address");