1
2
3
4
5
6
7
8
9
10
11#include <fcntl.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/ioctl.h>
16
17#include "test_util.h"
18
19#include "kvm_util.h"
20#include "processor.h"
21
22#define X86_FEATURE_XSAVE (1<<26)
23#define X86_FEATURE_OSXSAVE (1<<27)
24#define VCPU_ID 1
25
26static inline bool cr4_cpuid_is_sync(void)
27{
28 int func, subfunc;
29 uint32_t eax, ebx, ecx, edx;
30 uint64_t cr4;
31
32 func = 0x1;
33 subfunc = 0x0;
34 __asm__ __volatile__("cpuid"
35 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
36 : "a"(func), "c"(subfunc));
37
38 cr4 = get_cr4();
39
40 return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE));
41}
42
43static void guest_code(void)
44{
45 uint64_t cr4;
46
47
48 cr4 = get_cr4();
49 cr4 |= X86_CR4_OSXSAVE;
50 set_cr4(cr4);
51
52
53 GUEST_ASSERT(cr4_cpuid_is_sync());
54
55
56 GUEST_SYNC(0);
57
58
59 GUEST_ASSERT(cr4_cpuid_is_sync());
60
61 GUEST_DONE();
62}
63
64int main(int argc, char *argv[])
65{
66 struct kvm_run *run;
67 struct kvm_vm *vm;
68 struct kvm_sregs sregs;
69 struct kvm_cpuid_entry2 *entry;
70 struct ucall uc;
71 int rc;
72
73 entry = kvm_get_supported_cpuid_entry(1);
74 if (!(entry->ecx & X86_FEATURE_XSAVE)) {
75 print_skip("XSAVE feature not supported");
76 return 0;
77 }
78
79
80 setbuf(stdout, NULL);
81
82
83 vm = vm_create_default(VCPU_ID, 0, guest_code);
84 run = vcpu_state(vm, VCPU_ID);
85
86 while (1) {
87 rc = _vcpu_run(vm, VCPU_ID);
88
89 TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc);
90 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
91 "Unexpected exit reason: %u (%s),\n",
92 run->exit_reason,
93 exit_reason_str(run->exit_reason));
94
95 switch (get_ucall(vm, VCPU_ID, &uc)) {
96 case UCALL_SYNC:
97
98 vcpu_sregs_get(vm, VCPU_ID, &sregs);
99 sregs.cr4 &= ~X86_CR4_OSXSAVE;
100 vcpu_sregs_set(vm, VCPU_ID, &sregs);
101 break;
102 case UCALL_ABORT:
103 TEST_FAIL("Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
104 break;
105 case UCALL_DONE:
106 goto done;
107 default:
108 TEST_FAIL("Unknown ucall %lu", uc.cmd);
109 }
110 }
111
112 kvm_vm_free(vm);
113
114done:
115 return 0;
116}
117