xref: /openbmc/qemu/tests/qtest/arm-cpu-features.c (revision 399e5e71)
11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth  * Arm CPU feature test cases
31e8a1faeSThomas Huth  *
41e8a1faeSThomas Huth  * Copyright (c) 2019 Red Hat Inc.
51e8a1faeSThomas Huth  * Authors:
61e8a1faeSThomas Huth  *  Andrew Jones <drjones@redhat.com>
71e8a1faeSThomas Huth  *
81e8a1faeSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
91e8a1faeSThomas Huth  * See the COPYING file in the top-level directory.
101e8a1faeSThomas Huth  */
111e8a1faeSThomas Huth #include "qemu/osdep.h"
121e8a1faeSThomas Huth #include "qemu/bitops.h"
13907b5105SMarc-André Lureau #include "libqtest.h"
141e8a1faeSThomas Huth #include "qapi/qmp/qdict.h"
151e8a1faeSThomas Huth #include "qapi/qmp/qjson.h"
161e8a1faeSThomas Huth 
171e8a1faeSThomas Huth /*
181e8a1faeSThomas Huth  * We expect the SVE max-vq to be 16. Also it must be <= 64
191e8a1faeSThomas Huth  * for our test code, otherwise 'vls' can't just be a uint64_t.
201e8a1faeSThomas Huth  */
211e8a1faeSThomas Huth #define SVE_MAX_VQ 16
221e8a1faeSThomas Huth 
231e8a1faeSThomas Huth #define MACHINE     "-machine virt,gic-version=max -accel tcg "
24500a0accSFabiano Rosas #define MACHINE_KVM "-machine virt,gic-version=max -accel kvm "
251e8a1faeSThomas Huth #define QUERY_HEAD  "{ 'execute': 'query-cpu-model-expansion', " \
261e8a1faeSThomas Huth                     "  'arguments': { 'type': 'full', "
271e8a1faeSThomas Huth #define QUERY_TAIL  "}}"
281e8a1faeSThomas Huth 
do_query_no_props(QTestState * qts,const char * cpu_type)291e8a1faeSThomas Huth static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
301e8a1faeSThomas Huth {
311e8a1faeSThomas Huth     return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
321e8a1faeSThomas Huth                           QUERY_TAIL, cpu_type);
331e8a1faeSThomas Huth }
341e8a1faeSThomas Huth 
350472b2e5SDaniel P. Berrangé G_GNUC_PRINTF(3, 4)
do_query(QTestState * qts,const char * cpu_type,const char * fmt,...)361e8a1faeSThomas Huth static QDict *do_query(QTestState *qts, const char *cpu_type,
371e8a1faeSThomas Huth                        const char *fmt, ...)
381e8a1faeSThomas Huth {
391e8a1faeSThomas Huth     QDict *resp;
401e8a1faeSThomas Huth 
411e8a1faeSThomas Huth     if (fmt) {
421e8a1faeSThomas Huth         QDict *args;
431e8a1faeSThomas Huth         va_list ap;
441e8a1faeSThomas Huth 
451e8a1faeSThomas Huth         va_start(ap, fmt);
461e8a1faeSThomas Huth         args = qdict_from_vjsonf_nofail(fmt, ap);
471e8a1faeSThomas Huth         va_end(ap);
481e8a1faeSThomas Huth 
491e8a1faeSThomas Huth         resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
501e8a1faeSThomas Huth                                                     "'props': %p }"
511e8a1faeSThomas Huth                               QUERY_TAIL, cpu_type, args);
521e8a1faeSThomas Huth     } else {
531e8a1faeSThomas Huth         resp = do_query_no_props(qts, cpu_type);
541e8a1faeSThomas Huth     }
551e8a1faeSThomas Huth 
561e8a1faeSThomas Huth     return resp;
571e8a1faeSThomas Huth }
581e8a1faeSThomas Huth 
resp_get_error(QDict * resp)591e8a1faeSThomas Huth static const char *resp_get_error(QDict *resp)
601e8a1faeSThomas Huth {
611e8a1faeSThomas Huth     QDict *qdict;
621e8a1faeSThomas Huth 
631e8a1faeSThomas Huth     g_assert(resp);
641e8a1faeSThomas Huth 
651e8a1faeSThomas Huth     qdict = qdict_get_qdict(resp, "error");
661e8a1faeSThomas Huth     if (qdict) {
671e8a1faeSThomas Huth         return qdict_get_str(qdict, "desc");
681e8a1faeSThomas Huth     }
691e8a1faeSThomas Huth 
701e8a1faeSThomas Huth     return NULL;
711e8a1faeSThomas Huth }
721e8a1faeSThomas Huth 
731e8a1faeSThomas Huth #define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
741e8a1faeSThomas Huth ({                                                                     \
751e8a1faeSThomas Huth     QDict *_resp;                                                      \
761e8a1faeSThomas Huth     const char *_error;                                                \
771e8a1faeSThomas Huth                                                                        \
781e8a1faeSThomas Huth     _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
791e8a1faeSThomas Huth     g_assert(_resp);                                                   \
801e8a1faeSThomas Huth     _error = resp_get_error(_resp);                                    \
811e8a1faeSThomas Huth     g_assert(_error);                                                  \
821e8a1faeSThomas Huth     g_assert(g_str_equal(_error, expected_error));                     \
831e8a1faeSThomas Huth     qobject_unref(_resp);                                              \
841e8a1faeSThomas Huth })
851e8a1faeSThomas Huth 
resp_has_props(QDict * resp)861e8a1faeSThomas Huth static bool resp_has_props(QDict *resp)
871e8a1faeSThomas Huth {
881e8a1faeSThomas Huth     QDict *qdict;
891e8a1faeSThomas Huth 
901e8a1faeSThomas Huth     g_assert(resp);
911e8a1faeSThomas Huth 
921e8a1faeSThomas Huth     if (!qdict_haskey(resp, "return")) {
931e8a1faeSThomas Huth         return false;
941e8a1faeSThomas Huth     }
951e8a1faeSThomas Huth     qdict = qdict_get_qdict(resp, "return");
961e8a1faeSThomas Huth 
971e8a1faeSThomas Huth     if (!qdict_haskey(qdict, "model")) {
981e8a1faeSThomas Huth         return false;
991e8a1faeSThomas Huth     }
1001e8a1faeSThomas Huth     qdict = qdict_get_qdict(qdict, "model");
1011e8a1faeSThomas Huth 
1021e8a1faeSThomas Huth     return qdict_haskey(qdict, "props");
1031e8a1faeSThomas Huth }
1041e8a1faeSThomas Huth 
resp_get_props(QDict * resp)1051e8a1faeSThomas Huth static QDict *resp_get_props(QDict *resp)
1061e8a1faeSThomas Huth {
1071e8a1faeSThomas Huth     QDict *qdict;
1081e8a1faeSThomas Huth 
1091e8a1faeSThomas Huth     g_assert(resp);
1101e8a1faeSThomas Huth     g_assert(resp_has_props(resp));
1111e8a1faeSThomas Huth 
1121e8a1faeSThomas Huth     qdict = qdict_get_qdict(resp, "return");
1131e8a1faeSThomas Huth     qdict = qdict_get_qdict(qdict, "model");
1141e8a1faeSThomas Huth     qdict = qdict_get_qdict(qdict, "props");
1151e8a1faeSThomas Huth 
1161e8a1faeSThomas Huth     return qdict;
1171e8a1faeSThomas Huth }
1181e8a1faeSThomas Huth 
resp_get_feature(QDict * resp,const char * feature)1191e8a1faeSThomas Huth static bool resp_get_feature(QDict *resp, const char *feature)
1201e8a1faeSThomas Huth {
1211e8a1faeSThomas Huth     QDict *props;
1221e8a1faeSThomas Huth 
1231e8a1faeSThomas Huth     g_assert(resp);
1241e8a1faeSThomas Huth     g_assert(resp_has_props(resp));
1251e8a1faeSThomas Huth     props = resp_get_props(resp);
1261e8a1faeSThomas Huth     g_assert(qdict_get(props, feature));
1271e8a1faeSThomas Huth     return qdict_get_bool(props, feature);
1281e8a1faeSThomas Huth }
1291e8a1faeSThomas Huth 
1301e8a1faeSThomas Huth #define assert_has_feature(qts, cpu_type, feature)                     \
1311e8a1faeSThomas Huth ({                                                                     \
1321e8a1faeSThomas Huth     QDict *_resp = do_query_no_props(qts, cpu_type);                   \
1331e8a1faeSThomas Huth     g_assert(_resp);                                                   \
1341e8a1faeSThomas Huth     g_assert(resp_has_props(_resp));                                   \
1351e8a1faeSThomas Huth     g_assert(qdict_get(resp_get_props(_resp), feature));               \
1361e8a1faeSThomas Huth     qobject_unref(_resp);                                              \
1371e8a1faeSThomas Huth })
1381e8a1faeSThomas Huth 
1391e8a1faeSThomas Huth #define assert_has_not_feature(qts, cpu_type, feature)                 \
1401e8a1faeSThomas Huth ({                                                                     \
1411e8a1faeSThomas Huth     QDict *_resp = do_query_no_props(qts, cpu_type);                   \
1421e8a1faeSThomas Huth     g_assert(_resp);                                                   \
1431e8a1faeSThomas Huth     g_assert(!resp_has_props(_resp) ||                                 \
1441e8a1faeSThomas Huth              !qdict_get(resp_get_props(_resp), feature));              \
1451e8a1faeSThomas Huth     qobject_unref(_resp);                                              \
1461e8a1faeSThomas Huth })
1471e8a1faeSThomas Huth 
14892a70997SAndrew Jones #define resp_assert_feature(resp, feature, expected_value)             \
149789a35efSAndrew Jones ({                                                                     \
15092a70997SAndrew Jones     QDict *_props;                                                     \
151789a35efSAndrew Jones                                                                        \
152789a35efSAndrew Jones     g_assert(_resp);                                                   \
153789a35efSAndrew Jones     g_assert(resp_has_props(_resp));                                   \
154789a35efSAndrew Jones     _props = resp_get_props(_resp);                                    \
155789a35efSAndrew Jones     g_assert(qdict_get(_props, feature));                              \
156789a35efSAndrew Jones     g_assert(qdict_get_bool(_props, feature) == (expected_value));     \
15792a70997SAndrew Jones })
15892a70997SAndrew Jones 
15992a70997SAndrew Jones #define assert_feature(qts, cpu_type, feature, expected_value)         \
16092a70997SAndrew Jones ({                                                                     \
16192a70997SAndrew Jones     QDict *_resp;                                                      \
16292a70997SAndrew Jones                                                                        \
16392a70997SAndrew Jones     _resp = do_query_no_props(qts, cpu_type);                          \
16492a70997SAndrew Jones     g_assert(_resp);                                                   \
16592a70997SAndrew Jones     resp_assert_feature(_resp, feature, expected_value);               \
16692a70997SAndrew Jones     qobject_unref(_resp);                                              \
16792a70997SAndrew Jones })
16892a70997SAndrew Jones 
16992a70997SAndrew Jones #define assert_set_feature(qts, cpu_type, feature, value)              \
17092a70997SAndrew Jones ({                                                                     \
17192a70997SAndrew Jones     const char *_fmt = (value) ? "{ %s: true }" : "{ %s: false }";     \
17292a70997SAndrew Jones     QDict *_resp;                                                      \
17392a70997SAndrew Jones                                                                        \
17492a70997SAndrew Jones     _resp = do_query(qts, cpu_type, _fmt, feature);                    \
17592a70997SAndrew Jones     g_assert(_resp);                                                   \
17692a70997SAndrew Jones     resp_assert_feature(_resp, feature, value);                        \
177789a35efSAndrew Jones     qobject_unref(_resp);                                              \
178789a35efSAndrew Jones })
179789a35efSAndrew Jones 
180789a35efSAndrew Jones #define assert_has_feature_enabled(qts, cpu_type, feature)             \
181789a35efSAndrew Jones     assert_feature(qts, cpu_type, feature, true)
182789a35efSAndrew Jones 
183789a35efSAndrew Jones #define assert_has_feature_disabled(qts, cpu_type, feature)            \
184789a35efSAndrew Jones     assert_feature(qts, cpu_type, feature, false)
185789a35efSAndrew Jones 
assert_type_full(QTestState * qts)1861e8a1faeSThomas Huth static void assert_type_full(QTestState *qts)
1871e8a1faeSThomas Huth {
1881e8a1faeSThomas Huth     const char *error;
1891e8a1faeSThomas Huth     QDict *resp;
1901e8a1faeSThomas Huth 
1911e8a1faeSThomas Huth     resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
1921e8a1faeSThomas Huth                             "'arguments': { 'type': 'static', "
1931e8a1faeSThomas Huth                                            "'model': { 'name': 'foo' }}}");
1941e8a1faeSThomas Huth     g_assert(resp);
1951e8a1faeSThomas Huth     error = resp_get_error(resp);
1961e8a1faeSThomas Huth     g_assert(error);
1971e8a1faeSThomas Huth     g_assert(g_str_equal(error,
1981e8a1faeSThomas Huth                          "The requested expansion type is not supported"));
1991e8a1faeSThomas Huth     qobject_unref(resp);
2001e8a1faeSThomas Huth }
2011e8a1faeSThomas Huth 
assert_bad_props(QTestState * qts,const char * cpu_type)2021e8a1faeSThomas Huth static void assert_bad_props(QTestState *qts, const char *cpu_type)
2031e8a1faeSThomas Huth {
2041e8a1faeSThomas Huth     const char *error;
2051e8a1faeSThomas Huth     QDict *resp;
2061e8a1faeSThomas Huth 
2071e8a1faeSThomas Huth     resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
2081e8a1faeSThomas Huth                             "'arguments': { 'type': 'full', "
2091e8a1faeSThomas Huth                                            "'model': { 'name': %s, "
2101e8a1faeSThomas Huth                                                       "'props': false }}}",
2111e8a1faeSThomas Huth                      cpu_type);
2121e8a1faeSThomas Huth     g_assert(resp);
2131e8a1faeSThomas Huth     error = resp_get_error(resp);
2141e8a1faeSThomas Huth     g_assert(error);
2151e8a1faeSThomas Huth     g_assert(g_str_equal(error,
2161e8a1faeSThomas Huth                          "Invalid parameter type for 'props', expected: dict"));
2171e8a1faeSThomas Huth     qobject_unref(resp);
2181e8a1faeSThomas Huth }
2191e8a1faeSThomas Huth 
resp_get_sve_vls(QDict * resp)2201e8a1faeSThomas Huth static uint64_t resp_get_sve_vls(QDict *resp)
2211e8a1faeSThomas Huth {
2221e8a1faeSThomas Huth     QDict *props;
2231e8a1faeSThomas Huth     const QDictEntry *e;
2241e8a1faeSThomas Huth     uint64_t vls = 0;
2251e8a1faeSThomas Huth     int n = 0;
2261e8a1faeSThomas Huth 
2271e8a1faeSThomas Huth     g_assert(resp);
2281e8a1faeSThomas Huth     g_assert(resp_has_props(resp));
2291e8a1faeSThomas Huth 
2301e8a1faeSThomas Huth     props = resp_get_props(resp);
2311e8a1faeSThomas Huth 
2321e8a1faeSThomas Huth     for (e = qdict_first(props); e; e = qdict_next(props, e)) {
2331e8a1faeSThomas Huth         if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
2341e8a1faeSThomas Huth             g_ascii_isdigit(e->key[3])) {
2351e8a1faeSThomas Huth             char *endptr;
2361e8a1faeSThomas Huth             int bits;
2371e8a1faeSThomas Huth 
2381e8a1faeSThomas Huth             bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
2391e8a1faeSThomas Huth             if (!bits || *endptr != '\0') {
2401e8a1faeSThomas Huth                 continue;
2411e8a1faeSThomas Huth             }
2421e8a1faeSThomas Huth 
2431e8a1faeSThomas Huth             if (qdict_get_bool(props, e->key)) {
2441e8a1faeSThomas Huth                 vls |= BIT_ULL((bits / 128) - 1);
2451e8a1faeSThomas Huth             }
2461e8a1faeSThomas Huth             ++n;
2471e8a1faeSThomas Huth         }
2481e8a1faeSThomas Huth     }
2491e8a1faeSThomas Huth 
2501e8a1faeSThomas Huth     g_assert(n == SVE_MAX_VQ);
2511e8a1faeSThomas Huth 
2521e8a1faeSThomas Huth     return vls;
2531e8a1faeSThomas Huth }
2541e8a1faeSThomas Huth 
2551e8a1faeSThomas Huth #define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
2561e8a1faeSThomas Huth ({                                                                     \
2571e8a1faeSThomas Huth     QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
2581e8a1faeSThomas Huth     g_assert(_resp);                                                   \
2591e8a1faeSThomas Huth     g_assert(resp_has_props(_resp));                                   \
2601e8a1faeSThomas Huth     g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
2611e8a1faeSThomas Huth     qobject_unref(_resp);                                              \
2621e8a1faeSThomas Huth })
2631e8a1faeSThomas Huth 
sve_tests_default(QTestState * qts,const char * cpu_type)2641e8a1faeSThomas Huth static void sve_tests_default(QTestState *qts, const char *cpu_type)
2651e8a1faeSThomas Huth {
2661e8a1faeSThomas Huth     /*
2671e8a1faeSThomas Huth      * With no sve-max-vq or sve<N> properties on the command line
2681e8a1faeSThomas Huth      * the default is to have all vector lengths enabled. This also
2691e8a1faeSThomas Huth      * tests that 'sve' is 'on' by default.
2701e8a1faeSThomas Huth      */
2711e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, BIT_ULL(SVE_MAX_VQ) - 1, NULL);
2721e8a1faeSThomas Huth 
2731e8a1faeSThomas Huth     /* With SVE off, all vector lengths should also be off. */
2741e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
2751e8a1faeSThomas Huth 
2761e8a1faeSThomas Huth     /* With SVE on, we must have at least one vector length enabled. */
2771e8a1faeSThomas Huth     assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
2781e8a1faeSThomas Huth 
2791e8a1faeSThomas Huth     /* Basic enable/disable tests. */
2801e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve384': true }");
2811e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, ((BIT_ULL(SVE_MAX_VQ) - 1) & ~BIT_ULL(2)),
2821e8a1faeSThomas Huth                    "{ 'sve384': false }");
2831e8a1faeSThomas Huth 
2841e8a1faeSThomas Huth     /*
2851e8a1faeSThomas Huth      * ---------------------------------------------------------------------
2861e8a1faeSThomas Huth      *               power-of-two(vq)   all-power-            can      can
2871e8a1faeSThomas Huth      *                                  of-two(< vq)        enable   disable
2881e8a1faeSThomas Huth      * ---------------------------------------------------------------------
2891e8a1faeSThomas Huth      * vq < max_vq      no                MUST*              yes      yes
2901e8a1faeSThomas Huth      * vq < max_vq      yes               MUST*              yes      no
2911e8a1faeSThomas Huth      * ---------------------------------------------------------------------
2921e8a1faeSThomas Huth      * vq == max_vq     n/a               MUST*              yes**    yes**
2931e8a1faeSThomas Huth      * ---------------------------------------------------------------------
2941e8a1faeSThomas Huth      * vq > max_vq      n/a               no                 no       yes
2951e8a1faeSThomas Huth      * vq > max_vq      n/a               yes                yes      yes
2961e8a1faeSThomas Huth      * ---------------------------------------------------------------------
2971e8a1faeSThomas Huth      *
2981e8a1faeSThomas Huth      * [*] "MUST" means this requirement must already be satisfied,
2991e8a1faeSThomas Huth      *     otherwise 'max_vq' couldn't itself be enabled.
3001e8a1faeSThomas Huth      *
3011e8a1faeSThomas Huth      * [**] Not testable with the QMP interface, only with the command line.
3021e8a1faeSThomas Huth      */
3031e8a1faeSThomas Huth 
3041e8a1faeSThomas Huth     /* max_vq := 8 */
3051e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
3061e8a1faeSThomas Huth 
3071e8a1faeSThomas Huth     /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
3081e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x8f,
3091e8a1faeSThomas Huth                    "{ 'sve1024': true, 'sve384': true }");
3101e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x8b,
3111e8a1faeSThomas Huth                    "{ 'sve1024': true, 'sve384': false }");
3121e8a1faeSThomas Huth 
3131e8a1faeSThomas Huth     /* max_vq := 8, vq < max_vq, power-of-two(vq) */
3141e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x8b,
3151e8a1faeSThomas Huth                    "{ 'sve1024': true, 'sve256': true }");
3161e8a1faeSThomas Huth     assert_error(qts, cpu_type, "cannot disable sve256",
3171e8a1faeSThomas Huth                  "{ 'sve1024': true, 'sve256': false }");
3181e8a1faeSThomas Huth 
3191e8a1faeSThomas Huth     /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
3201e8a1faeSThomas Huth     assert_error(qts, cpu_type, "cannot disable sve512",
3211e8a1faeSThomas Huth                  "{ 'sve384': true, 'sve512': false, 'sve640': true }");
3221e8a1faeSThomas Huth 
3231e8a1faeSThomas Huth     /*
3241e8a1faeSThomas Huth      * We can disable power-of-two vector lengths when all larger lengths
3251e8a1faeSThomas Huth      * are also disabled. We only need to disable the power-of-two length,
3261e8a1faeSThomas Huth      * as all non-enabled larger lengths will then be auto-disabled.
3271e8a1faeSThomas Huth      */
3281e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
3291e8a1faeSThomas Huth 
3301e8a1faeSThomas Huth     /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
3311e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0x1f,
3321e8a1faeSThomas Huth                    "{ 'sve384': true, 'sve512': true, 'sve640': true }");
3331e8a1faeSThomas Huth     assert_sve_vls(qts, cpu_type, 0xf,
3341e8a1faeSThomas Huth                    "{ 'sve384': true, 'sve512': true, 'sve640': false }");
3351e8a1faeSThomas Huth }
3361e8a1faeSThomas Huth 
sve_tests_sve_max_vq_8(const void * data)3371e8a1faeSThomas Huth static void sve_tests_sve_max_vq_8(const void *data)
3381e8a1faeSThomas Huth {
3391e8a1faeSThomas Huth     QTestState *qts;
3401e8a1faeSThomas Huth 
3411e8a1faeSThomas Huth     qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
3421e8a1faeSThomas Huth 
3431e8a1faeSThomas Huth     assert_sve_vls(qts, "max", BIT_ULL(8) - 1, NULL);
3441e8a1faeSThomas Huth 
3451e8a1faeSThomas Huth     /*
3461e8a1faeSThomas Huth      * Disabling the max-vq set by sve-max-vq is not allowed, but
3471e8a1faeSThomas Huth      * of course enabling it is OK.
3481e8a1faeSThomas Huth      */
3491e8a1faeSThomas Huth     assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
3501e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
3511e8a1faeSThomas Huth 
3521e8a1faeSThomas Huth     /*
3531e8a1faeSThomas Huth      * Enabling anything larger than max-vq set by sve-max-vq is not
3541e8a1faeSThomas Huth      * allowed, but of course disabling everything larger is OK.
3551e8a1faeSThomas Huth      */
3561e8a1faeSThomas Huth     assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
3571e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
3581e8a1faeSThomas Huth 
3591e8a1faeSThomas Huth     /*
3601e8a1faeSThomas Huth      * We can enable/disable non power-of-two lengths smaller than the
3611e8a1faeSThomas Huth      * max-vq set by sve-max-vq, but, while we can enable power-of-two
3621e8a1faeSThomas Huth      * lengths, we can't disable them.
3631e8a1faeSThomas Huth      */
3641e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0xff, "{ 'sve384': true }");
3651e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
3661e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0xff, "{ 'sve256': true }");
3671e8a1faeSThomas Huth     assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
3681e8a1faeSThomas Huth 
3691e8a1faeSThomas Huth     qtest_quit(qts);
3701e8a1faeSThomas Huth }
3711e8a1faeSThomas Huth 
sve_tests_sve_off(const void * data)3721e8a1faeSThomas Huth static void sve_tests_sve_off(const void *data)
3731e8a1faeSThomas Huth {
3741e8a1faeSThomas Huth     QTestState *qts;
3751e8a1faeSThomas Huth 
3761e8a1faeSThomas Huth     qts = qtest_init(MACHINE "-cpu max,sve=off");
3771e8a1faeSThomas Huth 
3781e8a1faeSThomas Huth     /* SVE is off, so the map should be empty. */
3791e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0, NULL);
3801e8a1faeSThomas Huth 
3811e8a1faeSThomas Huth     /* The map stays empty even if we turn lengths off. */
3821e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
3831e8a1faeSThomas Huth 
3841e8a1faeSThomas Huth     /* It's an error to enable lengths when SVE is off. */
3851e8a1faeSThomas Huth     assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }");
3861e8a1faeSThomas Huth 
3871e8a1faeSThomas Huth     /* With SVE re-enabled we should get all vector lengths enabled. */
3881e8a1faeSThomas Huth     assert_sve_vls(qts, "max", BIT_ULL(SVE_MAX_VQ) - 1, "{ 'sve': true }");
3891e8a1faeSThomas Huth 
3901e8a1faeSThomas Huth     /* Or enable SVE with just specific vector lengths. */
3911e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0x3,
3921e8a1faeSThomas Huth                    "{ 'sve': true, 'sve128': true, 'sve256': true }");
3931e8a1faeSThomas Huth 
3941e8a1faeSThomas Huth     qtest_quit(qts);
3951e8a1faeSThomas Huth }
3961e8a1faeSThomas Huth 
sve_tests_sve_off_kvm(const void * data)3971e8a1faeSThomas Huth static void sve_tests_sve_off_kvm(const void *data)
3981e8a1faeSThomas Huth {
3991e8a1faeSThomas Huth     QTestState *qts;
4001e8a1faeSThomas Huth 
4011e8a1faeSThomas Huth     qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
4021e8a1faeSThomas Huth 
4031e8a1faeSThomas Huth     /*
4041e8a1faeSThomas Huth      * We don't know if this host supports SVE so we don't
4051e8a1faeSThomas Huth      * attempt to test enabling anything. We only test that
4061e8a1faeSThomas Huth      * everything is disabled (as it should be with sve=off)
4071e8a1faeSThomas Huth      * and that using sve<N>=off to explicitly disable vector
4081e8a1faeSThomas Huth      * lengths is OK too.
4091e8a1faeSThomas Huth      */
4101e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0, NULL);
4111e8a1faeSThomas Huth     assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
4121e8a1faeSThomas Huth 
4131e8a1faeSThomas Huth     qtest_quit(qts);
4141e8a1faeSThomas Huth }
4151e8a1faeSThomas Huth 
pauth_tests_default(QTestState * qts,const char * cpu_type)416eb94284dSRichard Henderson static void pauth_tests_default(QTestState *qts, const char *cpu_type)
417eb94284dSRichard Henderson {
418eb94284dSRichard Henderson     assert_has_feature_enabled(qts, cpu_type, "pauth");
419eb94284dSRichard Henderson     assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
420*399e5e71SRichard Henderson     assert_has_feature_disabled(qts, cpu_type, "pauth-qarma3");
421eb94284dSRichard Henderson     assert_set_feature(qts, cpu_type, "pauth", false);
422eb94284dSRichard Henderson     assert_set_feature(qts, cpu_type, "pauth", true);
423eb94284dSRichard Henderson     assert_set_feature(qts, cpu_type, "pauth-impdef", true);
424eb94284dSRichard Henderson     assert_set_feature(qts, cpu_type, "pauth-impdef", false);
425*399e5e71SRichard Henderson     assert_set_feature(qts, cpu_type, "pauth-qarma3", true);
426*399e5e71SRichard Henderson     assert_set_feature(qts, cpu_type, "pauth-qarma3", false);
427*399e5e71SRichard Henderson     assert_error(qts, cpu_type,
428*399e5e71SRichard Henderson                  "cannot enable pauth-impdef or pauth-qarma3 without pauth",
429eb94284dSRichard Henderson                  "{ 'pauth': false, 'pauth-impdef': true }");
430*399e5e71SRichard Henderson     assert_error(qts, cpu_type,
431*399e5e71SRichard Henderson                  "cannot enable pauth-impdef or pauth-qarma3 without pauth",
432*399e5e71SRichard Henderson                  "{ 'pauth': false, 'pauth-qarma3': true }");
433*399e5e71SRichard Henderson     assert_error(qts, cpu_type,
434*399e5e71SRichard Henderson                  "cannot enable both pauth-impdef and pauth-qarma3",
435*399e5e71SRichard Henderson                  "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true }");
436eb94284dSRichard Henderson }
437eb94284dSRichard Henderson 
test_query_cpu_model_expansion(const void * data)4381e8a1faeSThomas Huth static void test_query_cpu_model_expansion(const void *data)
4391e8a1faeSThomas Huth {
4401e8a1faeSThomas Huth     QTestState *qts;
4411e8a1faeSThomas Huth 
4421e8a1faeSThomas Huth     qts = qtest_init(MACHINE "-cpu max");
4431e8a1faeSThomas Huth 
4441e8a1faeSThomas Huth     /* Test common query-cpu-model-expansion input validation */
4451e8a1faeSThomas Huth     assert_type_full(qts);
4461e8a1faeSThomas Huth     assert_bad_props(qts, "max");
4471e8a1faeSThomas Huth     assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
4481e8a1faeSThomas Huth                  "ARM CPU type", NULL);
4491e8a1faeSThomas Huth     assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
4501e8a1faeSThomas Huth                  "{ 'not-a-prop': false }");
4511e8a1faeSThomas Huth     assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
4521e8a1faeSThomas Huth 
4531e8a1faeSThomas Huth     /* Test expected feature presence/absence for some cpu types */
454789a35efSAndrew Jones     assert_has_feature_enabled(qts, "cortex-a15", "pmu");
4551e8a1faeSThomas Huth     assert_has_not_feature(qts, "cortex-a15", "aarch64");
4561e8a1faeSThomas Huth 
45792a70997SAndrew Jones     /* Enabling and disabling pmu should always work. */
45892a70997SAndrew Jones     assert_has_feature_enabled(qts, "max", "pmu");
45992a70997SAndrew Jones     assert_set_feature(qts, "max", "pmu", false);
46092a70997SAndrew Jones     assert_set_feature(qts, "max", "pmu", true);
46192a70997SAndrew Jones 
462dea101a1SAndrew Jones     assert_has_not_feature(qts, "max", "kvm-no-adjvtime");
46368970d1eSAndrew Jones     assert_has_not_feature(qts, "max", "kvm-steal-time");
464dea101a1SAndrew Jones 
4651e8a1faeSThomas Huth     if (g_str_equal(qtest_get_arch(), "aarch64")) {
466789a35efSAndrew Jones         assert_has_feature_enabled(qts, "max", "aarch64");
467789a35efSAndrew Jones         assert_has_feature_enabled(qts, "max", "sve");
468789a35efSAndrew Jones         assert_has_feature_enabled(qts, "max", "sve128");
469789a35efSAndrew Jones         assert_has_feature_enabled(qts, "cortex-a57", "pmu");
470789a35efSAndrew Jones         assert_has_feature_enabled(qts, "cortex-a57", "aarch64");
4711e8a1faeSThomas Huth 
472499243e1SShuuichirou Ishii         assert_has_feature_enabled(qts, "a64fx", "pmu");
473499243e1SShuuichirou Ishii         assert_has_feature_enabled(qts, "a64fx", "aarch64");
474499243e1SShuuichirou Ishii         /*
475499243e1SShuuichirou Ishii          * A64FX does not support any other vector lengths besides those
476499243e1SShuuichirou Ishii          * that are enabled by default(128bit, 256bits, 512bit).
477499243e1SShuuichirou Ishii          */
478499243e1SShuuichirou Ishii         assert_has_feature_enabled(qts, "a64fx", "sve");
479499243e1SShuuichirou Ishii         assert_sve_vls(qts, "a64fx", 0xb, NULL);
480499243e1SShuuichirou Ishii         assert_error(qts, "a64fx", "cannot enable sve384",
481499243e1SShuuichirou Ishii                      "{ 'sve384': true }");
482499243e1SShuuichirou Ishii         assert_error(qts, "a64fx", "cannot enable sve640",
483499243e1SShuuichirou Ishii                      "{ 'sve640': true }");
484499243e1SShuuichirou Ishii 
4851e8a1faeSThomas Huth         sve_tests_default(qts, "max");
486eb94284dSRichard Henderson         pauth_tests_default(qts, "max");
4871e8a1faeSThomas Huth 
4881e8a1faeSThomas Huth         /* Test that features that depend on KVM generate errors without. */
4891e8a1faeSThomas Huth         assert_error(qts, "max",
4901e8a1faeSThomas Huth                      "'aarch64' feature cannot be disabled "
4911e8a1faeSThomas Huth                      "unless KVM is enabled and 32-bit EL1 "
4921e8a1faeSThomas Huth                      "is supported",
4931e8a1faeSThomas Huth                      "{ 'aarch64': false }");
4941e8a1faeSThomas Huth     }
4951e8a1faeSThomas Huth 
4961e8a1faeSThomas Huth     qtest_quit(qts);
4971e8a1faeSThomas Huth }
4981e8a1faeSThomas Huth 
test_query_cpu_model_expansion_kvm(const void * data)4991e8a1faeSThomas Huth static void test_query_cpu_model_expansion_kvm(const void *data)
5001e8a1faeSThomas Huth {
5011e8a1faeSThomas Huth     QTestState *qts;
5021e8a1faeSThomas Huth 
5031e8a1faeSThomas Huth     qts = qtest_init(MACHINE_KVM "-cpu max");
5041e8a1faeSThomas Huth 
50592a70997SAndrew Jones     /* Enabling and disabling kvm-no-adjvtime should always work. */
506dea101a1SAndrew Jones     assert_has_feature_disabled(qts, "host", "kvm-no-adjvtime");
50792a70997SAndrew Jones     assert_set_feature(qts, "host", "kvm-no-adjvtime", true);
50892a70997SAndrew Jones     assert_set_feature(qts, "host", "kvm-no-adjvtime", false);
509dea101a1SAndrew Jones 
5101e8a1faeSThomas Huth     if (g_str_equal(qtest_get_arch(), "aarch64")) {
51168970d1eSAndrew Jones         bool kvm_supports_steal_time;
5121e8a1faeSThomas Huth         bool kvm_supports_sve;
5131e8a1faeSThomas Huth         char max_name[8], name[8];
5141e8a1faeSThomas Huth         uint32_t max_vq, vq;
5151e8a1faeSThomas Huth         uint64_t vls;
5161e8a1faeSThomas Huth         QDict *resp;
5171e8a1faeSThomas Huth         char *error;
5181e8a1faeSThomas Huth 
519557ed03aSFabiano Rosas         /*
520557ed03aSFabiano Rosas          * When using KVM, only the 'host' and 'max' CPU models are
521557ed03aSFabiano Rosas          * supported. Test that we're emitting a suitable error for
522557ed03aSFabiano Rosas          * unsupported CPU models.
523557ed03aSFabiano Rosas          */
524557ed03aSFabiano Rosas         if (qtest_has_accel("tcg")) {
525557ed03aSFabiano Rosas             assert_error(qts, "cortex-a7",
526557ed03aSFabiano Rosas                          "We cannot guarantee the CPU type 'cortex-a7' works "
52768970d1eSAndrew Jones                          "with KVM on this host", NULL);
528557ed03aSFabiano Rosas         } else {
529557ed03aSFabiano Rosas             /*
530557ed03aSFabiano Rosas              * With a KVM-only build the 32-bit CPUs are not present.
531557ed03aSFabiano Rosas              */
532557ed03aSFabiano Rosas             assert_error(qts, "cortex-a7",
533557ed03aSFabiano Rosas                          "The CPU type 'cortex-a7' is not a "
534557ed03aSFabiano Rosas                          "recognized ARM CPU type", NULL);
535557ed03aSFabiano Rosas         }
53668970d1eSAndrew Jones 
537789a35efSAndrew Jones         assert_has_feature_enabled(qts, "host", "aarch64");
53892a70997SAndrew Jones 
53992a70997SAndrew Jones         /* Enabling and disabling pmu should always work. */
540789a35efSAndrew Jones         assert_has_feature_enabled(qts, "host", "pmu");
54192a70997SAndrew Jones         assert_set_feature(qts, "host", "pmu", false);
54292a70997SAndrew Jones         assert_set_feature(qts, "host", "pmu", true);
5431e8a1faeSThomas Huth 
54468970d1eSAndrew Jones         /*
54568970d1eSAndrew Jones          * Some features would be enabled by default, but they're disabled
54668970d1eSAndrew Jones          * because this instance of KVM doesn't support them. Test that the
54768970d1eSAndrew Jones          * features are present, and, when enabled, issue further tests.
54868970d1eSAndrew Jones          */
54968970d1eSAndrew Jones         assert_has_feature(qts, "host", "kvm-steal-time");
5501e8a1faeSThomas Huth         assert_has_feature(qts, "host", "sve");
55168970d1eSAndrew Jones 
5521e8a1faeSThomas Huth         resp = do_query_no_props(qts, "host");
55368970d1eSAndrew Jones         kvm_supports_steal_time = resp_get_feature(resp, "kvm-steal-time");
5541e8a1faeSThomas Huth         kvm_supports_sve = resp_get_feature(resp, "sve");
5551e8a1faeSThomas Huth         vls = resp_get_sve_vls(resp);
5561e8a1faeSThomas Huth         qobject_unref(resp);
5571e8a1faeSThomas Huth 
55868970d1eSAndrew Jones         if (kvm_supports_steal_time) {
55968970d1eSAndrew Jones             /* If we have steal-time then we should be able to toggle it. */
56068970d1eSAndrew Jones             assert_set_feature(qts, "host", "kvm-steal-time", false);
56168970d1eSAndrew Jones             assert_set_feature(qts, "host", "kvm-steal-time", true);
56268970d1eSAndrew Jones         }
56368970d1eSAndrew Jones 
5641e8a1faeSThomas Huth         if (kvm_supports_sve) {
5651e8a1faeSThomas Huth             g_assert(vls != 0);
5661e8a1faeSThomas Huth             max_vq = 64 - __builtin_clzll(vls);
5673dc05792SAlexChen             sprintf(max_name, "sve%u", max_vq * 128);
5681e8a1faeSThomas Huth 
5691e8a1faeSThomas Huth             /* Enabling a supported length is of course fine. */
5701e8a1faeSThomas Huth             assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
5711e8a1faeSThomas Huth 
5721e8a1faeSThomas Huth             /* Get the next supported length smaller than max-vq. */
5731e8a1faeSThomas Huth             vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
5741e8a1faeSThomas Huth             if (vq) {
5751e8a1faeSThomas Huth                 /*
5761e8a1faeSThomas Huth                  * We have at least one length smaller than max-vq,
5771e8a1faeSThomas Huth                  * so we can disable max-vq.
5781e8a1faeSThomas Huth                  */
5791e8a1faeSThomas Huth                 assert_sve_vls(qts, "host", (vls & ~BIT_ULL(max_vq - 1)),
5801e8a1faeSThomas Huth                                "{ %s: false }", max_name);
5811e8a1faeSThomas Huth 
5821e8a1faeSThomas Huth                 /*
5831e8a1faeSThomas Huth                  * Smaller, supported vector lengths cannot be disabled
5841e8a1faeSThomas Huth                  * unless all larger, supported vector lengths are also
5851e8a1faeSThomas Huth                  * disabled.
5861e8a1faeSThomas Huth                  */
5873dc05792SAlexChen                 sprintf(name, "sve%u", vq * 128);
5881e8a1faeSThomas Huth                 error = g_strdup_printf("cannot disable %s", name);
5891e8a1faeSThomas Huth                 assert_error(qts, "host", error,
5901e8a1faeSThomas Huth                              "{ %s: true, %s: false }",
5911e8a1faeSThomas Huth                              max_name, name);
5921e8a1faeSThomas Huth                 g_free(error);
5931e8a1faeSThomas Huth             }
5941e8a1faeSThomas Huth 
5951e8a1faeSThomas Huth             /*
5961e8a1faeSThomas Huth              * The smallest, supported vector length is required, because
5971e8a1faeSThomas Huth              * we need at least one vector length enabled.
5981e8a1faeSThomas Huth              */
5991e8a1faeSThomas Huth             vq = __builtin_ffsll(vls);
6003dc05792SAlexChen             sprintf(name, "sve%u", vq * 128);
6011e8a1faeSThomas Huth             error = g_strdup_printf("cannot disable %s", name);
6021e8a1faeSThomas Huth             assert_error(qts, "host", error, "{ %s: false }", name);
6031e8a1faeSThomas Huth             g_free(error);
6041e8a1faeSThomas Huth 
6051e8a1faeSThomas Huth             /* Get an unsupported length. */
6061e8a1faeSThomas Huth             for (vq = 1; vq <= max_vq; ++vq) {
6071e8a1faeSThomas Huth                 if (!(vls & BIT_ULL(vq - 1))) {
6081e8a1faeSThomas Huth                     break;
6091e8a1faeSThomas Huth                 }
6101e8a1faeSThomas Huth             }
6111e8a1faeSThomas Huth             if (vq <= SVE_MAX_VQ) {
6123dc05792SAlexChen                 sprintf(name, "sve%u", vq * 128);
6131e8a1faeSThomas Huth                 error = g_strdup_printf("cannot enable %s", name);
6141e8a1faeSThomas Huth                 assert_error(qts, "host", error, "{ %s: true }", name);
6151e8a1faeSThomas Huth                 g_free(error);
6161e8a1faeSThomas Huth             }
6171e8a1faeSThomas Huth         } else {
6181e8a1faeSThomas Huth             g_assert(vls == 0);
6191e8a1faeSThomas Huth         }
6201e8a1faeSThomas Huth     } else {
6211e8a1faeSThomas Huth         assert_has_not_feature(qts, "host", "aarch64");
6221e8a1faeSThomas Huth         assert_has_not_feature(qts, "host", "pmu");
6231e8a1faeSThomas Huth         assert_has_not_feature(qts, "host", "sve");
62468970d1eSAndrew Jones         assert_has_not_feature(qts, "host", "kvm-steal-time");
6251e8a1faeSThomas Huth     }
6261e8a1faeSThomas Huth 
6271e8a1faeSThomas Huth     qtest_quit(qts);
6281e8a1faeSThomas Huth }
6291e8a1faeSThomas Huth 
main(int argc,char ** argv)6301e8a1faeSThomas Huth int main(int argc, char **argv)
6311e8a1faeSThomas Huth {
6321e8a1faeSThomas Huth     g_test_init(&argc, &argv, NULL);
6331e8a1faeSThomas Huth 
634500a0accSFabiano Rosas     if (qtest_has_accel("tcg")) {
6351e8a1faeSThomas Huth         qtest_add_data_func("/arm/query-cpu-model-expansion",
6361e8a1faeSThomas Huth                             NULL, test_query_cpu_model_expansion);
637500a0accSFabiano Rosas     }
638500a0accSFabiano Rosas 
639500a0accSFabiano Rosas     if (!g_str_equal(qtest_get_arch(), "aarch64")) {
640500a0accSFabiano Rosas         goto out;
641500a0accSFabiano Rosas     }
6421e8a1faeSThomas Huth 
6431e8a1faeSThomas Huth     /*
6441e8a1faeSThomas Huth      * For now we only run KVM specific tests with AArch64 QEMU in
6451e8a1faeSThomas Huth      * order avoid attempting to run an AArch32 QEMU with KVM on
6461e8a1faeSThomas Huth      * AArch64 hosts. That won't work and isn't easy to detect.
6471e8a1faeSThomas Huth      */
648500a0accSFabiano Rosas     if (qtest_has_accel("kvm")) {
64907e6ed2cSIgor Mammedov         /*
65007e6ed2cSIgor Mammedov          * This tests target the 'host' CPU type, so register it only if
65107e6ed2cSIgor Mammedov          * KVM is available.
65207e6ed2cSIgor Mammedov          */
6531e8a1faeSThomas Huth         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
6541e8a1faeSThomas Huth                             NULL, test_query_cpu_model_expansion_kvm);
6551e8a1faeSThomas Huth 
6561e8a1faeSThomas Huth         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
6571e8a1faeSThomas Huth                             NULL, sve_tests_sve_off_kvm);
6581e8a1faeSThomas Huth     }
6591e8a1faeSThomas Huth 
660500a0accSFabiano Rosas     if (qtest_has_accel("tcg")) {
661500a0accSFabiano Rosas         qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
662500a0accSFabiano Rosas                             NULL, sve_tests_sve_max_vq_8);
663500a0accSFabiano Rosas         qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
664500a0accSFabiano Rosas                             NULL, sve_tests_sve_off);
665500a0accSFabiano Rosas     }
666500a0accSFabiano Rosas 
667500a0accSFabiano Rosas out:
6681e8a1faeSThomas Huth     return g_test_run();
6691e8a1faeSThomas Huth }
670