Skip to content

Commit 6a58150

Browse files
pgondabonzini
authored andcommitted
selftest: KVM: Add intra host migration tests
Adds testcases for intra host migration for SEV and SEV-ES. Also adds locking test to confirm no deadlock exists. Signed-off-by: Peter Gonda <[email protected]> Suggested-by: Sean Christopherson <[email protected]> Cc: Marc Orr <[email protected]> Cc: Sean Christopherson <[email protected]> Cc: David Rientjes <[email protected]> Cc: Brijesh Singh <[email protected]> Cc: Tom Lendacky <[email protected]> Cc: Paolo Bonzini <[email protected]> Cc: [email protected] Cc: [email protected] Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 7a6ab3c commit 6a58150

File tree

2 files changed

+205
-1
lines changed

2 files changed

+205
-1
lines changed

tools/testing/selftests/kvm/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test
7373
TEST_GEN_PROGS_x86_64 += x86_64/vmx_pmu_msrs_test
7474
TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test
7575
TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
76-
TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
76+
TEST_GEN_PROGS_x86_64 += x86_64/vmx_pi_mmio_test
77+
TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
7778
TEST_GEN_PROGS_x86_64 += demand_paging_test
7879
TEST_GEN_PROGS_x86_64 += dirty_log_test
7980
TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
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+
#include "../lib/kvm_util_internal.h"
16+
17+
#define SEV_POLICY_ES 0b100
18+
19+
#define NR_MIGRATE_TEST_VCPUS 4
20+
#define NR_MIGRATE_TEST_VMS 3
21+
#define NR_LOCK_TESTING_THREADS 3
22+
#define NR_LOCK_TESTING_ITERATIONS 10000
23+
24+
static void sev_ioctl(int vm_fd, int cmd_id, void *data)
25+
{
26+
struct kvm_sev_cmd cmd = {
27+
.id = cmd_id,
28+
.data = (uint64_t)data,
29+
.sev_fd = open_sev_dev_path_or_exit(),
30+
};
31+
int ret;
32+
33+
ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
34+
TEST_ASSERT((ret == 0 || cmd.error == SEV_RET_SUCCESS),
35+
"%d failed: return code: %d, errno: %d, fw error: %d",
36+
cmd_id, ret, errno, cmd.error);
37+
}
38+
39+
static struct kvm_vm *sev_vm_create(bool es)
40+
{
41+
struct kvm_vm *vm;
42+
struct kvm_sev_launch_start start = { 0 };
43+
int i;
44+
45+
vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR);
46+
sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL);
47+
for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
48+
vm_vcpu_add(vm, i);
49+
if (es)
50+
start.policy |= SEV_POLICY_ES;
51+
sev_ioctl(vm->fd, KVM_SEV_LAUNCH_START, &start);
52+
if (es)
53+
sev_ioctl(vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
54+
return vm;
55+
}
56+
57+
static struct kvm_vm *__vm_create(void)
58+
{
59+
struct kvm_vm *vm;
60+
int i;
61+
62+
vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR);
63+
for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
64+
vm_vcpu_add(vm, i);
65+
66+
return vm;
67+
}
68+
69+
static int __sev_migrate_from(int dst_fd, int src_fd)
70+
{
71+
struct kvm_enable_cap cap = {
72+
.cap = KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM,
73+
.args = { src_fd }
74+
};
75+
76+
return ioctl(dst_fd, KVM_ENABLE_CAP, &cap);
77+
}
78+
79+
80+
static void sev_migrate_from(int dst_fd, int src_fd)
81+
{
82+
int ret;
83+
84+
ret = __sev_migrate_from(dst_fd, src_fd);
85+
TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno);
86+
}
87+
88+
static void test_sev_migrate_from(bool es)
89+
{
90+
struct kvm_vm *src_vm;
91+
struct kvm_vm *dst_vms[NR_MIGRATE_TEST_VMS];
92+
int i;
93+
94+
src_vm = sev_vm_create(es);
95+
for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
96+
dst_vms[i] = __vm_create();
97+
98+
/* Initial migration from the src to the first dst. */
99+
sev_migrate_from(dst_vms[0]->fd, src_vm->fd);
100+
101+
for (i = 1; i < NR_MIGRATE_TEST_VMS; i++)
102+
sev_migrate_from(dst_vms[i]->fd, dst_vms[i - 1]->fd);
103+
104+
/* Migrate the guest back to the original VM. */
105+
sev_migrate_from(src_vm->fd, dst_vms[NR_MIGRATE_TEST_VMS - 1]->fd);
106+
107+
kvm_vm_free(src_vm);
108+
for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
109+
kvm_vm_free(dst_vms[i]);
110+
}
111+
112+
struct locking_thread_input {
113+
struct kvm_vm *vm;
114+
int source_fds[NR_LOCK_TESTING_THREADS];
115+
};
116+
117+
static void *locking_test_thread(void *arg)
118+
{
119+
int i, j;
120+
struct locking_thread_input *input = (struct locking_thread_input *)arg;
121+
122+
for (i = 0; i < NR_LOCK_TESTING_ITERATIONS; ++i) {
123+
j = i % NR_LOCK_TESTING_THREADS;
124+
__sev_migrate_from(input->vm->fd, input->source_fds[j]);
125+
}
126+
127+
return NULL;
128+
}
129+
130+
static void test_sev_migrate_locking(void)
131+
{
132+
struct locking_thread_input input[NR_LOCK_TESTING_THREADS];
133+
pthread_t pt[NR_LOCK_TESTING_THREADS];
134+
int i;
135+
136+
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) {
137+
input[i].vm = sev_vm_create(/* es= */ false);
138+
input[0].source_fds[i] = input[i].vm->fd;
139+
}
140+
for (i = 1; i < NR_LOCK_TESTING_THREADS; ++i)
141+
memcpy(input[i].source_fds, input[0].source_fds,
142+
sizeof(input[i].source_fds));
143+
144+
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
145+
pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);
146+
147+
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
148+
pthread_join(pt[i], NULL);
149+
}
150+
151+
static void test_sev_migrate_parameters(void)
152+
{
153+
struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_no_sev,
154+
*sev_es_vm_no_vmsa;
155+
int ret;
156+
157+
sev_vm = sev_vm_create(/* es= */ false);
158+
sev_es_vm = sev_vm_create(/* es= */ true);
159+
vm_no_vcpu = vm_create(VM_MODE_DEFAULT, 0, O_RDWR);
160+
vm_no_sev = __vm_create();
161+
sev_es_vm_no_vmsa = vm_create(VM_MODE_DEFAULT, 0, O_RDWR);
162+
sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL);
163+
vm_vcpu_add(sev_es_vm_no_vmsa, 1);
164+
165+
166+
ret = __sev_migrate_from(sev_vm->fd, sev_es_vm->fd);
167+
TEST_ASSERT(
168+
ret == -1 && errno == EINVAL,
169+
"Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n",
170+
ret, errno);
171+
172+
ret = __sev_migrate_from(sev_es_vm->fd, sev_vm->fd);
173+
TEST_ASSERT(
174+
ret == -1 && errno == EINVAL,
175+
"Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n",
176+
ret, errno);
177+
178+
ret = __sev_migrate_from(vm_no_vcpu->fd, sev_es_vm->fd);
179+
TEST_ASSERT(
180+
ret == -1 && errno == EINVAL,
181+
"SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n",
182+
ret, errno);
183+
184+
ret = __sev_migrate_from(vm_no_vcpu->fd, sev_es_vm_no_vmsa->fd);
185+
TEST_ASSERT(
186+
ret == -1 && errno == EINVAL,
187+
"SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n",
188+
ret, errno);
189+
190+
ret = __sev_migrate_from(vm_no_vcpu->fd, vm_no_sev->fd);
191+
TEST_ASSERT(ret == -1 && errno == EINVAL,
192+
"Migrations require SEV enabled. ret %d, errno: %d\n", ret,
193+
errno);
194+
}
195+
196+
int main(int argc, char *argv[])
197+
{
198+
test_sev_migrate_from(/* es= */ false);
199+
test_sev_migrate_from(/* es= */ true);
200+
test_sev_migrate_locking();
201+
test_sev_migrate_parameters();
202+
return 0;
203+
}

0 commit comments

Comments
 (0)