Signed-off-by: Ackerley Tng <[email protected]>
---
 .../selftests/kvm/x86/sev_smoke_test.c        | 190 +++++++++++++++++-
 1 file changed, 185 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c 
b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
index 7e69da01cecf4..c40c359f78901 100644
--- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c
+++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c
@@ -253,17 +253,197 @@ static void test_sev_smoke(void *guest, uint32_t type, 
uint64_t policy)
        }
 }
 
+#define GHCB_MSR_REG_GPA_REQ           0x012
+#define GHCB_MSR_REG_GPA_REQ_VAL(v)                \
+       /* GHCBData[63:12] */                      \
+       (((u64)((v) & GENMASK_ULL(51, 0)) << 12) | \
+        /* GHCBData[11:0] */                      \
+        GHCB_MSR_REG_GPA_REQ)
+
+#define GHCB_MSR_REG_GPA_RESP          0x013
+#define GHCB_MSR_REG_GPA_RESP_VAL(v)                   \
+       /* GHCBData[63:12] */                           \
+       (((u64)(v) & GENMASK_ULL(63, 12)) >> 12)
+
+#define GHCB_DATA_LOW                  12
+#define GHCB_MSR_INFO_MASK             (BIT_ULL(GHCB_DATA_LOW) - 1)
+#define GHCB_RESP_CODE(v) ((v) & GHCB_MSR_INFO_MASK)
+
+/*
+ * SNP Page State Change Operation
+ *
+ * GHCBData[55:52] - Page operation:
+ *   0x0001    Page assignment, Private
+ *   0x0002    Page assignment, Shared
+ */
+enum psc_op {
+       SNP_PAGE_STATE_PRIVATE = 1,
+       SNP_PAGE_STATE_SHARED,
+};
+
+#define GHCB_MSR_PSC_REQ               0x014
+#define GHCB_MSR_PSC_REQ_GFN(gfn, op)                  \
+       /* GHCBData[55:52] */                           \
+       (((u64)((op) & 0xf) << 52) |                    \
+       /* GHCBData[51:12] */                           \
+       ((u64)((gfn) & GENMASK_ULL(39, 0)) << 12) |     \
+       /* GHCBData[11:0] */                            \
+       GHCB_MSR_PSC_REQ)
+
+#define GHCB_MSR_PSC_RESP              0x015
+#define GHCB_MSR_PSC_RESP_VAL(val)                     \
+       /* GHCBData[63:32] */                           \
+       (((u64)(val) & GENMASK_ULL(63, 32)) >> 32)
+
+static u64 ghcb_gpa;
+static void snp_register_ghcb(void)
+{
+       u64 ghcb_pfn = ghcb_gpa >> PAGE_SHIFT;
+       u64 val;
+
+       GUEST_ASSERT(ghcb_gpa);
+
+       wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_REG_GPA_REQ_VAL(ghcb_gpa >> 
PAGE_SHIFT));
+       vmgexit();
+
+       val = rdmsr(MSR_AMD64_SEV_ES_GHCB);
+       GUEST_ASSERT_EQ(GHCB_RESP_CODE(val), GHCB_MSR_REG_GPA_RESP);
+       GUEST_ASSERT_EQ(GHCB_MSR_REG_GPA_RESP_VAL(val), ghcb_pfn);
+}
+
+static void snp_page_state_change(u64 gpa, enum psc_op op)
+{
+       u64 val;
+
+       wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_PSC_REQ_GFN(gpa >> PAGE_SHIFT, 
op));
+       vmgexit();
+
+       val = rdmsr(MSR_AMD64_SEV_ES_GHCB);
+       GUEST_ASSERT_EQ(GHCB_RESP_CODE(val), GHCB_MSR_PSC_RESP);
+       GUEST_ASSERT_EQ(GHCB_MSR_PSC_RESP_VAL(val), 0);
+}
+
+#define RMP_PG_SIZE_4K                 0
+static inline void pvalidate(void *vaddr, bool validate)
+{
+       bool no_rmpupdate;
+       int rc;
+
+       /* "pvalidate" mnemonic support in binutils 2.36 and newer */
+       asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFF\n\t"
+                    : "=@ccc"(no_rmpupdate), "=a"(rc)
+                    : "a"(vaddr), "c"(RMP_PG_SIZE_4K), "d"(validate)
+                    : "memory", "cc");
+
+       GUEST_ASSERT(!no_rmpupdate);
+       GUEST_ASSERT_EQ(rc, 0);
+}
+
+#define CONVERSION_TEST_VALUE_SHARED_1 0xab
+#define CONVERSION_TEST_VALUE_SHARED_2 0xcd
+#define CONVERSION_TEST_VALUE_PRIVATE 0xef
+#define CONVERSION_TEST_VALUE_SHARED_3 0xbc
+static void guest_code_conversion(u8 *test_shared_gva, u8 *test_private_gva, 
u64 test_gpa)
+{
+       snp_register_ghcb();
+
+       GUEST_ASSERT_EQ(READ_ONCE(*test_shared_gva), 
CONVERSION_TEST_VALUE_SHARED_1);
+       WRITE_ONCE(*test_shared_gva, CONVERSION_TEST_VALUE_SHARED_2);
+
+       snp_page_state_change(test_gpa, SNP_PAGE_STATE_PRIVATE);
+       pvalidate(test_private_gva, true);
+
+       WRITE_ONCE(*test_private_gva, CONVERSION_TEST_VALUE_PRIVATE);
+       GUEST_ASSERT_EQ(READ_ONCE(*test_private_gva), 
CONVERSION_TEST_VALUE_PRIVATE);
+
+       pvalidate(test_private_gva, false);
+       snp_page_state_change(test_gpa, SNP_PAGE_STATE_SHARED);
+
+       WRITE_ONCE(*test_shared_gva, CONVERSION_TEST_VALUE_SHARED_3);
+
+       wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
+       vmgexit();
+}
+
+static void test_conversion(uint64_t policy)
+{
+       vm_vaddr_t test_private_gva;
+       vm_vaddr_t test_shared_gva;
+       struct kvm_vcpu *vcpu;
+       vm_vaddr_t ghcb_gva;
+       vm_paddr_t test_gpa;
+       struct kvm_vm *vm;
+       void *ghcb_hva;
+       void *test_hva;
+
+       vm = vm_sev_create_with_one_vcpu(KVM_X86_SNP_VM, guest_code_conversion, 
&vcpu);
+
+       ghcb_gva = vm_vaddr_alloc_shared(vm, PAGE_SIZE, KVM_UTIL_MIN_VADDR,
+                                        MEM_REGION_TEST_DATA);
+       ghcb_hva = addr_gva2hva(vm, ghcb_gva);
+       ghcb_gpa = addr_gva2gpa(vm, ghcb_gva);
+       sync_global_to_guest(vm, ghcb_gpa);
+
+       test_shared_gva = vm_vaddr_alloc_shared(vm, PAGE_SIZE, 
KVM_UTIL_MIN_VADDR,
+                                               MEM_REGION_TEST_DATA);
+       test_hva = addr_gva2hva(vm, test_shared_gva);
+       test_gpa = addr_gva2gpa(vm, test_shared_gva);
+
+       test_private_gva = vm_vaddr_unused_gap(vm, PAGE_SIZE, 
KVM_UTIL_MIN_VADDR);
+       ___virt_pg_map(vm, &vm->mmu, test_private_gva, test_gpa, PG_SIZE_4K, 
true);
+
+       vcpu_args_set(vcpu, 3, test_shared_gva, test_private_gva, test_gpa);
+
+       vm_sev_launch(vm, policy, NULL);
+
+       WRITE_ONCE(*(u8 *)test_hva, CONVERSION_TEST_VALUE_SHARED_1);
+
+       fprintf(stderr, "ghcb_hva=%p ghcb_gpa=%lx ghcb_gva=%lx\n", ghcb_hva, 
ghcb_gpa, ghcb_gva);
+       fprintf(stderr, "test_hva=%p test_gpa=%lx test_private_gva=%lx 
test_shared_gva=%lx\n", test_hva, test_gpa, test_private_gva, test_shared_gva);
+
+       vcpu_run(vcpu);
+
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_HYPERCALL);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.nr, KVM_HC_MAP_GPA_RANGE);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[0], test_gpa);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[1], 1);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[2], 
KVM_MAP_GPA_RANGE_ENCRYPTED | KVM_MAP_GPA_RANGE_PAGE_SZ_4K);
+
+       vm_mem_set_private(vm, test_gpa, PAGE_SIZE, 
KVM_SET_MEMORY_ATTRIBUTES2_MODE_UNSPECIFIED);
+
+       vcpu_run(vcpu);
+
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_HYPERCALL);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.nr, KVM_HC_MAP_GPA_RANGE);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[0], test_gpa);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[1], 1);
+       TEST_ASSERT_EQ(vcpu->run->hypercall.args[2], 
KVM_MAP_GPA_RANGE_DECRYPTED | KVM_MAP_GPA_RANGE_PAGE_SZ_4K);
+
+       vm_mem_set_shared(vm, test_gpa, PAGE_SIZE, 
KVM_SET_MEMORY_ATTRIBUTES2_MODE_UNSPECIFIED);
+
+       vcpu_run(vcpu);
+
+       TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_SYSTEM_EVENT);
+       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);
+
+       TEST_ASSERT_EQ(*(u8 *)test_hva, CONVERSION_TEST_VALUE_SHARED_3);
+}
+
 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);
+       // test_sev_smoke(guest_sev_code, KVM_X86_SEV_VM, 0);
 
-       if (kvm_cpu_has(X86_FEATURE_SEV_ES))
-               test_sev_smoke(guest_sev_es_code, KVM_X86_SEV_ES_VM, 
SEV_POLICY_ES);
+       // if (kvm_cpu_has(X86_FEATURE_SEV_ES))
+       //      test_sev_smoke(guest_sev_es_code, KVM_X86_SEV_ES_VM, 
SEV_POLICY_ES);
 
-       if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
-               test_sev_smoke(guest_snp_code, KVM_X86_SNP_VM, 
snp_default_policy());
+       if (kvm_cpu_has(X86_FEATURE_SEV_SNP)) {
+               test_conversion(snp_default_policy());
+               // test_sev_smoke(guest_snp_code, KVM_X86_SNP_VM, 
snp_default_policy());
+       }
 
        return 0;
 }
-- 
2.53.0.1018.g2bb0e51243-goog


Reply via email to