xref: /linux/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c (revision f4b0c4b508364fde023e4f7b9f23f7e38c663dfe)
1be250ff4SPeter Gonda // SPDX-License-Identifier: GPL-2.0-only
2be250ff4SPeter Gonda #include <fcntl.h>
3be250ff4SPeter Gonda #include <stdio.h>
4be250ff4SPeter Gonda #include <stdlib.h>
5be250ff4SPeter Gonda #include <string.h>
6be250ff4SPeter Gonda #include <sys/ioctl.h>
7*8c53183dSPaolo Bonzini #include <math.h>
8be250ff4SPeter Gonda 
9be250ff4SPeter Gonda #include "test_util.h"
10be250ff4SPeter Gonda #include "kvm_util.h"
11be250ff4SPeter Gonda #include "processor.h"
12be250ff4SPeter Gonda #include "svm_util.h"
13be250ff4SPeter Gonda #include "linux/psp-sev.h"
14be250ff4SPeter Gonda #include "sev.h"
15be250ff4SPeter Gonda 
1640e09b3cSSean Christopherson 
17*8c53183dSPaolo Bonzini #define XFEATURE_MASK_X87_AVX (XFEATURE_MASK_FP | XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)
18*8c53183dSPaolo Bonzini 
guest_sev_es_code(void)1940e09b3cSSean Christopherson static void guest_sev_es_code(void)
2040e09b3cSSean Christopherson {
2140e09b3cSSean Christopherson 	/* TODO: Check CPUID after GHCB-based hypercall support is added. */
2240e09b3cSSean Christopherson 	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED);
2340e09b3cSSean Christopherson 	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ES_ENABLED);
2440e09b3cSSean Christopherson 
2540e09b3cSSean Christopherson 	/*
2640e09b3cSSean Christopherson 	 * TODO: Add GHCB and ucall support for SEV-ES guests.  For now, simply
2740e09b3cSSean Christopherson 	 * force "termination" to signal "done" via the GHCB MSR protocol.
2840e09b3cSSean Christopherson 	 */
2940e09b3cSSean Christopherson 	wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
3040e09b3cSSean Christopherson 	__asm__ __volatile__("rep; vmmcall");
3140e09b3cSSean Christopherson }
3240e09b3cSSean Christopherson 
guest_sev_code(void)33be250ff4SPeter Gonda static void guest_sev_code(void)
34be250ff4SPeter Gonda {
35be250ff4SPeter Gonda 	GUEST_ASSERT(this_cpu_has(X86_FEATURE_SEV));
36be250ff4SPeter Gonda 	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ENABLED);
37be250ff4SPeter Gonda 
38be250ff4SPeter Gonda 	GUEST_DONE();
39be250ff4SPeter Gonda }
40be250ff4SPeter Gonda 
41*8c53183dSPaolo Bonzini /* Stash state passed via VMSA before any compiled code runs.  */
42*8c53183dSPaolo Bonzini extern void guest_code_xsave(void);
43*8c53183dSPaolo Bonzini asm("guest_code_xsave:\n"
44*8c53183dSPaolo Bonzini     "mov $-1, %eax\n"
45*8c53183dSPaolo Bonzini     "mov $-1, %edx\n"
46*8c53183dSPaolo Bonzini     "xsave (%rdi)\n"
47*8c53183dSPaolo Bonzini     "jmp guest_sev_es_code");
48*8c53183dSPaolo Bonzini 
compare_xsave(u8 * from_host,u8 * from_guest)49*8c53183dSPaolo Bonzini static void compare_xsave(u8 *from_host, u8 *from_guest)
50*8c53183dSPaolo Bonzini {
51*8c53183dSPaolo Bonzini 	int i;
52*8c53183dSPaolo Bonzini 	bool bad = false;
53*8c53183dSPaolo Bonzini 	for (i = 0; i < 4095; i++) {
54*8c53183dSPaolo Bonzini 		if (from_host[i] != from_guest[i]) {
55*8c53183dSPaolo Bonzini 			printf("mismatch at %02hhx | %02hhx %02hhx\n", i, from_host[i], from_guest[i]);
56*8c53183dSPaolo Bonzini 			bad = true;
57*8c53183dSPaolo Bonzini 		}
58*8c53183dSPaolo Bonzini 	}
59*8c53183dSPaolo Bonzini 
60*8c53183dSPaolo Bonzini 	if (bad)
61*8c53183dSPaolo Bonzini 		abort();
62*8c53183dSPaolo Bonzini }
63*8c53183dSPaolo Bonzini 
test_sync_vmsa(uint32_t policy)64*8c53183dSPaolo Bonzini static void test_sync_vmsa(uint32_t policy)
65*8c53183dSPaolo Bonzini {
66*8c53183dSPaolo Bonzini 	struct kvm_vcpu *vcpu;
67*8c53183dSPaolo Bonzini 	struct kvm_vm *vm;
68*8c53183dSPaolo Bonzini 	vm_vaddr_t gva;
69*8c53183dSPaolo Bonzini 	void *hva;
70*8c53183dSPaolo Bonzini 
71*8c53183dSPaolo Bonzini 	double x87val = M_PI;
72*8c53183dSPaolo Bonzini 	struct kvm_xsave __attribute__((aligned(64))) xsave = { 0 };
73*8c53183dSPaolo Bonzini 	struct kvm_sregs sregs;
74*8c53183dSPaolo Bonzini 	struct kvm_xcrs xcrs = {
75*8c53183dSPaolo Bonzini 		.nr_xcrs = 1,
76*8c53183dSPaolo Bonzini 		.xcrs[0].xcr = 0,
77*8c53183dSPaolo Bonzini 		.xcrs[0].value = XFEATURE_MASK_X87_AVX,
78*8c53183dSPaolo Bonzini 	};
79*8c53183dSPaolo Bonzini 
80*8c53183dSPaolo Bonzini 	vm = vm_sev_create_with_one_vcpu(KVM_X86_SEV_ES_VM, guest_code_xsave, &vcpu);
81*8c53183dSPaolo Bonzini 	gva = vm_vaddr_alloc_shared(vm, PAGE_SIZE, KVM_UTIL_MIN_VADDR,
82*8c53183dSPaolo Bonzini 				    MEM_REGION_TEST_DATA);
83*8c53183dSPaolo Bonzini 	hva = addr_gva2hva(vm, gva);
84*8c53183dSPaolo Bonzini 
85*8c53183dSPaolo Bonzini 	vcpu_args_set(vcpu, 1, gva);
86*8c53183dSPaolo Bonzini 
87*8c53183dSPaolo Bonzini 	vcpu_sregs_get(vcpu, &sregs);
88*8c53183dSPaolo Bonzini 	sregs.cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXSAVE;
89*8c53183dSPaolo Bonzini 	vcpu_sregs_set(vcpu, &sregs);
90*8c53183dSPaolo Bonzini 
91*8c53183dSPaolo Bonzini 	vcpu_xcrs_set(vcpu, &xcrs);
92*8c53183dSPaolo Bonzini 	asm("fninit\n"
93*8c53183dSPaolo Bonzini 	    "vpcmpeqb %%ymm4, %%ymm4, %%ymm4\n"
94*8c53183dSPaolo Bonzini 	    "fldl %3\n"
95*8c53183dSPaolo Bonzini 	    "xsave (%2)\n"
96*8c53183dSPaolo Bonzini 	    "fstp %%st\n"
97*8c53183dSPaolo Bonzini 	    : "=m"(xsave)
98*8c53183dSPaolo Bonzini 	    : "A"(XFEATURE_MASK_X87_AVX), "r"(&xsave), "m" (x87val)
99*8c53183dSPaolo Bonzini 	    : "ymm4", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)");
100*8c53183dSPaolo Bonzini 	vcpu_xsave_set(vcpu, &xsave);
101*8c53183dSPaolo Bonzini 
102*8c53183dSPaolo Bonzini 	vm_sev_launch(vm, SEV_POLICY_ES | policy, NULL);
103*8c53183dSPaolo Bonzini 
104*8c53183dSPaolo Bonzini 	/* This page is shared, so make it decrypted.  */
105*8c53183dSPaolo Bonzini 	memset(hva, 0, 4096);
106*8c53183dSPaolo Bonzini 
107*8c53183dSPaolo Bonzini 	vcpu_run(vcpu);
108*8c53183dSPaolo Bonzini 
109*8c53183dSPaolo Bonzini 	TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
110*8c53183dSPaolo Bonzini 		    "Wanted SYSTEM_EVENT, got %s",
111*8c53183dSPaolo Bonzini 		    exit_reason_str(vcpu->run->exit_reason));
112*8c53183dSPaolo Bonzini 	TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM);
113*8c53183dSPaolo Bonzini 	TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1);
114*8c53183dSPaolo Bonzini 	TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ);
115*8c53183dSPaolo Bonzini 
116*8c53183dSPaolo Bonzini 	compare_xsave((u8 *)&xsave, (u8 *)hva);
117*8c53183dSPaolo Bonzini 
118*8c53183dSPaolo Bonzini 	kvm_vm_free(vm);
119*8c53183dSPaolo Bonzini }
120*8c53183dSPaolo Bonzini 
test_sev(void * guest_code,uint64_t policy)121be250ff4SPeter Gonda static void test_sev(void *guest_code, uint64_t policy)
122be250ff4SPeter Gonda {
123be250ff4SPeter Gonda 	struct kvm_vcpu *vcpu;
124be250ff4SPeter Gonda 	struct kvm_vm *vm;
125be250ff4SPeter Gonda 	struct ucall uc;
126be250ff4SPeter Gonda 
1274c180a57SPaolo Bonzini 	uint32_t type = policy & SEV_POLICY_ES ? KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
1284c180a57SPaolo Bonzini 
1294c180a57SPaolo Bonzini 	vm = vm_sev_create_with_one_vcpu(type, guest_code, &vcpu);
1304c180a57SPaolo Bonzini 
1314c180a57SPaolo Bonzini 	/* TODO: Validate the measurement is as expected. */
1324c180a57SPaolo Bonzini 	vm_sev_launch(vm, policy, NULL);
133be250ff4SPeter Gonda 
134be250ff4SPeter Gonda 	for (;;) {
135be250ff4SPeter Gonda 		vcpu_run(vcpu);
136be250ff4SPeter Gonda 
13740e09b3cSSean Christopherson 		if (policy & SEV_POLICY_ES) {
13840e09b3cSSean Christopherson 			TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
13940e09b3cSSean Christopherson 				    "Wanted SYSTEM_EVENT, got %s",
14040e09b3cSSean Christopherson 				    exit_reason_str(vcpu->run->exit_reason));
14140e09b3cSSean Christopherson 			TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM);
14240e09b3cSSean Christopherson 			TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1);
14340e09b3cSSean Christopherson 			TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ);
14440e09b3cSSean Christopherson 			break;
14540e09b3cSSean Christopherson 		}
14640e09b3cSSean Christopherson 
147be250ff4SPeter Gonda 		switch (get_ucall(vcpu, &uc)) {
148be250ff4SPeter Gonda 		case UCALL_SYNC:
149be250ff4SPeter Gonda 			continue;
150be250ff4SPeter Gonda 		case UCALL_DONE:
151be250ff4SPeter Gonda 			return;
152be250ff4SPeter Gonda 		case UCALL_ABORT:
153be250ff4SPeter Gonda 			REPORT_GUEST_ASSERT(uc);
154be250ff4SPeter Gonda 		default:
155be250ff4SPeter Gonda 			TEST_FAIL("Unexpected exit: %s",
156be250ff4SPeter Gonda 				  exit_reason_str(vcpu->run->exit_reason));
157be250ff4SPeter Gonda 		}
158be250ff4SPeter Gonda 	}
159be250ff4SPeter Gonda 
160be250ff4SPeter Gonda 	kvm_vm_free(vm);
161be250ff4SPeter Gonda }
162be250ff4SPeter Gonda 
main(int argc,char * argv[])163be250ff4SPeter Gonda int main(int argc, char *argv[])
164be250ff4SPeter Gonda {
165be250ff4SPeter Gonda 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
166be250ff4SPeter Gonda 
167be250ff4SPeter Gonda 	test_sev(guest_sev_code, SEV_POLICY_NO_DBG);
168be250ff4SPeter Gonda 	test_sev(guest_sev_code, 0);
169be250ff4SPeter Gonda 
17040e09b3cSSean Christopherson 	if (kvm_cpu_has(X86_FEATURE_SEV_ES)) {
17140e09b3cSSean Christopherson 		test_sev(guest_sev_es_code, SEV_POLICY_ES | SEV_POLICY_NO_DBG);
17240e09b3cSSean Christopherson 		test_sev(guest_sev_es_code, SEV_POLICY_ES);
173*8c53183dSPaolo Bonzini 
174*8c53183dSPaolo Bonzini 		if (kvm_has_cap(KVM_CAP_XCRS) &&
175*8c53183dSPaolo Bonzini 		    (xgetbv(0) & XFEATURE_MASK_X87_AVX) == XFEATURE_MASK_X87_AVX) {
176*8c53183dSPaolo Bonzini 			test_sync_vmsa(0);
177*8c53183dSPaolo Bonzini 			test_sync_vmsa(SEV_POLICY_NO_DBG);
178*8c53183dSPaolo Bonzini 		}
17940e09b3cSSean Christopherson 	}
18040e09b3cSSean Christopherson 
181be250ff4SPeter Gonda 	return 0;
182be250ff4SPeter Gonda }
183