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 16 #define SVM_SEV_FEAT_DEBUG_SWAP 32u 17 18 /* 19 * Some features may have hidden dependencies, or may only work 20 * for certain VM types. Err on the side of safety and don't 21 * expect that all supported features can be passed one by one 22 * to KVM_SEV_INIT2. 23 * 24 * (Well, right now there's only one...) 25 */ 26 #define KNOWN_FEATURES SVM_SEV_FEAT_DEBUG_SWAP 27 28 int kvm_fd; 29 u64 supported_vmsa_features; 30 bool have_sev_es; 31 32 static int __sev_ioctl(int vm_fd, int cmd_id, void *data) 33 { 34 struct kvm_sev_cmd cmd = { 35 .id = cmd_id, 36 .data = (uint64_t)data, 37 .sev_fd = open_sev_dev_path_or_exit(), 38 }; 39 int ret; 40 41 ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd); 42 TEST_ASSERT(ret < 0 || cmd.error == SEV_RET_SUCCESS, 43 "%d failed: fw error: %d\n", 44 cmd_id, cmd.error); 45 46 return ret; 47 } 48 49 static void test_init2(unsigned long vm_type, struct kvm_sev_init *init) 50 { 51 struct kvm_vm *vm; 52 int ret; 53 54 vm = vm_create_barebones_type(vm_type); 55 ret = __sev_ioctl(vm->fd, KVM_SEV_INIT2, init); 56 TEST_ASSERT(ret == 0, 57 "KVM_SEV_INIT2 return code is %d (expected 0), errno: %d", 58 ret, errno); 59 kvm_vm_free(vm); 60 } 61 62 static void test_init2_invalid(unsigned long vm_type, struct kvm_sev_init *init, const char *msg) 63 { 64 struct kvm_vm *vm; 65 int ret; 66 67 vm = vm_create_barebones_type(vm_type); 68 ret = __sev_ioctl(vm->fd, KVM_SEV_INIT2, init); 69 TEST_ASSERT(ret == -1 && errno == EINVAL, 70 "KVM_SEV_INIT2 should fail, %s.", 71 msg); 72 kvm_vm_free(vm); 73 } 74 75 void test_vm_types(void) 76 { 77 test_init2(KVM_X86_SEV_VM, &(struct kvm_sev_init){}); 78 79 /* 80 * TODO: check that unsupported types cannot be created. Probably 81 * a separate selftest. 82 */ 83 if (have_sev_es) 84 test_init2(KVM_X86_SEV_ES_VM, &(struct kvm_sev_init){}); 85 86 test_init2_invalid(0, &(struct kvm_sev_init){}, 87 "VM type is KVM_X86_DEFAULT_VM"); 88 if (kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM)) 89 test_init2_invalid(KVM_X86_SW_PROTECTED_VM, &(struct kvm_sev_init){}, 90 "VM type is KVM_X86_SW_PROTECTED_VM"); 91 } 92 93 void test_flags(uint32_t vm_type) 94 { 95 int i; 96 97 for (i = 0; i < 32; i++) 98 test_init2_invalid(vm_type, 99 &(struct kvm_sev_init){ .flags = BIT(i) }, 100 "invalid flag"); 101 } 102 103 void test_features(uint32_t vm_type, uint64_t supported_features) 104 { 105 int i; 106 107 for (i = 0; i < 64; i++) { 108 if (!(supported_features & BIT_ULL(i))) 109 test_init2_invalid(vm_type, 110 &(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) }, 111 "unknown feature"); 112 else if (KNOWN_FEATURES & BIT_ULL(i)) 113 test_init2(vm_type, 114 &(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) }); 115 } 116 } 117 118 int main(int argc, char *argv[]) 119 { 120 int kvm_fd = open_kvm_dev_path_or_exit(); 121 bool have_sev; 122 123 TEST_REQUIRE(__kvm_has_device_attr(kvm_fd, KVM_X86_GRP_SEV, 124 KVM_X86_SEV_VMSA_FEATURES) == 0); 125 kvm_device_attr_get(kvm_fd, KVM_X86_GRP_SEV, 126 KVM_X86_SEV_VMSA_FEATURES, 127 &supported_vmsa_features); 128 129 have_sev = kvm_cpu_has(X86_FEATURE_SEV); 130 TEST_ASSERT(have_sev == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_VM)), 131 "sev: KVM_CAP_VM_TYPES (%x) does not match cpuid (checking %x)", 132 kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_VM); 133 134 TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_VM)); 135 have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES); 136 137 TEST_ASSERT(have_sev_es == !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SEV_ES_VM)), 138 "sev-es: KVM_CAP_VM_TYPES (%x) does not match cpuid (checking %x)", 139 kvm_check_cap(KVM_CAP_VM_TYPES), 1 << KVM_X86_SEV_ES_VM); 140 141 test_vm_types(); 142 143 test_flags(KVM_X86_SEV_VM); 144 if (have_sev_es) 145 test_flags(KVM_X86_SEV_ES_VM); 146 147 test_features(KVM_X86_SEV_VM, 0); 148 if (have_sev_es) 149 test_features(KVM_X86_SEV_ES_VM, supported_vmsa_features); 150 151 return 0; 152 } 153
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.