~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php