From: "Tycho Andersen (AMD)" In addition to the errno, sometimes it is useful to know the underlying SEV firmware error. Update the raw vm ioctl macro to allow for optionally retrieving this. Signed-off-by: Tycho Andersen (AMD) --- tools/testing/selftests/kvm/include/x86/sev.h | 6 ++++-- tools/testing/selftests/kvm/x86/sev_migrate_tests.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h index 008b4169f5e2..fd11f4222ec2 100644 --- a/tools/testing/selftests/kvm/include/x86/sev.h +++ b/tools/testing/selftests/kvm/include/x86/sev.h @@ -76,7 +76,7 @@ static inline u64 snp_default_policy(void) * creating an overlay to pass in an "unsigned long" without a cast (casting * will make the compiler unhappy due to dereferencing an aliased pointer). */ -#define __vm_sev_ioctl(vm, cmd, arg) \ +#define __vm_sev_ioctl(vm, cmd, arg, errorp) \ ({ \ int r; \ \ @@ -90,12 +90,14 @@ static inline u64 snp_default_policy(void) } }; \ \ r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &sev_cmd.raw); \ + if (errorp != NULL) \ + *((__u32 *)errorp) = sev_cmd.c.error; \ r ?: sev_cmd.c.error; \ }) #define vm_sev_ioctl(vm, cmd, arg) \ ({ \ - int ret = __vm_sev_ioctl(vm, cmd, arg); \ + int ret = __vm_sev_ioctl(vm, cmd, arg, NULL); \ \ __TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, vm); \ }) diff --git a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c index 0a6dfba3905b..18f3091e0bd8 100644 --- a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c @@ -232,7 +232,7 @@ static void verify_mirror_allowed_cmds(struct kvm_vm *vm) * These commands should be disallowed before the data * parameter is examined so NULL is OK here. */ - ret = __vm_sev_ioctl(vm, cmd_id, NULL); + ret = __vm_sev_ioctl(vm, cmd_id, NULL, NULL); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able call command: %d. ret: %d, errno: %d", -- 2.53.0 From: "Tycho Andersen (AMD)" As in the comment, check to make sure that SEV-ES VMs are allowed before running the test. Otherwise, there is a generic: ==== Test Assertion Failure ==== lib/x86/sev.c:91: !ret pid=3678 tid=3678 errno=5 - Input/output error 1 0x0000000000417000: sev_vm_launch at sev.c:91 (discriminator 4) 2 0x0000000000417d49: vm_sev_launch at sev.c:191 3 0x0000000000402a7d: test_sev at sev_smoke_test.c:132 4 0x000000000040328f: test_sev_smoke at sev_smoke_test.c:198 5 0x00000000004026c8: main at sev_smoke_test.c:223 6 0x00007fdde5c2a1c9: ?? ??:0 7 0x00007fdde5c2a28a: ?? ??:0 8 0x00000000004027f4: _start at ??:? KVM_SEV_LAUNCH_START failed, rc: -1 errno: 5 (Input/output error) Signed-off-by: Tycho Andersen (AMD) --- .../selftests/kvm/x86/sev_smoke_test.c | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c index 86ad1c7d068f..c7fda9fc324b 100644 --- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c +++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c @@ -213,13 +213,48 @@ static void test_sev_smoke(void *guest, uint32_t type, uint64_t policy) } } +static bool sev_es_allowed(void) +{ + struct kvm_sev_launch_start launch_start = { + .policy = SEV_POLICY_ES, + }; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int firmware_error, ret; + bool supported = true; + + if (!kvm_cpu_has(X86_FEATURE_SEV_ES)) + return false; + + if (!kvm_cpu_has(X86_FEATURE_SEV_SNP)) + return true; + + /* + * In some cases when SEV-SNP is enabled, firmware disallows starting + * an SEV-ES VM. When SEV-SNP is enabled try to launch an SEV-ES, and + * check the underlying firmware error for this case. + */ + vm = vm_sev_create_with_one_vcpu(KVM_X86_SEV_ES_VM, guest_sev_es_code, + &vcpu); + + ret = __vm_sev_ioctl(vm, KVM_SEV_LAUNCH_START, &launch_start, + &firmware_error); + if (ret == -1 && firmware_error == SEV_RET_UNSUPPORTED) { + pr_info("SEV-ES not supported with SNP\n"); + supported = false; + } + + kvm_vm_free(vm); + return supported; +} + int main(int argc, char *argv[]) { TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV)); test_sev_smoke(guest_sev_code, KVM_X86_SEV_VM, 0); - if (kvm_cpu_has(X86_FEATURE_SEV_ES)) + if (sev_es_allowed()) test_sev_smoke(guest_sev_es_code, KVM_X86_SEV_ES_VM, SEV_POLICY_ES); if (kvm_cpu_has(X86_FEATURE_SEV_SNP)) -- 2.53.0 From: "Tycho Andersen (AMD)" The kernel allows setting the RAPL_DIS policy bit, but had no way to set the RAPL_DIS bit during SNP_INIT_EX. Setting the policy bit would always result in: [ 898.840286] ccp 0000:a9:00.5: sev command 0xa0 failed (0x00000007) Allow setting the RAPL_DIS bit during SNP_INIT_EX via a module parameter. If the hardware does not support RAPL_DIS, log and disable the module parameter. Signed-off-by: Tycho Andersen (AMD) --- drivers/crypto/ccp/sev-dev.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 096f993974d1..362126453ef0 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -75,6 +75,10 @@ static bool psp_init_on_probe = true; module_param(psp_init_on_probe, bool, 0444); MODULE_PARM_DESC(psp_init_on_probe, " if true, the PSP will be initialized on module init. Else the PSP will be initialized on the first command requiring it"); +static bool rapl_disable; +module_param(rapl_disable, bool, 0444); +MODULE_PARM_DESC(rapl_disable, " if true, the RAPL_DIS bit will be set during INIT_EX if supported"); + #if IS_ENABLED(CONFIG_PCI_TSM) static bool sev_tio_enabled = true; module_param_named(tio, sev_tio_enabled, bool, 0444); @@ -1428,6 +1432,16 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) data.max_snp_asid = max_snp_asid; } + if (rapl_disable) { + if (sev->snp_feat_info_0.ecx & SNP_RAPL_DISABLE_SUPPORTED) { + data.rapl_dis = 1; + } else { + dev_info(sev->dev, + "SEV: RAPL_DIS requested, but not supported"); + rapl_disable = false; + } + } + data.init_rmp = 1; data.list_paddr_en = 1; data.list_paddr = __psp_pa(snp_range_list); -- 2.53.0 From: "Tycho Andersen (AMD)" If the hardware supports the RAPL_DIS policy bit and the ccp has been loaded with the RAPL_DIS bit set, make sure a VM can actually start using it. Signed-off-by: Tycho Andersen (AMD) --- tools/testing/selftests/kvm/include/x86/sev.h | 1 + .../selftests/kvm/x86/sev_smoke_test.c | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h index fd11f4222ec2..e9a566ff6df1 100644 --- a/tools/testing/selftests/kvm/include/x86/sev.h +++ b/tools/testing/selftests/kvm/include/x86/sev.h @@ -28,6 +28,7 @@ enum sev_guest_state { #define SNP_POLICY_SMT (1ULL << 16) #define SNP_POLICY_RSVD_MBO (1ULL << 17) #define SNP_POLICY_DBG (1ULL << 19) +#define SNP_POLICY_RAPL_DIS (1ULL << 23) #define GHCB_MSR_TERM_REQ 0x100 diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c index c7fda9fc324b..e4cf5b99b19a 100644 --- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c +++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c @@ -248,6 +248,18 @@ static bool sev_es_allowed(void) return supported; } +static u64 supported_policy_mask(void) +{ + int kvm_fd = open_kvm_dev_path_or_exit(); + u64 policy_mask = 0; + + kvm_device_attr_get(kvm_fd, KVM_X86_GRP_SEV, + KVM_X86_SNP_POLICY_BITS, + &policy_mask); + close(kvm_fd); + return policy_mask; +} + int main(int argc, char *argv[]) { TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV)); @@ -257,8 +269,18 @@ int main(int argc, char *argv[]) if (sev_es_allowed()) test_sev_smoke(guest_sev_es_code, KVM_X86_SEV_ES_VM, SEV_POLICY_ES); - if (kvm_cpu_has(X86_FEATURE_SEV_SNP)) + if (kvm_cpu_has(X86_FEATURE_SEV_SNP)) { + int supported_policy = supported_policy_mask(); + test_sev_smoke(guest_snp_code, KVM_X86_SNP_VM, snp_default_policy()); + if (supported_policy & SNP_POLICY_RAPL_DIS && + kvm_get_module_param_bool("ccp", "rapl_disable")) { + uint32_t policy = snp_default_policy() | SNP_POLICY_RAPL_DIS; + + test_sev_smoke(guest_snp_code, KVM_X86_SNP_VM, policy); + } + } + return 0; } -- 2.53.0