summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kvm/x86_64/sev_init2_tests.c
blob: 3fb967f40c6a1626d1d2cff1032c0e2562c8a205 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/kvm.h>
#include <linux/psp-sev.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>

#include "test_util.h"
#include "kvm_util.h"
#include "processor.h"
#include "svm_util.h"
#include "kselftest.h"

#define SVM_SEV_FEAT_DEBUG_SWAP 32u

/*
 * Some features may have hidden dependencies, or may only work
 * for certain VM types.  Err on the side of safety and don't
 * expect that all supported features can be passed one by one
 * to KVM_SEV_INIT2.
 *
 * (Well, right now there's only one...)
 */
#define KNOWN_FEATURES SVM_SEV_FEAT_DEBUG_SWAP

int kvm_fd;
u64 supported_vmsa_features;
bool have_sev_es;

static int __sev_ioctl(int vm_fd, int cmd_id, void *data)
{
	struct kvm_sev_cmd cmd = {
		.id = cmd_id,
		.data = (uint64_t)data,
		.sev_fd = open_sev_dev_path_or_exit(),
	};
	int ret;

	ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
	TEST_ASSERT(ret < 0 || cmd.error == SEV_RET_SUCCESS,
		    "%d failed: fw error: %d\n",
		    cmd_id, cmd.error);

	return ret;
}

static void test_init2(unsigned long vm_type, struct kvm_sev_init *init)
{
	struct kvm_vm *vm;
	int ret;

	vm = vm_create_barebones_type(vm_type);
	ret = __sev_ioctl(vm->fd, KVM_SEV_INIT2, init);
	TEST_ASSERT(ret == 0,
		    "KVM_SEV_INIT2 return code is %d (expected 0), errno: %d",
		    ret, errno);
	kvm_vm_free(vm);
}

static void test_init2_invalid(unsigned long vm_type, struct kvm_sev_init *init, const char *msg)
{
	struct kvm_vm *vm;
	int ret;

	vm = vm_create_barebones_type(vm_type);
	ret = __sev_ioctl(vm->fd, KVM_SEV_INIT2, init);
	TEST_ASSERT(ret == -1 && errno == EINVAL,
		    "KVM_SEV_INIT2 should fail, %s.",
		    msg);
	kvm_vm_free(vm);
}

void test_vm_types(void)
{
	test_init2(KVM_X86_SEV_VM, &(struct kvm_sev_init){});

	/*
	 * TODO: check that unsupported types cannot be created.  Probably
	 * a separate selftest.
	 */
	if (have_sev_es)
		test_init2(KVM_X86_SEV_ES_VM, &(struct kvm_sev_init){});

	test_init2_invalid(0, &(struct kvm_sev_init){},
			   "VM type is KVM_X86_DEFAULT_VM");
	if (kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM))
		test_init2_invalid(KVM_X86_SW_PROTECTED_VM, &(struct kvm_sev_init){},
				   "VM type is KVM_X86_SW_PROTECTED_VM");
}

void test_flags(uint32_t vm_type)
{
	int i;

	for (i = 0; i < 32; i++)
		test_init2_invalid(vm_type,
			&(struct kvm_sev_init){ .flags = BIT(i) },
			"invalid flag");
}

void test_features(uint32_t vm_type, uint64_t supported_features)
{
	int i;

	for (i = 0; i < 64; i++) {
		if (!(supported_features & BIT_ULL(i)))
			test_init2_invalid(vm_type,
				&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) },
				"unknown feature");
		else if (KNOWN_FEATURES & BIT_ULL(i))
			test_init2(vm_type,
				&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) });
	}
}

int main(int argc, char *argv[])
{
	int kvm_fd = open_kvm_dev_path_or_exit();
	bool have_sev;

	TEST_REQUIRE(__kvm_has_device_attr(kvm_fd, KVM_X86_GRP_SEV,
					   KVM_X86_SEV_VMSA_FEATURES) == 0);
	kvm_device_attr_get(kvm_fd, KVM_X86_GRP_SEV,
			    KVM_X86_SEV_VMSA_FEATURES,
			    &supported_vmsa_features);

	have_sev = kvm_cpu_has(X86_FEATURE_SEV);
	TEST_ASSERT(have_sev == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_VM)),
		    "sev: KVM_CAP_VM_TYPES (%x) does not match cpuid (checking %x)",
		    kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_VM);

	TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_VM));
	have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);

	TEST_ASSERT(have_sev_es == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_ES_VM)),
		    "sev-es: KVM_CAP_VM_TYPES (%x) does not match cpuid (checking %x)",
		    kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_ES_VM);

	test_vm_types();

	test_flags(KVM_X86_SEV_VM);
	if (have_sev_es)
		test_flags(KVM_X86_SEV_ES_VM);

	test_features(KVM_X86_SEV_VM, 0);
	if (have_sev_es)
		test_features(KVM_X86_SEV_ES_VM, supported_vmsa_features);

	return 0;
}