44#include <stdlib.h>
55#include <string.h>
66#include <sys/ioctl.h>
7+ #include <math.h>
78
89#include "test_util.h"
910#include "kvm_util.h"
1314#include "sev.h"
1415
1516
17+ #define XFEATURE_MASK_X87_AVX (XFEATURE_MASK_FP | XFEATURE_MASK_SSE | XFEATURE_MASK_YMM)
18+
1619static void guest_sev_es_code (void )
1720{
1821 /* TODO: Check CPUID after GHCB-based hypercall support is added. */
@@ -35,6 +38,86 @@ static void guest_sev_code(void)
3538 GUEST_DONE ();
3639}
3740
41+ /* Stash state passed via VMSA before any compiled code runs. */
42+ extern void guest_code_xsave (void );
43+ asm("guest_code_xsave:\n"
44+ "mov $-1, %eax\n"
45+ "mov $-1, %edx\n"
46+ "xsave (%rdi)\n"
47+ "jmp guest_sev_es_code" );
48+
49+ static void compare_xsave (u8 * from_host , u8 * from_guest )
50+ {
51+ int i ;
52+ bool bad = false;
53+ for (i = 0 ; i < 4095 ; i ++ ) {
54+ if (from_host [i ] != from_guest [i ]) {
55+ printf ("mismatch at %02hhx | %02hhx %02hhx\n" , i , from_host [i ], from_guest [i ]);
56+ bad = true;
57+ }
58+ }
59+
60+ if (bad )
61+ abort ();
62+ }
63+
64+ static void test_sync_vmsa (uint32_t policy )
65+ {
66+ struct kvm_vcpu * vcpu ;
67+ struct kvm_vm * vm ;
68+ vm_vaddr_t gva ;
69+ void * hva ;
70+
71+ double x87val = M_PI ;
72+ struct kvm_xsave __attribute__((aligned (64 ))) xsave = { 0 };
73+ struct kvm_sregs sregs ;
74+ struct kvm_xcrs xcrs = {
75+ .nr_xcrs = 1 ,
76+ .xcrs [0 ].xcr = 0 ,
77+ .xcrs [0 ].value = XFEATURE_MASK_X87_AVX ,
78+ };
79+
80+ vm = vm_sev_create_with_one_vcpu (KVM_X86_SEV_ES_VM , guest_code_xsave , & vcpu );
81+ gva = vm_vaddr_alloc_shared (vm , PAGE_SIZE , KVM_UTIL_MIN_VADDR ,
82+ MEM_REGION_TEST_DATA );
83+ hva = addr_gva2hva (vm , gva );
84+
85+ vcpu_args_set (vcpu , 1 , gva );
86+
87+ vcpu_sregs_get (vcpu , & sregs );
88+ sregs .cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXSAVE ;
89+ vcpu_sregs_set (vcpu , & sregs );
90+
91+ vcpu_xcrs_set (vcpu , & xcrs );
92+ asm("fninit\n"
93+ "vpcmpeqb %%ymm4, %%ymm4, %%ymm4\n"
94+ "fldl %3\n"
95+ "xsave (%2)\n"
96+ "fstp %%st\n"
97+ : "=m" (xsave )
98+ : "A" (XFEATURE_MASK_X87_AVX ), "r" (& xsave ), "m" (x87val )
99+ : "ymm4" , "st" , "st(1)" , "st(2)" , "st(3)" , "st(4)" , "st(5)" , "st(6)" , "st(7)" );
100+ vcpu_xsave_set (vcpu , & xsave );
101+
102+ vm_sev_launch (vm , SEV_POLICY_ES | policy , NULL );
103+
104+ /* This page is shared, so make it decrypted. */
105+ memset (hva , 0 , 4096 );
106+
107+ vcpu_run (vcpu );
108+
109+ TEST_ASSERT (vcpu -> run -> exit_reason == KVM_EXIT_SYSTEM_EVENT ,
110+ "Wanted SYSTEM_EVENT, got %s" ,
111+ exit_reason_str (vcpu -> run -> exit_reason ));
112+ TEST_ASSERT_EQ (vcpu -> run -> system_event .type , KVM_SYSTEM_EVENT_SEV_TERM );
113+ TEST_ASSERT_EQ (vcpu -> run -> system_event .ndata , 1 );
114+ TEST_ASSERT_EQ (vcpu -> run -> system_event .data [0 ], GHCB_MSR_TERM_REQ );
115+
116+ compare_xsave ((u8 * )& xsave , (u8 * )hva );
117+
118+ kvm_vm_free (vm );
119+ }
120+
38121static void test_sev (void * guest_code , uint64_t policy )
39122{
40123 struct kvm_vcpu * vcpu ;
@@ -87,6 +170,12 @@ int main(int argc, char *argv[])
87170 if (kvm_cpu_has (X86_FEATURE_SEV_ES )) {
88171 test_sev (guest_sev_es_code , SEV_POLICY_ES | SEV_POLICY_NO_DBG );
89172 test_sev (guest_sev_es_code , SEV_POLICY_ES );
173+
174+ if (kvm_has_cap (KVM_CAP_XCRS ) &&
175+ (xgetbv (0 ) & XFEATURE_MASK_X87_AVX ) == XFEATURE_MASK_X87_AVX ) {
176+ test_sync_vmsa (0 );
177+ test_sync_vmsa (SEV_POLICY_NO_DBG );
178+ }
90179 }
91180
92181 return 0 ;
0 commit comments