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