diff options
| -rw-r--r-- | tools/testing/selftests/kvm/guest_memfd_test.c | 64 | 
1 files changed, 64 insertions, 0 deletions
| diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index b88f580b2fd6..b3ca6737f304 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -13,6 +13,7 @@  #include <linux/bitmap.h>  #include <linux/falloc.h> +#include <linux/sizes.h>  #include <setjmp.h>  #include <signal.h>  #include <sys/mman.h> @@ -21,6 +22,7 @@  #include "kvm_util.h"  #include "test_util.h" +#include "ucall_common.h"  static void test_file_read_write(int fd)  { @@ -298,6 +300,66 @@ static void test_guest_memfd(unsigned long vm_type)  	kvm_vm_free(vm);  } +static void guest_code(uint8_t *mem, uint64_t size) +{ +	size_t i; + +	for (i = 0; i < size; i++) +		__GUEST_ASSERT(mem[i] == 0xaa, +			       "Guest expected 0xaa at offset %lu, got 0x%x", i, mem[i]); + +	memset(mem, 0xff, size); +	GUEST_DONE(); +} + +static void test_guest_memfd_guest(void) +{ +	/* +	 * Skip the first 4gb and slot0.  slot0 maps <1gb and is used to back +	 * the guest's code, stack, and page tables, and low memory contains +	 * the PCI hole and other MMIO regions that need to be avoided. +	 */ +	const uint64_t gpa = SZ_4G; +	const int slot = 1; + +	struct kvm_vcpu *vcpu; +	struct kvm_vm *vm; +	uint8_t *mem; +	size_t size; +	int fd, i; + +	if (!kvm_has_cap(KVM_CAP_GUEST_MEMFD_MMAP)) +		return; + +	vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, guest_code); + +	TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP), +		    "Default VM type should always support guest_memfd mmap()"); + +	size = vm->page_size; +	fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP); +	vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, size, NULL, fd, 0); + +	mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +	TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); +	memset(mem, 0xaa, size); +	munmap(mem, size); + +	virt_pg_map(vm, gpa, gpa); +	vcpu_args_set(vcpu, 2, gpa, size); +	vcpu_run(vcpu); + +	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); + +	mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +	TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); +	for (i = 0; i < size; i++) +		TEST_ASSERT_EQ(mem[i], 0xff); + +	close(fd); +	kvm_vm_free(vm); +} +  int main(int argc, char *argv[])  {  	unsigned long vm_types, vm_type; @@ -314,4 +376,6 @@ int main(int argc, char *argv[])  	for_each_set_bit(vm_type, &vm_types, BITS_PER_TYPE(vm_types))  		test_guest_memfd(vm_type); + +	test_guest_memfd_guest();  } | 
