qemu/tests/arm-cpu-features.c
<<
>>
Prefs
   1/*
   2 * Arm CPU feature test cases
   3 *
   4 * Copyright (c) 2019 Red Hat Inc.
   5 * Authors:
   6 *  Andrew Jones <drjones@redhat.com>
   7 *
   8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   9 * See the COPYING file in the top-level directory.
  10 */
  11#include "qemu/osdep.h"
  12#include "qemu/bitops.h"
  13#include "libqtest.h"
  14#include "qapi/qmp/qdict.h"
  15#include "qapi/qmp/qjson.h"
  16
  17/*
  18 * We expect the SVE max-vq to be 16. Also it must be <= 64
  19 * for our test code, otherwise 'vls' can't just be a uint64_t.
  20 */
  21#define SVE_MAX_VQ 16
  22
  23#define MACHINE     "-machine virt,gic-version=max,accel=tcg "
  24#define MACHINE_KVM "-machine virt,gic-version=max,accel=kvm:tcg "
  25#define QUERY_HEAD  "{ 'execute': 'query-cpu-model-expansion', " \
  26                    "  'arguments': { 'type': 'full', "
  27#define QUERY_TAIL  "}}"
  28
  29static bool kvm_enabled(QTestState *qts)
  30{
  31    QDict *resp, *qdict;
  32    bool enabled;
  33
  34    resp = qtest_qmp(qts, "{ 'execute': 'query-kvm' }");
  35    g_assert(qdict_haskey(resp, "return"));
  36    qdict = qdict_get_qdict(resp, "return");
  37    g_assert(qdict_haskey(qdict, "enabled"));
  38    enabled = qdict_get_bool(qdict, "enabled");
  39    qobject_unref(resp);
  40
  41    return enabled;
  42}
  43
  44static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
  45{
  46    return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
  47                          QUERY_TAIL, cpu_type);
  48}
  49
  50static QDict *do_query(QTestState *qts, const char *cpu_type,
  51                       const char *fmt, ...)
  52{
  53    QDict *resp;
  54
  55    if (fmt) {
  56        QDict *args;
  57        va_list ap;
  58
  59        va_start(ap, fmt);
  60        args = qdict_from_vjsonf_nofail(fmt, ap);
  61        va_end(ap);
  62
  63        resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
  64                                                    "'props': %p }"
  65                              QUERY_TAIL, cpu_type, args);
  66    } else {
  67        resp = do_query_no_props(qts, cpu_type);
  68    }
  69
  70    return resp;
  71}
  72
  73static const char *resp_get_error(QDict *resp)
  74{
  75    QDict *qdict;
  76
  77    g_assert(resp);
  78
  79    qdict = qdict_get_qdict(resp, "error");
  80    if (qdict) {
  81        return qdict_get_str(qdict, "desc");
  82    }
  83
  84    return NULL;
  85}
  86
  87#define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
  88({                                                                     \
  89    QDict *_resp;                                                      \
  90    const char *_error;                                                \
  91                                                                       \
  92    _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
  93    g_assert(_resp);                                                   \
  94    _error = resp_get_error(_resp);                                    \
  95    g_assert(_error);                                                  \
  96    g_assert(g_str_equal(_error, expected_error));                     \
  97    qobject_unref(_resp);                                              \
  98})
  99
 100static bool resp_has_props(QDict *resp)
 101{
 102    QDict *qdict;
 103
 104    g_assert(resp);
 105
 106    if (!qdict_haskey(resp, "return")) {
 107        return false;
 108    }
 109    qdict = qdict_get_qdict(resp, "return");
 110
 111    if (!qdict_haskey(qdict, "model")) {
 112        return false;
 113    }
 114    qdict = qdict_get_qdict(qdict, "model");
 115
 116    return qdict_haskey(qdict, "props");
 117}
 118
 119static QDict *resp_get_props(QDict *resp)
 120{
 121    QDict *qdict;
 122
 123    g_assert(resp);
 124    g_assert(resp_has_props(resp));
 125
 126    qdict = qdict_get_qdict(resp, "return");
 127    qdict = qdict_get_qdict(qdict, "model");
 128    qdict = qdict_get_qdict(qdict, "props");
 129
 130    return qdict;
 131}
 132
 133static bool resp_get_feature(QDict *resp, const char *feature)
 134{
 135    QDict *props;
 136
 137    g_assert(resp);
 138    g_assert(resp_has_props(resp));
 139    props = resp_get_props(resp);
 140    g_assert(qdict_get(props, feature));
 141    return qdict_get_bool(props, feature);
 142}
 143
 144#define assert_has_feature(qts, cpu_type, feature)                     \
 145({                                                                     \
 146    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
 147    g_assert(_resp);                                                   \
 148    g_assert(resp_has_props(_resp));                                   \
 149    g_assert(qdict_get(resp_get_props(_resp), feature));               \
 150    qobject_unref(_resp);                                              \
 151})
 152
 153#define assert_has_not_feature(qts, cpu_type, feature)                 \
 154({                                                                     \
 155    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
 156    g_assert(_resp);                                                   \
 157    g_assert(!resp_has_props(_resp) ||                                 \
 158             !qdict_get(resp_get_props(_resp), feature));              \
 159    qobject_unref(_resp);                                              \
 160})
 161
 162static void assert_type_full(QTestState *qts)
 163{
 164    const char *error;
 165    QDict *resp;
 166
 167    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
 168                            "'arguments': { 'type': 'static', "
 169                                           "'model': { 'name': 'foo' }}}");
 170    g_assert(resp);
 171    error = resp_get_error(resp);
 172    g_assert(error);
 173    g_assert(g_str_equal(error,
 174                         "The requested expansion type is not supported"));
 175    qobject_unref(resp);
 176}
 177
 178static void assert_bad_props(QTestState *qts, const char *cpu_type)
 179{
 180    const char *error;
 181    QDict *resp;
 182
 183    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
 184                            "'arguments': { 'type': 'full', "
 185                                           "'model': { 'name': %s, "
 186                                                      "'props': false }}}",
 187                     cpu_type);
 188    g_assert(resp);
 189    error = resp_get_error(resp);
 190    g_assert(error);
 191    g_assert(g_str_equal(error,
 192                         "Invalid parameter type for 'props', expected: dict"));
 193    qobject_unref(resp);
 194}
 195
 196static uint64_t resp_get_sve_vls(QDict *resp)
 197{
 198    QDict *props;
 199    const QDictEntry *e;
 200    uint64_t vls = 0;
 201    int n = 0;
 202
 203    g_assert(resp);
 204    g_assert(resp_has_props(resp));
 205
 206    props = resp_get_props(resp);
 207
 208    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
 209        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
 210            g_ascii_isdigit(e->key[3])) {
 211            char *endptr;
 212            int bits;
 213
 214            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
 215            if (!bits || *endptr != '\0') {
 216                continue;
 217            }
 218
 219            if (qdict_get_bool(props, e->key)) {
 220                vls |= BIT_ULL((bits / 128) - 1);
 221            }
 222            ++n;
 223        }
 224    }
 225
 226    g_assert(n == SVE_MAX_VQ);
 227
 228    return vls;
 229}
 230
 231#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
 232({                                                                     \
 233    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
 234    g_assert(_resp);                                                   \
 235    g_assert(resp_has_props(_resp));                                   \
 236    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
 237    qobject_unref(_resp);                                              \
 238})
 239
 240static void sve_tests_default(QTestState *qts, const char *cpu_type)
 241{
 242    /*
 243     * With no sve-max-vq or sve<N> properties on the command line
 244     * the default is to have all vector lengths enabled. This also
 245     * tests that 'sve' is 'on' by default.
 246     */
 247    assert_sve_vls(qts, cpu_type, BIT_ULL(SVE_MAX_VQ) - 1, NULL);
 248
 249    /* With SVE off, all vector lengths should also be off. */
 250    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
 251
 252    /* With SVE on, we must have at least one vector length enabled. */
 253    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
 254
 255    /* Basic enable/disable tests. */
 256    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve384': true }");
 257    assert_sve_vls(qts, cpu_type, ((BIT_ULL(SVE_MAX_VQ) - 1) & ~BIT_ULL(2)),
 258                   "{ 'sve384': false }");
 259
 260    /*
 261     * ---------------------------------------------------------------------
 262     *               power-of-two(vq)   all-power-            can      can
 263     *                                  of-two(< vq)        enable   disable
 264     * ---------------------------------------------------------------------
 265     * vq < max_vq      no                MUST*              yes      yes
 266     * vq < max_vq      yes               MUST*              yes      no
 267     * ---------------------------------------------------------------------
 268     * vq == max_vq     n/a               MUST*              yes**    yes**
 269     * ---------------------------------------------------------------------
 270     * vq > max_vq      n/a               no                 no       yes
 271     * vq > max_vq      n/a               yes                yes      yes
 272     * ---------------------------------------------------------------------
 273     *
 274     * [*] "MUST" means this requirement must already be satisfied,
 275     *     otherwise 'max_vq' couldn't itself be enabled.
 276     *
 277     * [**] Not testable with the QMP interface, only with the command line.
 278     */
 279
 280    /* max_vq := 8 */
 281    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
 282
 283    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
 284    assert_sve_vls(qts, cpu_type, 0x8f,
 285                   "{ 'sve1024': true, 'sve384': true }");
 286    assert_sve_vls(qts, cpu_type, 0x8b,
 287                   "{ 'sve1024': true, 'sve384': false }");
 288
 289    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
 290    assert_sve_vls(qts, cpu_type, 0x8b,
 291                   "{ 'sve1024': true, 'sve256': true }");
 292    assert_error(qts, cpu_type, "cannot disable sve256",
 293                 "{ 'sve1024': true, 'sve256': false }");
 294
 295    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
 296    assert_error(qts, cpu_type, "cannot disable sve512",
 297                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
 298
 299    /*
 300     * We can disable power-of-two vector lengths when all larger lengths
 301     * are also disabled. We only need to disable the power-of-two length,
 302     * as all non-enabled larger lengths will then be auto-disabled.
 303     */
 304    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
 305
 306    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
 307    assert_sve_vls(qts, cpu_type, 0x1f,
 308                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
 309    assert_sve_vls(qts, cpu_type, 0xf,
 310                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
 311}
 312
 313static void sve_tests_sve_max_vq_8(const void *data)
 314{
 315    QTestState *qts;
 316
 317    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
 318
 319    assert_sve_vls(qts, "max", BIT_ULL(8) - 1, NULL);
 320
 321    /*
 322     * Disabling the max-vq set by sve-max-vq is not allowed, but
 323     * of course enabling it is OK.
 324     */
 325    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
 326    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
 327
 328    /*
 329     * Enabling anything larger than max-vq set by sve-max-vq is not
 330     * allowed, but of course disabling everything larger is OK.
 331     */
 332    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
 333    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
 334
 335    /*
 336     * We can enable/disable non power-of-two lengths smaller than the
 337     * max-vq set by sve-max-vq, but, while we can enable power-of-two
 338     * lengths, we can't disable them.
 339     */
 340    assert_sve_vls(qts, "max", 0xff, "{ 'sve384': true }");
 341    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
 342    assert_sve_vls(qts, "max", 0xff, "{ 'sve256': true }");
 343    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
 344
 345    qtest_quit(qts);
 346}
 347
 348static void sve_tests_sve_off(const void *data)
 349{
 350    QTestState *qts;
 351
 352    qts = qtest_init(MACHINE "-cpu max,sve=off");
 353
 354    /* SVE is off, so the map should be empty. */
 355    assert_sve_vls(qts, "max", 0, NULL);
 356
 357    /* The map stays empty even if we turn lengths off. */
 358    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
 359
 360    /* It's an error to enable lengths when SVE is off. */
 361    assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }");
 362
 363    /* With SVE re-enabled we should get all vector lengths enabled. */
 364    assert_sve_vls(qts, "max", BIT_ULL(SVE_MAX_VQ) - 1, "{ 'sve': true }");
 365
 366    /* Or enable SVE with just specific vector lengths. */
 367    assert_sve_vls(qts, "max", 0x3,
 368                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
 369
 370    qtest_quit(qts);
 371}
 372
 373static void sve_tests_sve_off_kvm(const void *data)
 374{
 375    QTestState *qts;
 376
 377    qts = qtest_init(MACHINE_KVM "-cpu max,sve=off");
 378
 379    /*
 380     * We don't know if this host supports SVE so we don't
 381     * attempt to test enabling anything. We only test that
 382     * everything is disabled (as it should be with sve=off)
 383     * and that using sve<N>=off to explicitly disable vector
 384     * lengths is OK too.
 385     */
 386    assert_sve_vls(qts, "max", 0, NULL);
 387    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
 388
 389    qtest_quit(qts);
 390}
 391
 392static void test_query_cpu_model_expansion(const void *data)
 393{
 394    QTestState *qts;
 395
 396    qts = qtest_init(MACHINE "-cpu max");
 397
 398    /* Test common query-cpu-model-expansion input validation */
 399    assert_type_full(qts);
 400    assert_bad_props(qts, "max");
 401    assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
 402                 "ARM CPU type", NULL);
 403    assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
 404                 "{ 'not-a-prop': false }");
 405    assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
 406
 407    /* Test expected feature presence/absence for some cpu types */
 408    assert_has_feature(qts, "max", "pmu");
 409    assert_has_feature(qts, "cortex-a15", "pmu");
 410    assert_has_not_feature(qts, "cortex-a15", "aarch64");
 411
 412    if (g_str_equal(qtest_get_arch(), "aarch64")) {
 413        assert_has_feature(qts, "max", "aarch64");
 414        assert_has_feature(qts, "max", "sve");
 415        assert_has_feature(qts, "max", "sve128");
 416        assert_has_feature(qts, "cortex-a57", "pmu");
 417        assert_has_feature(qts, "cortex-a57", "aarch64");
 418
 419        sve_tests_default(qts, "max");
 420
 421        /* Test that features that depend on KVM generate errors without. */
 422        assert_error(qts, "max",
 423                     "'aarch64' feature cannot be disabled "
 424                     "unless KVM is enabled and 32-bit EL1 "
 425                     "is supported",
 426                     "{ 'aarch64': false }");
 427    }
 428
 429    qtest_quit(qts);
 430}
 431
 432static void test_query_cpu_model_expansion_kvm(const void *data)
 433{
 434    QTestState *qts;
 435
 436    qts = qtest_init(MACHINE_KVM "-cpu max");
 437
 438    /*
 439     * These tests target the 'host' CPU type, so KVM must be enabled.
 440     */
 441    if (!kvm_enabled(qts)) {
 442        qtest_quit(qts);
 443        return;
 444    }
 445
 446    if (g_str_equal(qtest_get_arch(), "aarch64")) {
 447        bool kvm_supports_sve;
 448        char max_name[8], name[8];
 449        uint32_t max_vq, vq;
 450        uint64_t vls;
 451        QDict *resp;
 452        char *error;
 453
 454        assert_has_feature(qts, "host", "aarch64");
 455        assert_has_feature(qts, "host", "pmu");
 456
 457        assert_error(qts, "cortex-a15",
 458            "We cannot guarantee the CPU type 'cortex-a15' works "
 459            "with KVM on this host", NULL);
 460
 461        assert_has_feature(qts, "host", "sve");
 462        resp = do_query_no_props(qts, "host");
 463        kvm_supports_sve = resp_get_feature(resp, "sve");
 464        vls = resp_get_sve_vls(resp);
 465        qobject_unref(resp);
 466
 467        if (kvm_supports_sve) {
 468            g_assert(vls != 0);
 469            max_vq = 64 - __builtin_clzll(vls);
 470            sprintf(max_name, "sve%d", max_vq * 128);
 471
 472            /* Enabling a supported length is of course fine. */
 473            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
 474
 475            /* Get the next supported length smaller than max-vq. */
 476            vq = 64 - __builtin_clzll(vls & ~BIT_ULL(max_vq - 1));
 477            if (vq) {
 478                /*
 479                 * We have at least one length smaller than max-vq,
 480                 * so we can disable max-vq.
 481                 */
 482                assert_sve_vls(qts, "host", (vls & ~BIT_ULL(max_vq - 1)),
 483                               "{ %s: false }", max_name);
 484
 485                /*
 486                 * Smaller, supported vector lengths cannot be disabled
 487                 * unless all larger, supported vector lengths are also
 488                 * disabled.
 489                 */
 490                sprintf(name, "sve%d", vq * 128);
 491                error = g_strdup_printf("cannot disable %s", name);
 492                assert_error(qts, "host", error,
 493                             "{ %s: true, %s: false }",
 494                             max_name, name);
 495                g_free(error);
 496            }
 497
 498            /*
 499             * The smallest, supported vector length is required, because
 500             * we need at least one vector length enabled.
 501             */
 502            vq = __builtin_ffsll(vls);
 503            sprintf(name, "sve%d", vq * 128);
 504            error = g_strdup_printf("cannot disable %s", name);
 505            assert_error(qts, "host", error, "{ %s: false }", name);
 506            g_free(error);
 507
 508            /* Get an unsupported length. */
 509            for (vq = 1; vq <= max_vq; ++vq) {
 510                if (!(vls & BIT_ULL(vq - 1))) {
 511                    break;
 512                }
 513            }
 514            if (vq <= SVE_MAX_VQ) {
 515                sprintf(name, "sve%d", vq * 128);
 516                error = g_strdup_printf("cannot enable %s", name);
 517                assert_error(qts, "host", error, "{ %s: true }", name);
 518                g_free(error);
 519            }
 520        } else {
 521            g_assert(vls == 0);
 522        }
 523    } else {
 524        assert_has_not_feature(qts, "host", "aarch64");
 525        assert_has_not_feature(qts, "host", "pmu");
 526        assert_has_not_feature(qts, "host", "sve");
 527    }
 528
 529    qtest_quit(qts);
 530}
 531
 532int main(int argc, char **argv)
 533{
 534    g_test_init(&argc, &argv, NULL);
 535
 536    qtest_add_data_func("/arm/query-cpu-model-expansion",
 537                        NULL, test_query_cpu_model_expansion);
 538
 539    /*
 540     * For now we only run KVM specific tests with AArch64 QEMU in
 541     * order avoid attempting to run an AArch32 QEMU with KVM on
 542     * AArch64 hosts. That won't work and isn't easy to detect.
 543     */
 544    if (g_str_equal(qtest_get_arch(), "aarch64")) {
 545        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
 546                            NULL, test_query_cpu_model_expansion_kvm);
 547    }
 548
 549    if (g_str_equal(qtest_get_arch(), "aarch64")) {
 550        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
 551                            NULL, sve_tests_sve_max_vq_8);
 552        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
 553                            NULL, sve_tests_sve_off);
 554        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
 555                            NULL, sve_tests_sve_off_kvm);
 556    }
 557
 558    return g_test_run();
 559}
 560