if (type == UCALL_MMIO) {
vm_paddr_t gpa, start, end, step, offset;
+ unsigned bits;
bool ret;
if (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");