398 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#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 417#define NR_MIGRATE_TEST_VMS 318#define NR_LOCK_TESTING_THREADS 319#define NR_LOCK_TESTING_ITERATIONS 1000020 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 else32 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 44static 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 59static 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 65static 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 73static 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 100struct locking_thread_input {101 struct kvm_vm *vm;102 struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS];103};104 105static 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 118static 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 141static 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);190out:191 kvm_vm_free(vm_no_vcpu);192 kvm_vm_free(vm_no_sev);193}194 195static 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 201static 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 209static 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 are219 * 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 data233 * 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 245static 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 268static 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 312out:313 kvm_vm_free(sev_vm);314 kvm_vm_free(vm_with_vcpu);315 kvm_vm_free(vm_no_vcpu);316}317 318static 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 ensure354 * 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 372int 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