16efef58eSEduardo Habkost #include "qemu/osdep.h" 2*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h" 3*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h" 4*407bc4bfSDaniel P. Berrangé #include "qobject/qnum.h" 5*407bc4bfSDaniel P. Berrangé #include "qobject/qbool.h" 6dd210749SThomas Huth #include "libqtest-single.h" 76efef58eSEduardo Habkost 86efef58eSEduardo Habkost static char *get_cpu0_qom_path(void) 96efef58eSEduardo Habkost { 106efef58eSEduardo Habkost QDict *resp; 116efef58eSEduardo Habkost QList *ret; 126efef58eSEduardo Habkost QDict *cpu0; 136efef58eSEduardo Habkost char *path; 146efef58eSEduardo Habkost 158af54b91SDaniel P. Berrangé resp = qmp("{'execute': 'query-cpus-fast', 'arguments': {}}"); 166efef58eSEduardo Habkost g_assert(qdict_haskey(resp, "return")); 176efef58eSEduardo Habkost ret = qdict_get_qlist(resp, "return"); 186efef58eSEduardo Habkost 197dc847ebSMax Reitz cpu0 = qobject_to(QDict, qlist_peek(ret)); 208af54b91SDaniel P. Berrangé path = g_strdup(qdict_get_str(cpu0, "qom-path")); 21cb3e7f08SMarc-André Lureau qobject_unref(resp); 226efef58eSEduardo Habkost return path; 236efef58eSEduardo Habkost } 246efef58eSEduardo Habkost 256efef58eSEduardo Habkost static QObject *qom_get(const char *path, const char *prop) 266efef58eSEduardo Habkost { 276efef58eSEduardo Habkost QDict *resp = qmp("{ 'execute': 'qom-get'," 286efef58eSEduardo Habkost " 'arguments': { 'path': %s," 296efef58eSEduardo Habkost " 'property': %s } }", 306efef58eSEduardo Habkost path, prop); 316efef58eSEduardo Habkost QObject *ret = qdict_get(resp, "return"); 32cb3e7f08SMarc-André Lureau qobject_ref(ret); 33cb3e7f08SMarc-André Lureau qobject_unref(resp); 346efef58eSEduardo Habkost return ret; 356efef58eSEduardo Habkost } 366efef58eSEduardo Habkost 37a2f9976eSEduardo Habkost static bool qom_get_bool(const char *path, const char *prop) 38a2f9976eSEduardo Habkost { 397dc847ebSMax Reitz QBool *value = qobject_to(QBool, qom_get(path, prop)); 40a2f9976eSEduardo Habkost bool b = qbool_get_bool(value); 41a2f9976eSEduardo Habkost 42cb3e7f08SMarc-André Lureau qobject_unref(value); 43a2f9976eSEduardo Habkost return b; 44a2f9976eSEduardo Habkost } 45a2f9976eSEduardo Habkost 466efef58eSEduardo Habkost typedef struct CpuidTestArgs { 476efef58eSEduardo Habkost const char *cmdline; 486efef58eSEduardo Habkost const char *property; 496efef58eSEduardo Habkost int64_t expected_value; 506efef58eSEduardo Habkost } CpuidTestArgs; 516efef58eSEduardo Habkost 526efef58eSEduardo Habkost static void test_cpuid_prop(const void *data) 536efef58eSEduardo Habkost { 546efef58eSEduardo Habkost const CpuidTestArgs *args = data; 556efef58eSEduardo Habkost char *path; 5601b2ffceSMarc-André Lureau QNum *value; 5701b2ffceSMarc-André Lureau int64_t val; 586efef58eSEduardo Habkost 596efef58eSEduardo Habkost qtest_start(args->cmdline); 606efef58eSEduardo Habkost path = get_cpu0_qom_path(); 617dc847ebSMax Reitz value = qobject_to(QNum, qom_get(path, args->property)); 6201b2ffceSMarc-André Lureau g_assert(qnum_get_try_int(value, &val)); 6301b2ffceSMarc-André Lureau g_assert_cmpint(val, ==, args->expected_value); 646efef58eSEduardo Habkost qtest_end(); 656efef58eSEduardo Habkost 66cb3e7f08SMarc-André Lureau qobject_unref(value); 676efef58eSEduardo Habkost g_free(path); 686efef58eSEduardo Habkost } 696efef58eSEduardo Habkost 70e08f6e0bSAni Sinha static void add_cpuid_test(const char *name, const char *cpu, 71e08f6e0bSAni Sinha const char *cpufeat, const char *machine, 726efef58eSEduardo Habkost const char *property, int64_t expected_value) 736efef58eSEduardo Habkost { 746efef58eSEduardo Habkost CpuidTestArgs *args = g_new0(CpuidTestArgs, 1); 75e08f6e0bSAni Sinha char *cmdline; 76e08f6e0bSAni Sinha char *save; 77e08f6e0bSAni Sinha 78e08f6e0bSAni Sinha if (!qtest_has_cpu_model(cpu)) { 79e08f6e0bSAni Sinha return; 80e08f6e0bSAni Sinha } 81e08f6e0bSAni Sinha cmdline = g_strdup_printf("-cpu %s", cpu); 82e08f6e0bSAni Sinha 83e08f6e0bSAni Sinha if (cpufeat) { 84e08f6e0bSAni Sinha save = cmdline; 85e08f6e0bSAni Sinha cmdline = g_strdup_printf("%s,%s", cmdline, cpufeat); 86e08f6e0bSAni Sinha g_free(save); 87e08f6e0bSAni Sinha } 88e08f6e0bSAni Sinha if (machine) { 89e08f6e0bSAni Sinha save = cmdline; 90e08f6e0bSAni Sinha cmdline = g_strdup_printf("-machine %s %s", machine, cmdline); 91e08f6e0bSAni Sinha g_free(save); 92e08f6e0bSAni Sinha } 936efef58eSEduardo Habkost args->cmdline = cmdline; 946efef58eSEduardo Habkost args->property = property; 956efef58eSEduardo Habkost args->expected_value = expected_value; 966efef58eSEduardo Habkost qtest_add_data_func(name, args, test_cpuid_prop); 976efef58eSEduardo Habkost } 986efef58eSEduardo Habkost 9917e8f541SEduardo Habkost 10017e8f541SEduardo Habkost /* Parameters to a add_feature_test() test case */ 10117e8f541SEduardo Habkost typedef struct FeatureTestArgs { 10217e8f541SEduardo Habkost /* cmdline to start QEMU */ 10317e8f541SEduardo Habkost const char *cmdline; 10417e8f541SEduardo Habkost /* 10517e8f541SEduardo Habkost * cpuid-input-eax and cpuid-input-ecx values to look for, 10617e8f541SEduardo Habkost * in "feature-words" and "filtered-features" properties. 10717e8f541SEduardo Habkost */ 10817e8f541SEduardo Habkost uint32_t in_eax, in_ecx; 10917e8f541SEduardo Habkost /* The register name to look for, in the X86CPUFeatureWordInfo array */ 11017e8f541SEduardo Habkost const char *reg; 11117e8f541SEduardo Habkost /* The bit to check in X86CPUFeatureWordInfo.features */ 11217e8f541SEduardo Habkost int bitnr; 11317e8f541SEduardo Habkost /* The expected value for the bit in (X86CPUFeatureWordInfo.features) */ 11417e8f541SEduardo Habkost bool expected_value; 11517e8f541SEduardo Habkost } FeatureTestArgs; 11617e8f541SEduardo Habkost 11717e8f541SEduardo Habkost /* Get the value for a feature word in a X86CPUFeatureWordInfo list */ 11817e8f541SEduardo Habkost static uint32_t get_feature_word(QList *features, uint32_t eax, uint32_t ecx, 11917e8f541SEduardo Habkost const char *reg) 12017e8f541SEduardo Habkost { 12117e8f541SEduardo Habkost const QListEntry *e; 12217e8f541SEduardo Habkost 12317e8f541SEduardo Habkost for (e = qlist_first(features); e; e = qlist_next(e)) { 1247dc847ebSMax Reitz QDict *w = qobject_to(QDict, qlist_entry_obj(e)); 12517e8f541SEduardo Habkost const char *rreg = qdict_get_str(w, "cpuid-register"); 12617e8f541SEduardo Habkost uint32_t reax = qdict_get_int(w, "cpuid-input-eax"); 12717e8f541SEduardo Habkost bool has_ecx = qdict_haskey(w, "cpuid-input-ecx"); 12817e8f541SEduardo Habkost uint32_t recx = 0; 12901b2ffceSMarc-André Lureau int64_t val; 13017e8f541SEduardo Habkost 13117e8f541SEduardo Habkost if (has_ecx) { 13217e8f541SEduardo Habkost recx = qdict_get_int(w, "cpuid-input-ecx"); 13317e8f541SEduardo Habkost } 13417e8f541SEduardo Habkost if (eax == reax && (!has_ecx || ecx == recx) && !strcmp(rreg, reg)) { 1357dc847ebSMax Reitz g_assert(qnum_get_try_int(qobject_to(QNum, 1367dc847ebSMax Reitz qdict_get(w, "features")), 13701b2ffceSMarc-André Lureau &val)); 13801b2ffceSMarc-André Lureau return val; 13917e8f541SEduardo Habkost } 14017e8f541SEduardo Habkost } 14117e8f541SEduardo Habkost return 0; 14217e8f541SEduardo Habkost } 14317e8f541SEduardo Habkost 14417e8f541SEduardo Habkost static void test_feature_flag(const void *data) 14517e8f541SEduardo Habkost { 14617e8f541SEduardo Habkost const FeatureTestArgs *args = data; 14717e8f541SEduardo Habkost char *path; 14817e8f541SEduardo Habkost QList *present, *filtered; 14917e8f541SEduardo Habkost uint32_t value; 15017e8f541SEduardo Habkost 15117e8f541SEduardo Habkost qtest_start(args->cmdline); 15217e8f541SEduardo Habkost path = get_cpu0_qom_path(); 1537dc847ebSMax Reitz present = qobject_to(QList, qom_get(path, "feature-words")); 1547dc847ebSMax Reitz filtered = qobject_to(QList, qom_get(path, "filtered-features")); 15517e8f541SEduardo Habkost value = get_feature_word(present, args->in_eax, args->in_ecx, args->reg); 15617e8f541SEduardo Habkost value |= get_feature_word(filtered, args->in_eax, args->in_ecx, args->reg); 15717e8f541SEduardo Habkost qtest_end(); 15817e8f541SEduardo Habkost 15917e8f541SEduardo Habkost g_assert(!!(value & (1U << args->bitnr)) == args->expected_value); 16017e8f541SEduardo Habkost 161cb3e7f08SMarc-André Lureau qobject_unref(present); 162cb3e7f08SMarc-André Lureau qobject_unref(filtered); 16317e8f541SEduardo Habkost g_free(path); 16417e8f541SEduardo Habkost } 16517e8f541SEduardo Habkost 16617e8f541SEduardo Habkost /* 16717e8f541SEduardo Habkost * Add test case to ensure that a given feature flag is set in 16817e8f541SEduardo Habkost * either "feature-words" or "filtered-features", when running QEMU 16917e8f541SEduardo Habkost * using cmdline 17017e8f541SEduardo Habkost */ 171e08f6e0bSAni Sinha static void add_feature_test(const char *name, const char *cpu, 172e08f6e0bSAni Sinha const char *cpufeat, uint32_t eax, 173e08f6e0bSAni Sinha uint32_t ecx, const char *reg, 174e08f6e0bSAni Sinha int bitnr, bool expected_value) 17517e8f541SEduardo Habkost { 17617e8f541SEduardo Habkost FeatureTestArgs *args = g_new0(FeatureTestArgs, 1); 177e08f6e0bSAni Sinha char *cmdline; 178e08f6e0bSAni Sinha 179e08f6e0bSAni Sinha if (!qtest_has_cpu_model(cpu)) { 180e08f6e0bSAni Sinha return; 181e08f6e0bSAni Sinha } 182e08f6e0bSAni Sinha 183e08f6e0bSAni Sinha if (cpufeat) { 184e08f6e0bSAni Sinha cmdline = g_strdup_printf("-cpu %s,%s", cpu, cpufeat); 185e08f6e0bSAni Sinha } else { 186e08f6e0bSAni Sinha cmdline = g_strdup_printf("-cpu %s", cpu); 187e08f6e0bSAni Sinha } 188e08f6e0bSAni Sinha 18917e8f541SEduardo Habkost args->cmdline = cmdline; 19017e8f541SEduardo Habkost args->in_eax = eax; 19117e8f541SEduardo Habkost args->in_ecx = ecx; 19217e8f541SEduardo Habkost args->reg = reg; 19317e8f541SEduardo Habkost args->bitnr = bitnr; 19417e8f541SEduardo Habkost args->expected_value = expected_value; 19517e8f541SEduardo Habkost qtest_add_data_func(name, args, test_feature_flag); 196e08f6e0bSAni Sinha return; 19717e8f541SEduardo Habkost } 19817e8f541SEduardo Habkost 19983a00f60SEduardo Habkost static void test_plus_minus_subprocess(void) 200a2f9976eSEduardo Habkost { 201a2f9976eSEduardo Habkost char *path; 202a2f9976eSEduardo Habkost 203e08f6e0bSAni Sinha if (!qtest_has_cpu_model("pentium")) { 204e08f6e0bSAni Sinha return; 205e08f6e0bSAni Sinha } 206e08f6e0bSAni Sinha 207a2f9976eSEduardo Habkost /* Rules: 208a2f9976eSEduardo Habkost * 1)"-foo" overrides "+foo" 209a2f9976eSEduardo Habkost * 2) "[+-]foo" overrides "foo=..." 210a2f9976eSEduardo Habkost * 3) Old feature names with underscores (e.g. "sse4_2") 211a2f9976eSEduardo Habkost * should keep working 212a2f9976eSEduardo Habkost * 21383a00f60SEduardo Habkost * Note: rules 1 and 2 are planned to be removed soon, and 21483a00f60SEduardo Habkost * should generate a warning. 215a2f9976eSEduardo Habkost */ 216a2f9976eSEduardo Habkost qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on"); 217a2f9976eSEduardo Habkost path = get_cpu0_qom_path(); 218a2f9976eSEduardo Habkost 219a2f9976eSEduardo Habkost g_assert_false(qom_get_bool(path, "fpu")); 220a2f9976eSEduardo Habkost g_assert_false(qom_get_bool(path, "mce")); 221a2f9976eSEduardo Habkost g_assert_true(qom_get_bool(path, "cx8")); 222a2f9976eSEduardo Habkost 223a2f9976eSEduardo Habkost /* Test both the original and the alias feature names: */ 224a2f9976eSEduardo Habkost g_assert_true(qom_get_bool(path, "sse4-1")); 225a2f9976eSEduardo Habkost g_assert_true(qom_get_bool(path, "sse4.1")); 226a2f9976eSEduardo Habkost 227a2f9976eSEduardo Habkost g_assert_true(qom_get_bool(path, "sse4-2")); 228a2f9976eSEduardo Habkost g_assert_true(qom_get_bool(path, "sse4.2")); 229a2f9976eSEduardo Habkost 230a2f9976eSEduardo Habkost qtest_end(); 231a2f9976eSEduardo Habkost g_free(path); 232a2f9976eSEduardo Habkost } 233a2f9976eSEduardo Habkost 23483a00f60SEduardo Habkost static void test_plus_minus(void) 23583a00f60SEduardo Habkost { 236e08f6e0bSAni Sinha if (!qtest_has_cpu_model("pentium")) { 237e08f6e0bSAni Sinha return; 238e08f6e0bSAni Sinha } 239e08f6e0bSAni Sinha 24083a00f60SEduardo Habkost g_test_trap_subprocess("/x86/cpuid/parsing-plus-minus/subprocess", 0, 0); 24183a00f60SEduardo Habkost g_test_trap_assert_passed(); 24283a00f60SEduardo Habkost g_test_trap_assert_stderr("*Ambiguous CPU model string. " 24383a00f60SEduardo Habkost "Don't mix both \"-mce\" and \"mce=on\"*"); 24483a00f60SEduardo Habkost g_test_trap_assert_stderr("*Ambiguous CPU model string. " 24583a00f60SEduardo Habkost "Don't mix both \"+cx8\" and \"cx8=off\"*"); 24683a00f60SEduardo Habkost g_test_trap_assert_stdout(""); 24783a00f60SEduardo Habkost } 24883a00f60SEduardo Habkost 2496efef58eSEduardo Habkost int main(int argc, char **argv) 2506efef58eSEduardo Habkost { 2516efef58eSEduardo Habkost g_test_init(&argc, &argv, NULL); 2526efef58eSEduardo Habkost 25383a00f60SEduardo Habkost g_test_add_func("/x86/cpuid/parsing-plus-minus/subprocess", 25483a00f60SEduardo Habkost test_plus_minus_subprocess); 25583a00f60SEduardo Habkost g_test_add_func("/x86/cpuid/parsing-plus-minus", test_plus_minus); 256a2f9976eSEduardo Habkost 2576efef58eSEduardo Habkost /* Original level values for CPU models: */ 2586efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/phenom/level", 259e08f6e0bSAni Sinha "phenom", NULL, NULL, "level", 5); 2606efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/Conroe/level", 261e08f6e0bSAni Sinha "Conroe", NULL, NULL, "level", 10); 2626efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/SandyBridge/level", 263e08f6e0bSAni Sinha "SandyBridge", NULL, NULL, "level", 0xd); 2646efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/486/xlevel", 265e08f6e0bSAni Sinha "486", NULL, NULL, "xlevel", 0); 2666efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/core2duo/xlevel", 267e08f6e0bSAni Sinha "core2duo", NULL, NULL, "xlevel", 0x80000008); 2686efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/phenom/xlevel", 269e08f6e0bSAni Sinha "phenom", NULL, NULL, "xlevel", 0x8000001A); 2700c3d7c00SEduardo Habkost add_cpuid_test("x86/cpuid/athlon/xlevel", 271e08f6e0bSAni Sinha "athlon", NULL, NULL, "xlevel", 0x80000008); 2726efef58eSEduardo Habkost 2736efef58eSEduardo Habkost /* If level is not large enough, it should increase automatically: */ 274c39c0edfSEduardo Habkost /* CPUID[6].EAX: */ 275e08f6e0bSAni Sinha add_cpuid_test("x86/cpuid/auto-level/486/arat", 276e08f6e0bSAni Sinha "486", "arat=on", NULL, "level", 6); 2776efef58eSEduardo Habkost /* CPUID[EAX=7,ECX=0].EBX: */ 2786efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase", 279e08f6e0bSAni Sinha "phenom", "fsgsbase=on", NULL, "level", 7); 280c39c0edfSEduardo Habkost /* CPUID[EAX=7,ECX=0].ECX: */ 281c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi", 282e08f6e0bSAni Sinha "phenom", "avx512vbmi=on", NULL, "level", 7); 283c39c0edfSEduardo Habkost /* CPUID[EAX=0xd,ECX=1].EAX: */ 284c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt", 285e08f6e0bSAni Sinha "phenom", "xsaveopt=on", NULL, "level", 0xd); 286c39c0edfSEduardo Habkost /* CPUID[8000_0001].EDX: */ 287c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow", 288e08f6e0bSAni Sinha "486", "3dnow=on", NULL, "xlevel", 0x80000001); 289c39c0edfSEduardo Habkost /* CPUID[8000_0001].ECX: */ 290c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a", 291e08f6e0bSAni Sinha "486", "sse4a=on", NULL, "xlevel", 0x80000001); 292c39c0edfSEduardo Habkost /* CPUID[8000_0007].EDX: */ 293c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc", 294e08f6e0bSAni Sinha "486", "invtsc=on", NULL, "xlevel", 0x80000007); 295c39c0edfSEduardo Habkost /* CPUID[8000_000A].EDX: */ 296c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/npt", 297e08f6e0bSAni Sinha "486", "svm=on,npt=on", NULL, "xlevel", 0x8000000A); 298c39c0edfSEduardo Habkost /* CPUID[C000_0001].EDX: */ 299c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore", 300e08f6e0bSAni Sinha "phenom", "xstore=on", NULL, "xlevel2", 0xC0000001); 3010c3d7c00SEduardo Habkost /* SVM needs CPUID[0x8000000A] */ 3020c3d7c00SEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm", 303e08f6e0bSAni Sinha "athlon", "svm=on", NULL, "xlevel", 0x8000000A); 304c39c0edfSEduardo Habkost 3056efef58eSEduardo Habkost 3066efef58eSEduardo Habkost /* If level is already large enough, it shouldn't change: */ 3076efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple", 308e08f6e0bSAni Sinha "SandyBridge", "arat=on,fsgsbase=on,avx512vbmi=on", 309e08f6e0bSAni Sinha NULL, "level", 0xd); 310c39c0edfSEduardo Habkost /* If level is explicitly set, it shouldn't change: */ 311c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF", 312e08f6e0bSAni Sinha "486", 313e08f6e0bSAni Sinha "level=0xF,arat=on,fsgsbase=on,avx512vbmi=on,xsaveopt=on", 314e08f6e0bSAni Sinha NULL, "level", 0xF); 315c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/486/fixed/2", 316e08f6e0bSAni Sinha "486", 317e08f6e0bSAni Sinha "level=2,arat=on,fsgsbase=on,avx512vbmi=on,xsaveopt=on", 318e08f6e0bSAni Sinha NULL, "level", 2); 319c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/486/fixed/0", 320e08f6e0bSAni Sinha "486", 321e08f6e0bSAni Sinha "level=0,arat=on,fsgsbase=on,avx512vbmi=on,xsaveopt=on", 322e08f6e0bSAni Sinha NULL, "level", 0); 3236efef58eSEduardo Habkost 3246efef58eSEduardo Habkost /* if xlevel is already large enough, it shouldn't change: */ 3256efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow", 326e08f6e0bSAni Sinha "phenom", "3dnow=on,sse4a=on,invtsc=on,npt=on,svm=on", 327e08f6e0bSAni Sinha NULL, "xlevel", 0x8000001A); 328c39c0edfSEduardo Habkost /* If xlevel is explicitly set, it shouldn't change: */ 329c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002", 330e08f6e0bSAni Sinha "486", 331e08f6e0bSAni Sinha "xlevel=0x80000002,3dnow=on,sse4a=on,invtsc=on,npt=on,svm=on", 332e08f6e0bSAni Sinha NULL, "xlevel", 0x80000002); 333c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A", 334e08f6e0bSAni Sinha "486", 335e08f6e0bSAni Sinha "xlevel=0x8000001A,3dnow=on,sse4a=on,invtsc=on,npt=on,svm=on", 336e08f6e0bSAni Sinha NULL, "xlevel", 0x8000001A); 337c39c0edfSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0", 338e08f6e0bSAni Sinha "486", 339e08f6e0bSAni Sinha "xlevel=0,3dnow=on,sse4a=on,invtsc=on,npt=on,svm=on", 340e08f6e0bSAni Sinha NULL, "xlevel", 0); 3416efef58eSEduardo Habkost 3426efef58eSEduardo Habkost /* if xlevel2 is already large enough, it shouldn't change: */ 3436efef58eSEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed", 344e08f6e0bSAni Sinha "486", "xlevel2=0xC0000002,xstore=on", 345e08f6e0bSAni Sinha NULL, "xlevel2", 0xC0000002); 3466efef58eSEduardo Habkost 347df3e9af8SEduardo Habkost /* Check compatibility of old machine-types that didn't 348df3e9af8SEduardo Habkost * auto-increase level/xlevel/xlevel2: */ 3497539fa01SThomas Huth if (qtest_has_machine("pc-i440fx-2.7")) { 350df3e9af8SEduardo Habkost add_cpuid_test("x86/cpuid/auto-level/pc-2.7", 351e08f6e0bSAni Sinha "486", "arat=on,avx512vbmi=on,xsaveopt=on", 352e08f6e0bSAni Sinha "pc-i440fx-2.7", "level", 1); 353df3e9af8SEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7", 354e08f6e0bSAni Sinha "486", "3dnow=on,sse4a=on,invtsc=on,npt=on,svm=on", 355e08f6e0bSAni Sinha "pc-i440fx-2.7", "xlevel", 0); 356df3e9af8SEduardo Habkost add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7", 357e08f6e0bSAni Sinha "486", "xstore=on", "pc-i440fx-2.7", 358df3e9af8SEduardo Habkost "xlevel2", 0); 3597539fa01SThomas Huth } 3607539fa01SThomas Huth if (qtest_has_machine("pc-i440fx-2.9")) { 3611f435716SEduardo Habkost add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/off", 362e08f6e0bSAni Sinha "Conroe", NULL, "pc-i440fx-2.9", 3631f435716SEduardo Habkost "level", 10); 3641f435716SEduardo Habkost add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/on", 365e08f6e0bSAni Sinha "Conroe", "erms=on", "pc-i440fx-2.9", 3661f435716SEduardo Habkost "level", 10); 3677539fa01SThomas Huth } 3681f435716SEduardo Habkost 3691f435716SEduardo Habkost /* 3701f435716SEduardo Habkost * xlevel doesn't have any feature that triggers auto-level 3711f435716SEduardo Habkost * code on old machine-types. Just check that the compat code 3721f435716SEduardo Habkost * is working correctly: 3731f435716SEduardo Habkost */ 3747539fa01SThomas Huth if (qtest_has_machine("pc-i440fx-2.4")) { 3751f435716SEduardo Habkost add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off", 376e08f6e0bSAni Sinha "SandyBridge", NULL, "pc-i440fx-2.4", 3771f435716SEduardo Habkost "xlevel", 0x80000008); 3781f435716SEduardo Habkost add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on", 379e08f6e0bSAni Sinha "SandyBridge", "svm=on,npt=on", "pc-i440fx-2.4", 3801f435716SEduardo Habkost "xlevel", 0x80000008); 3817539fa01SThomas Huth } 382df3e9af8SEduardo Habkost 38317e8f541SEduardo Habkost /* Test feature parsing */ 38417e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/plus", 385e08f6e0bSAni Sinha "486", "+arat", 38617e8f541SEduardo Habkost 6, 0, "EAX", 2, true); 38717e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/minus", 388e08f6e0bSAni Sinha "pentium", "-mmx", 38917e8f541SEduardo Habkost 1, 0, "EDX", 23, false); 39017e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/on", 391e08f6e0bSAni Sinha "486", "arat=on", 39217e8f541SEduardo Habkost 6, 0, "EAX", 2, true); 39317e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/off", 394e08f6e0bSAni Sinha "pentium", "mmx=off", 39517e8f541SEduardo Habkost 1, 0, "EDX", 23, false); 396e08f6e0bSAni Sinha 39717e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/max-plus-invtsc", 398e08f6e0bSAni Sinha "max" , "+invtsc", 39917e8f541SEduardo Habkost 0x80000007, 0, "EDX", 8, true); 40017e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/max-invtsc-on", 401e08f6e0bSAni Sinha "max", "invtsc=on", 40217e8f541SEduardo Habkost 0x80000007, 0, "EDX", 8, true); 40317e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/max-minus-mmx", 404e08f6e0bSAni Sinha "max", "-mmx", 40517e8f541SEduardo Habkost 1, 0, "EDX", 23, false); 40617e8f541SEduardo Habkost add_feature_test("x86/cpuid/features/max-invtsc-on,mmx=off", 407e08f6e0bSAni Sinha "max", "mmx=off", 40817e8f541SEduardo Habkost 1, 0, "EDX", 23, false); 40917e8f541SEduardo Habkost 4106efef58eSEduardo Habkost return g_test_run(); 4116efef58eSEduardo Habkost } 412