]>
Commit | Line | Data |
---|---|---|
6efef58e EH |
1 | #include "qemu/osdep.h" |
2 | #include "qemu-common.h" | |
3 | #include "qapi/qmp/qlist.h" | |
4 | #include "qapi/qmp/qdict.h" | |
5 | #include "qapi/qmp/qint.h" | |
6 | #include "libqtest.h" | |
7 | ||
8 | static char *get_cpu0_qom_path(void) | |
9 | { | |
10 | QDict *resp; | |
11 | QList *ret; | |
12 | QDict *cpu0; | |
13 | char *path; | |
14 | ||
15 | resp = qmp("{'execute': 'query-cpus', 'arguments': {}}"); | |
16 | g_assert(qdict_haskey(resp, "return")); | |
17 | ret = qdict_get_qlist(resp, "return"); | |
18 | ||
19 | cpu0 = qobject_to_qdict(qlist_peek(ret)); | |
20 | path = g_strdup(qdict_get_str(cpu0, "qom_path")); | |
21 | QDECREF(resp); | |
22 | return path; | |
23 | } | |
24 | ||
25 | static QObject *qom_get(const char *path, const char *prop) | |
26 | { | |
27 | QDict *resp = qmp("{ 'execute': 'qom-get'," | |
28 | " 'arguments': { 'path': %s," | |
29 | " 'property': %s } }", | |
30 | path, prop); | |
31 | QObject *ret = qdict_get(resp, "return"); | |
32 | qobject_incref(ret); | |
33 | QDECREF(resp); | |
34 | return ret; | |
35 | } | |
36 | ||
37 | typedef struct CpuidTestArgs { | |
38 | const char *cmdline; | |
39 | const char *property; | |
40 | int64_t expected_value; | |
41 | } CpuidTestArgs; | |
42 | ||
43 | static void test_cpuid_prop(const void *data) | |
44 | { | |
45 | const CpuidTestArgs *args = data; | |
46 | char *path; | |
47 | QInt *value; | |
48 | ||
49 | qtest_start(args->cmdline); | |
50 | path = get_cpu0_qom_path(); | |
51 | value = qobject_to_qint(qom_get(path, args->property)); | |
52 | g_assert_cmpint(qint_get_int(value), ==, args->expected_value); | |
53 | qtest_end(); | |
54 | ||
55 | QDECREF(value); | |
56 | g_free(path); | |
57 | } | |
58 | ||
59 | static void add_cpuid_test(const char *name, const char *cmdline, | |
60 | const char *property, int64_t expected_value) | |
61 | { | |
62 | CpuidTestArgs *args = g_new0(CpuidTestArgs, 1); | |
63 | args->cmdline = cmdline; | |
64 | args->property = property; | |
65 | args->expected_value = expected_value; | |
66 | qtest_add_data_func(name, args, test_cpuid_prop); | |
67 | } | |
68 | ||
69 | int main(int argc, char **argv) | |
70 | { | |
71 | g_test_init(&argc, &argv, NULL); | |
72 | ||
73 | /* Original level values for CPU models: */ | |
74 | add_cpuid_test("x86/cpuid/phenom/level", | |
75 | "-cpu phenom", "level", 5); | |
76 | add_cpuid_test("x86/cpuid/Conroe/level", | |
77 | "-cpu Conroe", "level", 10); | |
78 | add_cpuid_test("x86/cpuid/SandyBridge/level", | |
79 | "-cpu SandyBridge", "level", 0xd); | |
80 | add_cpuid_test("x86/cpuid/486/xlevel", | |
81 | "-cpu 486", "xlevel", 0); | |
82 | add_cpuid_test("x86/cpuid/core2duo/xlevel", | |
83 | "-cpu core2duo", "xlevel", 0x80000008); | |
84 | add_cpuid_test("x86/cpuid/phenom/xlevel", | |
85 | "-cpu phenom", "xlevel", 0x8000001A); | |
0c3d7c00 EH |
86 | add_cpuid_test("x86/cpuid/athlon/xlevel", |
87 | "-cpu athlon", "xlevel", 0x80000008); | |
6efef58e EH |
88 | |
89 | /* If level is not large enough, it should increase automatically: */ | |
c39c0edf EH |
90 | /* CPUID[6].EAX: */ |
91 | add_cpuid_test("x86/cpuid/auto-level/phenom/arat", | |
92 | "-cpu 486,+arat", "level", 6); | |
6efef58e EH |
93 | /* CPUID[EAX=7,ECX=0].EBX: */ |
94 | add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase", | |
95 | "-cpu phenom,+fsgsbase", "level", 7); | |
c39c0edf EH |
96 | /* CPUID[EAX=7,ECX=0].ECX: */ |
97 | add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi", | |
98 | "-cpu phenom,+avx512vbmi", "level", 7); | |
99 | /* CPUID[EAX=0xd,ECX=1].EAX: */ | |
100 | add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt", | |
101 | "-cpu phenom,+xsaveopt", "level", 0xd); | |
102 | /* CPUID[8000_0001].EDX: */ | |
103 | add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow", | |
104 | "-cpu 486,+3dnow", "xlevel", 0x80000001); | |
105 | /* CPUID[8000_0001].ECX: */ | |
106 | add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a", | |
107 | "-cpu 486,+sse4a", "xlevel", 0x80000001); | |
108 | /* CPUID[8000_0007].EDX: */ | |
109 | add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc", | |
110 | "-cpu 486,+invtsc", "xlevel", 0x80000007); | |
111 | /* CPUID[8000_000A].EDX: */ | |
112 | add_cpuid_test("x86/cpuid/auto-xlevel/486/npt", | |
113 | "-cpu 486,+npt", "xlevel", 0x8000000A); | |
114 | /* CPUID[C000_0001].EDX: */ | |
115 | add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore", | |
116 | "-cpu phenom,+xstore", "xlevel2", 0xC0000001); | |
0c3d7c00 EH |
117 | /* SVM needs CPUID[0x8000000A] */ |
118 | add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm", | |
119 | "-cpu athlon,+svm", "xlevel", 0x8000000A); | |
c39c0edf | 120 | |
6efef58e EH |
121 | |
122 | /* If level is already large enough, it shouldn't change: */ | |
123 | add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple", | |
124 | "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi", | |
125 | "level", 0xd); | |
c39c0edf EH |
126 | /* If level is explicitly set, it shouldn't change: */ |
127 | add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF", | |
128 | "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", | |
129 | "level", 0xF); | |
130 | add_cpuid_test("x86/cpuid/auto-level/486/fixed/2", | |
131 | "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", | |
132 | "level", 2); | |
133 | add_cpuid_test("x86/cpuid/auto-level/486/fixed/0", | |
134 | "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", | |
135 | "level", 0); | |
6efef58e EH |
136 | |
137 | /* if xlevel is already large enough, it shouldn't change: */ | |
138 | add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow", | |
0c3d7c00 | 139 | "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm", |
6efef58e | 140 | "xlevel", 0x8000001A); |
c39c0edf EH |
141 | /* If xlevel is explicitly set, it shouldn't change: */ |
142 | add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002", | |
0c3d7c00 | 143 | "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm", |
c39c0edf EH |
144 | "xlevel", 0x80000002); |
145 | add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A", | |
0c3d7c00 | 146 | "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm", |
c39c0edf EH |
147 | "xlevel", 0x8000001A); |
148 | add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0", | |
0c3d7c00 | 149 | "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm", |
c39c0edf | 150 | "xlevel", 0); |
6efef58e EH |
151 | |
152 | /* if xlevel2 is already large enough, it shouldn't change: */ | |
153 | add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed", | |
154 | "-cpu 486,xlevel2=0xC0000002,+xstore", | |
155 | "xlevel2", 0xC0000002); | |
156 | ||
df3e9af8 EH |
157 | /* Check compatibility of old machine-types that didn't |
158 | * auto-increase level/xlevel/xlevel2: */ | |
159 | ||
160 | add_cpuid_test("x86/cpuid/auto-level/pc-2.7", | |
161 | "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt", | |
162 | "level", 1); | |
163 | add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7", | |
0c3d7c00 | 164 | "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm", |
df3e9af8 EH |
165 | "xlevel", 0); |
166 | add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7", | |
167 | "-machine pc-i440fx-2.7 -cpu 486,+xstore", | |
168 | "xlevel2", 0); | |
169 | ||
6efef58e EH |
170 | return g_test_run(); |
171 | } |