Skip to content

Commit

Permalink
KVM: selftests: x86: Add selftest for private memory conversions
Browse files Browse the repository at this point in the history
Add a selftest to exercise implicit/explicit conversion functionality
within KVM and verify:

 - Shared memory is visible to host userspace
 - Private memory is not visible to host userspace
 - Host userspace and guest can communicate over shared memory
 - Data in shared backing is preserved across conversions (test's
   host userspace doesn't free the data)
 - Private memory is bound to the lifetime of the VM

TODO: rewrite this to allow backing a single region of guest memory with
mutliple memslots for _all_ backing types and shapes, i.e. make the code
for using a single backing fd across multiple memslots apply to regular
memory as well.

Signed-off-by: Vishal Annapurve <vannapurve@google.com>
Co-developed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
  • Loading branch information
vishals4gh authored and sean-jc committed May 17, 2023
1 parent cef1cee commit a0f5f8c
Show file tree
Hide file tree
Showing 5 changed files with 385 additions and 28 deletions.
1 change: 1 addition & 0 deletions tools/testing/selftests/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test
TEST_GEN_PROGS_x86_64 += x86_64/nested_exceptions_test
TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test
TEST_GEN_PROGS_x86_64 += x86_64/private_mem_conversions_test
TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
TEST_GEN_PROGS_x86_64 += x86_64/smaller_maxphyaddr_emulation_test
Expand Down
3 changes: 3 additions & 0 deletions tools/testing/selftests/kvm/include/kvm_util_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,9 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
uint32_t flags);
void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
uint32_t flags, int gmem_fd, uint64_t gmem_offset);

void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
Expand Down
12 changes: 12 additions & 0 deletions tools/testing/selftests/kvm/include/ucall_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa);
#define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \
ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4)
#define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage)

#define GUEST_SYNC1(arg0) ucall(UCALL_SYNC, 1, arg0)
#define GUEST_SYNC2(arg0, arg1) ucall(UCALL_SYNC, 2, arg0, arg1)
#define GUEST_SYNC3(arg0, arg1, arg2) \
ucall(UCALL_SYNC, 3, arg0, arg1, arg2)
#define GUEST_SYNC4(arg0, arg1, arg2, arg3) \
ucall(UCALL_SYNC, 4, arg0, arg1, arg2, arg3)
#define GUEST_SYNC5(arg0, arg1, arg2, arg3, arg4) \
ucall(UCALL_SYNC, 5, arg0, arg1, arg2, arg3, arg4)
#define GUEST_SYNC6(arg0, arg1, arg2, arg3, arg4, arg5) \
ucall(UCALL_SYNC, 6, arg0, arg1, arg2, arg3, arg4, arg5)

#define GUEST_DONE() ucall(UCALL_DONE, 0)

enum guest_assert_builtin_args {
Expand Down
48 changes: 20 additions & 28 deletions tools/testing/selftests/kvm/lib/kvm_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -849,32 +849,10 @@ void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
errno, strerror(errno));
}

/*
* VM Userspace Memory Region Add
*
* Input Args:
* vm - Virtual Machine
* src_type - Storage source for this region.
* NULL to use anonymous memory.
* guest_paddr - Starting guest physical address
* slot - KVM region slot
* npages - Number of physical pages
* flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES)
*
* Output Args: None
*
* Return: None
*
* Allocates a memory area of the number of pages specified by npages
* and maps it to the VM specified by vm, at a starting physical address
* given by guest_paddr. The region is created with a KVM region slot
* given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The
* region is created with the flags given by flags.
*/
void vm_userspace_mem_region_add(struct kvm_vm *vm,
enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
uint32_t flags)
/* FIXME: This thing needs to be ripped apart and rewritten. */
void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
uint32_t flags, int gmem_fd, uint64_t gmem_offset)
{
int ret;
struct userspace_mem_region *region;
Expand Down Expand Up @@ -989,8 +967,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
region->backing_src_type = src_type;

if (flags & KVM_MEM_PRIVATE) {
region->region.gmem_fd = vm_create_guest_memfd(vm, mem_size, 0);
region->region.gmem_offset = 0;
if (gmem_fd < 0) {
TEST_ASSERT(!gmem_offset,
"Offset must be zero when creating new guest_memfd");
gmem_fd = vm_create_guest_memfd(vm, mem_size, 0);
}

region->region.gmem_fd = gmem_fd;
region->region.gmem_offset = gmem_offset;
}

region->unused_phy_pages = sparsebit_alloc();
Expand Down Expand Up @@ -1029,6 +1013,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
}
}

void vm_userspace_mem_region_add(struct kvm_vm *vm,
enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot,
uint64_t npages, uint32_t flags)
{
vm_mem_add(vm, src_type, guest_paddr, slot, npages, flags, -1, 0);
}

/*
* Memslot to region
*
Expand Down
Loading

0 comments on commit a0f5f8c

Please sign in to comment.