1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2023, Google LLC.
4  */
5 #include <linux/kvm.h>
6 #include <pthread.h>
7 #include <stdint.h>
8 
9 #include "kvm_util.h"
10 #include "processor.h"
11 #include "test_util.h"
12 
13 /* Arbitrarily selected to avoid overlaps with anything else */
14 #define EXITS_TEST_GVA 0xc0000000
15 #define EXITS_TEST_GPA EXITS_TEST_GVA
16 #define EXITS_TEST_NPAGES 1
17 #define EXITS_TEST_SIZE (EXITS_TEST_NPAGES * PAGE_SIZE)
18 #define EXITS_TEST_SLOT 10
19 
guest_repeatedly_read(void)20 static uint64_t guest_repeatedly_read(void)
21 {
22 	volatile uint64_t value;
23 
24 	while (true)
25 		value = *((uint64_t *) EXITS_TEST_GVA);
26 
27 	return value;
28 }
29 
run_vcpu_get_exit_reason(struct kvm_vcpu * vcpu)30 static uint32_t run_vcpu_get_exit_reason(struct kvm_vcpu *vcpu)
31 {
32 	int r;
33 
34 	r = _vcpu_run(vcpu);
35 	if (r) {
36 		TEST_ASSERT(errno == EFAULT, KVM_IOCTL_ERROR(KVM_RUN, r));
37 		TEST_ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_MEMORY_FAULT);
38 	}
39 	return vcpu->run->exit_reason;
40 }
41 
42 const struct vm_shape protected_vm_shape = {
43 	.mode = VM_MODE_DEFAULT,
44 	.type = KVM_X86_SW_PROTECTED_VM,
45 };
46 
test_private_access_memslot_deleted(void)47 static void test_private_access_memslot_deleted(void)
48 {
49 	struct kvm_vm *vm;
50 	struct kvm_vcpu *vcpu;
51 	pthread_t vm_thread;
52 	void *thread_return;
53 	uint32_t exit_reason;
54 
55 	vm = vm_create_shape_with_one_vcpu(protected_vm_shape, &vcpu,
56 					   guest_repeatedly_read);
57 
58 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
59 				    EXITS_TEST_GPA, EXITS_TEST_SLOT,
60 				    EXITS_TEST_NPAGES,
61 				    KVM_MEM_GUEST_MEMFD);
62 
63 	virt_map(vm, EXITS_TEST_GVA, EXITS_TEST_GPA, EXITS_TEST_NPAGES);
64 
65 	/* Request to access page privately */
66 	vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
67 
68 	pthread_create(&vm_thread, NULL,
69 		       (void *(*)(void *))run_vcpu_get_exit_reason,
70 		       (void *)vcpu);
71 
72 	vm_mem_region_delete(vm, EXITS_TEST_SLOT);
73 
74 	pthread_join(vm_thread, &thread_return);
75 	exit_reason = (uint32_t)(uint64_t)thread_return;
76 
77 	TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
78 	TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
79 	TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
80 	TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
81 
82 	kvm_vm_free(vm);
83 }
84 
test_private_access_memslot_not_private(void)85 static void test_private_access_memslot_not_private(void)
86 {
87 	struct kvm_vm *vm;
88 	struct kvm_vcpu *vcpu;
89 	uint32_t exit_reason;
90 
91 	vm = vm_create_shape_with_one_vcpu(protected_vm_shape, &vcpu,
92 					   guest_repeatedly_read);
93 
94 	/* Add a non-private memslot (flags = 0) */
95 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
96 				    EXITS_TEST_GPA, EXITS_TEST_SLOT,
97 				    EXITS_TEST_NPAGES, 0);
98 
99 	virt_map(vm, EXITS_TEST_GVA, EXITS_TEST_GPA, EXITS_TEST_NPAGES);
100 
101 	/* Request to access page privately */
102 	vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
103 
104 	exit_reason = run_vcpu_get_exit_reason(vcpu);
105 
106 	TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
107 	TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
108 	TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
109 	TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
110 
111 	kvm_vm_free(vm);
112 }
113 
main(int argc,char * argv[])114 int main(int argc, char *argv[])
115 {
116 	TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM));
117 
118 	test_private_access_memslot_deleted();
119 	test_private_access_memslot_not_private();
120 }
121