xref: /qemu/tests/qtest/test-x86-cpuid-compat.c (revision a2f9976ea83c50b452d46b8b1189242617e4ac73)
16efef58eSEduardo Habkost #include "qemu/osdep.h"
26efef58eSEduardo Habkost #include "qemu-common.h"
36efef58eSEduardo Habkost #include "qapi/qmp/qlist.h"
46efef58eSEduardo Habkost #include "qapi/qmp/qdict.h"
56efef58eSEduardo Habkost #include "qapi/qmp/qint.h"
6*a2f9976eSEduardo Habkost #include "qapi/qmp/qbool.h"
76efef58eSEduardo Habkost #include "libqtest.h"
86efef58eSEduardo Habkost 
96efef58eSEduardo Habkost static char *get_cpu0_qom_path(void)
106efef58eSEduardo Habkost {
116efef58eSEduardo Habkost     QDict *resp;
126efef58eSEduardo Habkost     QList *ret;
136efef58eSEduardo Habkost     QDict *cpu0;
146efef58eSEduardo Habkost     char *path;
156efef58eSEduardo Habkost 
166efef58eSEduardo Habkost     resp = qmp("{'execute': 'query-cpus', 'arguments': {}}");
176efef58eSEduardo Habkost     g_assert(qdict_haskey(resp, "return"));
186efef58eSEduardo Habkost     ret = qdict_get_qlist(resp, "return");
196efef58eSEduardo Habkost 
206efef58eSEduardo Habkost     cpu0 = qobject_to_qdict(qlist_peek(ret));
216efef58eSEduardo Habkost     path = g_strdup(qdict_get_str(cpu0, "qom_path"));
226efef58eSEduardo Habkost     QDECREF(resp);
236efef58eSEduardo Habkost     return path;
246efef58eSEduardo Habkost }
256efef58eSEduardo Habkost 
266efef58eSEduardo Habkost static QObject *qom_get(const char *path, const char *prop)
276efef58eSEduardo Habkost {
286efef58eSEduardo Habkost     QDict *resp = qmp("{ 'execute': 'qom-get',"
296efef58eSEduardo Habkost                       "  'arguments': { 'path': %s,"
306efef58eSEduardo Habkost                       "                 'property': %s } }",
316efef58eSEduardo Habkost                       path, prop);
326efef58eSEduardo Habkost     QObject *ret = qdict_get(resp, "return");
336efef58eSEduardo Habkost     qobject_incref(ret);
346efef58eSEduardo Habkost     QDECREF(resp);
356efef58eSEduardo Habkost     return ret;
366efef58eSEduardo Habkost }
376efef58eSEduardo Habkost 
38*a2f9976eSEduardo Habkost static bool qom_get_bool(const char *path, const char *prop)
39*a2f9976eSEduardo Habkost {
40*a2f9976eSEduardo Habkost     QBool *value = qobject_to_qbool(qom_get(path, prop));
41*a2f9976eSEduardo Habkost     bool b = qbool_get_bool(value);
42*a2f9976eSEduardo Habkost 
43*a2f9976eSEduardo Habkost     QDECREF(value);
44*a2f9976eSEduardo Habkost     return b;
45*a2f9976eSEduardo Habkost }
46*a2f9976eSEduardo Habkost 
476efef58eSEduardo Habkost typedef struct CpuidTestArgs {
486efef58eSEduardo Habkost     const char *cmdline;
496efef58eSEduardo Habkost     const char *property;
506efef58eSEduardo Habkost     int64_t expected_value;
516efef58eSEduardo Habkost } CpuidTestArgs;
526efef58eSEduardo Habkost 
536efef58eSEduardo Habkost static void test_cpuid_prop(const void *data)
546efef58eSEduardo Habkost {
556efef58eSEduardo Habkost     const CpuidTestArgs *args = data;
566efef58eSEduardo Habkost     char *path;
576efef58eSEduardo Habkost     QInt *value;
586efef58eSEduardo Habkost 
596efef58eSEduardo Habkost     qtest_start(args->cmdline);
606efef58eSEduardo Habkost     path = get_cpu0_qom_path();
616efef58eSEduardo Habkost     value = qobject_to_qint(qom_get(path, args->property));
626efef58eSEduardo Habkost     g_assert_cmpint(qint_get_int(value), ==, args->expected_value);
636efef58eSEduardo Habkost     qtest_end();
646efef58eSEduardo Habkost 
656efef58eSEduardo Habkost     QDECREF(value);
666efef58eSEduardo Habkost     g_free(path);
676efef58eSEduardo Habkost }
686efef58eSEduardo Habkost 
696efef58eSEduardo Habkost static void add_cpuid_test(const char *name, const char *cmdline,
706efef58eSEduardo Habkost                            const char *property, int64_t expected_value)
716efef58eSEduardo Habkost {
726efef58eSEduardo Habkost     CpuidTestArgs *args = g_new0(CpuidTestArgs, 1);
736efef58eSEduardo Habkost     args->cmdline = cmdline;
746efef58eSEduardo Habkost     args->property = property;
756efef58eSEduardo Habkost     args->expected_value = expected_value;
766efef58eSEduardo Habkost     qtest_add_data_func(name, args, test_cpuid_prop);
776efef58eSEduardo Habkost }
786efef58eSEduardo Habkost 
79*a2f9976eSEduardo Habkost static void test_plus_minus(void)
80*a2f9976eSEduardo Habkost {
81*a2f9976eSEduardo Habkost     char *path;
82*a2f9976eSEduardo Habkost 
83*a2f9976eSEduardo Habkost     /* Rules:
84*a2f9976eSEduardo Habkost      * 1)"-foo" overrides "+foo"
85*a2f9976eSEduardo Habkost      * 2) "[+-]foo" overrides "foo=..."
86*a2f9976eSEduardo Habkost      * 3) Old feature names with underscores (e.g. "sse4_2")
87*a2f9976eSEduardo Habkost      *    should keep working
88*a2f9976eSEduardo Habkost      *
89*a2f9976eSEduardo Habkost      * Note: rules 1 and 2 are planned to be removed soon, but we
90*a2f9976eSEduardo Habkost      * need to keep compatibility for a while until we start
91*a2f9976eSEduardo Habkost      * warning users about it.
92*a2f9976eSEduardo Habkost      */
93*a2f9976eSEduardo Habkost     qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on");
94*a2f9976eSEduardo Habkost     path = get_cpu0_qom_path();
95*a2f9976eSEduardo Habkost 
96*a2f9976eSEduardo Habkost     g_assert_false(qom_get_bool(path, "fpu"));
97*a2f9976eSEduardo Habkost     g_assert_false(qom_get_bool(path, "mce"));
98*a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "cx8"));
99*a2f9976eSEduardo Habkost 
100*a2f9976eSEduardo Habkost     /* Test both the original and the alias feature names: */
101*a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4-1"));
102*a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4.1"));
103*a2f9976eSEduardo Habkost 
104*a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4-2"));
105*a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4.2"));
106*a2f9976eSEduardo Habkost 
107*a2f9976eSEduardo Habkost     qtest_end();
108*a2f9976eSEduardo Habkost     g_free(path);
109*a2f9976eSEduardo Habkost }
110*a2f9976eSEduardo Habkost 
1116efef58eSEduardo Habkost int main(int argc, char **argv)
1126efef58eSEduardo Habkost {
1136efef58eSEduardo Habkost     g_test_init(&argc, &argv, NULL);
1146efef58eSEduardo Habkost 
115*a2f9976eSEduardo Habkost     qtest_add_func("x86/cpuid/parsing-plus-minus", test_plus_minus);
116*a2f9976eSEduardo Habkost 
1176efef58eSEduardo Habkost     /* Original level values for CPU models: */
1186efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/phenom/level",
1196efef58eSEduardo Habkost                    "-cpu phenom", "level", 5);
1206efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/Conroe/level",
1216efef58eSEduardo Habkost                    "-cpu Conroe", "level", 10);
1226efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/SandyBridge/level",
1236efef58eSEduardo Habkost                    "-cpu SandyBridge", "level", 0xd);
1246efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/486/xlevel",
1256efef58eSEduardo Habkost                    "-cpu 486", "xlevel", 0);
1266efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/core2duo/xlevel",
1276efef58eSEduardo Habkost                    "-cpu core2duo", "xlevel", 0x80000008);
1286efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/phenom/xlevel",
1296efef58eSEduardo Habkost                    "-cpu phenom", "xlevel", 0x8000001A);
1300c3d7c00SEduardo Habkost     add_cpuid_test("x86/cpuid/athlon/xlevel",
1310c3d7c00SEduardo Habkost                    "-cpu athlon", "xlevel", 0x80000008);
1326efef58eSEduardo Habkost 
1336efef58eSEduardo Habkost     /* If level is not large enough, it should increase automatically: */
134c39c0edfSEduardo Habkost     /* CPUID[6].EAX: */
135c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/arat",
136c39c0edfSEduardo Habkost                    "-cpu 486,+arat", "level", 6);
1376efef58eSEduardo Habkost     /* CPUID[EAX=7,ECX=0].EBX: */
1386efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase",
1396efef58eSEduardo Habkost                    "-cpu phenom,+fsgsbase", "level", 7);
140c39c0edfSEduardo Habkost     /* CPUID[EAX=7,ECX=0].ECX: */
141c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi",
142c39c0edfSEduardo Habkost                    "-cpu phenom,+avx512vbmi", "level", 7);
143c39c0edfSEduardo Habkost     /* CPUID[EAX=0xd,ECX=1].EAX: */
144c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt",
145c39c0edfSEduardo Habkost                    "-cpu phenom,+xsaveopt", "level", 0xd);
146c39c0edfSEduardo Habkost     /* CPUID[8000_0001].EDX: */
147c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow",
148c39c0edfSEduardo Habkost                    "-cpu 486,+3dnow", "xlevel", 0x80000001);
149c39c0edfSEduardo Habkost     /* CPUID[8000_0001].ECX: */
150c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a",
151c39c0edfSEduardo Habkost                    "-cpu 486,+sse4a", "xlevel", 0x80000001);
152c39c0edfSEduardo Habkost     /* CPUID[8000_0007].EDX: */
153c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc",
154c39c0edfSEduardo Habkost                    "-cpu 486,+invtsc", "xlevel", 0x80000007);
155c39c0edfSEduardo Habkost     /* CPUID[8000_000A].EDX: */
156c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/npt",
157c39c0edfSEduardo Habkost                    "-cpu 486,+npt", "xlevel", 0x8000000A);
158c39c0edfSEduardo Habkost     /* CPUID[C000_0001].EDX: */
159c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore",
160c39c0edfSEduardo Habkost                    "-cpu phenom,+xstore", "xlevel2", 0xC0000001);
1610c3d7c00SEduardo Habkost     /* SVM needs CPUID[0x8000000A] */
1620c3d7c00SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm",
1630c3d7c00SEduardo Habkost                    "-cpu athlon,+svm", "xlevel", 0x8000000A);
164c39c0edfSEduardo Habkost 
1656efef58eSEduardo Habkost 
1666efef58eSEduardo Habkost     /* If level is already large enough, it shouldn't change: */
1676efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple",
1686efef58eSEduardo Habkost                    "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi",
1696efef58eSEduardo Habkost                    "level", 0xd);
170c39c0edfSEduardo Habkost     /* If level is explicitly set, it shouldn't change: */
171c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF",
172c39c0edfSEduardo Habkost                    "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
173c39c0edfSEduardo Habkost                    "level", 0xF);
174c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/2",
175c39c0edfSEduardo Habkost                    "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
176c39c0edfSEduardo Habkost                    "level", 2);
177c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/0",
178c39c0edfSEduardo Habkost                    "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
179c39c0edfSEduardo Habkost                    "level", 0);
1806efef58eSEduardo Habkost 
1816efef58eSEduardo Habkost     /* if xlevel is already large enough, it shouldn't change: */
1826efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow",
1830c3d7c00SEduardo Habkost                    "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm",
1846efef58eSEduardo Habkost                    "xlevel", 0x8000001A);
185c39c0edfSEduardo Habkost     /* If xlevel is explicitly set, it shouldn't change: */
186c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002",
1870c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm",
188c39c0edfSEduardo Habkost                    "xlevel", 0x80000002);
189c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A",
1900c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm",
191c39c0edfSEduardo Habkost                    "xlevel", 0x8000001A);
192c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0",
1930c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm",
194c39c0edfSEduardo Habkost                    "xlevel", 0);
1956efef58eSEduardo Habkost 
1966efef58eSEduardo Habkost     /* if xlevel2 is already large enough, it shouldn't change: */
1976efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed",
1986efef58eSEduardo Habkost                    "-cpu 486,xlevel2=0xC0000002,+xstore",
1996efef58eSEduardo Habkost                    "xlevel2", 0xC0000002);
2006efef58eSEduardo Habkost 
201df3e9af8SEduardo Habkost     /* Check compatibility of old machine-types that didn't
202df3e9af8SEduardo Habkost      * auto-increase level/xlevel/xlevel2: */
203df3e9af8SEduardo Habkost 
204df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/pc-2.7",
205df3e9af8SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt",
206df3e9af8SEduardo Habkost                    "level", 1);
207df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7",
2080c3d7c00SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm",
209df3e9af8SEduardo Habkost                    "xlevel", 0);
210df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7",
211df3e9af8SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+xstore",
212df3e9af8SEduardo Habkost                    "xlevel2", 0);
213df3e9af8SEduardo Habkost 
2146efef58eSEduardo Habkost     return g_test_run();
2156efef58eSEduardo Habkost }
216