xref: /qemu/tests/qtest/test-x86-cpuid-compat.c (revision 17e8f541263fd771aef58e9818a2060b81904c3f)
16efef58eSEduardo Habkost #include "qemu/osdep.h"
26efef58eSEduardo Habkost #include "qemu-common.h"
36efef58eSEduardo Habkost #include "qapi/qmp/qlist.h"
4*17e8f541SEduardo Habkost #include "qapi/qmp/qstring.h"
56efef58eSEduardo Habkost #include "qapi/qmp/qdict.h"
66efef58eSEduardo Habkost #include "qapi/qmp/qint.h"
7a2f9976eSEduardo Habkost #include "qapi/qmp/qbool.h"
86efef58eSEduardo Habkost #include "libqtest.h"
96efef58eSEduardo Habkost 
106efef58eSEduardo Habkost static char *get_cpu0_qom_path(void)
116efef58eSEduardo Habkost {
126efef58eSEduardo Habkost     QDict *resp;
136efef58eSEduardo Habkost     QList *ret;
146efef58eSEduardo Habkost     QDict *cpu0;
156efef58eSEduardo Habkost     char *path;
166efef58eSEduardo Habkost 
176efef58eSEduardo Habkost     resp = qmp("{'execute': 'query-cpus', 'arguments': {}}");
186efef58eSEduardo Habkost     g_assert(qdict_haskey(resp, "return"));
196efef58eSEduardo Habkost     ret = qdict_get_qlist(resp, "return");
206efef58eSEduardo Habkost 
216efef58eSEduardo Habkost     cpu0 = qobject_to_qdict(qlist_peek(ret));
226efef58eSEduardo Habkost     path = g_strdup(qdict_get_str(cpu0, "qom_path"));
236efef58eSEduardo Habkost     QDECREF(resp);
246efef58eSEduardo Habkost     return path;
256efef58eSEduardo Habkost }
266efef58eSEduardo Habkost 
276efef58eSEduardo Habkost static QObject *qom_get(const char *path, const char *prop)
286efef58eSEduardo Habkost {
296efef58eSEduardo Habkost     QDict *resp = qmp("{ 'execute': 'qom-get',"
306efef58eSEduardo Habkost                       "  'arguments': { 'path': %s,"
316efef58eSEduardo Habkost                       "                 'property': %s } }",
326efef58eSEduardo Habkost                       path, prop);
336efef58eSEduardo Habkost     QObject *ret = qdict_get(resp, "return");
346efef58eSEduardo Habkost     qobject_incref(ret);
356efef58eSEduardo Habkost     QDECREF(resp);
366efef58eSEduardo Habkost     return ret;
376efef58eSEduardo Habkost }
386efef58eSEduardo Habkost 
3983a00f60SEduardo Habkost #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
40a2f9976eSEduardo Habkost static bool qom_get_bool(const char *path, const char *prop)
41a2f9976eSEduardo Habkost {
42a2f9976eSEduardo Habkost     QBool *value = qobject_to_qbool(qom_get(path, prop));
43a2f9976eSEduardo Habkost     bool b = qbool_get_bool(value);
44a2f9976eSEduardo Habkost 
45a2f9976eSEduardo Habkost     QDECREF(value);
46a2f9976eSEduardo Habkost     return b;
47a2f9976eSEduardo Habkost }
4883a00f60SEduardo Habkost #endif
49a2f9976eSEduardo Habkost 
506efef58eSEduardo Habkost typedef struct CpuidTestArgs {
516efef58eSEduardo Habkost     const char *cmdline;
526efef58eSEduardo Habkost     const char *property;
536efef58eSEduardo Habkost     int64_t expected_value;
546efef58eSEduardo Habkost } CpuidTestArgs;
556efef58eSEduardo Habkost 
566efef58eSEduardo Habkost static void test_cpuid_prop(const void *data)
576efef58eSEduardo Habkost {
586efef58eSEduardo Habkost     const CpuidTestArgs *args = data;
596efef58eSEduardo Habkost     char *path;
606efef58eSEduardo Habkost     QInt *value;
616efef58eSEduardo Habkost 
626efef58eSEduardo Habkost     qtest_start(args->cmdline);
636efef58eSEduardo Habkost     path = get_cpu0_qom_path();
646efef58eSEduardo Habkost     value = qobject_to_qint(qom_get(path, args->property));
656efef58eSEduardo Habkost     g_assert_cmpint(qint_get_int(value), ==, args->expected_value);
666efef58eSEduardo Habkost     qtest_end();
676efef58eSEduardo Habkost 
686efef58eSEduardo Habkost     QDECREF(value);
696efef58eSEduardo Habkost     g_free(path);
706efef58eSEduardo Habkost }
716efef58eSEduardo Habkost 
726efef58eSEduardo Habkost static void add_cpuid_test(const char *name, const char *cmdline,
736efef58eSEduardo Habkost                            const char *property, int64_t expected_value)
746efef58eSEduardo Habkost {
756efef58eSEduardo Habkost     CpuidTestArgs *args = g_new0(CpuidTestArgs, 1);
766efef58eSEduardo Habkost     args->cmdline = cmdline;
776efef58eSEduardo Habkost     args->property = property;
786efef58eSEduardo Habkost     args->expected_value = expected_value;
796efef58eSEduardo Habkost     qtest_add_data_func(name, args, test_cpuid_prop);
806efef58eSEduardo Habkost }
816efef58eSEduardo Habkost 
82*17e8f541SEduardo Habkost 
83*17e8f541SEduardo Habkost /* Parameters to a add_feature_test() test case */
84*17e8f541SEduardo Habkost typedef struct FeatureTestArgs {
85*17e8f541SEduardo Habkost     /* cmdline to start QEMU */
86*17e8f541SEduardo Habkost     const char *cmdline;
87*17e8f541SEduardo Habkost     /*
88*17e8f541SEduardo Habkost      * cpuid-input-eax and cpuid-input-ecx values to look for,
89*17e8f541SEduardo Habkost      * in "feature-words" and "filtered-features" properties.
90*17e8f541SEduardo Habkost      */
91*17e8f541SEduardo Habkost     uint32_t in_eax, in_ecx;
92*17e8f541SEduardo Habkost     /* The register name to look for, in the X86CPUFeatureWordInfo array */
93*17e8f541SEduardo Habkost     const char *reg;
94*17e8f541SEduardo Habkost     /* The bit to check in X86CPUFeatureWordInfo.features */
95*17e8f541SEduardo Habkost     int bitnr;
96*17e8f541SEduardo Habkost     /* The expected value for the bit in (X86CPUFeatureWordInfo.features) */
97*17e8f541SEduardo Habkost     bool expected_value;
98*17e8f541SEduardo Habkost } FeatureTestArgs;
99*17e8f541SEduardo Habkost 
100*17e8f541SEduardo Habkost /* Get the value for a feature word in a X86CPUFeatureWordInfo list */
101*17e8f541SEduardo Habkost static uint32_t get_feature_word(QList *features, uint32_t eax, uint32_t ecx,
102*17e8f541SEduardo Habkost                                  const char *reg)
103*17e8f541SEduardo Habkost {
104*17e8f541SEduardo Habkost     const QListEntry *e;
105*17e8f541SEduardo Habkost 
106*17e8f541SEduardo Habkost     for (e = qlist_first(features); e; e = qlist_next(e)) {
107*17e8f541SEduardo Habkost         QDict *w = qobject_to_qdict(qlist_entry_obj(e));
108*17e8f541SEduardo Habkost         const char *rreg = qdict_get_str(w, "cpuid-register");
109*17e8f541SEduardo Habkost         uint32_t reax = qdict_get_int(w, "cpuid-input-eax");
110*17e8f541SEduardo Habkost         bool has_ecx = qdict_haskey(w, "cpuid-input-ecx");
111*17e8f541SEduardo Habkost         uint32_t recx = 0;
112*17e8f541SEduardo Habkost 
113*17e8f541SEduardo Habkost         if (has_ecx) {
114*17e8f541SEduardo Habkost             recx = qdict_get_int(w, "cpuid-input-ecx");
115*17e8f541SEduardo Habkost         }
116*17e8f541SEduardo Habkost         if (eax == reax && (!has_ecx || ecx == recx) && !strcmp(rreg, reg)) {
117*17e8f541SEduardo Habkost             return qint_get_int(qobject_to_qint(qdict_get(w, "features")));
118*17e8f541SEduardo Habkost         }
119*17e8f541SEduardo Habkost     }
120*17e8f541SEduardo Habkost     return 0;
121*17e8f541SEduardo Habkost }
122*17e8f541SEduardo Habkost 
123*17e8f541SEduardo Habkost static void test_feature_flag(const void *data)
124*17e8f541SEduardo Habkost {
125*17e8f541SEduardo Habkost     const FeatureTestArgs *args = data;
126*17e8f541SEduardo Habkost     char *path;
127*17e8f541SEduardo Habkost     QList *present, *filtered;
128*17e8f541SEduardo Habkost     uint32_t value;
129*17e8f541SEduardo Habkost 
130*17e8f541SEduardo Habkost     qtest_start(args->cmdline);
131*17e8f541SEduardo Habkost     path = get_cpu0_qom_path();
132*17e8f541SEduardo Habkost     present = qobject_to_qlist(qom_get(path, "feature-words"));
133*17e8f541SEduardo Habkost     filtered = qobject_to_qlist(qom_get(path, "filtered-features"));
134*17e8f541SEduardo Habkost     value = get_feature_word(present, args->in_eax, args->in_ecx, args->reg);
135*17e8f541SEduardo Habkost     value |= get_feature_word(filtered, args->in_eax, args->in_ecx, args->reg);
136*17e8f541SEduardo Habkost     qtest_end();
137*17e8f541SEduardo Habkost 
138*17e8f541SEduardo Habkost     g_assert(!!(value & (1U << args->bitnr)) == args->expected_value);
139*17e8f541SEduardo Habkost 
140*17e8f541SEduardo Habkost     QDECREF(present);
141*17e8f541SEduardo Habkost     QDECREF(filtered);
142*17e8f541SEduardo Habkost     g_free(path);
143*17e8f541SEduardo Habkost }
144*17e8f541SEduardo Habkost 
145*17e8f541SEduardo Habkost /*
146*17e8f541SEduardo Habkost  * Add test case to ensure that a given feature flag is set in
147*17e8f541SEduardo Habkost  * either "feature-words" or "filtered-features", when running QEMU
148*17e8f541SEduardo Habkost  * using cmdline
149*17e8f541SEduardo Habkost  */
150*17e8f541SEduardo Habkost static FeatureTestArgs *add_feature_test(const char *name, const char *cmdline,
151*17e8f541SEduardo Habkost                                          uint32_t eax, uint32_t ecx,
152*17e8f541SEduardo Habkost                                          const char *reg, int bitnr,
153*17e8f541SEduardo Habkost                                          bool expected_value)
154*17e8f541SEduardo Habkost {
155*17e8f541SEduardo Habkost     FeatureTestArgs *args = g_new0(FeatureTestArgs, 1);
156*17e8f541SEduardo Habkost     args->cmdline = cmdline;
157*17e8f541SEduardo Habkost     args->in_eax = eax;
158*17e8f541SEduardo Habkost     args->in_ecx = ecx;
159*17e8f541SEduardo Habkost     args->reg = reg;
160*17e8f541SEduardo Habkost     args->bitnr = bitnr;
161*17e8f541SEduardo Habkost     args->expected_value = expected_value;
162*17e8f541SEduardo Habkost     qtest_add_data_func(name, args, test_feature_flag);
163*17e8f541SEduardo Habkost     return args;
164*17e8f541SEduardo Habkost }
165*17e8f541SEduardo Habkost 
16683a00f60SEduardo Habkost #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
16783a00f60SEduardo Habkost static void test_plus_minus_subprocess(void)
168a2f9976eSEduardo Habkost {
169a2f9976eSEduardo Habkost     char *path;
170a2f9976eSEduardo Habkost 
171a2f9976eSEduardo Habkost     /* Rules:
172a2f9976eSEduardo Habkost      * 1)"-foo" overrides "+foo"
173a2f9976eSEduardo Habkost      * 2) "[+-]foo" overrides "foo=..."
174a2f9976eSEduardo Habkost      * 3) Old feature names with underscores (e.g. "sse4_2")
175a2f9976eSEduardo Habkost      *    should keep working
176a2f9976eSEduardo Habkost      *
17783a00f60SEduardo Habkost      * Note: rules 1 and 2 are planned to be removed soon, and
17883a00f60SEduardo Habkost      * should generate a warning.
179a2f9976eSEduardo Habkost      */
180a2f9976eSEduardo Habkost     qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on");
181a2f9976eSEduardo Habkost     path = get_cpu0_qom_path();
182a2f9976eSEduardo Habkost 
183a2f9976eSEduardo Habkost     g_assert_false(qom_get_bool(path, "fpu"));
184a2f9976eSEduardo Habkost     g_assert_false(qom_get_bool(path, "mce"));
185a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "cx8"));
186a2f9976eSEduardo Habkost 
187a2f9976eSEduardo Habkost     /* Test both the original and the alias feature names: */
188a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4-1"));
189a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4.1"));
190a2f9976eSEduardo Habkost 
191a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4-2"));
192a2f9976eSEduardo Habkost     g_assert_true(qom_get_bool(path, "sse4.2"));
193a2f9976eSEduardo Habkost 
194a2f9976eSEduardo Habkost     qtest_end();
195a2f9976eSEduardo Habkost     g_free(path);
196a2f9976eSEduardo Habkost }
197a2f9976eSEduardo Habkost 
19883a00f60SEduardo Habkost static void test_plus_minus(void)
19983a00f60SEduardo Habkost {
20083a00f60SEduardo Habkost     g_test_trap_subprocess("/x86/cpuid/parsing-plus-minus/subprocess", 0, 0);
20183a00f60SEduardo Habkost     g_test_trap_assert_passed();
20283a00f60SEduardo Habkost     g_test_trap_assert_stderr("*Ambiguous CPU model string. "
20383a00f60SEduardo Habkost                               "Don't mix both \"-mce\" and \"mce=on\"*");
20483a00f60SEduardo Habkost     g_test_trap_assert_stderr("*Ambiguous CPU model string. "
20583a00f60SEduardo Habkost                               "Don't mix both \"+cx8\" and \"cx8=off\"*");
20683a00f60SEduardo Habkost     g_test_trap_assert_stdout("");
20783a00f60SEduardo Habkost }
20883a00f60SEduardo Habkost #endif
20983a00f60SEduardo Habkost 
2106efef58eSEduardo Habkost int main(int argc, char **argv)
2116efef58eSEduardo Habkost {
2126efef58eSEduardo Habkost     g_test_init(&argc, &argv, NULL);
2136efef58eSEduardo Habkost 
21483a00f60SEduardo Habkost #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
21583a00f60SEduardo Habkost     g_test_add_func("/x86/cpuid/parsing-plus-minus/subprocess",
21683a00f60SEduardo Habkost                     test_plus_minus_subprocess);
21783a00f60SEduardo Habkost     g_test_add_func("/x86/cpuid/parsing-plus-minus", test_plus_minus);
21883a00f60SEduardo Habkost #endif
219a2f9976eSEduardo Habkost 
2206efef58eSEduardo Habkost     /* Original level values for CPU models: */
2216efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/phenom/level",
2226efef58eSEduardo Habkost                    "-cpu phenom", "level", 5);
2236efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/Conroe/level",
2246efef58eSEduardo Habkost                    "-cpu Conroe", "level", 10);
2256efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/SandyBridge/level",
2266efef58eSEduardo Habkost                    "-cpu SandyBridge", "level", 0xd);
2276efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/486/xlevel",
2286efef58eSEduardo Habkost                    "-cpu 486", "xlevel", 0);
2296efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/core2duo/xlevel",
2306efef58eSEduardo Habkost                    "-cpu core2duo", "xlevel", 0x80000008);
2316efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/phenom/xlevel",
2326efef58eSEduardo Habkost                    "-cpu phenom", "xlevel", 0x8000001A);
2330c3d7c00SEduardo Habkost     add_cpuid_test("x86/cpuid/athlon/xlevel",
2340c3d7c00SEduardo Habkost                    "-cpu athlon", "xlevel", 0x80000008);
2356efef58eSEduardo Habkost 
2366efef58eSEduardo Habkost     /* If level is not large enough, it should increase automatically: */
237c39c0edfSEduardo Habkost     /* CPUID[6].EAX: */
238c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/arat",
239c39c0edfSEduardo Habkost                    "-cpu 486,+arat", "level", 6);
2406efef58eSEduardo Habkost     /* CPUID[EAX=7,ECX=0].EBX: */
2416efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase",
2426efef58eSEduardo Habkost                    "-cpu phenom,+fsgsbase", "level", 7);
243c39c0edfSEduardo Habkost     /* CPUID[EAX=7,ECX=0].ECX: */
244c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi",
245c39c0edfSEduardo Habkost                    "-cpu phenom,+avx512vbmi", "level", 7);
246c39c0edfSEduardo Habkost     /* CPUID[EAX=0xd,ECX=1].EAX: */
247c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt",
248c39c0edfSEduardo Habkost                    "-cpu phenom,+xsaveopt", "level", 0xd);
249c39c0edfSEduardo Habkost     /* CPUID[8000_0001].EDX: */
250c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow",
251c39c0edfSEduardo Habkost                    "-cpu 486,+3dnow", "xlevel", 0x80000001);
252c39c0edfSEduardo Habkost     /* CPUID[8000_0001].ECX: */
253c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a",
254c39c0edfSEduardo Habkost                    "-cpu 486,+sse4a", "xlevel", 0x80000001);
255c39c0edfSEduardo Habkost     /* CPUID[8000_0007].EDX: */
256c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc",
257c39c0edfSEduardo Habkost                    "-cpu 486,+invtsc", "xlevel", 0x80000007);
258c39c0edfSEduardo Habkost     /* CPUID[8000_000A].EDX: */
259c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/npt",
260c39c0edfSEduardo Habkost                    "-cpu 486,+npt", "xlevel", 0x8000000A);
261c39c0edfSEduardo Habkost     /* CPUID[C000_0001].EDX: */
262c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore",
263c39c0edfSEduardo Habkost                    "-cpu phenom,+xstore", "xlevel2", 0xC0000001);
2640c3d7c00SEduardo Habkost     /* SVM needs CPUID[0x8000000A] */
2650c3d7c00SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm",
2660c3d7c00SEduardo Habkost                    "-cpu athlon,+svm", "xlevel", 0x8000000A);
267c39c0edfSEduardo Habkost 
2686efef58eSEduardo Habkost 
2696efef58eSEduardo Habkost     /* If level is already large enough, it shouldn't change: */
2706efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple",
2716efef58eSEduardo Habkost                    "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi",
2726efef58eSEduardo Habkost                    "level", 0xd);
273c39c0edfSEduardo Habkost     /* If level is explicitly set, it shouldn't change: */
274c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF",
275c39c0edfSEduardo Habkost                    "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
276c39c0edfSEduardo Habkost                    "level", 0xF);
277c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/2",
278c39c0edfSEduardo Habkost                    "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
279c39c0edfSEduardo Habkost                    "level", 2);
280c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/486/fixed/0",
281c39c0edfSEduardo Habkost                    "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt",
282c39c0edfSEduardo Habkost                    "level", 0);
2836efef58eSEduardo Habkost 
2846efef58eSEduardo Habkost     /* if xlevel is already large enough, it shouldn't change: */
2856efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow",
2860c3d7c00SEduardo Habkost                    "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm",
2876efef58eSEduardo Habkost                    "xlevel", 0x8000001A);
288c39c0edfSEduardo Habkost     /* If xlevel is explicitly set, it shouldn't change: */
289c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002",
2900c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm",
291c39c0edfSEduardo Habkost                    "xlevel", 0x80000002);
292c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A",
2930c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm",
294c39c0edfSEduardo Habkost                    "xlevel", 0x8000001A);
295c39c0edfSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0",
2960c3d7c00SEduardo Habkost                    "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm",
297c39c0edfSEduardo Habkost                    "xlevel", 0);
2986efef58eSEduardo Habkost 
2996efef58eSEduardo Habkost     /* if xlevel2 is already large enough, it shouldn't change: */
3006efef58eSEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed",
3016efef58eSEduardo Habkost                    "-cpu 486,xlevel2=0xC0000002,+xstore",
3026efef58eSEduardo Habkost                    "xlevel2", 0xC0000002);
3036efef58eSEduardo Habkost 
304df3e9af8SEduardo Habkost     /* Check compatibility of old machine-types that didn't
305df3e9af8SEduardo Habkost      * auto-increase level/xlevel/xlevel2: */
306df3e9af8SEduardo Habkost 
307df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-level/pc-2.7",
308df3e9af8SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt",
309df3e9af8SEduardo Habkost                    "level", 1);
310df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7",
3110c3d7c00SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm",
312df3e9af8SEduardo Habkost                    "xlevel", 0);
313df3e9af8SEduardo Habkost     add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7",
314df3e9af8SEduardo Habkost                    "-machine pc-i440fx-2.7 -cpu 486,+xstore",
315df3e9af8SEduardo Habkost                    "xlevel2", 0);
316df3e9af8SEduardo Habkost 
317*17e8f541SEduardo Habkost     /* Test feature parsing */
318*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/plus",
319*17e8f541SEduardo Habkost                      "-cpu 486,+arat",
320*17e8f541SEduardo Habkost                      6, 0, "EAX", 2, true);
321*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/minus",
322*17e8f541SEduardo Habkost                      "-cpu pentium,-mmx",
323*17e8f541SEduardo Habkost                      1, 0, "EDX", 23, false);
324*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/on",
325*17e8f541SEduardo Habkost                      "-cpu 486,arat=on",
326*17e8f541SEduardo Habkost                      6, 0, "EAX", 2, true);
327*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/off",
328*17e8f541SEduardo Habkost                      "-cpu pentium,mmx=off",
329*17e8f541SEduardo Habkost                      1, 0, "EDX", 23, false);
330*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/max-plus-invtsc",
331*17e8f541SEduardo Habkost                      "-cpu max,+invtsc",
332*17e8f541SEduardo Habkost                      0x80000007, 0, "EDX", 8, true);
333*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/max-invtsc-on",
334*17e8f541SEduardo Habkost                      "-cpu max,invtsc=on",
335*17e8f541SEduardo Habkost                      0x80000007, 0, "EDX", 8, true);
336*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/max-minus-mmx",
337*17e8f541SEduardo Habkost                      "-cpu max,-mmx",
338*17e8f541SEduardo Habkost                      1, 0, "EDX", 23, false);
339*17e8f541SEduardo Habkost     add_feature_test("x86/cpuid/features/max-invtsc-on,mmx=off",
340*17e8f541SEduardo Habkost                      "-cpu max,mmx=off",
341*17e8f541SEduardo Habkost                      1, 0, "EDX", 23, false);
342*17e8f541SEduardo Habkost 
3436efef58eSEduardo Habkost     return g_test_run();
3446efef58eSEduardo Habkost }
345