Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: selftests: create alias mappings when using shared memory

When a memory region is added with a src_type specifying that it should
use some kind of shared memory, also create an alias mapping to the same
underlying physical pages.

And, add an API so tests can get access to these alias addresses.
Basically, for a guest physical address, let us look up the analogous
host *alias* address.

In a future commit, we'll modify the demand paging test to take
advantage of this to exercise UFFD minor faults. The idea is, we
pre-fault the underlying pages *via the alias*. When the *guest*
faults, it gets a "minor" fault (PTEs don't exist yet, but a page is
already in the page cache). Then, the userfaultfd theads can handle the
fault: they could potentially modify the underlying memory *via the
alias* if they wanted to, and then they install the PTEs and let the
guest carry on via a UFFDIO_CONTINUE ioctl.

Reviewed-by: Ben Gardon <bgardon@google.com>
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Message-Id: <20210519200339.829146-9-axelrasmussen@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Axel Rasmussen and committed by
Paolo Bonzini
94f3f2b3 c9befd59

+52
+1
tools/testing/selftests/kvm/include/kvm_util.h
··· 147 147 void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); 148 148 void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); 149 149 vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); 150 + void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa); 150 151 151 152 /* 152 153 * Address Guest Virtual to Guest Physical
+49
tools/testing/selftests/kvm/lib/kvm_util.c
··· 903 903 vm_userspace_mem_region_gpa_insert(&vm->regions.gpa_tree, region); 904 904 vm_userspace_mem_region_hva_insert(&vm->regions.hva_tree, region); 905 905 hash_add(vm->regions.slot_hash, &region->slot_node, slot); 906 + 907 + /* If shared memory, create an alias. */ 908 + if (region->fd >= 0) { 909 + region->mmap_alias = mmap(NULL, region->mmap_size, 910 + PROT_READ | PROT_WRITE, 911 + vm_mem_backing_src_alias(src_type)->flag, 912 + region->fd, 0); 913 + TEST_ASSERT(region->mmap_alias != MAP_FAILED, 914 + "mmap of alias failed, errno: %i", errno); 915 + 916 + /* Align host alias address */ 917 + region->host_alias = align(region->mmap_alias, alignment); 918 + } 906 919 } 907 920 908 921 /* ··· 1344 1331 1345 1332 TEST_FAIL("No mapping to a guest physical address, hva: %p", hva); 1346 1333 return -1; 1334 + } 1335 + 1336 + /* 1337 + * Address VM physical to Host Virtual *alias*. 1338 + * 1339 + * Input Args: 1340 + * vm - Virtual Machine 1341 + * gpa - VM physical address 1342 + * 1343 + * Output Args: None 1344 + * 1345 + * Return: 1346 + * Equivalent address within the host virtual *alias* area, or NULL 1347 + * (without failing the test) if the guest memory is not shared (so 1348 + * no alias exists). 1349 + * 1350 + * When vm_create() and related functions are called with a shared memory 1351 + * src_type, we also create a writable, shared alias mapping of the 1352 + * underlying guest memory. This allows the host to manipulate guest memory 1353 + * without mapping that memory in the guest's address space. And, for 1354 + * userfaultfd-based demand paging, we can do so without triggering userfaults. 1355 + */ 1356 + void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa) 1357 + { 1358 + struct userspace_mem_region *region; 1359 + uintptr_t offset; 1360 + 1361 + region = userspace_mem_region_find(vm, gpa, gpa); 1362 + if (!region) 1363 + return NULL; 1364 + 1365 + if (!region->host_alias) 1366 + return NULL; 1367 + 1368 + offset = gpa - region->region.guest_phys_addr; 1369 + return (void *) ((uintptr_t) region->host_alias + offset); 1347 1370 } 1348 1371 1349 1372 /*
+2
tools/testing/selftests/kvm/lib/kvm_util_internal.h
··· 19 19 int fd; 20 20 off_t offset; 21 21 void *host_mem; 22 + void *host_alias; 22 23 void *mmap_start; 24 + void *mmap_alias; 23 25 size_t mmap_size; 24 26 struct rb_node gpa_node; 25 27 struct rb_node hva_node;