KVM: selftests: Add a basic SEV-ES smoke test
authorSean Christopherson <seanjc@google.com>
Fri, 23 Feb 2024 00:42:58 +0000 (16:42 -0800)
committerSean Christopherson <seanjc@google.com>
Thu, 29 Feb 2024 00:39:55 +0000 (16:39 -0800)
Extend sev_smoke_test to also run a minimal SEV-ES smoke test so that it's
possible to test KVM's unique VMRUN=>#VMEXIT path for SEV-ES guests
without needing a full blown SEV-ES capable VM, which requires a rather
absurd amount of properly configured collateral.

Punt on proper GHCB and ucall support, and instead use the GHCB MSR
protocol to signal test completion.  The most important thing at this
point is to have _any_ kind of testing of KVM's __svm_sev_es_vcpu_run().

Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Michael Roth <michael.roth@amd.com>
Cc: Peter Gonda <pgonda@google.com>
Cc: Carlos Bilbao <carlos.bilbao@amd.com>
Tested-by: Carlos Bilbao <carlos.bilbao@amd.com>
Link: https://lore.kernel.org/r/20240223004258.3104051-12-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
tools/testing/selftests/kvm/include/x86_64/sev.h
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/sev.c
tools/testing/selftests/kvm/x86_64/sev_smoke_test.c

index de5283bef7527eb44688814ca37cb92eb4b470f8..8a1bf88474c92f176069a8888171067c90387d37 100644 (file)
@@ -25,6 +25,8 @@ enum sev_guest_state {
 #define SEV_POLICY_NO_DBG      (1UL << 0)
 #define SEV_POLICY_ES          (1UL << 2)
 
+#define GHCB_MSR_TERM_REQ      0x100
+
 void sev_vm_launch(struct kvm_vm *vm, uint32_t policy);
 void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement);
 void sev_vm_launch_finish(struct kvm_vm *vm);
index f1139ba35112801b90713f8ce2612e5feefbe4a4..49288fe10cd34eeb84a252260d4acbc271b1d5ac 100644 (file)
@@ -1072,7 +1072,7 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
 
 void kvm_init_vm_address_properties(struct kvm_vm *vm)
 {
-       if (vm->subtype == VM_SUBTYPE_SEV) {
+       if (vm->subtype == VM_SUBTYPE_SEV || vm->subtype == VM_SUBTYPE_SEV_ES) {
                vm->arch.c_bit = BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT));
                vm->gpa_tag_mask = vm->arch.c_bit;
        }
index 9f5a3dbb5e65b3064cb0f3c2e818e05c38a2bd2e..e248d3364b9c3b21fc375647920d5f558d5bca96 100644 (file)
@@ -53,6 +53,9 @@ void sev_vm_launch(struct kvm_vm *vm, uint32_t policy)
        hash_for_each(vm->regions.slot_hash, ctr, region, slot_node)
                encrypt_region(vm, region);
 
+       if (policy & SEV_POLICY_ES)
+               vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
+
        vm->arch.is_pt_protected = true;
 }
 
@@ -90,7 +93,8 @@ struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_code,
        struct vm_shape shape = {
                .type = VM_TYPE_DEFAULT,
                .mode = VM_MODE_DEFAULT,
-               .subtype = VM_SUBTYPE_SEV,
+               .subtype = policy & SEV_POLICY_ES ? VM_SUBTYPE_SEV_ES :
+                                                   VM_SUBTYPE_SEV,
        };
        struct kvm_vm *vm;
        struct kvm_vcpu *cpus[1];
index 54d72efd9b4d9a4d4d87b9a109f9d381c0470f5b..026779f3ed06dec85838bfbaa2d3bf8730169418 100644 (file)
 #include "linux/psp-sev.h"
 #include "sev.h"
 
+
+static void guest_sev_es_code(void)
+{
+       /* TODO: Check CPUID after GHCB-based hypercall support is added. */
+       GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED);
+       GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ES_ENABLED);
+
+       /*
+        * TODO: Add GHCB and ucall support for SEV-ES guests.  For now, simply
+        * force "termination" to signal "done" via the GHCB MSR protocol.
+        */
+       wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
+       __asm__ __volatile__("rep; vmmcall");
+}
+
 static void guest_sev_code(void)
 {
        GUEST_ASSERT(this_cpu_has(X86_FEATURE_SEV));
@@ -31,6 +46,16 @@ static void test_sev(void *guest_code, uint64_t policy)
        for (;;) {
                vcpu_run(vcpu);
 
+               if (policy & SEV_POLICY_ES) {
+                       TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
+                                   "Wanted SYSTEM_EVENT, got %s",
+                                   exit_reason_str(vcpu->run->exit_reason));
+                       TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM);
+                       TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1);
+                       TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ);
+                       break;
+               }
+
                switch (get_ucall(vcpu, &uc)) {
                case UCALL_SYNC:
                        continue;
@@ -54,5 +79,10 @@ int main(int argc, char *argv[])
        test_sev(guest_sev_code, SEV_POLICY_NO_DBG);
        test_sev(guest_sev_code, 0);
 
+       if (kvm_cpu_has(X86_FEATURE_SEV_ES)) {
+               test_sev(guest_sev_es_code, SEV_POLICY_ES | SEV_POLICY_NO_DBG);
+               test_sev(guest_sev_es_code, SEV_POLICY_ES);
+       }
+
        return 0;
 }