xref: /linux/tools/testing/selftests/kvm/x86/sev_migrate_tests.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/kvm.h>
3 #include <linux/psp-sev.h>
4 #include <stdio.h>
5 #include <sys/ioctl.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <pthread.h>
9 
10 #include "test_util.h"
11 #include "kvm_util.h"
12 #include "processor.h"
13 #include "sev.h"
14 #include "kselftest.h"
15 
16 #define NR_MIGRATE_TEST_VCPUS 4
17 #define NR_MIGRATE_TEST_VMS 3
18 #define NR_LOCK_TESTING_THREADS 3
19 #define NR_LOCK_TESTING_ITERATIONS 10000
20 
21 bool have_sev_es;
22 
23 static struct kvm_vm *sev_vm_create(bool es)
24 {
25 	struct kvm_vm *vm;
26 	int i;
27 
28 	vm = vm_create_barebones();
29 	if (!es)
30 		sev_vm_init(vm);
31 	else
32 		sev_es_vm_init(vm);
33 
34 	for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
35 		__vm_vcpu_add(vm, i);
36 
37 	sev_vm_launch(vm, es ? SEV_POLICY_ES : 0);
38 
39 	return vm;
40 }
41 
42 static struct kvm_vm *aux_vm_create(bool with_vcpus)
43 {
44 	struct kvm_vm *vm;
45 	int i;
46 
47 	vm = vm_create_barebones();
48 	if (!with_vcpus)
49 		return vm;
50 
51 	for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
52 		__vm_vcpu_add(vm, i);
53 
54 	return vm;
55 }
56 
57 static int __sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)
58 {
59 	return __vm_enable_cap(dst, KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, src->fd);
60 }
61 
62 
63 static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)
64 {
65 	int ret;
66 
67 	ret = __sev_migrate_from(dst, src);
68 	TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d", ret, errno);
69 }
70 
71 static void test_sev_migrate_from(bool es)
72 {
73 	struct kvm_vm *src_vm;
74 	struct kvm_vm *dst_vms[NR_MIGRATE_TEST_VMS];
75 	int i, ret;
76 
77 	src_vm = sev_vm_create(es);
78 	for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
79 		dst_vms[i] = aux_vm_create(true);
80 
81 	/* Initial migration from the src to the first dst. */
82 	sev_migrate_from(dst_vms[0], src_vm);
83 
84 	for (i = 1; i < NR_MIGRATE_TEST_VMS; i++)
85 		sev_migrate_from(dst_vms[i], dst_vms[i - 1]);
86 
87 	/* Migrate the guest back to the original VM. */
88 	ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]);
89 	TEST_ASSERT(ret == -1 && errno == EIO,
90 		    "VM that was migrated from should be dead. ret %d, errno: %d", ret,
91 		    errno);
92 
93 	kvm_vm_free(src_vm);
94 	for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
95 		kvm_vm_free(dst_vms[i]);
96 }
97 
98 struct locking_thread_input {
99 	struct kvm_vm *vm;
100 	struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS];
101 };
102 
103 static void *locking_test_thread(void *arg)
104 {
105 	int i, j;
106 	struct locking_thread_input *input = (struct locking_thread_input *)arg;
107 
108 	for (i = 0; i < NR_LOCK_TESTING_ITERATIONS; ++i) {
109 		j = i % NR_LOCK_TESTING_THREADS;
110 		__sev_migrate_from(input->vm, input->source_vms[j]);
111 	}
112 
113 	return NULL;
114 }
115 
116 static void test_sev_migrate_locking(void)
117 {
118 	struct locking_thread_input input[NR_LOCK_TESTING_THREADS];
119 	pthread_t pt[NR_LOCK_TESTING_THREADS];
120 	int i;
121 
122 	for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) {
123 		input[i].vm = sev_vm_create(/* es= */ false);
124 		input[0].source_vms[i] = input[i].vm;
125 	}
126 	for (i = 1; i < NR_LOCK_TESTING_THREADS; ++i)
127 		memcpy(input[i].source_vms, input[0].source_vms,
128 		       sizeof(input[i].source_vms));
129 
130 	for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
131 		pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);
132 
133 	for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
134 		pthread_join(pt[i], NULL);
135 	for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
136 		kvm_vm_free(input[i].vm);
137 }
138 
139 static void test_sev_migrate_parameters(void)
140 {
141 	struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_no_sev,
142 		*sev_es_vm_no_vmsa;
143 	int ret;
144 
145 	vm_no_vcpu = vm_create_barebones();
146 	vm_no_sev = aux_vm_create(true);
147 	ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev);
148 	TEST_ASSERT(ret == -1 && errno == EINVAL,
149 		    "Migrations require SEV enabled. ret %d, errno: %d", ret,
150 		    errno);
151 
152 	if (!have_sev_es)
153 		goto out;
154 
155 	sev_vm = sev_vm_create(/* es= */ false);
156 	sev_es_vm = sev_vm_create(/* es= */ true);
157 	sev_es_vm_no_vmsa = vm_create_barebones();
158 	sev_es_vm_init(sev_es_vm_no_vmsa);
159 	__vm_vcpu_add(sev_es_vm_no_vmsa, 1);
160 
161 	ret = __sev_migrate_from(sev_vm, sev_es_vm);
162 	TEST_ASSERT(
163 		ret == -1 && errno == EINVAL,
164 		"Should not be able migrate to SEV enabled VM. ret: %d, errno: %d",
165 		ret, errno);
166 
167 	ret = __sev_migrate_from(sev_es_vm, sev_vm);
168 	TEST_ASSERT(
169 		ret == -1 && errno == EINVAL,
170 		"Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d",
171 		ret, errno);
172 
173 	ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm);
174 	TEST_ASSERT(
175 		ret == -1 && errno == EINVAL,
176 		"SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d",
177 		ret, errno);
178 
179 	ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa);
180 	TEST_ASSERT(
181 		ret == -1 && errno == EINVAL,
182 		"SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d",
183 		ret, errno);
184 
185 	kvm_vm_free(sev_vm);
186 	kvm_vm_free(sev_es_vm);
187 	kvm_vm_free(sev_es_vm_no_vmsa);
188 out:
189 	kvm_vm_free(vm_no_vcpu);
190 	kvm_vm_free(vm_no_sev);
191 }
192 
193 static int __sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)
194 {
195 	return __vm_enable_cap(dst, KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, src->fd);
196 }
197 
198 
199 static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)
200 {
201 	int ret;
202 
203 	ret = __sev_mirror_create(dst, src);
204 	TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d", ret, errno);
205 }
206 
207 static void verify_mirror_allowed_cmds(struct kvm_vm *vm)
208 {
209 	struct kvm_sev_guest_status status;
210 	int cmd_id;
211 
212 	for (cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) {
213 		int ret;
214 
215 		/*
216 		 * These commands are allowed for mirror VMs, all others are
217 		 * not.
218 		 */
219 		switch (cmd_id) {
220 		case KVM_SEV_LAUNCH_UPDATE_VMSA:
221 		case KVM_SEV_GUEST_STATUS:
222 		case KVM_SEV_DBG_DECRYPT:
223 		case KVM_SEV_DBG_ENCRYPT:
224 			continue;
225 		default:
226 			break;
227 		}
228 
229 		/*
230 		 * These commands should be disallowed before the data
231 		 * parameter is examined so NULL is OK here.
232 		 */
233 		ret = __vm_sev_ioctl(vm, cmd_id, NULL);
234 		TEST_ASSERT(
235 			ret == -1 && errno == EINVAL,
236 			"Should not be able call command: %d. ret: %d, errno: %d",
237 			cmd_id, ret, errno);
238 	}
239 
240 	vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status);
241 }
242 
243 static void test_sev_mirror(bool es)
244 {
245 	struct kvm_vm *src_vm, *dst_vm;
246 	int i;
247 
248 	src_vm = sev_vm_create(es);
249 	dst_vm = aux_vm_create(false);
250 
251 	sev_mirror_create(dst_vm, src_vm);
252 
253 	/* Check that we can complete creation of the mirror VM.  */
254 	for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
255 		__vm_vcpu_add(dst_vm, i);
256 
257 	if (es)
258 		vm_sev_ioctl(dst_vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
259 
260 	verify_mirror_allowed_cmds(dst_vm);
261 
262 	kvm_vm_free(src_vm);
263 	kvm_vm_free(dst_vm);
264 }
265 
266 static void test_sev_mirror_parameters(void)
267 {
268 	struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_with_vcpu;
269 	int ret;
270 
271 	sev_vm = sev_vm_create(/* es= */ false);
272 	vm_with_vcpu = aux_vm_create(true);
273 	vm_no_vcpu = aux_vm_create(false);
274 
275 	ret = __sev_mirror_create(sev_vm, sev_vm);
276 	TEST_ASSERT(
277 		ret == -1 && errno == EINVAL,
278 		"Should not be able copy context to self. ret: %d, errno: %d",
279 		ret, errno);
280 
281 	ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu);
282 	TEST_ASSERT(ret == -1 && errno == EINVAL,
283 		    "Copy context requires SEV enabled. ret %d, errno: %d", ret,
284 		    errno);
285 
286 	ret = __sev_mirror_create(vm_with_vcpu, sev_vm);
287 	TEST_ASSERT(
288 		ret == -1 && errno == EINVAL,
289 		"SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d",
290 		ret, errno);
291 
292 	if (!have_sev_es)
293 		goto out;
294 
295 	sev_es_vm = sev_vm_create(/* es= */ true);
296 	ret = __sev_mirror_create(sev_vm, sev_es_vm);
297 	TEST_ASSERT(
298 		ret == -1 && errno == EINVAL,
299 		"Should not be able copy context to SEV enabled VM. ret: %d, errno: %d",
300 		ret, errno);
301 
302 	ret = __sev_mirror_create(sev_es_vm, sev_vm);
303 	TEST_ASSERT(
304 		ret == -1 && errno == EINVAL,
305 		"Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d",
306 		ret, errno);
307 
308 	kvm_vm_free(sev_es_vm);
309 
310 out:
311 	kvm_vm_free(sev_vm);
312 	kvm_vm_free(vm_with_vcpu);
313 	kvm_vm_free(vm_no_vcpu);
314 }
315 
316 static void test_sev_move_copy(void)
317 {
318 	struct kvm_vm *dst_vm, *dst2_vm, *dst3_vm, *sev_vm, *mirror_vm,
319 		      *dst_mirror_vm, *dst2_mirror_vm, *dst3_mirror_vm;
320 
321 	sev_vm = sev_vm_create(/* es= */ false);
322 	dst_vm = aux_vm_create(true);
323 	dst2_vm = aux_vm_create(true);
324 	dst3_vm = aux_vm_create(true);
325 	mirror_vm = aux_vm_create(false);
326 	dst_mirror_vm = aux_vm_create(false);
327 	dst2_mirror_vm = aux_vm_create(false);
328 	dst3_mirror_vm = aux_vm_create(false);
329 
330 	sev_mirror_create(mirror_vm, sev_vm);
331 
332 	sev_migrate_from(dst_mirror_vm, mirror_vm);
333 	sev_migrate_from(dst_vm, sev_vm);
334 
335 	sev_migrate_from(dst2_vm, dst_vm);
336 	sev_migrate_from(dst2_mirror_vm, dst_mirror_vm);
337 
338 	sev_migrate_from(dst3_mirror_vm, dst2_mirror_vm);
339 	sev_migrate_from(dst3_vm, dst2_vm);
340 
341 	kvm_vm_free(dst_vm);
342 	kvm_vm_free(sev_vm);
343 	kvm_vm_free(dst2_vm);
344 	kvm_vm_free(dst3_vm);
345 	kvm_vm_free(mirror_vm);
346 	kvm_vm_free(dst_mirror_vm);
347 	kvm_vm_free(dst2_mirror_vm);
348 	kvm_vm_free(dst3_mirror_vm);
349 
350 	/*
351 	 * Run similar test be destroy mirrors before mirrored VMs to ensure
352 	 * destruction is done safely.
353 	 */
354 	sev_vm = sev_vm_create(/* es= */ false);
355 	dst_vm = aux_vm_create(true);
356 	mirror_vm = aux_vm_create(false);
357 	dst_mirror_vm = aux_vm_create(false);
358 
359 	sev_mirror_create(mirror_vm, sev_vm);
360 
361 	sev_migrate_from(dst_mirror_vm, mirror_vm);
362 	sev_migrate_from(dst_vm, sev_vm);
363 
364 	kvm_vm_free(mirror_vm);
365 	kvm_vm_free(dst_mirror_vm);
366 	kvm_vm_free(dst_vm);
367 	kvm_vm_free(sev_vm);
368 }
369 
370 int main(int argc, char *argv[])
371 {
372 	TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM));
373 	TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM));
374 
375 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
376 
377 	have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);
378 
379 	if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) {
380 		test_sev_migrate_from(/* es= */ false);
381 		if (have_sev_es)
382 			test_sev_migrate_from(/* es= */ true);
383 		test_sev_migrate_locking();
384 		test_sev_migrate_parameters();
385 		if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM))
386 			test_sev_move_copy();
387 	}
388 	if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) {
389 		test_sev_mirror(/* es= */ false);
390 		if (have_sev_es)
391 			test_sev_mirror(/* es= */ true);
392 		test_sev_mirror_parameters();
393 	}
394 	return 0;
395 }
396