Path: blob/master/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
38237 views
// SPDX-License-Identifier: GPL-2.0-only1#include <linux/kvm.h>2#include <linux/psp-sev.h>3#include <stdio.h>4#include <sys/ioctl.h>5#include <stdlib.h>6#include <errno.h>7#include <pthread.h>89#include "test_util.h"10#include "kvm_util.h"11#include "processor.h"12#include "sev.h"13#include "kselftest.h"1415#define NR_MIGRATE_TEST_VCPUS 416#define NR_MIGRATE_TEST_VMS 317#define NR_LOCK_TESTING_THREADS 318#define NR_LOCK_TESTING_ITERATIONS 100001920bool have_sev_es;2122static struct kvm_vm *sev_vm_create(bool es)23{24struct kvm_vm *vm;25int i;2627vm = vm_create_barebones();28if (!es)29sev_vm_init(vm);30else31sev_es_vm_init(vm);3233for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)34__vm_vcpu_add(vm, i);3536sev_vm_launch(vm, es ? SEV_POLICY_ES : 0);3738if (es)39vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);40return vm;41}4243static struct kvm_vm *aux_vm_create(bool with_vcpus)44{45struct kvm_vm *vm;46int i;4748vm = vm_create_barebones();49if (!with_vcpus)50return vm;5152for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)53__vm_vcpu_add(vm, i);5455return vm;56}5758static int __sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)59{60return __vm_enable_cap(dst, KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, src->fd);61}626364static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)65{66int ret;6768ret = __sev_migrate_from(dst, src);69TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d", ret, errno);70}7172static void test_sev_migrate_from(bool es)73{74struct kvm_vm *src_vm;75struct kvm_vm *dst_vms[NR_MIGRATE_TEST_VMS];76int i, ret;7778src_vm = sev_vm_create(es);79for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)80dst_vms[i] = aux_vm_create(true);8182/* Initial migration from the src to the first dst. */83sev_migrate_from(dst_vms[0], src_vm);8485for (i = 1; i < NR_MIGRATE_TEST_VMS; i++)86sev_migrate_from(dst_vms[i], dst_vms[i - 1]);8788/* Migrate the guest back to the original VM. */89ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]);90TEST_ASSERT(ret == -1 && errno == EIO,91"VM that was migrated from should be dead. ret %d, errno: %d", ret,92errno);9394kvm_vm_free(src_vm);95for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)96kvm_vm_free(dst_vms[i]);97}9899struct locking_thread_input {100struct kvm_vm *vm;101struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS];102};103104static void *locking_test_thread(void *arg)105{106int i, j;107struct locking_thread_input *input = (struct locking_thread_input *)arg;108109for (i = 0; i < NR_LOCK_TESTING_ITERATIONS; ++i) {110j = i % NR_LOCK_TESTING_THREADS;111__sev_migrate_from(input->vm, input->source_vms[j]);112}113114return NULL;115}116117static void test_sev_migrate_locking(void)118{119struct locking_thread_input input[NR_LOCK_TESTING_THREADS];120pthread_t pt[NR_LOCK_TESTING_THREADS];121int i;122123for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) {124input[i].vm = sev_vm_create(/* es= */ false);125input[0].source_vms[i] = input[i].vm;126}127for (i = 1; i < NR_LOCK_TESTING_THREADS; ++i)128memcpy(input[i].source_vms, input[0].source_vms,129sizeof(input[i].source_vms));130131for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)132pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);133134for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)135pthread_join(pt[i], NULL);136for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)137kvm_vm_free(input[i].vm);138}139140static void test_sev_migrate_parameters(void)141{142struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_no_sev,143*sev_es_vm_no_vmsa;144int ret;145146vm_no_vcpu = vm_create_barebones();147vm_no_sev = aux_vm_create(true);148ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev);149TEST_ASSERT(ret == -1 && errno == EINVAL,150"Migrations require SEV enabled. ret %d, errno: %d", ret,151errno);152153if (!have_sev_es)154goto out;155156sev_vm = sev_vm_create(/* es= */ false);157sev_es_vm = sev_vm_create(/* es= */ true);158sev_es_vm_no_vmsa = vm_create_barebones();159sev_es_vm_init(sev_es_vm_no_vmsa);160__vm_vcpu_add(sev_es_vm_no_vmsa, 1);161162ret = __sev_migrate_from(sev_vm, sev_es_vm);163TEST_ASSERT(164ret == -1 && errno == EINVAL,165"Should not be able migrate to SEV enabled VM. ret: %d, errno: %d",166ret, errno);167168ret = __sev_migrate_from(sev_es_vm, sev_vm);169TEST_ASSERT(170ret == -1 && errno == EINVAL,171"Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d",172ret, errno);173174ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm);175TEST_ASSERT(176ret == -1 && errno == EINVAL,177"SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d",178ret, errno);179180ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa);181TEST_ASSERT(182ret == -1 && errno == EINVAL,183"SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d",184ret, errno);185186kvm_vm_free(sev_vm);187kvm_vm_free(sev_es_vm);188kvm_vm_free(sev_es_vm_no_vmsa);189out:190kvm_vm_free(vm_no_vcpu);191kvm_vm_free(vm_no_sev);192}193194static int __sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)195{196return __vm_enable_cap(dst, KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, src->fd);197}198199200static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)201{202int ret;203204ret = __sev_mirror_create(dst, src);205TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d", ret, errno);206}207208static void verify_mirror_allowed_cmds(struct kvm_vm *vm)209{210struct kvm_sev_guest_status status;211int cmd_id;212213for (cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) {214int ret;215216/*217* These commands are allowed for mirror VMs, all others are218* not.219*/220switch (cmd_id) {221case KVM_SEV_LAUNCH_UPDATE_VMSA:222case KVM_SEV_GUEST_STATUS:223case KVM_SEV_DBG_DECRYPT:224case KVM_SEV_DBG_ENCRYPT:225continue;226default:227break;228}229230/*231* These commands should be disallowed before the data232* parameter is examined so NULL is OK here.233*/234ret = __vm_sev_ioctl(vm, cmd_id, NULL);235TEST_ASSERT(236ret == -1 && errno == EINVAL,237"Should not be able call command: %d. ret: %d, errno: %d",238cmd_id, ret, errno);239}240241vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status);242}243244static void test_sev_mirror(bool es)245{246struct kvm_vm *src_vm, *dst_vm;247int i;248249src_vm = sev_vm_create(es);250dst_vm = aux_vm_create(false);251252sev_mirror_create(dst_vm, src_vm);253254/* Check that we can complete creation of the mirror VM. */255for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)256__vm_vcpu_add(dst_vm, i);257258if (es)259vm_sev_ioctl(dst_vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);260261verify_mirror_allowed_cmds(dst_vm);262263kvm_vm_free(src_vm);264kvm_vm_free(dst_vm);265}266267static void test_sev_mirror_parameters(void)268{269struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_with_vcpu;270int ret;271272sev_vm = sev_vm_create(/* es= */ false);273vm_with_vcpu = aux_vm_create(true);274vm_no_vcpu = aux_vm_create(false);275276ret = __sev_mirror_create(sev_vm, sev_vm);277TEST_ASSERT(278ret == -1 && errno == EINVAL,279"Should not be able copy context to self. ret: %d, errno: %d",280ret, errno);281282ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu);283TEST_ASSERT(ret == -1 && errno == EINVAL,284"Copy context requires SEV enabled. ret %d, errno: %d", ret,285errno);286287ret = __sev_mirror_create(vm_with_vcpu, sev_vm);288TEST_ASSERT(289ret == -1 && errno == EINVAL,290"SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d",291ret, errno);292293if (!have_sev_es)294goto out;295296sev_es_vm = sev_vm_create(/* es= */ true);297ret = __sev_mirror_create(sev_vm, sev_es_vm);298TEST_ASSERT(299ret == -1 && errno == EINVAL,300"Should not be able copy context to SEV enabled VM. ret: %d, errno: %d",301ret, errno);302303ret = __sev_mirror_create(sev_es_vm, sev_vm);304TEST_ASSERT(305ret == -1 && errno == EINVAL,306"Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d",307ret, errno);308309kvm_vm_free(sev_es_vm);310311out:312kvm_vm_free(sev_vm);313kvm_vm_free(vm_with_vcpu);314kvm_vm_free(vm_no_vcpu);315}316317static void test_sev_move_copy(void)318{319struct kvm_vm *dst_vm, *dst2_vm, *dst3_vm, *sev_vm, *mirror_vm,320*dst_mirror_vm, *dst2_mirror_vm, *dst3_mirror_vm;321322sev_vm = sev_vm_create(/* es= */ false);323dst_vm = aux_vm_create(true);324dst2_vm = aux_vm_create(true);325dst3_vm = aux_vm_create(true);326mirror_vm = aux_vm_create(false);327dst_mirror_vm = aux_vm_create(false);328dst2_mirror_vm = aux_vm_create(false);329dst3_mirror_vm = aux_vm_create(false);330331sev_mirror_create(mirror_vm, sev_vm);332333sev_migrate_from(dst_mirror_vm, mirror_vm);334sev_migrate_from(dst_vm, sev_vm);335336sev_migrate_from(dst2_vm, dst_vm);337sev_migrate_from(dst2_mirror_vm, dst_mirror_vm);338339sev_migrate_from(dst3_mirror_vm, dst2_mirror_vm);340sev_migrate_from(dst3_vm, dst2_vm);341342kvm_vm_free(dst_vm);343kvm_vm_free(sev_vm);344kvm_vm_free(dst2_vm);345kvm_vm_free(dst3_vm);346kvm_vm_free(mirror_vm);347kvm_vm_free(dst_mirror_vm);348kvm_vm_free(dst2_mirror_vm);349kvm_vm_free(dst3_mirror_vm);350351/*352* Run similar test be destroy mirrors before mirrored VMs to ensure353* destruction is done safely.354*/355sev_vm = sev_vm_create(/* es= */ false);356dst_vm = aux_vm_create(true);357mirror_vm = aux_vm_create(false);358dst_mirror_vm = aux_vm_create(false);359360sev_mirror_create(mirror_vm, sev_vm);361362sev_migrate_from(dst_mirror_vm, mirror_vm);363sev_migrate_from(dst_vm, sev_vm);364365kvm_vm_free(mirror_vm);366kvm_vm_free(dst_mirror_vm);367kvm_vm_free(dst_vm);368kvm_vm_free(sev_vm);369}370371int main(int argc, char *argv[])372{373TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM));374TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM));375376TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));377378have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);379380if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) {381test_sev_migrate_from(/* es= */ false);382if (have_sev_es)383test_sev_migrate_from(/* es= */ true);384test_sev_migrate_locking();385test_sev_migrate_parameters();386if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM))387test_sev_move_copy();388}389if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) {390test_sev_mirror(/* es= */ false);391if (have_sev_es)392test_sev_mirror(/* es= */ true);393test_sev_mirror_parameters();394}395return 0;396}397398399