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 153 154 155 156 157 158 159 160 161 162 163 164 165
|
// 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;
bool have_snp;
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){});
if (have_snp)
test_init2(KVM_X86_SNP_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);
have_snp = kvm_cpu_has(X86_FEATURE_SEV_SNP);
TEST_ASSERT(have_snp == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SNP_VM)),
"sev-snp: KVM_CAP_VM_TYPES (%x) indicates SNP support (bit %d), but CPUID does not",
kvm_check_cap(KVM_CAP_VM_TYPES), KVM_X86_SNP_VM);
test_vm_types();
test_flags(KVM_X86_SEV_VM);
if (have_sev_es)
test_flags(KVM_X86_SEV_ES_VM);
if (have_snp)
test_flags(KVM_X86_SNP_VM);
test_features(KVM_X86_SEV_VM, 0);
if (have_sev_es)
test_features(KVM_X86_SEV_ES_VM, supported_vmsa_features);
if (have_snp)
test_features(KVM_X86_SNP_VM, supported_vmsa_features);
return 0;
}
|