xref: /qemu/tests/qtest/arm-cpu-features.c (revision 6fa8a37949d912bb463caa0c139ff0ca88c6ec33)
1bd31b751SAndrew Jones /*
2bd31b751SAndrew Jones  * Arm CPU feature test cases
3bd31b751SAndrew Jones  *
4bd31b751SAndrew Jones  * Copyright (c) 2019 Red Hat Inc.
5bd31b751SAndrew Jones  * Authors:
6bd31b751SAndrew Jones  *  Andrew Jones <drjones@redhat.com>
7bd31b751SAndrew Jones  *
8bd31b751SAndrew Jones  * This work is licensed under the terms of the GNU GPL, version 2 or later.
9bd31b751SAndrew Jones  * See the COPYING file in the top-level directory.
10bd31b751SAndrew Jones  */
11bd31b751SAndrew Jones #include "qemu/osdep.h"
120df9142dSAndrew Jones #include "qemu/bitops.h"
13bd31b751SAndrew Jones #include "libqtest.h"
14bd31b751SAndrew Jones #include "qapi/qmp/qdict.h"
15bd31b751SAndrew Jones #include "qapi/qmp/qjson.h"
16bd31b751SAndrew Jones 
170df9142dSAndrew Jones /*
180df9142dSAndrew Jones  * We expect the SVE max-vq to be 16. Also it must be <= 64
190df9142dSAndrew Jones  * for our test code, otherwise 'vls' can't just be a uint64_t.
200df9142dSAndrew Jones  */
210df9142dSAndrew Jones #define SVE_MAX_VQ 16
220df9142dSAndrew Jones 
23bd31b751SAndrew Jones #define MACHINE     "-machine virt,gic-version=max,accel=tcg "
24bd31b751SAndrew Jones #define MACHINE_KVM "-machine virt,gic-version=max,accel=kvm:tcg "
25bd31b751SAndrew Jones #define QUERY_HEAD  "{ 'execute': 'query-cpu-model-expansion', " \
26bd31b751SAndrew Jones                     "  'arguments': { 'type': 'full', "
27bd31b751SAndrew Jones #define QUERY_TAIL  "}}"
28bd31b751SAndrew Jones 
29bd31b751SAndrew Jones static bool kvm_enabled(QTestState *qts)
30bd31b751SAndrew Jones {
31bd31b751SAndrew Jones     QDict *resp, *qdict;
32bd31b751SAndrew Jones     bool enabled;
33bd31b751SAndrew Jones 
34bd31b751SAndrew Jones     resp = qtest_qmp(qts, "{ 'execute': 'query-kvm' }");
35bd31b751SAndrew Jones     g_assert(qdict_haskey(resp, "return"));
36bd31b751SAndrew Jones     qdict = qdict_get_qdict(resp, "return");
37bd31b751SAndrew Jones     g_assert(qdict_haskey(qdict, "enabled"));
38bd31b751SAndrew Jones     enabled = qdict_get_bool(qdict, "enabled");
39bd31b751SAndrew Jones     qobject_unref(resp);
40bd31b751SAndrew Jones 
41bd31b751SAndrew Jones     return enabled;
42bd31b751SAndrew Jones }
43bd31b751SAndrew Jones 
44bd31b751SAndrew Jones static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
45bd31b751SAndrew Jones {
46bd31b751SAndrew Jones     return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
47bd31b751SAndrew Jones                           QUERY_TAIL, cpu_type);
48bd31b751SAndrew Jones }
49bd31b751SAndrew Jones 
50bd31b751SAndrew Jones static QDict *do_query(QTestState *qts, const char *cpu_type,
51bd31b751SAndrew Jones                        const char *fmt, ...)
52bd31b751SAndrew Jones {
53bd31b751SAndrew Jones     QDict *resp;
54bd31b751SAndrew Jones 
55bd31b751SAndrew Jones     if (fmt) {
56bd31b751SAndrew Jones         QDict *args;
57bd31b751SAndrew Jones         va_list ap;
58bd31b751SAndrew Jones 
59bd31b751SAndrew Jones         va_start(ap, fmt);
60bd31b751SAndrew Jones         args = qdict_from_vjsonf_nofail(fmt, ap);
61bd31b751SAndrew Jones         va_end(ap);
62bd31b751SAndrew Jones 
63bd31b751SAndrew Jones         resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
64bd31b751SAndrew Jones                                                     "'props': %p }"
65bd31b751SAndrew Jones                               QUERY_TAIL, cpu_type, args);
66bd31b751SAndrew Jones     } else {
67bd31b751SAndrew Jones         resp = do_query_no_props(qts, cpu_type);
68bd31b751SAndrew Jones     }
69bd31b751SAndrew Jones 
70bd31b751SAndrew Jones     return resp;
71bd31b751SAndrew Jones }
72bd31b751SAndrew Jones 
73bd31b751SAndrew Jones static const char *resp_get_error(QDict *resp)
74bd31b751SAndrew Jones {
75bd31b751SAndrew Jones     QDict *qdict;
76bd31b751SAndrew Jones 
77bd31b751SAndrew Jones     g_assert(resp);
78bd31b751SAndrew Jones 
79bd31b751SAndrew Jones     qdict = qdict_get_qdict(resp, "error");
80bd31b751SAndrew Jones     if (qdict) {
81bd31b751SAndrew Jones         return qdict_get_str(qdict, "desc");
82bd31b751SAndrew Jones     }
83bd31b751SAndrew Jones 
84bd31b751SAndrew Jones     return NULL;
85bd31b751SAndrew Jones }
86bd31b751SAndrew Jones 
87bd31b751SAndrew Jones #define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
88bd31b751SAndrew Jones ({                                                                     \
89bd31b751SAndrew Jones     QDict *_resp;                                                      \
90bd31b751SAndrew Jones     const char *_error;                                                \
91bd31b751SAndrew Jones                                                                        \
92bd31b751SAndrew Jones     _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
93bd31b751SAndrew Jones     g_assert(_resp);                                                   \
94bd31b751SAndrew Jones     _error = resp_get_error(_resp);                                    \
95bd31b751SAndrew Jones     g_assert(_error);                                                  \
96bd31b751SAndrew Jones     g_assert(g_str_equal(_error, expected_error));                     \
97bd31b751SAndrew Jones     qobject_unref(_resp);                                              \
98bd31b751SAndrew Jones })
99bd31b751SAndrew Jones 
100bd31b751SAndrew Jones static bool resp_has_props(QDict *resp)
101bd31b751SAndrew Jones {
102bd31b751SAndrew Jones     QDict *qdict;
103bd31b751SAndrew Jones 
104bd31b751SAndrew Jones     g_assert(resp);
105bd31b751SAndrew Jones 
106bd31b751SAndrew Jones     if (!qdict_haskey(resp, "return")) {
107bd31b751SAndrew Jones         return false;
108bd31b751SAndrew Jones     }
109bd31b751SAndrew Jones     qdict = qdict_get_qdict(resp, "return");
110bd31b751SAndrew Jones 
111bd31b751SAndrew Jones     if (!qdict_haskey(qdict, "model")) {
112bd31b751SAndrew Jones         return false;
113bd31b751SAndrew Jones     }
114bd31b751SAndrew Jones     qdict = qdict_get_qdict(qdict, "model");
115bd31b751SAndrew Jones 
116bd31b751SAndrew Jones     return qdict_haskey(qdict, "props");
117bd31b751SAndrew Jones }
118bd31b751SAndrew Jones 
119bd31b751SAndrew Jones static QDict *resp_get_props(QDict *resp)
120bd31b751SAndrew Jones {
121bd31b751SAndrew Jones     QDict *qdict;
122bd31b751SAndrew Jones 
123bd31b751SAndrew Jones     g_assert(resp);
124bd31b751SAndrew Jones     g_assert(resp_has_props(resp));
125bd31b751SAndrew Jones 
126bd31b751SAndrew Jones     qdict = qdict_get_qdict(resp, "return");
127bd31b751SAndrew Jones     qdict = qdict_get_qdict(qdict, "model");
128bd31b751SAndrew Jones     qdict = qdict_get_qdict(qdict, "props");
129bd31b751SAndrew Jones 
130bd31b751SAndrew Jones     return qdict;
131bd31b751SAndrew Jones }
132bd31b751SAndrew Jones 
133*6fa8a379SAndrew Jones static bool resp_get_feature(QDict *resp, const char *feature)
134*6fa8a379SAndrew Jones {
135*6fa8a379SAndrew Jones     QDict *props;
136*6fa8a379SAndrew Jones 
137*6fa8a379SAndrew Jones     g_assert(resp);
138*6fa8a379SAndrew Jones     g_assert(resp_has_props(resp));
139*6fa8a379SAndrew Jones     props = resp_get_props(resp);
140*6fa8a379SAndrew Jones     g_assert(qdict_get(props, feature));
141*6fa8a379SAndrew Jones     return qdict_get_bool(props, feature);
142*6fa8a379SAndrew Jones }
143*6fa8a379SAndrew Jones 
144bd31b751SAndrew Jones #define assert_has_feature(qts, cpu_type, feature)                     \
145bd31b751SAndrew Jones ({                                                                     \
146bd31b751SAndrew Jones     QDict *_resp = do_query_no_props(qts, cpu_type);                   \
147bd31b751SAndrew Jones     g_assert(_resp);                                                   \
148bd31b751SAndrew Jones     g_assert(resp_has_props(_resp));                                   \
149bd31b751SAndrew Jones     g_assert(qdict_get(resp_get_props(_resp), feature));               \
150bd31b751SAndrew Jones     qobject_unref(_resp);                                              \
151bd31b751SAndrew Jones })
152bd31b751SAndrew Jones 
153bd31b751SAndrew Jones #define assert_has_not_feature(qts, cpu_type, feature)                 \
154bd31b751SAndrew Jones ({                                                                     \
155bd31b751SAndrew Jones     QDict *_resp = do_query_no_props(qts, cpu_type);                   \
156bd31b751SAndrew Jones     g_assert(_resp);                                                   \
157bd31b751SAndrew Jones     g_assert(!resp_has_props(_resp) ||                                 \
158bd31b751SAndrew Jones              !qdict_get(resp_get_props(_resp), feature));              \
159bd31b751SAndrew Jones     qobject_unref(_resp);                                              \
160bd31b751SAndrew Jones })
161bd31b751SAndrew Jones 
162bd31b751SAndrew Jones static void assert_type_full(QTestState *qts)
163bd31b751SAndrew Jones {
164bd31b751SAndrew Jones     const char *error;
165bd31b751SAndrew Jones     QDict *resp;
166bd31b751SAndrew Jones 
167bd31b751SAndrew Jones     resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
168bd31b751SAndrew Jones                             "'arguments': { 'type': 'static', "
169bd31b751SAndrew Jones                                            "'model': { 'name': 'foo' }}}");
170bd31b751SAndrew Jones     g_assert(resp);
171bd31b751SAndrew Jones     error = resp_get_error(resp);
172bd31b751SAndrew Jones     g_assert(error);
173bd31b751SAndrew Jones     g_assert(g_str_equal(error,
174bd31b751SAndrew Jones                          "The requested expansion type is not supported"));
175bd31b751SAndrew Jones     qobject_unref(resp);
176bd31b751SAndrew Jones }
177bd31b751SAndrew Jones 
178bd31b751SAndrew Jones static void assert_bad_props(QTestState *qts, const char *cpu_type)
179bd31b751SAndrew Jones {
180bd31b751SAndrew Jones     const char *error;
181bd31b751SAndrew Jones     QDict *resp;
182bd31b751SAndrew Jones 
183bd31b751SAndrew Jones     resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
184bd31b751SAndrew Jones                             "'arguments': { 'type': 'full', "
185bd31b751SAndrew Jones                                            "'model': { 'name': %s, "
186bd31b751SAndrew Jones                                                       "'props': false }}}",
187bd31b751SAndrew Jones                      cpu_type);
188bd31b751SAndrew Jones     g_assert(resp);
189bd31b751SAndrew Jones     error = resp_get_error(resp);
190bd31b751SAndrew Jones     g_assert(error);
191bd31b751SAndrew Jones     g_assert(g_str_equal(error,
192bd31b751SAndrew Jones                          "Invalid parameter type for 'props', expected: dict"));
193bd31b751SAndrew Jones     qobject_unref(resp);
194bd31b751SAndrew Jones }
195bd31b751SAndrew Jones 
1960df9142dSAndrew Jones static uint64_t resp_get_sve_vls(QDict *resp)
1970df9142dSAndrew Jones {
1980df9142dSAndrew Jones     QDict *props;
1990df9142dSAndrew Jones     const QDictEntry *e;
2000df9142dSAndrew Jones     uint64_t vls = 0;
2010df9142dSAndrew Jones     int n = 0;
2020df9142dSAndrew Jones 
2030df9142dSAndrew Jones     g_assert(resp);
2040df9142dSAndrew Jones     g_assert(resp_has_props(resp));
2050df9142dSAndrew Jones 
2060df9142dSAndrew Jones     props = resp_get_props(resp);
2070df9142dSAndrew Jones 
2080df9142dSAndrew Jones     for (e = qdict_first(props); e; e = qdict_next(props, e)) {
2090df9142dSAndrew Jones         if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
2100df9142dSAndrew Jones             g_ascii_isdigit(e->key[3])) {
2110df9142dSAndrew Jones             char *endptr;
2120df9142dSAndrew Jones             int bits;
2130df9142dSAndrew Jones 
2140df9142dSAndrew Jones             bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
2150df9142dSAndrew Jones             if (!bits || *endptr != '\0') {
2160df9142dSAndrew Jones                 continue;
2170df9142dSAndrew Jones             }
2180df9142dSAndrew Jones 
2190df9142dSAndrew Jones             if (qdict_get_bool(props, e->key)) {
2200df9142dSAndrew Jones                 vls |= BIT_ULL((bits / 128) - 1);
2210df9142dSAndrew Jones             }
2220df9142dSAndrew Jones             ++n;
2230df9142dSAndrew Jones         }
2240df9142dSAndrew Jones     }
2250df9142dSAndrew Jones 
2260df9142dSAndrew Jones     g_assert(n == SVE_MAX_VQ);
2270df9142dSAndrew Jones 
2280df9142dSAndrew Jones     return vls;
2290df9142dSAndrew Jones }
2300df9142dSAndrew Jones 
2310df9142dSAndrew Jones #define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
2320df9142dSAndrew Jones ({                                                                     \
2330df9142dSAndrew Jones     QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
2340df9142dSAndrew Jones     g_assert(_resp);                                                   \
2350df9142dSAndrew Jones     g_assert(resp_has_props(_resp));                                   \
2360df9142dSAndrew Jones     g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
2370df9142dSAndrew Jones     qobject_unref(_resp);                                              \
2380df9142dSAndrew Jones })
2390df9142dSAndrew Jones 
2400df9142dSAndrew Jones static void sve_tests_default(QTestState *qts, const char *cpu_type)
2410df9142dSAndrew Jones {
2420df9142dSAndrew Jones     /*
2430df9142dSAndrew Jones      * With no sve-max-vq or sve<N> properties on the command line
2440df9142dSAndrew Jones      * the default is to have all vector lengths enabled. This also
2450df9142dSAndrew Jones      * tests that 'sve' is 'on' by default.
2460df9142dSAndrew Jones      */
2470df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, BIT_ULL(SVE_MAX_VQ) - 1, NULL);
2480df9142dSAndrew Jones 
2490df9142dSAndrew Jones     /* With SVE off, all vector lengths should also be off. */
2500df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
2510df9142dSAndrew Jones 
2520df9142dSAndrew Jones     /* With SVE on, we must have at least one vector length enabled. */
2530df9142dSAndrew Jones     assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
2540df9142dSAndrew Jones 
2550df9142dSAndrew Jones     /* Basic enable/disable tests. */
2560df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve384': true }");
2570df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, ((BIT_ULL(SVE_MAX_VQ) - 1) & ~BIT_ULL(2)),
2580df9142dSAndrew Jones                    "{ 'sve384': false }");
2590df9142dSAndrew Jones 
2600df9142dSAndrew Jones     /*
2610df9142dSAndrew Jones      * ---------------------------------------------------------------------
2620df9142dSAndrew Jones      *               power-of-two(vq)   all-power-            can      can
2630df9142dSAndrew Jones      *                                  of-two(< vq)        enable   disable
2640df9142dSAndrew Jones      * ---------------------------------------------------------------------
2650df9142dSAndrew Jones      * vq < max_vq      no                MUST*              yes      yes
2660df9142dSAndrew Jones      * vq < max_vq      yes               MUST*              yes      no
2670df9142dSAndrew Jones      * ---------------------------------------------------------------------
2680df9142dSAndrew Jones      * vq == max_vq     n/a               MUST*              yes**    yes**
2690df9142dSAndrew Jones      * ---------------------------------------------------------------------
2700df9142dSAndrew Jones      * vq > max_vq      n/a               no                 no       yes
2710df9142dSAndrew Jones      * vq > max_vq      n/a               yes                yes      yes
2720df9142dSAndrew Jones      * ---------------------------------------------------------------------
2730df9142dSAndrew Jones      *
2740df9142dSAndrew Jones      * [*] "MUST" means this requirement must already be satisfied,
2750df9142dSAndrew Jones      *     otherwise 'max_vq' couldn't itself be enabled.
2760df9142dSAndrew Jones      *
2770df9142dSAndrew Jones      * [**] Not testable with the QMP interface, only with the command line.
2780df9142dSAndrew Jones      */
2790df9142dSAndrew Jones 
2800df9142dSAndrew Jones     /* max_vq := 8 */
2810df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
2820df9142dSAndrew Jones 
2830df9142dSAndrew Jones     /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
2840df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x8f,
2850df9142dSAndrew Jones                    "{ 'sve1024': true, 'sve384': true }");
2860df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x8b,
2870df9142dSAndrew Jones                    "{ 'sve1024': true, 'sve384': false }");
2880df9142dSAndrew Jones 
2890df9142dSAndrew Jones     /* max_vq := 8, vq < max_vq, power-of-two(vq) */
2900df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x8b,
2910df9142dSAndrew Jones                    "{ 'sve1024': true, 'sve256': true }");
2920df9142dSAndrew Jones     assert_error(qts, cpu_type, "cannot disable sve256",
2930df9142dSAndrew Jones                  "{ 'sve1024': true, 'sve256': false }");
2940df9142dSAndrew Jones 
2950df9142dSAndrew Jones     /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
2960df9142dSAndrew Jones     assert_error(qts, cpu_type, "cannot disable sve512",
2970df9142dSAndrew Jones                  "{ 'sve384': true, 'sve512': false, 'sve640': true }");
2980df9142dSAndrew Jones 
2990df9142dSAndrew Jones     /*
3000df9142dSAndrew Jones      * We can disable power-of-two vector lengths when all larger lengths
3010df9142dSAndrew Jones      * are also disabled. We only need to disable the power-of-two length,
3020df9142dSAndrew Jones      * as all non-enabled larger lengths will then be auto-disabled.
3030df9142dSAndrew Jones      */
3040df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
3050df9142dSAndrew Jones 
3060df9142dSAndrew Jones     /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
3070df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0x1f,
3080df9142dSAndrew Jones                    "{ 'sve384': true, 'sve512': true, 'sve640': true }");
3090df9142dSAndrew Jones     assert_sve_vls(qts, cpu_type, 0xf,
3100df9142dSAndrew Jones                    "{ 'sve384': true, 'sve512': true, 'sve640': false }");
3110df9142dSAndrew Jones }
3120df9142dSAndrew Jones 
3130df9142dSAndrew Jones static void sve_tests_sve_max_vq_8(const void *data)
3140df9142dSAndrew Jones {
3150df9142dSAndrew Jones     QTestState *qts;
3160df9142dSAndrew Jones 
3170df9142dSAndrew Jones     qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
3180df9142dSAndrew Jones 
3190df9142dSAndrew Jones     assert_sve_vls(qts, "max", BIT_ULL(8) - 1, NULL);
3200df9142dSAndrew Jones 
3210df9142dSAndrew Jones     /*
3220df9142dSAndrew Jones      * Disabling the max-vq set by sve-max-vq is not allowed, but
3230df9142dSAndrew Jones      * of course enabling it is OK.
3240df9142dSAndrew Jones      */
3250df9142dSAndrew Jones     assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
3260df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
3270df9142dSAndrew Jones 
3280df9142dSAndrew Jones     /*
3290df9142dSAndrew Jones      * Enabling anything larger than max-vq set by sve-max-vq is not
3300df9142dSAndrew Jones      * allowed, but of course disabling everything larger is OK.
3310df9142dSAndrew Jones      */
3320df9142dSAndrew Jones     assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
3330df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
3340df9142dSAndrew Jones 
3350df9142dSAndrew Jones     /*
3360df9142dSAndrew Jones      * We can enable/disable non power-of-two lengths smaller than the
3370df9142dSAndrew Jones      * max-vq set by sve-max-vq, but, while we can enable power-of-two
3380df9142dSAndrew Jones      * lengths, we can't disable them.
3390df9142dSAndrew Jones      */
3400df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0xff, "{ 'sve384': true }");
3410df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
3420df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0xff, "{ 'sve256': true }");
3430df9142dSAndrew Jones     assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
3440df9142dSAndrew Jones 
3450df9142dSAndrew Jones     qtest_quit(qts);
3460df9142dSAndrew Jones }
3470df9142dSAndrew Jones 
3480df9142dSAndrew Jones static void sve_tests_sve_off(const void *data)
3490df9142dSAndrew Jones {
3500df9142dSAndrew Jones     QTestState *qts;
3510df9142dSAndrew Jones 
3520df9142dSAndrew Jones     qts = qtest_init(MACHINE "-cpu max,sve=off");
3530df9142dSAndrew Jones 
3540df9142dSAndrew Jones     /* SVE is off, so the map should be empty. */
3550df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0, NULL);
3560df9142dSAndrew Jones 
3570df9142dSAndrew Jones     /* The map stays empty even if we turn lengths off. */
3580df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
3590df9142dSAndrew Jones 
3600df9142dSAndrew Jones     /* It's an error to enable lengths when SVE is off. */
3610df9142dSAndrew Jones     assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }");
3620df9142dSAndrew Jones 
3630df9142dSAndrew Jones     /* With SVE re-enabled we should get all vector lengths enabled. */
3640df9142dSAndrew Jones     assert_sve_vls(qts, "max", BIT_ULL(SVE_MAX_VQ) - 1, "{ 'sve': true }");
3650df9142dSAndrew Jones 
3660df9142dSAndrew Jones     /* Or enable SVE with just specific vector lengths. */
3670df9142dSAndrew Jones     assert_sve_vls(qts, "max", 0x3,
3680df9142dSAndrew Jones                    "{ 'sve': true, 'sve128': true, 'sve256': true }");
3690df9142dSAndrew Jones 
3700df9142dSAndrew Jones     qtest_quit(qts);
3710df9142dSAndrew Jones }
3720df9142dSAndrew Jones 
373*6fa8a379SAndrew Jones static void sve_tests_sve_off_kvm(const void *data)
374*6fa8a379SAndrew Jones {
375*6fa8a379SAndrew Jones     QTestState *qts;
376*6fa8a379SAndrew Jones 
377*6fa8a379SAndrew Jones     qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
378*6fa8a379SAndrew Jones 
379*6fa8a379SAndrew Jones     /*
380*6fa8a379SAndrew Jones      * We don't know if this host supports SVE so we don't
381*6fa8a379SAndrew Jones      * attempt to test enabling anything. We only test that
382*6fa8a379SAndrew Jones      * everything is disabled (as it should be with sve=off)
383*6fa8a379SAndrew Jones      * and that using sve<N>=off to explicitly disable vector
384*6fa8a379SAndrew Jones      * lengths is OK too.
385*6fa8a379SAndrew Jones      */
386*6fa8a379SAndrew Jones     assert_sve_vls(qts, "max", 0, NULL);
387*6fa8a379SAndrew Jones     assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
388*6fa8a379SAndrew Jones 
389*6fa8a379SAndrew Jones     qtest_quit(qts);
390*6fa8a379SAndrew Jones }
391*6fa8a379SAndrew Jones 
392bd31b751SAndrew Jones static void test_query_cpu_model_expansion(const void *data)
393bd31b751SAndrew Jones {
394bd31b751SAndrew Jones     QTestState *qts;
395bd31b751SAndrew Jones 
396bd31b751SAndrew Jones     qts = qtest_init(MACHINE "-cpu max");
397bd31b751SAndrew Jones 
398bd31b751SAndrew Jones     /* Test common query-cpu-model-expansion input validation */
399bd31b751SAndrew Jones     assert_type_full(qts);
400bd31b751SAndrew Jones     assert_bad_props(qts, "max");
401bd31b751SAndrew Jones     assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
402bd31b751SAndrew Jones                  "ARM CPU type", NULL);
403bd31b751SAndrew Jones     assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
404bd31b751SAndrew Jones                  "{ 'not-a-prop': false }");
405bd31b751SAndrew Jones     assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
406bd31b751SAndrew Jones 
407bd31b751SAndrew Jones     /* Test expected feature presence/absence for some cpu types */
408bd31b751SAndrew Jones     assert_has_feature(qts, "max", "pmu");
409bd31b751SAndrew Jones     assert_has_feature(qts, "cortex-a15", "pmu");
410bd31b751SAndrew Jones     assert_has_not_feature(qts, "cortex-a15", "aarch64");
411bd31b751SAndrew Jones 
412bd31b751SAndrew Jones     if (g_str_equal(qtest_get_arch(), "aarch64")) {
413bd31b751SAndrew Jones         assert_has_feature(qts, "max", "aarch64");
41473234775SAndrew Jones         assert_has_feature(qts, "max", "sve");
4150df9142dSAndrew Jones         assert_has_feature(qts, "max", "sve128");
416bd31b751SAndrew Jones         assert_has_feature(qts, "cortex-a57", "pmu");
417bd31b751SAndrew Jones         assert_has_feature(qts, "cortex-a57", "aarch64");
418bd31b751SAndrew Jones 
4190df9142dSAndrew Jones         sve_tests_default(qts, "max");
4200df9142dSAndrew Jones 
421bd31b751SAndrew Jones         /* Test that features that depend on KVM generate errors without. */
422bd31b751SAndrew Jones         assert_error(qts, "max",
423bd31b751SAndrew Jones                      "'aarch64' feature cannot be disabled "
424bd31b751SAndrew Jones                      "unless KVM is enabled and 32-bit EL1 "
425bd31b751SAndrew Jones                      "is supported",
426bd31b751SAndrew Jones                      "{ 'aarch64': false }");
427bd31b751SAndrew Jones     }
428bd31b751SAndrew Jones 
429bd31b751SAndrew Jones     qtest_quit(qts);
430bd31b751SAndrew Jones }
431bd31b751SAndrew Jones 
432bd31b751SAndrew Jones static void test_query_cpu_model_expansion_kvm(const void *data)
433bd31b751SAndrew Jones {
434bd31b751SAndrew Jones     QTestState *qts;
435bd31b751SAndrew Jones 
436bd31b751SAndrew Jones     qts = qtest_init(MACHINE_KVM "-cpu max");
437bd31b751SAndrew Jones 
438bd31b751SAndrew Jones     /*
439bd31b751SAndrew Jones      * These tests target the 'host' CPU type, so KVM must be enabled.
440bd31b751SAndrew Jones      */
441bd31b751SAndrew Jones     if (!kvm_enabled(qts)) {
442bd31b751SAndrew Jones         qtest_quit(qts);
443bd31b751SAndrew Jones         return;
444bd31b751SAndrew Jones     }
445bd31b751SAndrew Jones 
446bd31b751SAndrew Jones     if (g_str_equal(qtest_get_arch(), "aarch64")) {
447*6fa8a379SAndrew Jones         bool kvm_supports_sve;
448*6fa8a379SAndrew Jones         char max_name[8], name[8];
449*6fa8a379SAndrew Jones         uint32_t max_vq, vq;
450*6fa8a379SAndrew Jones         uint64_t vls;
451*6fa8a379SAndrew Jones         QDict *resp;
452*6fa8a379SAndrew Jones         char *error;
453*6fa8a379SAndrew Jones 
454bd31b751SAndrew Jones         assert_has_feature(qts, "host", "aarch64");
455bd31b751SAndrew Jones         assert_has_feature(qts, "host", "pmu");
456bd31b751SAndrew Jones 
457bd31b751SAndrew Jones         assert_error(qts, "cortex-a15",
458bd31b751SAndrew Jones             "We cannot guarantee the CPU type 'cortex-a15' works "
459bd31b751SAndrew Jones             "with KVM on this host", NULL);
460*6fa8a379SAndrew Jones 
461*6fa8a379SAndrew Jones         assert_has_feature(qts, "max", "sve");
462*6fa8a379SAndrew Jones         resp = do_query_no_props(qts, "max");
463*6fa8a379SAndrew Jones         kvm_supports_sve = resp_get_feature(resp, "sve");
464*6fa8a379SAndrew Jones         vls = resp_get_sve_vls(resp);
465*6fa8a379SAndrew Jones         qobject_unref(resp);
466*6fa8a379SAndrew Jones 
467*6fa8a379SAndrew Jones         if (kvm_supports_sve) {
468*6fa8a379SAndrew Jones             g_assert(vls != 0);
469*6fa8a379SAndrew Jones             max_vq = 64 - __builtin_clzll(vls);
470*6fa8a379SAndrew Jones             sprintf(max_name, "sve%d", max_vq * 128);
471*6fa8a379SAndrew Jones 
472*6fa8a379SAndrew Jones             /* Enabling a supported length is of course fine. */
473*6fa8a379SAndrew Jones             assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
474*6fa8a379SAndrew Jones 
475*6fa8a379SAndrew Jones             /* Get the next supported length smaller than max-vq. */
476*6fa8a379SAndrew Jones             vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
477*6fa8a379SAndrew Jones             if (vq) {
478*6fa8a379SAndrew Jones                 /*
479*6fa8a379SAndrew Jones                  * We have at least one length smaller than max-vq,
480*6fa8a379SAndrew Jones                  * so we can disable max-vq.
481*6fa8a379SAndrew Jones                  */
482*6fa8a379SAndrew Jones                 assert_sve_vls(qts, "max", (vls & ~BIT_ULL(max_vq - 1)),
483*6fa8a379SAndrew Jones                                "{ %s: false }", max_name);
484*6fa8a379SAndrew Jones 
485*6fa8a379SAndrew Jones                 /*
486*6fa8a379SAndrew Jones                  * Smaller, supported vector lengths cannot be disabled
487*6fa8a379SAndrew Jones                  * unless all larger, supported vector lengths are also
488*6fa8a379SAndrew Jones                  * disabled.
489*6fa8a379SAndrew Jones                  */
490*6fa8a379SAndrew Jones                 sprintf(name, "sve%d", vq * 128);
491*6fa8a379SAndrew Jones                 error = g_strdup_printf("cannot disable %s", name);
492*6fa8a379SAndrew Jones                 assert_error(qts, "max", error,
493*6fa8a379SAndrew Jones                              "{ %s: true, %s: false }",
494*6fa8a379SAndrew Jones                              max_name, name);
495*6fa8a379SAndrew Jones                 g_free(error);
496*6fa8a379SAndrew Jones             }
497*6fa8a379SAndrew Jones 
498*6fa8a379SAndrew Jones             /*
499*6fa8a379SAndrew Jones              * The smallest, supported vector length is required, because
500*6fa8a379SAndrew Jones              * we need at least one vector length enabled.
501*6fa8a379SAndrew Jones              */
502*6fa8a379SAndrew Jones             vq = __builtin_ffsll(vls);
503*6fa8a379SAndrew Jones             sprintf(name, "sve%d", vq * 128);
504*6fa8a379SAndrew Jones             error = g_strdup_printf("cannot disable %s", name);
505*6fa8a379SAndrew Jones             assert_error(qts, "max", error, "{ %s: false }", name);
506*6fa8a379SAndrew Jones             g_free(error);
507*6fa8a379SAndrew Jones 
508*6fa8a379SAndrew Jones             /* Get an unsupported length. */
509*6fa8a379SAndrew Jones             for (vq = 1; vq <= max_vq; ++vq) {
510*6fa8a379SAndrew Jones                 if (!(vls & BIT_ULL(vq - 1))) {
511*6fa8a379SAndrew Jones                     break;
512*6fa8a379SAndrew Jones                 }
513*6fa8a379SAndrew Jones             }
514*6fa8a379SAndrew Jones             if (vq <= SVE_MAX_VQ) {
515*6fa8a379SAndrew Jones                 sprintf(name, "sve%d", vq * 128);
516*6fa8a379SAndrew Jones                 error = g_strdup_printf("cannot enable %s", name);
517*6fa8a379SAndrew Jones                 assert_error(qts, "max", error, "{ %s: true }", name);
518*6fa8a379SAndrew Jones                 g_free(error);
519*6fa8a379SAndrew Jones             }
520*6fa8a379SAndrew Jones         } else {
521*6fa8a379SAndrew Jones             g_assert(vls == 0);
522*6fa8a379SAndrew Jones         }
523bd31b751SAndrew Jones     } else {
524bd31b751SAndrew Jones         assert_has_not_feature(qts, "host", "aarch64");
525bd31b751SAndrew Jones         assert_has_not_feature(qts, "host", "pmu");
52614e99e0fSAndrew Jones 
52714e99e0fSAndrew Jones         assert_has_not_feature(qts, "max", "sve");
528bd31b751SAndrew Jones     }
529bd31b751SAndrew Jones 
530bd31b751SAndrew Jones     qtest_quit(qts);
531bd31b751SAndrew Jones }
532bd31b751SAndrew Jones 
533bd31b751SAndrew Jones int main(int argc, char **argv)
534bd31b751SAndrew Jones {
535bd31b751SAndrew Jones     g_test_init(&argc, &argv, NULL);
536bd31b751SAndrew Jones 
537bd31b751SAndrew Jones     qtest_add_data_func("/arm/query-cpu-model-expansion",
538bd31b751SAndrew Jones                         NULL, test_query_cpu_model_expansion);
539bd31b751SAndrew Jones 
540bd31b751SAndrew Jones     /*
541bd31b751SAndrew Jones      * For now we only run KVM specific tests with AArch64 QEMU in
542bd31b751SAndrew Jones      * order avoid attempting to run an AArch32 QEMU with KVM on
543bd31b751SAndrew Jones      * AArch64 hosts. That won't work and isn't easy to detect.
544bd31b751SAndrew Jones      */
545bd31b751SAndrew Jones     if (g_str_equal(qtest_get_arch(), "aarch64")) {
546bd31b751SAndrew Jones         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
547bd31b751SAndrew Jones                             NULL, test_query_cpu_model_expansion_kvm);
548bd31b751SAndrew Jones     }
549bd31b751SAndrew Jones 
5500df9142dSAndrew Jones     if (g_str_equal(qtest_get_arch(), "aarch64")) {
5510df9142dSAndrew Jones         qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
5520df9142dSAndrew Jones                             NULL, sve_tests_sve_max_vq_8);
5530df9142dSAndrew Jones         qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
5540df9142dSAndrew Jones                             NULL, sve_tests_sve_off);
555*6fa8a379SAndrew Jones         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
556*6fa8a379SAndrew Jones                             NULL, sve_tests_sve_off_kvm);
5570df9142dSAndrew Jones     }
5580df9142dSAndrew Jones 
559bd31b751SAndrew Jones     return g_test_run();
560bd31b751SAndrew Jones }
561