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