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