Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 395 lines 9.8 kB view raw
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 21bool have_sev_es; 22 23static 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 42static 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 57static 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 63static 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 71static 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 98struct locking_thread_input { 99 struct kvm_vm *vm; 100 struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS]; 101}; 102 103static 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 116static 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 139static 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); 188out: 189 kvm_vm_free(vm_no_vcpu); 190 kvm_vm_free(vm_no_sev); 191} 192 193static 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 199static 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 207static 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 243static 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 266static 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 310out: 311 kvm_vm_free(sev_vm); 312 kvm_vm_free(vm_with_vcpu); 313 kvm_vm_free(vm_no_vcpu); 314} 315 316static 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 370int 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}