All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/9] target/arm/kvm: enable SVE in guests
@ 2019-09-24 11:30 Andrew Jones
  2019-09-24 11:30 ` [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
                   ` (8 more replies)
  0 siblings, 9 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:30 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Since Linux kernel v5.2-rc1 KVM has support for enabling SVE in guests.
This series provides the QEMU bits for that enablement. First, we
select existing CPU properties representing features we want to
advertise in addition to the SVE vector lengths and prepare
them for a qmp query. Then we introduce the qmp query, applying
it immediately to those selected features. We also document ARM CPU
features at this time. We next add a qtest for the selected CPU
features that uses the qmp query for its tests - and we continue to
add tests as we add CPU features with the following patches. So then,
once we have the support we need for CPU feature querying and testing,
we add our first SVE CPU feature property, 'sve', which just allows
SVE to be completely enabled/disabled. Following that feature property,
we add all 16 vector length properties along with the input validation
they need and tests to prove the validation works. At this point the
SVE features are still only for TCG, so we provide some patches to
prepare for KVM and then a patch that allows the 'max' CPU type to
enable SVE with KVM, but at first without vector length properties.
After a bit more preparation we add the SVE vector length properties
to the KVM-enabled 'max' CPU type along with the additional input
validation and tests that that needs.  Finally we allow the 'host'
CPU type to also enjoy these properties by simply sharing them with it.

v4:
  - Integrated Richard Henderson's rework for the sve property
    validation, in order to do all validating at finalize time
    and save several lines of code.
  - Fixed 'host' cpu SVE default. It was still off by default.
  - Cleaned up #ifdef's for sve_bswap64()
  - Removed redundant KVM_CAP_ARM_SVE extension check in
    kvm_arm_sve_get_vls()
  - Improved the KVM SVE qtest
  - Renamed sve<vl-bits> to sve<N> everywhere
  - Renamed power-of-2 to power-of-two everywhere
  - Picked up some more tags from Richard

Thanks!
drew


Andrew Jones (9):
  target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  tests: arm: Introduce cpu feature tests
  target/arm: Allow SVE to be disabled via a CPU property
  target/arm/cpu64: max cpu: Introduce sve<N> properties
  target/arm/kvm64: Add kvm_arch_get/put_sve
  target/arm/kvm64: max cpu: Enable SVE when available
  target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features
  target/arm/cpu64: max cpu: Support sve properties with KVM
  target/arm/kvm: host cpu: Add support for sve<N> properties

 docs/arm-cpu-features.rst | 301 +++++++++++++++++++++
 qapi/machine-target.json  |   6 +-
 target/arm/cpu.c          |  25 +-
 target/arm/cpu.h          |  21 ++
 target/arm/cpu64.c        | 341 +++++++++++++++++++++++-
 target/arm/helper.c       |  13 +-
 target/arm/kvm.c          |  25 +-
 target/arm/kvm32.c        |   6 +-
 target/arm/kvm64.c        | 277 +++++++++++++++++++-
 target/arm/kvm_arm.h      |  39 +++
 target/arm/monitor.c      | 157 +++++++++++
 tests/Makefile.include    |   5 +-
 tests/arm-cpu-features.c  | 537 ++++++++++++++++++++++++++++++++++++++
 13 files changed, 1718 insertions(+), 35 deletions(-)
 create mode 100644 docs/arm-cpu-features.rst
 create mode 100644 tests/arm-cpu-features.c

-- 
2.20.1



^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
@ 2019-09-24 11:30 ` Andrew Jones
  2019-09-24 15:06   ` Auger Eric
  2019-09-24 11:30 ` [PATCH v4 2/9] tests: arm: Introduce cpu feature tests Andrew Jones
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:30 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Add support for the query-cpu-model-expansion QMP command to Arm. We
do this selectively, only exposing CPU properties which represent
optional CPU features which the user may want to enable/disable.
Additionally we restrict the list of queryable cpu models to 'max',
'host', or the current type when KVM is in use. And, finally, we only
implement expansion type 'full', as Arm does not yet have a "base"
CPU type. More details and example queries are described in a new
document (docs/arm-cpu-features.rst).

Note, certainly more features may be added to the list of advertised
features, e.g. 'vfp' and 'neon'. The only requirement is that we can
detect invalid configurations and emit failures at QMP query time.
For 'vfp' and 'neon' this will require some refactoring to share a
validation function between the QMP query and the CPU realize
functions.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 docs/arm-cpu-features.rst | 137 +++++++++++++++++++++++++++++++++++
 qapi/machine-target.json  |   6 +-
 target/arm/monitor.c      | 145 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 285 insertions(+), 3 deletions(-)
 create mode 100644 docs/arm-cpu-features.rst

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
new file mode 100644
index 000000000000..c79dcffb5556
--- /dev/null
+++ b/docs/arm-cpu-features.rst
@@ -0,0 +1,137 @@
+================
+ARM CPU Features
+================
+
+Examples of probing and using ARM CPU features
+
+Introduction
+============
+
+CPU features are optional features that a CPU of supporting type may
+choose to implement or not.  In QEMU, optional CPU features have
+corresponding boolean CPU proprieties that, when enabled, indicate
+that the feature is implemented, and, conversely, when disabled,
+indicate that it is not implemented. An example of an ARM CPU feature
+is the Performance Monitoring Unit (PMU).  CPU types such as the
+Cortex-A15 and the Cortex-A57, which respectively implement ARM
+architecture reference manuals ARMv7-A and ARMv8-A, may both optionally
+implement PMUs.  For example, if a user wants to use a Cortex-A15 without
+a PMU, then the `-cpu` parameter should contain `pmu=off` on the QEMU
+command line, i.e. `-cpu cortex-a15,pmu=off`.
+
+As not all CPU types support all optional CPU features, then whether or
+not a CPU property exists depends on the CPU type.  For example, CPUs
+that implement the ARMv8-A architecture reference manual may optionally
+support the AArch32 CPU feature, which may be enabled by disabling the
+`aarch64` CPU property.  A CPU type such as the Cortex-A15, which does
+not implement ARMv8-A, will not have the `aarch64` CPU property.
+
+QEMU's support may be limited for some CPU features, only partially
+supporting the feature or only supporting the feature under certain
+configurations.  For example, the `aarch64` CPU feature, which, when
+disabled, enables the optional AArch32 CPU feature, is only supported
+when using the KVM accelerator and when running on a host CPU type that
+supports the feature.
+
+CPU Feature Probing
+===================
+
+Determining which CPU features are available and functional for a given
+CPU type is possible with the `query-cpu-model-expansion` QMP command.
+Below are some examples where `scripts/qmp/qmp-shell` (see the top comment
+block in the script for usage) is used to issue the QMP commands.
+
+(1) Determine which CPU features are available for the `max` CPU type
+    (Note, we started QEMU with qemu-system-aarch64, so `max` is
+     implementing the ARMv8-A reference manual in this case)::
+
+      (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
+      { "return": {
+        "model": { "name": "max", "props": {
+        "pmu": true, "aarch64": true
+      }}}}
+
+We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
+We also see that the CPU features are enabled, as they are all `true`.
+
+(2) Let's try to disable the PMU::
+
+      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
+      { "return": {
+        "model": { "name": "max", "props": {
+        "pmu": false, "aarch64": true
+      }}}}
+
+We see it worked, as `pmu` is now `false`.
+
+(3) Let's try to disable `aarch64`, which enables the AArch32 CPU feature::
+
+      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"aarch64":false}}
+      {"error": {
+       "class": "GenericError", "desc":
+       "'aarch64' feature cannot be disabled unless KVM is enabled and 32-bit EL1 is supported"
+      }}
+
+It looks like this feature is limited to a configuration we do not
+currently have.
+
+(4) Let's try probing CPU features for the Cortex-A15 CPU type::
+
+      (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
+      {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
+
+Only the `pmu` CPU feature is available.
+
+A note about CPU feature dependencies
+-------------------------------------
+
+It's possible for features to have dependencies on other features. I.e.
+it may be possible to change one feature at a time without error, but
+when attempting to change all features at once an error could occur
+depending on the order they are processed.  It's also possible changing
+all at once doesn't generate an error, because a feature's dependencies
+are satisfied with other features, but the same feature cannot be changed
+independently without error.  For these reasons callers should always
+attempt to make their desired changes all at once in order to ensure the
+collection is valid.
+
+A note about CPU models and KVM
+-------------------------------
+
+Named CPU models generally do not work with KVM.  There are a few cases
+that do work, e.g. using the named CPU model `cortex-a57` with KVM on a
+seattle host, but mostly if KVM is enabled the `host` CPU type must be
+used.  This means the guest is provided all the same CPU features as the
+host CPU type has.  And, for this reason, the `host` CPU type should
+enable all CPU features that the host has by default.  Indeed it's even
+a bit strange to allow disabling CPU features that the host has when using
+the `host` CPU type, but in the absence of CPU models it's the best we can
+do if we want to launch guests without all the host's CPU features enabled.
+
+Enabling KVM also affects the `query-cpu-model-expansion` QMP command.  The
+affect is not only limited to specific features, as pointed out in example
+(3) of "CPU Feature Probing", but also to which CPU types may be expanded.
+When KVM is enabled, only the `max`, `host`, and current CPU type may be
+expanded.  This restriction is necessary as it's not possible to know all
+CPU types that may work with KVM, but it does impose a small risk of users
+experiencing unexpected errors.  For example on a seattle, as mentioned
+above, the `cortex-a57` CPU type is also valid when KVM is enabled.
+Therefore a user could use the `host` CPU type for the current type, but
+then attempt to query `cortex-a57`, however that query will fail with our
+restrictions.  This shouldn't be an issue though as management layers and
+users have been preferring the `host` CPU type for use with KVM for quite
+some time.  Additionally, if the KVM-enabled QEMU instance running on a
+seattle host is using the `cortex-a57` CPU type, then querying `cortex-a57`
+will work.
+
+Using CPU Features
+==================
+
+After determining which CPU features are available and supported for a
+given CPU type, then they may be selectively enabled or disabled on the
+QEMU command line with that CPU type::
+
+  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
+
+The example above disables the PMU for the `max` CPU type.
+
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index 55310a6aa226..04623224720d 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -212,7 +212,7 @@
 ##
 { 'struct': 'CpuModelExpansionInfo',
   'data': { 'model': 'CpuModelInfo' },
-  'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
+  'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
 
 ##
 # @query-cpu-model-expansion:
@@ -237,7 +237,7 @@
 #   query-cpu-model-expansion while using these is not advised.
 #
 # Some architectures may not support all expansion types. s390x supports
-# "full" and "static".
+# "full" and "static". Arm only supports "full".
 #
 # Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
 #          not supported, if the model cannot be expanded, if the model contains
@@ -251,7 +251,7 @@
   'data': { 'type': 'CpuModelExpansionType',
             'model': 'CpuModelInfo' },
   'returns': 'CpuModelExpansionInfo',
-  'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
+  'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
 
 ##
 # @CpuDefinitionInfo:
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 6457c3c87f7c..edca8aa885f0 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -21,8 +21,16 @@
  */
 
 #include "qemu/osdep.h"
+#include "hw/boards.h"
 #include "kvm_arm.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qapi-commands-machine-target.h"
 #include "qapi/qapi-commands-misc-target.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qdict.h"
+#include "qom/qom-qobject.h"
 
 static GICCapability *gic_cap_new(int version)
 {
@@ -81,3 +89,140 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
 
     return head;
 }
+
+/*
+ * These are cpu model features we want to advertise. The order here
+ * matters as this is the order in which qmp_query_cpu_model_expansion
+ * will attempt to set them. If there are dependencies between features,
+ * then the order that considers those dependencies must be used.
+ */
+static const char *cpu_model_advertised_features[] = {
+    "aarch64", "pmu",
+    NULL
+};
+
+CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
+                                                     CpuModelInfo *model,
+                                                     Error **errp)
+{
+    CpuModelExpansionInfo *expansion_info;
+    const QDict *qdict_in = NULL;
+    QDict *qdict_out;
+    ObjectClass *oc;
+    Object *obj;
+    const char *name;
+    int i;
+
+    if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
+        error_setg(errp, "The requested expansion type is not supported");
+        return NULL;
+    }
+
+    if (!kvm_enabled() && !strcmp(model->name, "host")) {
+        error_setg(errp, "The CPU type '%s' requires KVM", model->name);
+        return NULL;
+    }
+
+    oc = cpu_class_by_name(TYPE_ARM_CPU, model->name);
+    if (!oc) {
+        error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type",
+                   model->name);
+        return NULL;
+    }
+
+    if (kvm_enabled()) {
+        const char *cpu_type = current_machine->cpu_type;
+        int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX);
+        bool supported = false;
+
+        if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) {
+            /* These are kvmarm's recommended cpu types */
+            supported = true;
+        } else if (strlen(model->name) == len &&
+                   !strncmp(model->name, cpu_type, len)) {
+            /* KVM is enabled and we're using this type, so it works. */
+            supported = true;
+        }
+        if (!supported) {
+            error_setg(errp, "We cannot guarantee the CPU type '%s' works "
+                             "with KVM on this host", model->name);
+            return NULL;
+        }
+    }
+
+    if (model->props) {
+        qdict_in = qobject_to(QDict, model->props);
+        if (!qdict_in) {
+            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
+            return NULL;
+        }
+    }
+
+    obj = object_new(object_class_get_name(oc));
+
+    if (qdict_in) {
+        Visitor *visitor;
+        Error *err = NULL;
+
+        visitor = qobject_input_visitor_new(model->props);
+        visit_start_struct(visitor, NULL, NULL, 0, &err);
+        if (err) {
+            object_unref(obj);
+            error_propagate(errp, err);
+            return NULL;
+        }
+
+        i = 0;
+        while ((name = cpu_model_advertised_features[i++]) != NULL) {
+            if (qdict_get(qdict_in, name)) {
+                object_property_set(obj, visitor, name, &err);
+                if (err) {
+                    break;
+                }
+            }
+        }
+
+        if (!err) {
+            visit_check_struct(visitor, &err);
+        }
+        visit_end_struct(visitor, NULL);
+        visit_free(visitor);
+        if (err) {
+            object_unref(obj);
+            error_propagate(errp, err);
+            return NULL;
+        }
+    }
+
+    expansion_info = g_new0(CpuModelExpansionInfo, 1);
+    expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
+    expansion_info->model->name = g_strdup(model->name);
+
+    qdict_out = qdict_new();
+
+    i = 0;
+    while ((name = cpu_model_advertised_features[i++]) != NULL) {
+        ObjectProperty *prop = object_property_find(obj, name, NULL);
+        if (prop) {
+            Error *err = NULL;
+            QObject *value;
+
+            assert(prop->get);
+            value = object_property_get_qobject(obj, name, &err);
+            assert(!err);
+
+            qdict_put_obj(qdict_out, name, value);
+        }
+    }
+
+    if (!qdict_size(qdict_out)) {
+        qobject_unref(qdict_out);
+    } else {
+        expansion_info->model->props = QOBJECT(qdict_out);
+        expansion_info->model->has_props = true;
+    }
+
+    object_unref(obj);
+
+    return expansion_info;
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 2/9] tests: arm: Introduce cpu feature tests
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
  2019-09-24 11:30 ` [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
@ 2019-09-24 11:30 ` Andrew Jones
  2019-09-24 11:30 ` [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:30 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Now that Arm CPUs have advertised features lets add tests to ensure
we maintain their expected availability with and without KVM.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
 tests/Makefile.include   |   5 +-
 tests/arm-cpu-features.c | 242 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 tests/arm-cpu-features.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 793632ca72a5..3eee8fdf9637 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -258,6 +258,7 @@ check-qtest-sparc64-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
 check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
 check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
+check-qtest-arm-y += tests/arm-cpu-features$(EXESUF)
 check-qtest-arm-y += tests/microbit-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
@@ -265,7 +266,8 @@ check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y += tests/hexloader-test$(EXESUF)
 check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF)
 
-check-qtest-aarch64-y = tests/numa-test$(EXESUF)
+check-qtest-aarch64-y += tests/arm-cpu-features$(EXESUF)
+check-qtest-aarch64-y += tests/numa-test$(EXESUF)
 check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-aarch64-y += tests/migration-test$(EXESUF)
 # TODO: once aarch64 TCG is fixed on ARM 32 bit host, make test unconditional
@@ -828,6 +830,7 @@ tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
 tests/numa-test$(EXESUF): tests/numa-test.o
 tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
 tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
+tests/arm-cpu-features$(EXESUF): tests/arm-cpu-features.o
 
 tests/migration/stress$(EXESUF): tests/migration/stress.o
 	$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
new file mode 100644
index 000000000000..198ff6d6b495
--- /dev/null
+++ b/tests/arm-cpu-features.c
@@ -0,0 +1,242 @@
+/*
+ * Arm CPU feature test cases
+ *
+ * Copyright (c) 2019 Red Hat Inc.
+ * Authors:
+ *  Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+
+#define MACHINE    "-machine virt,gic-version=max "
+#define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
+                     "'arguments': { 'type': 'full', "
+#define QUERY_TAIL "}}"
+
+static QDict *do_query_no_props(QTestState *qts, const char *cpu_type)
+{
+    return qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s }"
+                          QUERY_TAIL, cpu_type);
+}
+
+static QDict *do_query(QTestState *qts, const char *cpu_type,
+                       const char *fmt, ...)
+{
+    QDict *resp;
+
+    if (fmt) {
+        QDict *args;
+        va_list ap;
+
+        va_start(ap, fmt);
+        args = qdict_from_vjsonf_nofail(fmt, ap);
+        va_end(ap);
+
+        resp = qtest_qmp(qts, QUERY_HEAD "'model': { 'name': %s, "
+                                                    "'props': %p }"
+                              QUERY_TAIL, cpu_type, args);
+    } else {
+        resp = do_query_no_props(qts, cpu_type);
+    }
+
+    return resp;
+}
+
+static const char *resp_get_error(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+
+    qdict = qdict_get_qdict(resp, "error");
+    if (qdict) {
+        return qdict_get_str(qdict, "desc");
+    }
+    return NULL;
+}
+
+#define assert_error(qts, cpu_type, expected_error, fmt, ...)          \
+({                                                                     \
+    QDict *_resp;                                                      \
+    const char *_error;                                                \
+                                                                       \
+    _resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);               \
+    g_assert(_resp);                                                   \
+    _error = resp_get_error(_resp);                                    \
+    g_assert(_error);                                                  \
+    g_assert(g_str_equal(_error, expected_error));                     \
+    qobject_unref(_resp);                                              \
+})
+
+static bool resp_has_props(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+
+    if (!qdict_haskey(resp, "return")) {
+        return false;
+    }
+    qdict = qdict_get_qdict(resp, "return");
+
+    if (!qdict_haskey(qdict, "model")) {
+        return false;
+    }
+    qdict = qdict_get_qdict(qdict, "model");
+
+    return qdict_haskey(qdict, "props");
+}
+
+static QDict *resp_get_props(QDict *resp)
+{
+    QDict *qdict;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+
+    qdict = qdict_get_qdict(resp, "return");
+    qdict = qdict_get_qdict(qdict, "model");
+    qdict = qdict_get_qdict(qdict, "props");
+    return qdict;
+}
+
+#define assert_has_feature(qts, cpu_type, feature)                     \
+({                                                                     \
+    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
+    g_assert(_resp);                                                   \
+    g_assert(resp_has_props(_resp));                                   \
+    g_assert(qdict_get(resp_get_props(_resp), feature));               \
+    qobject_unref(_resp);                                              \
+})
+
+#define assert_has_not_feature(qts, cpu_type, feature)                 \
+({                                                                     \
+    QDict *_resp = do_query_no_props(qts, cpu_type);                   \
+    g_assert(_resp);                                                   \
+    g_assert(resp_has_props(_resp));                                   \
+    g_assert(!qdict_get(resp_get_props(_resp), feature));              \
+    qobject_unref(_resp);                                              \
+})
+
+static void assert_type_full(QTestState *qts)
+{
+    const char *error;
+    QDict *resp;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
+                            "'arguments': { 'type': 'static', "
+                                           "'model': { 'name': 'foo' }}}");
+    g_assert(resp);
+    error = resp_get_error(resp);
+    g_assert(error);
+    g_assert(g_str_equal(error,
+                         "The requested expansion type is not supported"));
+    qobject_unref(resp);
+}
+
+static void assert_bad_props(QTestState *qts, const char *cpu_type)
+{
+    const char *error;
+    QDict *resp;
+
+    resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', "
+                            "'arguments': { 'type': 'full', "
+                                           "'model': { 'name': %s, "
+                                                      "'props': false }}}",
+                     cpu_type);
+    g_assert(resp);
+    error = resp_get_error(resp);
+    g_assert(error);
+    g_assert(g_str_equal(error,
+                         "Invalid parameter type for 'props', expected: dict"));
+    qobject_unref(resp);
+}
+
+static void test_query_cpu_model_expansion(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max");
+
+    /* Test common query-cpu-model-expansion input validation */
+    assert_type_full(qts);
+    assert_bad_props(qts, "max");
+    assert_error(qts, "foo", "The CPU type 'foo' is not a recognized "
+                 "ARM CPU type", NULL);
+    assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected",
+                 "{ 'not-a-prop': false }");
+    assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
+
+    /* Test expected feature presence/absence for some cpu types */
+    assert_has_feature(qts, "max", "pmu");
+    assert_has_feature(qts, "cortex-a15", "pmu");
+    assert_has_not_feature(qts, "cortex-a15", "aarch64");
+
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        assert_has_feature(qts, "max", "aarch64");
+        assert_has_feature(qts, "cortex-a57", "pmu");
+        assert_has_feature(qts, "cortex-a57", "aarch64");
+
+        /* Test that features that depend on KVM generate errors without. */
+        assert_error(qts, "max",
+                     "'aarch64' feature cannot be disabled "
+                     "unless KVM is enabled and 32-bit EL1 "
+                     "is supported",
+                     "{ 'aarch64': false }");
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_query_cpu_model_expansion_kvm(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-accel kvm -cpu host");
+
+    assert_has_feature(qts, "host", "pmu");
+
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        assert_has_feature(qts, "host", "aarch64");
+
+        assert_error(qts, "cortex-a15",
+            "We cannot guarantee the CPU type 'cortex-a15' works "
+            "with KVM on this host", NULL);
+    } else {
+        assert_error(qts, "host",
+                     "'pmu' feature not supported by KVM on this host",
+                     "{ 'pmu': true }");
+    }
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    bool kvm_available = false;
+
+    if (!access("/dev/kvm",  R_OK | W_OK)) {
+#if defined(HOST_AARCH64)
+        kvm_available = g_str_equal(qtest_get_arch(), "aarch64");
+#elif defined(HOST_ARM)
+        kvm_available = g_str_equal(qtest_get_arch(), "arm");
+#endif
+    }
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_data_func("/arm/query-cpu-model-expansion",
+                        NULL, test_query_cpu_model_expansion);
+
+    if (kvm_available) {
+        qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
+                            NULL, test_query_cpu_model_expansion_kvm);
+    }
+
+    return g_test_run();
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
  2019-09-24 11:30 ` [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
  2019-09-24 11:30 ` [PATCH v4 2/9] tests: arm: Introduce cpu feature tests Andrew Jones
@ 2019-09-24 11:30 ` Andrew Jones
  2019-09-24 15:06   ` Auger Eric
  2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:30 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Since 97a28b0eeac14 ("target/arm: Allow VFP and Neon to be disabled via
a CPU property") we can disable the 'max' cpu model's VFP and neon
features, but there's no way to disable SVE. Add the 'sve=on|off'
property to give it that flexibility. We also rename
cpu_max_get/set_sve_vq to cpu_max_get/set_sve_max_vq in order for them
to follow the typical *_get/set_<property-name> pattern.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.c         |  3 ++-
 target/arm/cpu64.c       | 42 ++++++++++++++++++++++++++++++++++------
 target/arm/monitor.c     |  2 +-
 tests/arm-cpu-features.c |  1 +
 4 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2399c144718d..73be2ebfdd39 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -200,7 +200,8 @@ static void arm_cpu_reset(CPUState *s)
         env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
         env->cp15.cptr_el[3] |= CPTR_EZ;
         /* with maximum vector length */
-        env->vfp.zcr_el[1] = cpu->sve_max_vq - 1;
+        env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ?
+                             cpu->sve_max_vq - 1 : 0;
         env->vfp.zcr_el[2] = env->vfp.zcr_el[1];
         env->vfp.zcr_el[3] = env->vfp.zcr_el[1];
         /*
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index d7f5bf610a7d..8cdb0c79fa7a 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -256,15 +256,15 @@ static void aarch64_a72_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
 }
 
-static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name,
-                               void *opaque, Error **errp)
+static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
+                                   void *opaque, Error **errp)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
 }
 
-static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
-                               void *opaque, Error **errp)
+static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
+                                   void *opaque, Error **errp)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     Error *err = NULL;
@@ -279,6 +279,34 @@ static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
     error_propagate(errp, err);
 }
 
+static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
+                            void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    bool value = cpu_isar_feature(aa64_sve, cpu);
+
+    visit_type_bool(v, name, &value, errp);
+}
+
+static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
+                            void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    Error *err = NULL;
+    bool value;
+    uint64_t t;
+
+    visit_type_bool(v, name, &value, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    t = cpu->isar.id_aa64pfr0;
+    t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
+    cpu->isar.id_aa64pfr0 = t;
+}
+
 /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
  * otherwise, a CPU with as many features enabled as our emulation supports.
  * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
@@ -391,8 +419,10 @@ static void aarch64_max_initfn(Object *obj)
 #endif
 
         cpu->sve_max_vq = ARM_MAX_VQ;
-        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_vq,
-                            cpu_max_set_sve_vq, NULL, NULL, &error_fatal);
+        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
+                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
+        object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
+                            cpu_arm_set_sve, NULL, NULL, &error_fatal);
     }
 }
 
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index edca8aa885f0..4fddb6c252a3 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -97,7 +97,7 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
  * then the order that considers those dependencies must be used.
  */
 static const char *cpu_model_advertised_features[] = {
-    "aarch64", "pmu",
+    "aarch64", "pmu", "sve",
     NULL
 };
 
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 198ff6d6b495..202bc0e3e823 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -179,6 +179,7 @@ static void test_query_cpu_model_expansion(const void *data)
 
     if (g_str_equal(qtest_get_arch(), "aarch64")) {
         assert_has_feature(qts, "max", "aarch64");
+        assert_has_feature(qts, "max", "sve");
         assert_has_feature(qts, "cortex-a57", "pmu");
         assert_has_feature(qts, "cortex-a57", "aarch64");
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (2 preceding siblings ...)
  2019-09-24 11:30 ` [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-24 13:55   ` Andrew Jones
                     ` (2 more replies)
  2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
                   ` (4 subsequent siblings)
  8 siblings, 3 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Introduce cpu properties to give fine control over SVE vector lengths.
We introduce a property for each valid length up to the current
maximum supported, which is 2048-bits. The properties are named, e.g.
sve128, sve256, sve384, sve512, ..., where the number is the number of
bits. See the updates to docs/arm-cpu-features.rst for a description
of the semantics and for example uses.

Note, as sve-max-vq is still present and we'd like to be able to
support qmp_query_cpu_model_expansion with guests launched with e.g.
-cpu max,sve-max-vq=8 on their command lines, then we do allow
sve-max-vq and sve<N> properties to be provided at the same time, but
this is not recommended, and is why sve-max-vq is not mentioned in the
document.  If sve-max-vq is provided then it enables all lengths smaller
than and including the max and disables all lengths larger. It also has
the side-effect that no larger lengths may be enabled and that the max
itself cannot be disabled. Smaller non-power-of-two lengths may,
however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
guest the vector lengths 128, 256, and 512 bits.

This patch has been co-authored with Richard Henderson, who reworked
the target/arm/cpu64.c changes in order to push all the validation and
auto-enabling/disabling steps into the finalizer, resulting in a nice
LOC reduction.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst | 157 +++++++++++++++++++++++++++++--
 target/arm/cpu.c          |  19 ++++
 target/arm/cpu.h          |  19 ++++
 target/arm/cpu64.c        | 190 +++++++++++++++++++++++++++++++++++++-
 target/arm/helper.c       |  13 ++-
 target/arm/monitor.c      |  12 +++
 tests/arm-cpu-features.c  | 189 +++++++++++++++++++++++++++++++++++++
 7 files changed, 587 insertions(+), 12 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index c79dcffb5556..1262fddc6201 100644
--- a/docs/arm-cpu-features.rst
+++ b/docs/arm-cpu-features.rst
@@ -48,18 +48,28 @@ block in the script for usage) is used to issue the QMP commands.
       (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
       { "return": {
         "model": { "name": "max", "props": {
-        "pmu": true, "aarch64": true
+        "sve1664": true, "pmu": true, "sve1792": true, "sve1920": true,
+        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
+        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
+        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
+        "sve896": true, "sve1280": true, "sve2048": true
       }}}}
 
-We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
-We also see that the CPU features are enabled, as they are all `true`.
+We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many
+`sve<N>` CPU features.  We also see that all the CPU features are
+enabled, as they are all `true`.  (The `sve<N>` CPU features are all
+optional SVE vector lengths.  See "SVE CPU Properties".)
 
 (2) Let's try to disable the PMU::
 
       (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
       { "return": {
         "model": { "name": "max", "props": {
-        "pmu": false, "aarch64": true
+        "sve1664": true, "pmu": false, "sve1792": true, "sve1920": true,
+        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
+        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
+        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
+        "sve896": true, "sve1280": true, "sve2048": true
       }}}}
 
 We see it worked, as `pmu` is now `false`.
@@ -75,7 +85,22 @@ We see it worked, as `pmu` is now `false`.
 It looks like this feature is limited to a configuration we do not
 currently have.
 
-(4) Let's try probing CPU features for the Cortex-A15 CPU type::
+(4) Let's disable `sve` and see what happens to all the optional SVE
+    vector lengths::
+
+      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}}
+      { "return": {
+        "model": { "name": "max", "props": {
+        "sve1664": false, "pmu": true, "sve1792": false, "sve1920": false,
+        "sve128": false, "aarch64": true, "sve1024": false, "sve": false,
+        "sve640": false, "sve768": false, "sve1408": false, "sve256": false,
+        "sve1152": false, "sve512": false, "sve384": false, "sve1536": false,
+        "sve896": false, "sve1280": false, "sve2048": false
+      }}}}
+
+As expected they are now all `false`.
+
+(5) Let's try probing CPU features for the Cortex-A15 CPU type::
 
       (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
       {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
@@ -131,7 +156,125 @@ After determining which CPU features are available and supported for a
 given CPU type, then they may be selectively enabled or disabled on the
 QEMU command line with that CPU type::
 
-  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
+  $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on
+
+The example above disables the PMU and enables the first two SVE vector
+lengths for the `max` CPU type.  Note, the `sve=on` isn't actually
+necessary, because, as we observed above with our probe of the `max` CPU
+type, `sve` is already on by default.  Also, based on our probe of
+defaults, it would seem we need to disable many SVE vector lengths, rather
+than only enabling the two we want.  This isn't the case, because, as
+disabling many SVE vector lengths would be quite verbose, the `sve<N>` CPU
+properties have special semantics (see "SVE CPU Property Parsing
+Semantics").
+
+SVE CPU Properties
+==================
+
+There are two types of SVE CPU properties: `sve` and `sve<N>`.  The first
+is used to enable or disable the entire SVE feature, just as the `pmu`
+CPU property completely enables or disables the PMU.  The second type
+is used to enable or disable specific vector lengths, where `N` is the
+number of bits of the length.  The `sve<N>` CPU properties have special
+dependencies and constraints, see "SVE CPU Property Dependencies and
+Constraints" below.  Additionally, as we want all supported vector lengths
+to be enabled by default, then, in order to avoid overly verbose command
+lines (command lines full of `sve<N>=off`, for all `N` not wanted), we
+provide the parsing semantics listed in "SVE CPU Property Parsing
+Semantics".
+
+SVE CPU Property Dependencies and Constraints
+---------------------------------------------
+
+  1) At least one vector length must be enabled when `sve` is enabled.
+
+  2) If a vector length `N` is enabled, then all power-of-two vector
+     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
+     is enabled, then `sve128` and `sve256` must also be enabled,
+     but `sve384` is not required.
+
+SVE CPU Property Parsing Semantics
+----------------------------------
+
+  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
+     are enabled or disabled is irrelevant to the guest, as the entire
+     SVE feature is disabled and that disables all vector lengths for
+     the guest.  However QEMU will still track any `sve<N>` CPU
+     properties provided by the user.  If later an `sve=on` is provided,
+     then the guest will get only the enabled lengths.
+
+  2) If SVE is enabled (`sve=on`), but no `sve<N>` CPU properties are
+     provided, then all supported vector lengths are enabled.
+
+  3) If SVE is enabled, then an error is generated when attempting to
+     disable the last enabled vector length (see constraint (1) of "SVE
+     CPU Property Dependencies and Constraints").
+
+  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
+     CPU properties are set `on`, then the specified vector lengths are
+     disabled but the default for any unspecified lengths remains enabled.
+     Disabling a power-of-two vector length also disables all vector
+     lengths larger than the power-of-two length (see constraint (2) of
+     "SVE CPU Property Dependencies and Constraints").
+
+  5) If one or more `sve<N>` CPU properties are set to `on`, then they
+     are enabled and all unspecified lengths default to disabled, except
+     for the required lengths per constraint (2) of "SVE CPU Property
+     Dependencies and Constraints", which will even be auto-enabled if
+     they were not explicitly enabled.
+
+  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
+     explicitly disabled (i.e. avoiding the error specified in (3) of
+     "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
+     provided an error will be generated.  To avoid this error, one must
+     enable at least one vector length prior to enabling SVE.
+
+SVE CPU Property Examples
+-------------------------
+
+  1) Disable SVE::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve=off
+
+  2) Implicitly enable all vector lengths for the `max` CPU type::
+
+     $ qemu-system-aarch64 -M virt -cpu max
+
+  3) Only enable the 128-bit vector length::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve128=on
+
+  4) Disable the 256-bit vector length and all larger vector lengths
+     since 256 is a power-of-two (this results in only the 128-bit length
+     being enabled)::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve256=off
+
+  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
+
+  6) The same as (5), but since the 128-bit and 256-bit vector
+     lengths are required for the 512-bit vector length to be enabled,
+     then allow them to be auto-enabled::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve512=on
+
+  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on
+
+  8) Force errors regarding the last vector length::
+
+     $ qemu-system-aarch64 -M virt -cpu max,sve128=off
+     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
+
+SVE CPU Property Recommendations
+--------------------------------
 
-The example above disables the PMU for the `max` CPU type.
+The examples in "SVE CPU Property Examples" exhibit many ways to select
+vector lengths which developers may find useful in order to avoid overly
+verbose command lines.  However, the recommended way to select vector
+lengths is to explicitly enable each desired length.  Therefore only
+example's (1), (3), and (5) exhibit recommended uses of the properties.
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 73be2ebfdd39..522fed95b339 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1199,6 +1199,19 @@ static void arm_cpu_finalizefn(Object *obj)
 #endif
 }
 
+void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
+{
+    Error *local_err = NULL;
+
+    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+        arm_cpu_sve_finalize(cpu, &local_err);
+        if (local_err != NULL) {
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+}
+
 static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
@@ -1255,6 +1268,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
+    arm_cpu_finalize_features(cpu, &local_err);
+    if (local_err != NULL) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
     if (arm_feature(env, ARM_FEATURE_AARCH64) &&
         cpu->has_vfp != cpu->has_neon) {
         /*
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 297ad5e47ad8..11162484465a 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -184,8 +184,13 @@ typedef struct {
 
 #ifdef TARGET_AARCH64
 # define ARM_MAX_VQ    16
+void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
+uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
 #else
 # define ARM_MAX_VQ    1
+static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
+static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
+{ return 0; }
 #endif
 
 typedef struct ARMVectorReg {
@@ -915,6 +920,18 @@ struct ARMCPU {
 
     /* Used to set the maximum vector length the cpu will support.  */
     uint32_t sve_max_vq;
+
+    /*
+     * In sve_vq_map each set bit is a supported vector length of
+     * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
+     * length in quadwords.
+     *
+     * While processing properties during initialization, corresponding
+     * sve_vq_init bits are set for bits in sve_vq_map that have been
+     * set by properties.
+     */
+    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
+    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
 };
 
 void arm_cpu_post_init(Object *obj);
@@ -1834,6 +1851,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
     return (env->features & (1ULL << feature)) != 0;
 }
 
+void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
+
 #if !defined(CONFIG_USER_ONLY)
 /* Return true if exception levels below EL3 are in secure state,
  * or would be following an exception return to that level.
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 8cdb0c79fa7a..606e3eceb9c0 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -256,11 +256,152 @@ static void aarch64_a72_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
 }
 
+void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
+{
+    /*
+     * If any vector lengths are explicitly enabled with sve<N> properties,
+     * then all other lengths are implicitly disabled.  If sve-max-vq is
+     * specified then it is the same as explicitly enabling all lengths
+     * up to and including the specified maximum, which means all larger
+     * lengths will be implicitly disabled.  If no sve<N> properties
+     * are enabled and sve-max-vq is not specified, then all lengths not
+     * explicitly disabled will be enabled.  Additionally, all power-of-two
+     * vector lengths less than the maximum enabled length will be
+     * automatically enabled and all vector lengths larger than the largest
+     * disabled power-of-two vector length will be automatically disabled.
+     * Errors are generated if the user provided input that interferes with
+     * any of the above.  Finally, if SVE is not disabled, then at least one
+     * vector length must be enabled.
+     */
+    DECLARE_BITMAP(tmp, ARM_MAX_VQ);
+    uint32_t vq, max_vq = 0;
+
+    /*
+     * Process explicit sve<N> properties.
+     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
+     * Check first for any sve<N> enabled.
+     */
+    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
+        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
+
+        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
+            error_setg(errp, "cannot enable sve%d", max_vq * 128);
+            error_append_hint(errp, "sve%d is larger than the maximum vector "
+                              "length, sve-max-vq=%d (%d bits)\n",
+                              max_vq * 128, cpu->sve_max_vq,
+                              cpu->sve_max_vq * 128);
+            return;
+        }
+
+        /* Propagate enabled bits down through required powers-of-two. */
+        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
+                set_bit(vq - 1, cpu->sve_vq_map);
+            }
+        }
+    } else if (cpu->sve_max_vq == 0) {
+        /*
+         * No explicit bits enabled, and no implicit bits from sve-max-vq.
+         */
+        if (!cpu_isar_feature(aa64_sve, cpu)) {
+            /* SVE is disabled and so are all vector lengths.  Good. */
+            return;
+        }
+
+        /* Disabling a power-of-two disables all larger lengths. */
+        if (test_bit(0, cpu->sve_vq_init)) {
+            error_setg(errp, "cannot disable sve128");
+            error_append_hint(errp, "Disabling sve128 results in all vector "
+                              "lengths being disabled.\n");
+            error_append_hint(errp, "With SVE enabled, at least one vector "
+                              "length must be enabled.\n");
+            return;
+        }
+        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
+            if (test_bit(vq - 1, cpu->sve_vq_init)) {
+                break;
+            }
+        }
+        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
+
+        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
+        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
+    }
+
+    /*
+     * Process the sve-max-vq property.
+     * Note that we know from the above that no bit above
+     * sve-max-vq is currently set.
+     */
+    if (cpu->sve_max_vq != 0) {
+        max_vq = cpu->sve_max_vq;
+
+        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
+            test_bit(max_vq - 1, cpu->sve_vq_init)) {
+            error_setg(errp, "cannot disable sve%d", max_vq * 128);
+            error_append_hint(errp, "The maximum vector length must be "
+                              "enabled, sve-max-vq=%d (%d bits)\n",
+                              max_vq, max_vq * 128);
+            return;
+        }
+
+        /* Set all bits not explicitly set within sve-max-vq. */
+        bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
+        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
+    }
+
+    /*
+     * We should know what max-vq is now.  Also, as we're done
+     * manipulating sve-vq-map, we ensure any bits above max-vq
+     * are clear, just in case anybody looks.
+     */
+    assert(max_vq != 0);
+    bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
+
+    /* Ensure all required powers-of-two are enabled. */
+    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+            error_setg(errp, "cannot disable sve%d", vq * 128);
+            error_append_hint(errp, "sve%d is required as it "
+                              "is a power-of-two length smaller than "
+                              "the maximum, sve%d\n",
+                              vq * 128, max_vq * 128);
+            return;
+        }
+    }
+
+    /* From now on sve_max_vq is the actual maximum supported length. */
+    cpu->sve_max_vq = max_vq;
+}
+
+uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
+{
+    uint32_t bitnum;
+
+    /*
+     * We allow vq == ARM_MAX_VQ + 1 to be input because the caller may want
+     * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
+     * function always returns the next smaller than the input.
+     */
+    assert(vq && vq <= ARM_MAX_VQ + 1);
+
+    bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
+    return bitnum == vq - 1 ? 0 : bitnum + 1;
+}
+
 static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
                                    void *opaque, Error **errp)
 {
     ARMCPU *cpu = ARM_CPU(obj);
-    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
+    uint32_t value;
+
+    /* All vector lengths are disabled when SVE is off. */
+    if (!cpu_isar_feature(aa64_sve, cpu)) {
+        value = 0;
+    } else {
+        value = cpu->sve_max_vq;
+    }
+    visit_type_uint32(v, name, &value, errp);
 }
 
 static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
@@ -279,6 +420,44 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
     error_propagate(errp, err);
 }
 
+static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    uint32_t vq = atoi(&name[3]) / 128;
+    bool value;
+
+    /* All vector lengths are disabled when SVE is off. */
+    if (!cpu_isar_feature(aa64_sve, cpu)) {
+        value = false;
+    } else {
+        value = test_bit(vq - 1, cpu->sve_vq_map);
+    }
+    visit_type_bool(v, name, &value, errp);
+}
+
+static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    uint32_t vq = atoi(&name[3]) / 128;
+    Error *err = NULL;
+    bool value;
+
+    visit_type_bool(v, name, &value, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    if (value) {
+        set_bit(vq - 1, cpu->sve_vq_map);
+    } else {
+        clear_bit(vq - 1, cpu->sve_vq_map);
+    }
+    set_bit(vq - 1, cpu->sve_vq_init);
+}
+
 static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
                             void *opaque, Error **errp)
 {
@@ -315,6 +494,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
 static void aarch64_max_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    uint32_t vq;
 
     if (kvm_enabled()) {
         kvm_arm_set_cpu_features_from_host(cpu);
@@ -418,11 +598,17 @@ static void aarch64_max_initfn(Object *obj)
         cpu->dcz_blocksize = 7; /*  512 bytes */
 #endif
 
-        cpu->sve_max_vq = ARM_MAX_VQ;
         object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
                             cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
         object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
                             cpu_arm_set_sve, NULL, NULL, &error_fatal);
+
+        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+            char name[8];
+            sprintf(name, "sve%d", vq * 128);
+            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
+                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
+        }
     }
 }
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 507026c9154b..f33284c247d5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5351,6 +5351,13 @@ int sve_exception_el(CPUARMState *env, int el)
     return 0;
 }
 
+static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
+{
+    uint32_t start_vq = (start_len & 0xf) + 1;
+
+    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
+}
+
 /*
  * Given that SVE is enabled, return the vector length for EL.
  */
@@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
     uint32_t zcr_len = cpu->sve_max_vq - 1;
 
     if (el <= 1) {
-        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
+        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
     }
     if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
-        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
+        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
     }
     if (arm_feature(env, ARM_FEATURE_EL3)) {
-        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
+        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
     }
     return zcr_len;
 }
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 4fddb6c252a3..e912ed2cefa0 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -90,6 +90,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
     return head;
 }
 
+QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
+
 /*
  * These are cpu model features we want to advertise. The order here
  * matters as this is the order in which qmp_query_cpu_model_expansion
@@ -98,6 +100,9 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
  */
 static const char *cpu_model_advertised_features[] = {
     "aarch64", "pmu", "sve",
+    "sve128", "sve256", "sve384", "sve512",
+    "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
+    "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
     NULL
 };
 
@@ -185,6 +190,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         if (!err) {
             visit_check_struct(visitor, &err);
         }
+        if (!err) {
+            arm_cpu_finalize_features(ARM_CPU(obj), &err);
+        }
         visit_end_struct(visitor, NULL);
         visit_free(visitor);
         if (err) {
@@ -192,6 +200,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
             error_propagate(errp, err);
             return NULL;
         }
+    } else {
+        Error *err = NULL;
+        arm_cpu_finalize_features(ARM_CPU(obj), &err);
+        assert(err == NULL);
     }
 
     expansion_info = g_new0(CpuModelExpansionInfo, 1);
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 202bc0e3e823..9a2dd402b769 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -13,6 +13,18 @@
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
 
+#if __SIZEOF_LONG__ == 8
+#define BIT(n) (1UL << (n))
+#else
+#define BIT(n) (1ULL << (n))
+#endif
+
+/*
+ * We expect the SVE max-vq to be 16. Also it must be <= 64
+ * for our test code, otherwise 'vls' can't just be a uint64_t.
+ */
+#define SVE_MAX_VQ 16
+
 #define MACHINE    "-machine virt,gic-version=max "
 #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
                      "'arguments': { 'type': 'full', "
@@ -157,6 +169,173 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type)
     qobject_unref(resp);
 }
 
+static uint64_t resp_get_sve_vls(QDict *resp)
+{
+    QDict *props;
+    const QDictEntry *e;
+    uint64_t vls = 0;
+    int n = 0;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+
+    props = resp_get_props(resp);
+
+    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
+        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
+            g_ascii_isdigit(e->key[3])) {
+            char *endptr;
+            int bits;
+
+            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
+            if (!bits || *endptr != '\0') {
+                continue;
+            }
+
+            if (qdict_get_bool(props, e->key)) {
+                vls |= BIT((bits / 128) - 1);
+            }
+            ++n;
+        }
+    }
+
+    g_assert(n == SVE_MAX_VQ);
+
+    return vls;
+}
+
+#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
+({                                                                     \
+    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
+    g_assert(_resp);                                                   \
+    g_assert(resp_has_props(_resp));                                   \
+    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
+    qobject_unref(_resp);                                              \
+})
+
+static void sve_tests_default(QTestState *qts, const char *cpu_type)
+{
+    /*
+     * With no sve-max-vq or sve<N> properties on the command line
+     * the default is to have all vector lengths enabled. This also
+     * tests that 'sve' is 'on' by default.
+     */
+    assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL);
+
+    /* With SVE off, all vector lengths should also be off. */
+    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
+
+    /* With SVE on, we must have at least one vector length enabled. */
+    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
+
+    /*
+     * ---------------------------------------------------------------------
+     *               power-of-two(vq)   all-power-            can      can
+     *                                  of-two(< vq)        enable   disable
+     * ---------------------------------------------------------------------
+     * vq < max_vq      no                MUST*              yes      yes
+     * vq < max_vq      yes               MUST*              yes      no
+     * ---------------------------------------------------------------------
+     * vq == max_vq     n/a               MUST*              yes**    yes**
+     * ---------------------------------------------------------------------
+     * vq > max_vq      n/a               no                 no       yes
+     * vq > max_vq      n/a               yes                yes      yes
+     * ---------------------------------------------------------------------
+     *
+     * [*] "MUST" means this requirement must already be satisfied,
+     *     otherwise 'max_vq' couldn't itself be enabled.
+     *
+     * [**] Not testable with the QMP interface, only with the command line.
+     */
+
+    /* max_vq := 8 */
+    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
+
+    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
+    assert_sve_vls(qts, cpu_type, 0x8f,
+                   "{ 'sve1024': true, 'sve384': true }");
+    assert_sve_vls(qts, cpu_type, 0x8b,
+                   "{ 'sve1024': true, 'sve384': false }");
+
+    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
+    assert_sve_vls(qts, cpu_type, 0x8b,
+                   "{ 'sve1024': true, 'sve256': true }");
+    assert_error(qts, cpu_type, "cannot disable sve256",
+                 "{ 'sve1024': true, 'sve256': false }");
+
+    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
+    assert_error(qts, cpu_type, "cannot disable sve512",
+                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
+
+    /*
+     * We can disable power-of-two vector lengths when all larger lengths
+     * are also disabled. We only need to disable the power-of-two length,
+     * as all non-enabled larger lengths will then be auto-disabled.
+     */
+    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
+
+    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
+    assert_sve_vls(qts, cpu_type, 0x1f,
+                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
+    assert_sve_vls(qts, cpu_type, 0xf,
+                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
+}
+
+static void sve_tests_sve_max_vq_8(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
+
+    assert_sve_vls(qts, "max", BIT(8) - 1, NULL);
+
+    /*
+     * Disabling the max-vq set by sve-max-vq is not allowed, but
+     * of course enabling it is OK.
+     */
+    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
+
+    /*
+     * Enabling anything larger than max-vq set by sve-max-vq is not
+     * allowed, but of course disabling everything larger is OK.
+     */
+    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
+    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
+
+    /*
+     * We can disable non power-of-two lengths smaller than the max-vq
+     * set by sve-max-vq, but not power-of-two lengths.
+     */
+    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
+    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
+
+    qtest_quit(qts);
+}
+
+static void sve_tests_sve_off(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-cpu max,sve=off");
+
+    /* SVE is off, so the map should be empty. */
+    assert_sve_vls(qts, "max", 0, NULL);
+
+    /* The map stays empty even if we turn lengths on or off. */
+    assert_sve_vls(qts, "max", 0, "{ 'sve128': true }");
+    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+
+    /* With SVE re-enabled we should get all vector lengths enabled. */
+    assert_sve_vls(qts, "max", BIT(SVE_MAX_VQ) - 1, "{ 'sve': true }");
+
+    /* Or enable SVE with just specific vector lengths. */
+    assert_sve_vls(qts, "max", 0x3,
+                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
+
+    qtest_quit(qts);
+}
+
 static void test_query_cpu_model_expansion(const void *data)
 {
     QTestState *qts;
@@ -180,9 +359,12 @@ static void test_query_cpu_model_expansion(const void *data)
     if (g_str_equal(qtest_get_arch(), "aarch64")) {
         assert_has_feature(qts, "max", "aarch64");
         assert_has_feature(qts, "max", "sve");
+        assert_has_feature(qts, "max", "sve128");
         assert_has_feature(qts, "cortex-a57", "pmu");
         assert_has_feature(qts, "cortex-a57", "aarch64");
 
+        sve_tests_default(qts, "max");
+
         /* Test that features that depend on KVM generate errors without. */
         assert_error(qts, "max",
                      "'aarch64' feature cannot be disabled "
@@ -234,6 +416,13 @@ int main(int argc, char **argv)
     qtest_add_data_func("/arm/query-cpu-model-expansion",
                         NULL, test_query_cpu_model_expansion);
 
+    if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
+                            NULL, sve_tests_sve_max_vq_8);
+        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
+                            NULL, sve_tests_sve_off);
+    }
+
     if (kvm_available) {
         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
                             NULL, test_query_cpu_model_expansion_kvm);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (3 preceding siblings ...)
  2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-25 13:58   ` Auger Eric
                     ` (2 more replies)
  2019-09-24 11:31 ` [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
                   ` (3 subsequent siblings)
  8 siblings, 3 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

These are the SVE equivalents to kvm_arch_get/put_fpsimd. Note, the
swabbing is different than it is for fpsmid because the vector format
is a little-endian stream of words.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm64.c | 137 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 133 insertions(+), 4 deletions(-)

diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 28f6db57d5ee..ea454c613919 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -671,11 +671,12 @@ int kvm_arch_destroy_vcpu(CPUState *cs)
 bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
 {
     /* Return true if the regidx is a register we should synchronize
-     * via the cpreg_tuples array (ie is not a core reg we sync by
-     * hand in kvm_arch_get/put_registers())
+     * via the cpreg_tuples array (ie is not a core or sve reg that
+     * we sync by hand in kvm_arch_get/put_registers())
      */
     switch (regidx & KVM_REG_ARM_COPROC_MASK) {
     case KVM_REG_ARM_CORE:
+    case KVM_REG_ARM64_SVE:
         return false;
     default:
         return true;
@@ -761,6 +762,78 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
     return 0;
 }
 
+/*
+ * SVE registers are encoded in KVM's memory in an endianness-invariant format.
+ * The byte at offset i from the start of the in-memory representation contains
+ * the bits [(7 + 8 * i) : (8 * i)] of the register value. As this means the
+ * lowest offsets are stored in the lowest memory addresses, then that nearly
+ * matches QEMU's representation, which is to use an array of host-endian
+ * uint64_t's, where the lower offsets are at the lower indices. To complete
+ * the translation we just need to byte swap the uint64_t's on big-endian hosts.
+ */
+static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+    int i;
+
+    for (i = 0; i < nr; ++i) {
+        dst[i] = bswap64(src[i]);
+    }
+
+    return dst;
+#else
+    return src;
+#endif
+}
+
+/*
+ * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
+ * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
+ * code the slice index to zero for now as it's unlikely we'll need more than
+ * one slice for quite some time.
+ */
+static int kvm_arch_put_sve(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    uint64_t tmp[ARM_MAX_VQ * 2];
+    uint64_t *r;
+    struct kvm_one_reg reg;
+    int n, ret;
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
+        r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2);
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
+        r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0],
+                        DIV_ROUND_UP(cpu->sve_max_vq, 8));
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    r = sve_bswap64(tmp, &env->vfp.pregs[FFR_PRED_NUM].p[0],
+                    DIV_ROUND_UP(cpu->sve_max_vq, 8));
+    reg.addr = (uintptr_t)r;
+    reg.id = KVM_REG_ARM64_SVE_FFR(0);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    return 0;
+}
+
 int kvm_arch_put_registers(CPUState *cs, int level)
 {
     struct kvm_one_reg reg;
@@ -855,7 +928,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         }
     }
 
-    ret = kvm_arch_put_fpsimd(cs);
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arch_put_sve(cs);
+    } else {
+        ret = kvm_arch_put_fpsimd(cs);
+    }
     if (ret) {
         return ret;
     }
@@ -918,6 +995,54 @@ static int kvm_arch_get_fpsimd(CPUState *cs)
     return 0;
 }
 
+/*
+ * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
+ * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
+ * code the slice index to zero for now as it's unlikely we'll need more than
+ * one slice for quite some time.
+ */
+static int kvm_arch_get_sve(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    struct kvm_one_reg reg;
+    uint64_t *r;
+    int n, ret;
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
+        r = &env->vfp.zregs[n].d[0];
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, cpu->sve_max_vq * 2);
+    }
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
+        r = &env->vfp.pregs[n].p[0];
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+    }
+
+    r = &env->vfp.pregs[FFR_PRED_NUM].p[0];
+    reg.addr = (uintptr_t)r;
+    reg.id = KVM_REG_ARM64_SVE_FFR(0);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+
+    return 0;
+}
+
 int kvm_arch_get_registers(CPUState *cs)
 {
     struct kvm_one_reg reg;
@@ -1012,7 +1137,11 @@ int kvm_arch_get_registers(CPUState *cs)
         env->spsr = env->banked_spsr[i];
     }
 
-    ret = kvm_arch_get_fpsimd(cs);
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arch_get_sve(cs);
+    } else {
+        ret = kvm_arch_get_fpsimd(cs);
+    }
     if (ret) {
         return ret;
     }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (4 preceding siblings ...)
  2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-26  6:53   ` Auger Eric
  2019-09-24 11:31 ` [PATCH v4 7/9] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Enable SVE in the KVM guest when the 'max' cpu type is configured
and KVM supports it. KVM SVE requires use of the new finalize
vcpu ioctl, so we add that now too. For starters SVE can only be
turned on or off, getting all vector lengths the host CPU supports
when on. We'll add the other SVE CPU properties in later patches.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu64.c       | 17 ++++++++++++++---
 target/arm/kvm.c         |  5 +++++
 target/arm/kvm64.c       | 20 +++++++++++++++++++-
 target/arm/kvm_arm.h     | 27 +++++++++++++++++++++++++++
 tests/arm-cpu-features.c |  1 +
 5 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 606e3eceb9c0..b7eff4e1e107 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -481,6 +481,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
         return;
     }
 
+    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
+        error_setg(errp, "'sve' feature not supported by KVM on this host");
+        return;
+    }
+
     t = cpu->isar.id_aa64pfr0;
     t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
     cpu->isar.id_aa64pfr0 = t;
@@ -495,11 +500,16 @@ static void aarch64_max_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq;
+    uint64_t t;
 
     if (kvm_enabled()) {
         kvm_arm_set_cpu_features_from_host(cpu);
+        if (kvm_arm_sve_supported(CPU(cpu))) {
+            t = cpu->isar.id_aa64pfr0;
+            t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
+            cpu->isar.id_aa64pfr0 = t;
+        }
     } else {
-        uint64_t t;
         uint32_t u;
         aarch64_a57_initfn(obj);
 
@@ -600,8 +610,6 @@ static void aarch64_max_initfn(Object *obj)
 
         object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
                             cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
-        object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
-                            cpu_arm_set_sve, NULL, NULL, &error_fatal);
 
         for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
             char name[8];
@@ -610,6 +618,9 @@ static void aarch64_max_initfn(Object *obj)
                                 cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
         }
     }
+
+    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
+                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
 }
 
 struct ARMCPUInfo {
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b2eaa50b8df9..72569f71236e 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -51,6 +51,11 @@ int kvm_arm_vcpu_init(CPUState *cs)
     return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
 }
 
+int kvm_arm_vcpu_finalize(CPUState *cs, int feature)
+{
+    return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_FINALIZE, &feature);
+}
+
 void kvm_arm_init_serror_injection(CPUState *cs)
 {
     cap_has_inject_serror_esr = kvm_check_extension(cs->kvm_state,
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index ea454c613919..fc62bab8684e 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -602,6 +602,13 @@ bool kvm_arm_aarch32_supported(CPUState *cpu)
     return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT);
 }
 
+bool kvm_arm_sve_supported(CPUState *cpu)
+{
+    KVMState *s = KVM_STATE(current_machine->accelerator);
+
+    return kvm_check_extension(s, KVM_CAP_ARM_SVE);
+}
+
 #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
 
 int kvm_arch_init_vcpu(CPUState *cs)
@@ -630,13 +637,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
     }
     if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
-            cpu->has_pmu = false;
+        cpu->has_pmu = false;
     }
     if (cpu->has_pmu) {
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
     } else {
         unset_feature(&env->features, ARM_FEATURE_PMU);
     }
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        assert(kvm_arm_sve_supported(cs));
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE;
+    }
 
     /* Do KVM_ARM_VCPU_INIT ioctl */
     ret = kvm_arm_vcpu_init(cs);
@@ -644,6 +655,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
         return ret;
     }
 
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
+        if (ret) {
+            return ret;
+        }
+    }
+
     /*
      * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
      * Currently KVM has its own idea about MPIDR assignment, so we
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index b3106c8600af..1151877f97ea 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -27,6 +27,20 @@
  */
 int kvm_arm_vcpu_init(CPUState *cs);
 
+/**
+ * kvm_arm_vcpu_finalize
+ * @cs: CPUState
+ * @feature: int
+ *
+ * Finalizes the configuration of the specified VCPU feature by
+ * invoking the KVM_ARM_VCPU_FINALIZE ioctl. Features requiring
+ * this are documented in the "KVM_ARM_VCPU_FINALIZE" section of
+ * KVM's API documentation.
+ *
+ * Returns: 0 if success else < 0 error code
+ */
+int kvm_arm_vcpu_finalize(CPUState *cs, int feature);
+
 /**
  * kvm_arm_register_device:
  * @mr: memory region for this device
@@ -225,6 +239,14 @@ bool kvm_arm_aarch32_supported(CPUState *cs);
  */
 bool kvm_arm_pmu_supported(CPUState *cs);
 
+/**
+ * bool kvm_arm_sve_supported:
+ * @cs: CPUState
+ *
+ * Returns true if the KVM VCPU can enable SVE and false otherwise.
+ */
+bool kvm_arm_sve_supported(CPUState *cs);
+
 /**
  * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the
  * IPA address space supported by KVM
@@ -275,6 +297,11 @@ static inline bool kvm_arm_pmu_supported(CPUState *cs)
     return false;
 }
 
+static inline bool kvm_arm_sve_supported(CPUState *cs)
+{
+    return false;
+}
+
 static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
 {
     return -ENOENT;
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 9a2dd402b769..d50f98cb6aea 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -386,6 +386,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
 
     if (g_str_equal(qtest_get_arch(), "aarch64")) {
         assert_has_feature(qts, "host", "aarch64");
+        assert_has_feature(qts, "max", "sve");
 
         assert_error(qts, "cortex-a15",
             "We cannot guarantee the CPU type 'cortex-a15' works "
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 7/9] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (5 preceding siblings ...)
  2019-09-24 11:31 ` [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-24 11:31 ` [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
  2019-09-24 11:31 ` [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties Andrew Jones
  8 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

kvm_arm_create_scratch_host_vcpu() takes a struct kvm_vcpu_init
parameter. Rather than just using it as an output parameter to
pass back the preferred target, use it also as an input parameter,
allowing a caller to pass a selected target if they wish and to
also pass cpu features. If the caller doesn't want to select a
target they can pass -1 for the target which indicates they want
to use the preferred target and have it passed back like before.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
 target/arm/kvm.c   | 20 +++++++++++++++-----
 target/arm/kvm32.c |  6 +++++-
 target/arm/kvm64.c |  6 +++++-
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 72569f71236e..7a540d9591f9 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -66,7 +66,7 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
                                       int *fdarray,
                                       struct kvm_vcpu_init *init)
 {
-    int ret, kvmfd = -1, vmfd = -1, cpufd = -1;
+    int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
 
     kvmfd = qemu_open("/dev/kvm", O_RDWR);
     if (kvmfd < 0) {
@@ -86,7 +86,14 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
         goto finish;
     }
 
-    ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, init);
+    if (init->target == -1) {
+        struct kvm_vcpu_init preferred;
+
+        ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &preferred);
+        if (!ret) {
+            init->target = preferred.target;
+        }
+    }
     if (ret >= 0) {
         ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
         if (ret < 0) {
@@ -98,10 +105,12 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
          * creating one kind of guest CPU which is its preferred
          * CPU type.
          */
+        struct kvm_vcpu_init try;
+
         while (*cpus_to_try != QEMU_KVM_ARM_TARGET_NONE) {
-            init->target = *cpus_to_try++;
-            memset(init->features, 0, sizeof(init->features));
-            ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
+            try.target = *cpus_to_try++;
+            memcpy(try.features, init->features, sizeof(init->features));
+            ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, &try);
             if (ret >= 0) {
                 break;
             }
@@ -109,6 +118,7 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
         if (ret < 0) {
             goto err;
         }
+        init->target = try.target;
     } else {
         /* Treat a NULL cpus_to_try argument the same as an empty
          * list, which means we will fail the call since this must
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 2451a2d4bbef..32bf8d6757c4 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -53,7 +53,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
         QEMU_KVM_ARM_TARGET_CORTEX_A15,
         QEMU_KVM_ARM_TARGET_NONE
     };
-    struct kvm_vcpu_init init;
+    /*
+     * target = -1 informs kvm_arm_create_scratch_host_vcpu()
+     * to use the preferred target
+     */
+    struct kvm_vcpu_init init = { .target = -1, };
 
     if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
         return false;
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index fc62bab8684e..f96649ae0349 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -502,7 +502,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
         KVM_ARM_TARGET_CORTEX_A57,
         QEMU_KVM_ARM_TARGET_NONE
     };
-    struct kvm_vcpu_init init;
+    /*
+     * target = -1 informs kvm_arm_create_scratch_host_vcpu()
+     * to use the preferred target
+     */
+    struct kvm_vcpu_init init = { .target = -1, };
 
     if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
         return false;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (6 preceding siblings ...)
  2019-09-24 11:31 ` [PATCH v4 7/9] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-26  6:52   ` Auger Eric
  2019-09-24 11:31 ` [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties Andrew Jones
  8 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Extend the SVE vq map initialization and validation with KVM's
supported vector lengths when KVM is enabled. In order to determine
and select supported lengths we add two new KVM functions for getting
and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.

This patch has been co-authored with Richard Henderson, who reworked
the target/arm/cpu64.c changes in order to push all the validation and
auto-enabling/disabling steps into the finalizer, resulting in a nice
LOC reduction.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst |  36 +++++---
 target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
 target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
 target/arm/kvm_arm.h      |  12 +++
 tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
 5 files changed, 368 insertions(+), 52 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index 1262fddc6201..939366f959cf 100644
--- a/docs/arm-cpu-features.rst
+++ b/docs/arm-cpu-features.rst
@@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
 
   1) At least one vector length must be enabled when `sve` is enabled.
 
-  2) If a vector length `N` is enabled, then all power-of-two vector
-     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
-     is enabled, then `sve128` and `sve256` must also be enabled,
-     but `sve384` is not required.
+  2) If a vector length `N` is enabled, then, when KVM is enabled, all
+     smaller, host supported vector lengths must also be enabled.  If
+     KVM is not enabled, then only all the smaller, power-of-two vector
+     lengths must be enabled.  E.g. with KVM if the host supports all
+     vector lengths up to 512-bits (128, 256, 384, 512), then if
+     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
+     be enabled. Without KVM, `sve384` would not be required.
+
+  3) If KVM is enabled then only vector lengths that the host CPU type
+     support may be enabled.  If SVE is not supported by the host, then
+     no `sve*` properties may be enabled.
 
 SVE CPU Property Parsing Semantics
 ----------------------------------
@@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
      disable the last enabled vector length (see constraint (1) of "SVE
      CPU Property Dependencies and Constraints").
 
-  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
+  4) When KVM is enabled, if the host does not support SVE, then an error
+     is generated when attempting to enable any `sve*` properties.
+
+  5) When KVM is enabled, if the host does support SVE, then an error is
+     generated when attempting to enable any vector lengths not supported
+     by the host.
+
+  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
      CPU properties are set `on`, then the specified vector lengths are
      disabled but the default for any unspecified lengths remains enabled.
-     Disabling a power-of-two vector length also disables all vector
-     lengths larger than the power-of-two length (see constraint (2) of
-     "SVE CPU Property Dependencies and Constraints").
+     When KVM is not enabled, disabling a power-of-two vector length also
+     disables all vector lengths larger than the power-of-two length.
+     When KVM is enabled, then disabling any supported vector length also
+     disables all larger vector lengths (see constraint (2) of "SVE CPU
+     Property Dependencies and Constraints").
 
-  5) If one or more `sve<N>` CPU properties are set to `on`, then they
+  7) If one or more `sve<N>` CPU properties are set to `on`, then they
      are enabled and all unspecified lengths default to disabled, except
      for the required lengths per constraint (2) of "SVE CPU Property
      Dependencies and Constraints", which will even be auto-enabled if
      they were not explicitly enabled.
 
-  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
+  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
      explicitly disabled (i.e. avoiding the error specified in (3) of
      "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
      provided an error will be generated.  To avoid this error, one must
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index b7eff4e1e107..18dd5e24ec61 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
      * any of the above.  Finally, if SVE is not disabled, then at least one
      * vector length must be enabled.
      */
+    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
     DECLARE_BITMAP(tmp, ARM_MAX_VQ);
     uint32_t vq, max_vq = 0;
 
+    /* Collect the set of vector lengths supported by KVM. */
+    bitmap_zero(kvm_supported, ARM_MAX_VQ);
+    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
+        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
+    } else if (kvm_enabled()) {
+        assert(!cpu_isar_feature(aa64_sve, cpu));
+    }
+
     /*
      * Process explicit sve<N> properties.
      * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
@@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
             return;
         }
 
-        /* Propagate enabled bits down through required powers-of-two. */
-        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
-            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
-                set_bit(vq - 1, cpu->sve_vq_map);
+        if (kvm_enabled()) {
+            /*
+             * For KVM we have to automatically enable all supported unitialized
+             * lengths, even when the smaller lengths are not all powers-of-two.
+             */
+            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
+            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
+        } else {
+            /* Propagate enabled bits down through required powers-of-two. */
+            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
+                    set_bit(vq - 1, cpu->sve_vq_map);
+                }
             }
         }
     } else if (cpu->sve_max_vq == 0) {
@@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
             return;
         }
 
-        /* Disabling a power-of-two disables all larger lengths. */
-        if (test_bit(0, cpu->sve_vq_init)) {
-            error_setg(errp, "cannot disable sve128");
-            error_append_hint(errp, "Disabling sve128 results in all vector "
-                              "lengths being disabled.\n");
-            error_append_hint(errp, "With SVE enabled, at least one vector "
-                              "length must be enabled.\n");
-            return;
-        }
-        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
-            if (test_bit(vq - 1, cpu->sve_vq_init)) {
-                break;
+        if (kvm_enabled()) {
+            /* Disabling a supported length disables all larger lengths. */
+            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+                if (test_bit(vq - 1, cpu->sve_vq_init) &&
+                    test_bit(vq - 1, kvm_supported)) {
+                    break;
+                }
+            }
+            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
+            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
+                          cpu->sve_vq_init, max_vq);
+            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
+                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
+                error_setg(errp, "cannot disable sve%d", vq * 128);
+                error_append_hint(errp, "Disabling sve%d results in all "
+                                  "vector lengths being disabled.\n",
+                                  vq * 128);
+                error_append_hint(errp, "With SVE enabled, at least one "
+                                  "vector length must be enabled.\n");
+                return;
+            }
+        } else {
+            /* Disabling a power-of-two disables all larger lengths. */
+            if (test_bit(0, cpu->sve_vq_init)) {
+                error_setg(errp, "cannot disable sve128");
+                error_append_hint(errp, "Disabling sve128 results in all "
+                                  "vector lengths being disabled.\n");
+                error_append_hint(errp, "With SVE enabled, at least one "
+                                  "vector length must be enabled.\n");
+                return;
+            }
+            for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
+                if (test_bit(vq - 1, cpu->sve_vq_init)) {
+                    break;
+                }
             }
+            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
+            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
         }
-        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
 
-        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
         max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
     }
 
@@ -358,16 +399,48 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
     assert(max_vq != 0);
     bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
 
-    /* Ensure all required powers-of-two are enabled. */
-    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
-        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
-            error_setg(errp, "cannot disable sve%d", vq * 128);
-            error_append_hint(errp, "sve%d is required as it "
-                              "is a power-of-two length smaller than "
-                              "the maximum, sve%d\n",
-                              vq * 128, max_vq * 128);
+    if (kvm_enabled()) {
+        /* Ensure the set of lengths matches what KVM supports. */
+        bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
+        if (!bitmap_empty(tmp, max_vq)) {
+            vq = find_last_bit(tmp, max_vq) + 1;
+            if (test_bit(vq - 1, cpu->sve_vq_map)) {
+                if (cpu->sve_max_vq) {
+                    error_setg(errp, "cannot set sve-max-vq=%d",
+                               cpu->sve_max_vq);
+                    error_append_hint(errp, "This KVM host does not support "
+                                      "the vector length %d-bits.\n",
+                                      vq * 128);
+                    error_append_hint(errp, "It may not be possible to use "
+                                      "sve-max-vq with this KVM host. Try "
+                                      "using only sve<N> properties.\n");
+                } else {
+                    error_setg(errp, "cannot enable sve%d", vq * 128);
+                    error_append_hint(errp, "This KVM host does not support "
+                                      "the vector length %d-bits.\n",
+                                      vq * 128);
+                }
+            } else {
+                error_setg(errp, "cannot disable sve%d", vq * 128);
+                error_append_hint(errp, "The KVM host requires all "
+                                  "supported vector lengths smaller "
+                                  "than %d bits to also be enabled.\n",
+                                  max_vq * 128);
+            }
             return;
         }
+    } else {
+        /* Ensure all required powers-of-two are enabled. */
+        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
+            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+                error_setg(errp, "cannot disable sve%d", vq * 128);
+                error_append_hint(errp, "sve%d is required as it "
+                                  "is a power-of-two length smaller than "
+                                  "the maximum, sve%d\n",
+                                  vq * 128, max_vq * 128);
+                return;
+            }
+        }
     }
 
     /* From now on sve_max_vq is the actual maximum supported length. */
@@ -411,13 +484,22 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
     Error *err = NULL;
 
     visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
 
-    if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) {
-        error_setg(&err, "unsupported SVE vector length");
-        error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n",
+    if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
+        error_setg(errp, "cannot set sve-max-vq");
+        error_append_hint(errp, "SVE not supported by KVM on this host\n");
+        return;
+    }
+
+    if (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ) {
+        error_setg(errp, "unsupported SVE vector length");
+        error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n",
                           ARM_MAX_VQ);
     }
-    error_propagate(errp, err);
 }
 
 static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
@@ -450,6 +532,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
         return;
     }
 
+    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
+        error_setg(errp, "cannot enable %s", name);
+        error_append_hint(errp, "SVE not supported by KVM on this host\n");
+        return;
+    }
+
     if (value) {
         set_bit(vq - 1, cpu->sve_vq_map);
     } else {
@@ -607,20 +695,19 @@ static void aarch64_max_initfn(Object *obj)
         cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
         cpu->dcz_blocksize = 7; /*  512 bytes */
 #endif
-
-        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
-                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
-
-        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-            char name[8];
-            sprintf(name, "sve%d", vq * 128);
-            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
-                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
-        }
     }
 
     object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
                         cpu_arm_set_sve, NULL, NULL, &error_fatal);
+    object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
+                        cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        char name[8];
+        sprintf(name, "sve%d", vq * 128);
+        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
+                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
+    }
 }
 
 struct ARMCPUInfo {
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index f96649ae0349..cff4217a8469 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -613,6 +613,100 @@ bool kvm_arm_sve_supported(CPUState *cpu)
     return kvm_check_extension(s, KVM_CAP_ARM_SVE);
 }
 
+QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
+
+void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
+{
+    /* Only call this function if kvm_arm_sve_supported() returns true. */
+    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
+    static bool probed;
+    uint32_t vq = 0;
+    int i, j;
+
+    bitmap_clear(map, 0, ARM_MAX_VQ);
+
+    /*
+     * KVM ensures all host CPUs support the same set of vector lengths.
+     * So we only need to create the scratch VCPUs once and then cache
+     * the results.
+     */
+    if (!probed) {
+        struct kvm_vcpu_init init = {
+            .target = -1,
+            .features[0] = (1 << KVM_ARM_VCPU_SVE),
+        };
+        struct kvm_one_reg reg = {
+            .id = KVM_REG_ARM64_SVE_VLS,
+            .addr = (uint64_t)&vls[0],
+        };
+        int fdarray[3], ret;
+
+        probed = true;
+
+        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
+            error_report("failed to create scratch VCPU with SVE enabled");
+            abort();
+        }
+        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
+        kvm_arm_destroy_scratch_host_vcpu(fdarray);
+        if (ret) {
+            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
+                         strerror(errno));
+            abort();
+        }
+
+        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
+            if (vls[i]) {
+                vq = 64 - clz64(vls[i]) + i * 64;
+                break;
+            }
+        }
+        if (vq > ARM_MAX_VQ) {
+            warn_report("KVM supports vector lengths larger than "
+                        "QEMU can enable");
+        }
+    }
+
+    for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) {
+        if (!vls[i]) {
+            continue;
+        }
+        for (j = 1; j <= 64; ++j) {
+            vq = j + i * 64;
+            if (vq > ARM_MAX_VQ) {
+                return;
+            }
+            if (vls[i] & (1UL << (j - 1))) {
+                set_bit(vq - 1, map);
+            }
+        }
+    }
+}
+
+static int kvm_arm_sve_set_vls(CPUState *cs)
+{
+    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0};
+    struct kvm_one_reg reg = {
+        .id = KVM_REG_ARM64_SVE_VLS,
+        .addr = (uint64_t)&vls[0],
+    };
+    ARMCPU *cpu = ARM_CPU(cs);
+    uint32_t vq;
+    int i, j;
+
+    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
+
+    for (vq = 1; vq <= cpu->sve_max_vq; ++vq) {
+        if (test_bit(vq - 1, cpu->sve_vq_map)) {
+            i = (vq - 1) / 64;
+            j = (vq - 1) % 64;
+            vls[i] |= 1UL << j;
+        }
+    }
+
+    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+}
+
 #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
 
 int kvm_arch_init_vcpu(CPUState *cs)
@@ -624,7 +718,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
 
     if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
         !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
-        fprintf(stderr, "KVM is not supported for this guest CPU type\n");
+        error_report("KVM is not supported for this guest CPU type");
         return -EINVAL;
     }
 
@@ -660,6 +754,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
     }
 
     if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arm_sve_set_vls(cs);
+        if (ret) {
+            return ret;
+        }
         ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
         if (ret) {
             return ret;
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 1151877f97ea..a1cc6513f72b 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -212,6 +212,17 @@ typedef struct ARMHostCPUFeatures {
  */
 bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
 
+/**
+ * kvm_arm_sve_get_vls:
+ * @cs: CPUState
+ * @map: bitmap to fill in
+ *
+ * Get all the SVE vector lengths supported by the KVM host, setting
+ * the bits corresponding to their length in quadwords minus one
+ * (vq - 1) in @map up to ARM_MAX_VQ.
+ */
+void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
+
 /**
  * kvm_arm_set_cpu_features_from_host:
  * @cpu: ARMCPU to set the features for
@@ -315,6 +326,7 @@ static inline int kvm_arm_vgic_probe(void)
 static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
 static inline void kvm_arm_pmu_init(CPUState *cs) {}
 
+static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) {}
 #endif
 
 static inline const char *gic_class_name(void)
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index d50f98cb6aea..a0129aebf409 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -117,6 +117,17 @@ static QDict *resp_get_props(QDict *resp)
     return qdict;
 }
 
+static bool resp_get_feature(QDict *resp, const char *feature)
+{
+    QDict *props;
+
+    g_assert(resp);
+    g_assert(resp_has_props(resp));
+    props = resp_get_props(resp);
+    g_assert(qdict_get(props, feature));
+    return qdict_get_bool(props, feature);
+}
+
 #define assert_has_feature(qts, cpu_type, feature)                     \
 ({                                                                     \
     QDict *_resp = do_query_no_props(qts, cpu_type);                   \
@@ -336,6 +347,25 @@ static void sve_tests_sve_off(const void *data)
     qtest_quit(qts);
 }
 
+static void sve_tests_sve_off_kvm(const void *data)
+{
+    QTestState *qts;
+
+    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
+
+    /*
+     * We don't know if this host supports SVE so we don't
+     * attempt to test enabling anything. We only test that
+     * everything is disabled (as it should be with sve=off)
+     * and that using sve<N>=off to explicitly disable vector
+     * lengths is OK too.
+     */
+    assert_sve_vls(qts, "max", 0, NULL);
+    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+
+    qtest_quit(qts);
+}
+
 static void test_query_cpu_model_expansion(const void *data)
 {
     QTestState *qts;
@@ -385,12 +415,81 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
     assert_has_feature(qts, "host", "pmu");
 
     if (g_str_equal(qtest_get_arch(), "aarch64")) {
+        bool kvm_supports_sve;
+        char max_name[8], name[8];
+        uint32_t max_vq, vq;
+        uint64_t vls;
+        QDict *resp;
+        char *error;
+
         assert_has_feature(qts, "host", "aarch64");
-        assert_has_feature(qts, "max", "sve");
 
         assert_error(qts, "cortex-a15",
             "We cannot guarantee the CPU type 'cortex-a15' works "
             "with KVM on this host", NULL);
+
+        assert_has_feature(qts, "max", "sve");
+        resp = do_query_no_props(qts, "max");
+        kvm_supports_sve = resp_get_feature(resp, "sve");
+        vls = resp_get_sve_vls(resp);
+        qobject_unref(resp);
+
+        if (kvm_supports_sve) {
+            g_assert(vls != 0);
+            max_vq = 64 - __builtin_clzll(vls);
+            sprintf(max_name, "sve%d", max_vq * 128);
+
+            /* Enabling a supported length is of course fine. */
+            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
+
+            /* Get the next supported length smaller than max-vq. */
+            vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
+            if (vq) {
+                /*
+                 * We have at least one length smaller than max-vq,
+                 * so we can disable max-vq.
+                 */
+                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
+                               "{ %s: false }", max_name);
+
+                /*
+                 * Smaller, supported vector lengths cannot be disabled
+                 * unless all larger, supported vector lengths are also
+                 * disabled.
+                 */
+                sprintf(name, "sve%d", vq * 128);
+                error = g_strdup_printf("cannot disable %s", name);
+                assert_error(qts, "max", error,
+                             "{ %s: true, %s: false }",
+                             max_name, name);
+                g_free(error);
+            }
+
+            /*
+             * The smallest, supported vector length is required, because
+             * we need at least one vector length enabled.
+             */
+            vq = __builtin_ffsll(vls);
+            sprintf(name, "sve%d", vq * 128);
+            error = g_strdup_printf("cannot disable %s", name);
+            assert_error(qts, "max", error, "{ %s: false }", name);
+            g_free(error);
+
+            /* Get an unsupported length. */
+            for (vq = 1; vq <= max_vq; ++vq) {
+                if (!(vls & BIT(vq - 1))) {
+                    break;
+                }
+            }
+            if (vq <= SVE_MAX_VQ) {
+                sprintf(name, "sve%d", vq * 128);
+                error = g_strdup_printf("cannot enable %s", name);
+                assert_error(qts, "max", error, "{ %s: true }", name);
+                g_free(error);
+            }
+        } else {
+            g_assert(vls == 0);
+        }
     } else {
         assert_error(qts, "host",
                      "'pmu' feature not supported by KVM on this host",
@@ -427,6 +526,10 @@ int main(int argc, char **argv)
     if (kvm_available) {
         qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
                             NULL, test_query_cpu_model_expansion_kvm);
+        if (g_str_equal(qtest_get_arch(), "aarch64")) {
+            qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
+                                NULL, sve_tests_sve_off_kvm);
+        }
     }
 
     return g_test_run();
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties
  2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (7 preceding siblings ...)
  2019-09-24 11:31 ` [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
@ 2019-09-24 11:31 ` Andrew Jones
  2019-09-26  7:07   ` Auger Eric
  8 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 11:31 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Allow cpu 'host' to enable SVE when it's available, unless the
user chooses to disable it with the added 'sve=off' cpu property.
Also give the user the ability to select vector lengths with the
sve<N> properties. We don't adopt 'max' cpu's other sve property,
sve-max-vq, because that property is difficult to use with KVM.
That property assumes all vector lengths in the range from 1 up
to and including the specified maximum length are supported, but
there may be optional lengths not supported by the host in that
range. With KVM one must be more specific when enabling vector
lengths.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst | 19 ++++++++++++-------
 target/arm/cpu.c          |  3 +++
 target/arm/cpu.h          |  2 ++
 target/arm/cpu64.c        | 33 +++++++++++++++++----------------
 target/arm/kvm64.c        | 14 +++++++++++++-
 tests/arm-cpu-features.c  | 21 +++++++++++----------
 6 files changed, 58 insertions(+), 34 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index 939366f959cf..0c16eef7c8c2 100644
--- a/docs/arm-cpu-features.rst
+++ b/docs/arm-cpu-features.rst
@@ -256,31 +256,36 @@ SVE CPU Property Examples
 
      $ qemu-system-aarch64 -M virt -cpu max
 
-  3) Only enable the 128-bit vector length::
+  3) When KVM is enabled, implicitly enable all host CPU supported vector
+     lengths with the `host` CPU type::
+
+     $ qemu-system-aarch64 -M virt,accel=kvm -cpu host
+
+  4) Only enable the 128-bit vector length::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve128=on
 
-  4) Disable the 256-bit vector length and all larger vector lengths
+  5) Disable the 256-bit vector length and all larger vector lengths
      since 256 is a power-of-two (this results in only the 128-bit length
      being enabled)::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve256=off
 
-  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
+  6) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
 
-  6) The same as (5), but since the 128-bit and 256-bit vector
+  7) The same as (6), but since the 128-bit and 256-bit vector
      lengths are required for the 512-bit vector length to be enabled,
      then allow them to be auto-enabled::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve512=on
 
-  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
+  8) Do the same as (7), but by first disabling SVE and then re-enabling it::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on
 
-  8) Force errors regarding the last vector length::
+  9) Force errors regarding the last vector length::
 
      $ qemu-system-aarch64 -M virt -cpu max,sve128=off
      $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
@@ -292,5 +297,5 @@ The examples in "SVE CPU Property Examples" exhibit many ways to select
 vector lengths which developers may find useful in order to avoid overly
 verbose command lines.  However, the recommended way to select vector
 lengths is to explicitly enable each desired length.  Therefore only
-example's (1), (3), and (5) exhibit recommended uses of the properties.
+example's (1), (4), and (6) exhibit recommended uses of the properties.
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 522fed95b339..7695ae551218 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2671,6 +2671,9 @@ static void arm_host_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
 
     kvm_arm_set_cpu_features_from_host(cpu);
+    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+        aarch64_add_sve_properties(obj);
+    }
     arm_cpu_post_init(obj);
 }
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 11162484465a..5b9c3e4cd73d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -974,11 +974,13 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
 void aarch64_sve_change_el(CPUARMState *env, int old_el,
                            int new_el, bool el0_a64);
+void aarch64_add_sve_properties(Object *obj);
 #else
 static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { }
 static inline void aarch64_sve_change_el(CPUARMState *env, int o,
                                          int n, bool a)
 { }
+static inline void aarch64_add_sve_properties(Object *obj) { }
 #endif
 
 #if !defined(CONFIG_TCG)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 18dd5e24ec61..e7cd420faa9d 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -579,6 +579,21 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
     cpu->isar.id_aa64pfr0 = t;
 }
 
+void aarch64_add_sve_properties(Object *obj)
+{
+    uint32_t vq;
+
+    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
+                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        char name[8];
+        sprintf(name, "sve%d", vq * 128);
+        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
+                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
+    }
+}
+
 /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
  * otherwise, a CPU with as many features enabled as our emulation supports.
  * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
@@ -587,17 +602,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
 static void aarch64_max_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
-    uint32_t vq;
-    uint64_t t;
 
     if (kvm_enabled()) {
         kvm_arm_set_cpu_features_from_host(cpu);
-        if (kvm_arm_sve_supported(CPU(cpu))) {
-            t = cpu->isar.id_aa64pfr0;
-            t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
-            cpu->isar.id_aa64pfr0 = t;
-        }
     } else {
+        uint64_t t;
         uint32_t u;
         aarch64_a57_initfn(obj);
 
@@ -697,17 +706,9 @@ static void aarch64_max_initfn(Object *obj)
 #endif
     }
 
-    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
-                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
+    aarch64_add_sve_properties(obj);
     object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
                         cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        char name[8];
-        sprintf(name, "sve%d", vq * 128);
-        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
-                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
-    }
 }
 
 struct ARMCPUInfo {
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index cff4217a8469..2da366ba113e 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -488,7 +488,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
      * and then query that CPU for the relevant ID registers.
      */
     int fdarray[3];
+    bool sve_supported;
     uint64_t features = 0;
+    uint64_t t;
     int err;
 
     /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
@@ -578,13 +580,23 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
                               ARM64_SYS_REG(3, 0, 0, 3, 2));
     }
 
+    sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0;
+
     kvm_arm_destroy_scratch_host_vcpu(fdarray);
 
     if (err < 0) {
         return false;
     }
 
-   /* We can assume any KVM supporting CPU is at least a v8
+    /* Add feature bits that can't appear until after VCPU init. */
+    if (sve_supported) {
+        t = ahcf->isar.id_aa64pfr0;
+        t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
+        ahcf->isar.id_aa64pfr0 = t;
+    }
+
+    /*
+     * We can assume any KVM supporting CPU is at least a v8
      * with VFPv4+Neon; this in turn implies most of the other
      * feature bits.
      */
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index a0129aebf409..4dc067fb5558 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -351,7 +351,7 @@ static void sve_tests_sve_off_kvm(const void *data)
 {
     QTestState *qts;
 
-    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
+    qts = qtest_init(MACHINE "-accel kvm -cpu host,sve=off");
 
     /*
      * We don't know if this host supports SVE so we don't
@@ -360,8 +360,8 @@ static void sve_tests_sve_off_kvm(const void *data)
      * and that using sve<N>=off to explicitly disable vector
      * lengths is OK too.
      */
-    assert_sve_vls(qts, "max", 0, NULL);
-    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
+    assert_sve_vls(qts, "host", 0, NULL);
+    assert_sve_vls(qts, "host", 0, "{ 'sve128': false }");
 
     qtest_quit(qts);
 }
@@ -428,8 +428,8 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
             "We cannot guarantee the CPU type 'cortex-a15' works "
             "with KVM on this host", NULL);
 
-        assert_has_feature(qts, "max", "sve");
-        resp = do_query_no_props(qts, "max");
+        assert_has_feature(qts, "host", "sve");
+        resp = do_query_no_props(qts, "host");
         kvm_supports_sve = resp_get_feature(resp, "sve");
         vls = resp_get_sve_vls(resp);
         qobject_unref(resp);
@@ -440,7 +440,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
             sprintf(max_name, "sve%d", max_vq * 128);
 
             /* Enabling a supported length is of course fine. */
-            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
+            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
 
             /* Get the next supported length smaller than max-vq. */
             vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
@@ -449,7 +449,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
                  * We have at least one length smaller than max-vq,
                  * so we can disable max-vq.
                  */
-                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
+                assert_sve_vls(qts, "host", (vls & ~BIT(max_vq - 1)),
                                "{ %s: false }", max_name);
 
                 /*
@@ -459,7 +459,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
                  */
                 sprintf(name, "sve%d", vq * 128);
                 error = g_strdup_printf("cannot disable %s", name);
-                assert_error(qts, "max", error,
+                assert_error(qts, "host", error,
                              "{ %s: true, %s: false }",
                              max_name, name);
                 g_free(error);
@@ -472,7 +472,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
             vq = __builtin_ffsll(vls);
             sprintf(name, "sve%d", vq * 128);
             error = g_strdup_printf("cannot disable %s", name);
-            assert_error(qts, "max", error, "{ %s: false }", name);
+            assert_error(qts, "host", error, "{ %s: false }", name);
             g_free(error);
 
             /* Get an unsupported length. */
@@ -484,13 +484,14 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
             if (vq <= SVE_MAX_VQ) {
                 sprintf(name, "sve%d", vq * 128);
                 error = g_strdup_printf("cannot enable %s", name);
-                assert_error(qts, "max", error, "{ %s: true }", name);
+                assert_error(qts, "host", error, "{ %s: true }", name);
                 g_free(error);
             }
         } else {
             g_assert(vls == 0);
         }
     } else {
+        assert_has_not_feature(qts, "host", "sve");
         assert_error(qts, "host",
                      "'pmu' feature not supported by KVM on this host",
                      "{ 'pmu': true }");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
@ 2019-09-24 13:55   ` Andrew Jones
  2019-09-25 13:53   ` Auger Eric
  2019-09-26 19:07   ` Richard Henderson
  2 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-24 13:55 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, abologna, eric.auger,
	imammedo, alex.bennee, Dave.Martin

On Tue, Sep 24, 2019 at 01:31:00PM +0200, Andrew Jones wrote:
> +SVE CPU Property Parsing Semantics
> +----------------------------------
> +
> +  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
> +     are enabled or disabled is irrelevant to the guest, as the entire
> +     SVE feature is disabled and that disables all vector lengths for
> +     the guest.  However QEMU will still track any `sve<N>` CPU
> +     properties provided by the user.  If later an `sve=on` is provided,
> +     then the guest will get only the enabled lengths.

I just spoke with Andrea, who is doing the libvirt side of this, about
this behavior. He suggests that we change it such that an error is
generated if sve=off and there are explicitly enabled vector lengths,
e.g. '-cpu max,sve=off,sve256=on' should generate an error. It would
still be possible to have sve<N>=on and sve=off on the same command
line, as long as the sve<N>=on is followed by sve<N>=off, like this
-cpu max,sve=off,sve256=on,sve256=off,sve128=off, but I don't think
we need to worry about that sort of thing. I'll add an error for
the non-empty vector length map with SVE off case for v5.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property
  2019-09-24 11:30 ` [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
@ 2019-09-24 15:06   ` Auger Eric
  0 siblings, 0 replies; 32+ messages in thread
From: Auger Eric @ 2019-09-24 15:06 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:30 PM, Andrew Jones wrote:
> Since 97a28b0eeac14 ("target/arm: Allow VFP and Neon to be disabled via
> a CPU property") we can disable the 'max' cpu model's VFP and neon
> features, but there's no way to disable SVE. Add the 'sve=on|off'
> property to give it that flexibility. We also rename
> cpu_max_get/set_sve_vq to cpu_max_get/set_sve_max_vq in order for them
> to follow the typical *_get/set_<property-name> pattern.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric
> ---
>  target/arm/cpu.c         |  3 ++-
>  target/arm/cpu64.c       | 42 ++++++++++++++++++++++++++++++++++------
>  target/arm/monitor.c     |  2 +-
>  tests/arm-cpu-features.c |  1 +
>  4 files changed, 40 insertions(+), 8 deletions(-)
> 
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 2399c144718d..73be2ebfdd39 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -200,7 +200,8 @@ static void arm_cpu_reset(CPUState *s)
>          env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
>          env->cp15.cptr_el[3] |= CPTR_EZ;
>          /* with maximum vector length */
> -        env->vfp.zcr_el[1] = cpu->sve_max_vq - 1;
> +        env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ?
> +                             cpu->sve_max_vq - 1 : 0;
>          env->vfp.zcr_el[2] = env->vfp.zcr_el[1];
>          env->vfp.zcr_el[3] = env->vfp.zcr_el[1];
>          /*
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index d7f5bf610a7d..8cdb0c79fa7a 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -256,15 +256,15 @@ static void aarch64_a72_initfn(Object *obj)
>      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
>  }
>  
> -static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name,
> -                               void *opaque, Error **errp)
> +static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
>  }
>  
> -static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
> -                               void *opaque, Error **errp)
> +static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      Error *err = NULL;
> @@ -279,6 +279,34 @@ static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
>      error_propagate(errp, err);
>  }
>  
> +static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
> +                            void *opaque, Error **errp)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +    bool value = cpu_isar_feature(aa64_sve, cpu);
> +
> +    visit_type_bool(v, name, &value, errp);
> +}
> +
> +static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
> +                            void *opaque, Error **errp)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +    Error *err = NULL;
> +    bool value;
> +    uint64_t t;
> +
> +    visit_type_bool(v, name, &value, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    t = cpu->isar.id_aa64pfr0;> +    t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
> +    cpu->isar.id_aa64pfr0 = t;
> +}
> +
>  /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
>   * otherwise, a CPU with as many features enabled as our emulation supports.
>   * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
> @@ -391,8 +419,10 @@ static void aarch64_max_initfn(Object *obj)
>  #endif
>  
>          cpu->sve_max_vq = ARM_MAX_VQ;
> -        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_vq,
> -                            cpu_max_set_sve_vq, NULL, NULL, &error_fatal);
> +        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> +                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> +        object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> +                            cpu_arm_set_sve, NULL, NULL, &error_fatal);
>      }
>  }
>  
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index edca8aa885f0..4fddb6c252a3 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -97,7 +97,7 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>   * then the order that considers those dependencies must be used.
>   */
>  static const char *cpu_model_advertised_features[] = {
> -    "aarch64", "pmu",
> +    "aarch64", "pmu", "sve",
>      NULL
>  };
>  
> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> index 198ff6d6b495..202bc0e3e823 100644
> --- a/tests/arm-cpu-features.c
> +++ b/tests/arm-cpu-features.c
> @@ -179,6 +179,7 @@ static void test_query_cpu_model_expansion(const void *data)
>  
>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
>          assert_has_feature(qts, "max", "aarch64");
> +        assert_has_feature(qts, "max", "sve");
>          assert_has_feature(qts, "cortex-a57", "pmu");
>          assert_has_feature(qts, "cortex-a57", "aarch64");
>  
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-09-24 11:30 ` [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
@ 2019-09-24 15:06   ` Auger Eric
  0 siblings, 0 replies; 32+ messages in thread
From: Auger Eric @ 2019-09-24 15:06 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:30 PM, Andrew Jones wrote:
> Add support for the query-cpu-model-expansion QMP command to Arm. We
> do this selectively, only exposing CPU properties which represent
> optional CPU features which the user may want to enable/disable.
> Additionally we restrict the list of queryable cpu models to 'max',
> 'host', or the current type when KVM is in use. And, finally, we only
> implement expansion type 'full', as Arm does not yet have a "base"
> CPU type. More details and example queries are described in a new
> document (docs/arm-cpu-features.rst).
> 
> Note, certainly more features may be added to the list of advertised
> features, e.g. 'vfp' and 'neon'. The only requirement is that we can
> detect invalid configurations and emit failures at QMP query time.
> For 'vfp' and 'neon' this will require some refactoring to share a
> validation function between the QMP query and the CPU realize
> functions.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric
> ---
>  docs/arm-cpu-features.rst | 137 +++++++++++++++++++++++++++++++++++
>  qapi/machine-target.json  |   6 +-
>  target/arm/monitor.c      | 145 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 285 insertions(+), 3 deletions(-)
>  create mode 100644 docs/arm-cpu-features.rst
> 
> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> new file mode 100644
> index 000000000000..c79dcffb5556
> --- /dev/null
> +++ b/docs/arm-cpu-features.rst
> @@ -0,0 +1,137 @@
> +================
> +ARM CPU Features
> +================
> +
> +Examples of probing and using ARM CPU features
> +
> +Introduction
> +============
> +
> +CPU features are optional features that a CPU of supporting type may
> +choose to implement or not.  In QEMU, optional CPU features have
> +corresponding boolean CPU proprieties that, when enabled, indicate
> +that the feature is implemented, and, conversely, when disabled,
> +indicate that it is not implemented. An example of an ARM CPU feature
> +is the Performance Monitoring Unit (PMU).  CPU types such as the
> +Cortex-A15 and the Cortex-A57, which respectively implement ARM
> +architecture reference manuals ARMv7-A and ARMv8-A, may both optionally
> +implement PMUs.  For example, if a user wants to use a Cortex-A15 without
> +a PMU, then the `-cpu` parameter should contain `pmu=off` on the QEMU
> +command line, i.e. `-cpu cortex-a15,pmu=off`.
> +
> +As not all CPU types support all optional CPU features, then whether or
> +not a CPU property exists depends on the CPU type.  For example, CPUs
> +that implement the ARMv8-A architecture reference manual may optionally
> +support the AArch32 CPU feature, which may be enabled by disabling the
> +`aarch64` CPU property.  A CPU type such as the Cortex-A15, which does
> +not implement ARMv8-A, will not have the `aarch64` CPU property.
> +
> +QEMU's support may be limited for some CPU features, only partially
> +supporting the feature or only supporting the feature under certain
> +configurations.  For example, the `aarch64` CPU feature, which, when
> +disabled, enables the optional AArch32 CPU feature, is only supported
> +when using the KVM accelerator and when running on a host CPU type that
> +supports the feature.
> +
> +CPU Feature Probing
> +===================
> +
> +Determining which CPU features are available and functional for a given
> +CPU type is possible with the `query-cpu-model-expansion` QMP command.
> +Below are some examples where `scripts/qmp/qmp-shell` (see the top comment
> +block in the script for usage) is used to issue the QMP commands.
> +
> +(1) Determine which CPU features are available for the `max` CPU type
> +    (Note, we started QEMU with qemu-system-aarch64, so `max` is
> +     implementing the ARMv8-A reference manual in this case)::
> +
> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
> +      { "return": {
> +        "model": { "name": "max", "props": {
> +        "pmu": true, "aarch64": true
> +      }}}}
> +
> +We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
> +We also see that the CPU features are enabled, as they are all `true`.
> +
> +(2) Let's try to disable the PMU::
> +
> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
> +      { "return": {
> +        "model": { "name": "max", "props": {
> +        "pmu": false, "aarch64": true
> +      }}}}
> +
> +We see it worked, as `pmu` is now `false`.
> +
> +(3) Let's try to disable `aarch64`, which enables the AArch32 CPU feature::
> +
> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"aarch64":false}}
> +      {"error": {
> +       "class": "GenericError", "desc":
> +       "'aarch64' feature cannot be disabled unless KVM is enabled and 32-bit EL1 is supported"
> +      }}
> +
> +It looks like this feature is limited to a configuration we do not
> +currently have.
> +
> +(4) Let's try probing CPU features for the Cortex-A15 CPU type::
> +
> +      (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
> +      {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
> +
> +Only the `pmu` CPU feature is available.
> +
> +A note about CPU feature dependencies
> +-------------------------------------
> +
> +It's possible for features to have dependencies on other features. I.e.
> +it may be possible to change one feature at a time without error, but
> +when attempting to change all features at once an error could occur
> +depending on the order they are processed.  It's also possible changing
> +all at once doesn't generate an error, because a feature's dependencies
> +are satisfied with other features, but the same feature cannot be changed
> +independently without error.  For these reasons callers should always
> +attempt to make their desired changes all at once in order to ensure the
> +collection is valid.
> +
> +A note about CPU models and KVM
> +-------------------------------
> +
> +Named CPU models generally do not work with KVM.  There are a few cases
> +that do work, e.g. using the named CPU model `cortex-a57` with KVM on a
> +seattle host, but mostly if KVM is enabled the `host` CPU type must be
> +used.  This means the guest is provided all the same CPU features as the
> +host CPU type has.  And, for this reason, the `host` CPU type should
> +enable all CPU features that the host has by default.  Indeed it's even
> +a bit strange to allow disabling CPU features that the host has when using
> +the `host` CPU type, but in the absence of CPU models it's the best we can
> +do if we want to launch guests without all the host's CPU features enabled.
> +
> +Enabling KVM also affects the `query-cpu-model-expansion` QMP command.  The
> +affect is not only limited to specific features, as pointed out in example
> +(3) of "CPU Feature Probing", but also to which CPU types may be expanded.
> +When KVM is enabled, only the `max`, `host`, and current CPU type may be
> +expanded.  This restriction is necessary as it's not possible to know all
> +CPU types that may work with KVM, but it does impose a small risk of users
> +experiencing unexpected errors.  For example on a seattle, as mentioned
> +above, the `cortex-a57` CPU type is also valid when KVM is enabled.
> +Therefore a user could use the `host` CPU type for the current type, but
> +then attempt to query `cortex-a57`, however that query will fail with our
> +restrictions.  This shouldn't be an issue though as management layers and
> +users have been preferring the `host` CPU type for use with KVM for quite
> +some time.  Additionally, if the KVM-enabled QEMU instance running on a
> +seattle host is using the `cortex-a57` CPU type, then querying `cortex-a57`
> +will work.
> +
> +Using CPU Features
> +==================
> +
> +After determining which CPU features are available and supported for a
> +given CPU type, then they may be selectively enabled or disabled on the
> +QEMU command line with that CPU type::
> +
> +  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
> +
> +The example above disables the PMU for the `max` CPU type.
> +
> diff --git a/qapi/machine-target.json b/qapi/machine-target.json
> index 55310a6aa226..04623224720d 100644
> --- a/qapi/machine-target.json
> +++ b/qapi/machine-target.json
> @@ -212,7 +212,7 @@
>  ##
>  { 'struct': 'CpuModelExpansionInfo',
>    'data': { 'model': 'CpuModelInfo' },
> -  'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
> +  'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
>  
>  ##
>  # @query-cpu-model-expansion:
> @@ -237,7 +237,7 @@
>  #   query-cpu-model-expansion while using these is not advised.
>  #
>  # Some architectures may not support all expansion types. s390x supports
> -# "full" and "static".
> +# "full" and "static". Arm only supports "full".
>  #
>  # Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
>  #          not supported, if the model cannot be expanded, if the model contains
> @@ -251,7 +251,7 @@
>    'data': { 'type': 'CpuModelExpansionType',
>              'model': 'CpuModelInfo' },
>    'returns': 'CpuModelExpansionInfo',
> -  'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
> +  'if': 'defined(TARGET_S390X) || defined(TARGET_I386) || defined(TARGET_ARM)' }
>  
>  ##
>  # @CpuDefinitionInfo:
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index 6457c3c87f7c..edca8aa885f0 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -21,8 +21,16 @@
>   */
>  
>  #include "qemu/osdep.h"
> +#include "hw/boards.h"
>  #include "kvm_arm.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "qapi/qobject-input-visitor.h"
> +#include "qapi/qapi-commands-machine-target.h"
>  #include "qapi/qapi-commands-misc-target.h"
> +#include "qapi/qmp/qerror.h"
> +#include "qapi/qmp/qdict.h"
> +#include "qom/qom-qobject.h"
>  
>  static GICCapability *gic_cap_new(int version)
>  {
> @@ -81,3 +89,140 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>  
>      return head;
>  }
> +
> +/*
> + * These are cpu model features we want to advertise. The order here
> + * matters as this is the order in which qmp_query_cpu_model_expansion
> + * will attempt to set them. If there are dependencies between features,
> + * then the order that considers those dependencies must be used.
> + */
> +static const char *cpu_model_advertised_features[] = {
> +    "aarch64", "pmu",
> +    NULL
> +};
> +
> +CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> +                                                     CpuModelInfo *model,
> +                                                     Error **errp)
> +{
> +    CpuModelExpansionInfo *expansion_info;
> +    const QDict *qdict_in = NULL;
> +    QDict *qdict_out;
> +    ObjectClass *oc;
> +    Object *obj;
> +    const char *name;
> +    int i;
> +
> +    if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
> +        error_setg(errp, "The requested expansion type is not supported");
> +        return NULL;
> +    }
> +
> +    if (!kvm_enabled() && !strcmp(model->name, "host")) {
> +        error_setg(errp, "The CPU type '%s' requires KVM", model->name);
> +        return NULL;
> +    }
> +
> +    oc = cpu_class_by_name(TYPE_ARM_CPU, model->name);
> +    if (!oc) {
> +        error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type",
> +                   model->name);
> +        return NULL;
> +    }
> +
> +    if (kvm_enabled()) {
> +        const char *cpu_type = current_machine->cpu_type;
> +        int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX);
> +        bool supported = false;
> +
> +        if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) {
> +            /* These are kvmarm's recommended cpu types */
> +            supported = true;
> +        } else if (strlen(model->name) == len &&
> +                   !strncmp(model->name, cpu_type, len)) {
> +            /* KVM is enabled and we're using this type, so it works. */
> +            supported = true;
> +        }
> +        if (!supported) {
> +            error_setg(errp, "We cannot guarantee the CPU type '%s' works "
> +                             "with KVM on this host", model->name);
> +            return NULL;
> +        }
> +    }
> +
> +    if (model->props) {
> +        qdict_in = qobject_to(QDict, model->props);
> +        if (!qdict_in) {
> +            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
> +            return NULL;
> +        }
> +    }
> +
> +    obj = object_new(object_class_get_name(oc));
> +
> +    if (qdict_in) {
> +        Visitor *visitor;
> +        Error *err = NULL;
> +
> +        visitor = qobject_input_visitor_new(model->props);
> +        visit_start_struct(visitor, NULL, NULL, 0, &err);
> +        if (err) {
> +            object_unref(obj);
> +            error_propagate(errp, err);
> +            return NULL;
> +        }
> +
> +        i = 0;
> +        while ((name = cpu_model_advertised_features[i++]) != NULL) {
> +            if (qdict_get(qdict_in, name)) {
> +                object_property_set(obj, visitor, name, &err);
> +                if (err) {
> +                    break;
> +                }
> +            }
> +        }
> +
> +        if (!err) {
> +            visit_check_struct(visitor, &err);
> +        }
> +        visit_end_struct(visitor, NULL);
> +        visit_free(visitor);
> +        if (err) {
> +            object_unref(obj);
> +            error_propagate(errp, err);
> +            return NULL;
> +        }
> +    }
> +
> +    expansion_info = g_new0(CpuModelExpansionInfo, 1);
> +    expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
> +    expansion_info->model->name = g_strdup(model->name);
> +
> +    qdict_out = qdict_new();
> +
> +    i = 0;
> +    while ((name = cpu_model_advertised_features[i++]) != NULL) {
> +        ObjectProperty *prop = object_property_find(obj, name, NULL);
> +        if (prop) {
> +            Error *err = NULL;
> +            QObject *value;
> +
> +            assert(prop->get);
> +            value = object_property_get_qobject(obj, name, &err);
> +            assert(!err);
> +
> +            qdict_put_obj(qdict_out, name, value);
> +        }
> +    }
> +
> +    if (!qdict_size(qdict_out)) {
> +        qobject_unref(qdict_out);
> +    } else {
> +        expansion_info->model->props = QOBJECT(qdict_out);
> +        expansion_info->model->has_props = true;
> +    }
> +
> +    object_unref(obj);
> +
> +    return expansion_info;
> +}
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
  2019-09-24 13:55   ` Andrew Jones
@ 2019-09-25 13:53   ` Auger Eric
  2019-09-26  8:21     ` Andrew Jones
  2019-09-26 19:07   ` Richard Henderson
  2 siblings, 1 reply; 32+ messages in thread
From: Auger Eric @ 2019-09-25 13:53 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:31 PM, Andrew Jones wrote:
> Introduce cpu properties to give fine control over SVE vector lengths.
> We introduce a property for each valid length up to the current
> maximum supported, which is 2048-bits. The properties are named, e.g.
> sve128, sve256, sve384, sve512, ..., where the number is the number of
> bits. See the updates to docs/arm-cpu-features.rst for a description
> of the semantics and for example uses.
> 
> Note, as sve-max-vq is still present and we'd like to be able to
> support qmp_query_cpu_model_expansion with guests launched with e.g.
> -cpu max,sve-max-vq=8 on their command lines, then we do allow
> sve-max-vq and sve<N> properties to be provided at the same time, but
> this is not recommended, and is why sve-max-vq is not mentioned in the
> document.  If sve-max-vq is provided then it enables all lengths smaller
> than and including the max and disables all lengths larger. It also has
> the side-effect that no larger lengths may be enabled and that the max
> itself cannot be disabled. Smaller non-power-of-two lengths may,
> however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
> guest the vector lengths 128, 256, and 512 bits.
> 
> This patch has been co-authored with Richard Henderson, who reworked
> the target/arm/cpu64.c changes in order to push all the validation and
> auto-enabling/disabling steps into the finalizer, resulting in a nice
> LOC reduction.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  docs/arm-cpu-features.rst | 157 +++++++++++++++++++++++++++++--
>  target/arm/cpu.c          |  19 ++++
>  target/arm/cpu.h          |  19 ++++
>  target/arm/cpu64.c        | 190 +++++++++++++++++++++++++++++++++++++-
>  target/arm/helper.c       |  13 ++-
>  target/arm/monitor.c      |  12 +++
>  tests/arm-cpu-features.c  | 189 +++++++++++++++++++++++++++++++++++++
>  7 files changed, 587 insertions(+), 12 deletions(-)
> 
> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> index c79dcffb5556..1262fddc6201 100644
> --- a/docs/arm-cpu-features.rst
> +++ b/docs/arm-cpu-features.rst
> @@ -48,18 +48,28 @@ block in the script for usage) is used to issue the QMP commands.
>        (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
>        { "return": {
>          "model": { "name": "max", "props": {
> -        "pmu": true, "aarch64": true
> +        "sve1664": true, "pmu": true, "sve1792": true, "sve1920": true,
> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> +        "sve896": true, "sve1280": true, "sve2048": true
I don't really understand why this gets printed unsorted as you
registered them in the logical order, any clue?

Note: This example is given with TCG or KVM with all those vectors
supported by the host.
>        }}}}
>  
> -We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
> -We also see that the CPU features are enabled, as they are all `true`.
> +We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many
> +`sve<N>` CPU features.  We also see that all the CPU features are
> +enabled, as they are all `true`.  (The `sve<N>` CPU features are all
> +optional SVE vector lengths.  See "SVE CPU Properties".)
>  
>  (2) Let's try to disable the PMU::
>  
>        (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
>        { "return": {
>          "model": { "name": "max", "props": {
> -        "pmu": false, "aarch64": true
> +        "sve1664": true, "pmu": false, "sve1792": true, "sve1920": true,
> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> +        "sve896": true, "sve1280": true, "sve2048": true
>        }}}}
>  
>  We see it worked, as `pmu` is now `false`.
> @@ -75,7 +85,22 @@ We see it worked, as `pmu` is now `false`.
>  It looks like this feature is limited to a configuration we do not
>  currently have.
>  
> -(4) Let's try probing CPU features for the Cortex-A15 CPU type::
> +(4) Let's disable `sve` and see what happens to all the optional SVE
> +    vector lengths::
> +
> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}}
> +      { "return": {
> +        "model": { "name": "max", "props": {
> +        "sve1664": false, "pmu": true, "sve1792": false, "sve1920": false,
> +        "sve128": false, "aarch64": true, "sve1024": false, "sve": false,
> +        "sve640": false, "sve768": false, "sve1408": false, "sve256": false,
> +        "sve1152": false, "sve512": false, "sve384": false, "sve1536": false,
> +        "sve896": false, "sve1280": false, "sve2048": false
> +      }}}}
> +
> +As expected they are now all `false`.
> +
> +(5) Let's try probing CPU features for the Cortex-A15 CPU type::
>  
>        (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
>        {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
> @@ -131,7 +156,125 @@ After determining which CPU features are available and supported for a
>  given CPU type, then they may be selectively enabled or disabled on the
>  QEMU command line with that CPU type::
>  
> -  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
> +  $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on
> +
> +The example above disables the PMU and enables the first two SVE vector
> +lengths for the `max` CPU type.  Note, the `sve=on` isn't actually
> +necessary, because, as we observed above with our probe of the `max` CPU
> +type, `sve` is already on by default.

This holds with TCG and not KVM.

Also, based on our probe of
> +defaults, it would seem we need to disable many SVE vector lengths, rather
> +than only enabling the two we want.  This isn't the case, because, as
> +disabling many SVE vector lengths would be quite verbose, the `sve<N>` CPU
> +properties have special semantics (see "SVE CPU Property Parsing
> +Semantics").
> +
> +SVE CPU Properties
> +==================
> +
> +There are two types of SVE CPU properties: `sve` and `sve<N>`.  The first
> +is used to enable or disable the entire SVE feature, just as the `pmu`
> +CPU property completely enables or disables the PMU.  The second type
> +is used to enable or disable specific vector lengths, where `N` is the
> +number of bits of the length.  The `sve<N>` CPU properties have special
> +dependencies and constraints, see "SVE CPU Property Dependencies and
> +Constraints" below.  Additionally, as we want all supported vector lengths
> +to be enabled by default, then, in order to avoid overly verbose command
> +lines (command lines full of `sve<N>=off`, for all `N` not wanted), we
> +provide the parsing semantics listed in "SVE CPU Property Parsing
> +Semantics".
> +
> +SVE CPU Property Dependencies and Constraints
> +---------------------------------------------
> +
> +  1) At least one vector length must be enabled when `sve` is enabled.> +
> +  2) If a vector length `N` is enabled, then all power-of-two vector
> +     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> +     is enabled, then `sve128` and `sve256` must also be enabled,
> +     but `sve384` is not required.
I would remove the eg. part. reading that I tend to understand that the
user must pass ,sve128=on, sve256=on and sve512=on whereas example 6
says only sve512=on can be set and other lower ^2 values are auto-enabled.
> +
> +SVE CPU Property Parsing Semantics
> +----------------------------------
> +
> +  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
> +     are enabled or disabled is irrelevant to the guest, as the entire
> +     SVE feature is disabled and that disables all vector lengths for
> +     the guest.  However QEMU will still track any `sve<N>` CPU
> +     properties provided by the user.  If later an `sve=on` is provided,
> +     then the guest will get only the enabled lengths.
> +
> +  2) If SVE is enabled (`sve=on`), but no `sve<N>` CPU properties are
> +     provided, then all supported vector lengths are enabled.
I understand from the code it also includes non ^2 values which is not
obvious.
> +
> +  3) If SVE is enabled, then an error is generated when attempting to
> +     disable the last enabled vector length (see constraint (1) of "SVE
> +     CPU Property Dependencies and Constraints").
the same happens if you attempt to disabled any lower ^2 value
> +
> +  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> +     CPU properties are set `on`, then the specified vector lengths are
> +     disabled but the default for any unspecified lengths remains enabled.
> +     Disabling a power-of-two vector length also disables all vector
> +     lengths larger than the power-of-two length (see constraint (2) of
> +     "SVE CPU Property Dependencies and Constraints").
So rephasing it:
disabling a non ^2 value only disable that one
disabling a ^2 value disables all larger lengths too
is that correct?

> +
> +  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> +     are enabled and all unspecified lengths default to disabled, except
> +     for the required lengths per constraint (2) of "SVE CPU Property
> +     Dependencies and Constraints", which will even be auto-enabled if
> +     they were not explicitly enabled.
> +
> +  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> +     explicitly disabled (i.e. avoiding the error specified in (3) of
> +     "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
> +     provided an error will be generated.  To avoid this error, one must
> +     enable at least one vector length prior to enabling SVE.
> +
> +SVE CPU Property Examples
> +-------------------------
> +
> +  1) Disable SVE::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off
> +
> +  2) Implicitly enable all vector lengths for the `max` CPU type::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max
> +
> +  3) Only enable the 128-bit vector length::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on
> +
> +  4) Disable the 256-bit vector length and all larger vector lengths
> +     since 256 is a power-of-two (this results in only the 128-bit length
> +     being enabled)::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve256=off
> +
> +  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
> +
> +  6) The same as (5), but since the 128-bit and 256-bit vector
> +     lengths are required for the 512-bit vector length to be enabled,
> +     then allow them to be auto-enabled::> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve512=on

You should also document
$ qemu-system-aarch64 -M virt -cpu max,sve512=off
as in that case this result in 128, 256 and 384. the fact you get non ^2
values is not obvious here because if you enable a ^2 value you onlt get
<= ^2 values.
> +
> +  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on> +
> +  8) Force errors regarding the last vector length::
You mean those commands will generate errors, right?
> +
> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=off
> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
> +
> +SVE CPU Property Recommendations
> +--------------------------------
>  
> -The example above disables the PMU for the `max` CPU type.
> +The examples in "SVE CPU Property Examples" exhibit many ways to select
> +vector lengths which developers may find useful in order to avoid overly
> +verbose command lines.  However, the recommended way to select vector
> +lengths is to explicitly enable each desired length.  Therefore only
> +example's (1), (3), and (5) exhibit recommended uses of the properties.
>  
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 73be2ebfdd39..522fed95b339 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -1199,6 +1199,19 @@ static void arm_cpu_finalizefn(Object *obj)
>  #endif
>  }
>  
> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
> +{
> +    Error *local_err = NULL;
> +
> +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> +        arm_cpu_sve_finalize(cpu, &local_err);
> +        if (local_err != NULL) {
nit: !local_err
> +            error_propagate(errp, local_err);
> +            return;
not needed
> +        }
> +    }
> +}
> +
>  static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>  {
>      CPUState *cs = CPU(dev);
> @@ -1255,6 +1268,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> +    arm_cpu_finalize_features(cpu, &local_err);
> +    if (local_err != NULL) {
same
> +        error_propagate(errp, local_err);
> +        return;> +    }
> +
>      if (arm_feature(env, ARM_FEATURE_AARCH64) &&
>          cpu->has_vfp != cpu->has_neon) {
>          /*
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 297ad5e47ad8..11162484465a 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -184,8 +184,13 @@ typedef struct {
>  
>  #ifdef TARGET_AARCH64
>  # define ARM_MAX_VQ    16
> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
>  #else
>  # define ARM_MAX_VQ    1
> +static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
> +static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> +{ return 0; }
>  #endif
>  
>  typedef struct ARMVectorReg {
> @@ -915,6 +920,18 @@ struct ARMCPU {
>  
>      /* Used to set the maximum vector length the cpu will support.  */
>      uint32_t sve_max_vq;
> +
> +    /*
> +     * In sve_vq_map each set bit is a supported vector length of
> +     * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
> +     * length in quadwords.
> +     *
> +     * While processing properties during initialization, corresponding
> +     * sve_vq_init bits are set for bits in sve_vq_map that have been
> +     * set by properties.
> +     */
> +    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
> +    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
>  };
>  
>  void arm_cpu_post_init(Object *obj);
> @@ -1834,6 +1851,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
>      return (env->features & (1ULL << feature)) != 0;
>  }
>  
> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
> +
>  #if !defined(CONFIG_USER_ONLY)
>  /* Return true if exception levels below EL3 are in secure state,
>   * or would be following an exception return to that level.
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 8cdb0c79fa7a..606e3eceb9c0 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -256,11 +256,152 @@ static void aarch64_a72_initfn(Object *obj)
>      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
>  }
>  
> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> +{
> +    /*
> +     * If any vector lengths are explicitly enabled with sve<N> properties,
> +     * then all other lengths are implicitly disabled.  If sve-max-vq is
> +     * specified then it is the same as explicitly enabling all lengths
> +     * up to and including the specified maximum, which means all larger
> +     * lengths will be implicitly disabled.  If no sve<N> properties
> +     * are enabled and sve-max-vq is not specified, then all lengths not
> +     * explicitly disabled will be enabled.  Additionally, all power-of-two
> +     * vector lengths less than the maximum enabled length will be
> +     * automatically enabled and all vector lengths larger than the largest
> +     * disabled power-of-two vector length will be automatically disabled.
> +     * Errors are generated if the user provided input that interferes with
> +     * any of the above.  Finally, if SVE is not disabled, then at least one
> +     * vector length must be enabled.
> +     */
> +    DECLARE_BITMAP(tmp, ARM_MAX_VQ);
> +    uint32_t vq, max_vq = 0;
> +
> +    /*
> +     * Process explicit sve<N> properties.
> +     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> +     * Check first for any sve<N> enabled.
> +     */
> +    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
> +        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
> +
> +        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
> +            error_setg(errp, "cannot enable sve%d", max_vq * 128);
> +            error_append_hint(errp, "sve%d is larger than the maximum vector "
> +                              "length, sve-max-vq=%d (%d bits)\n",
> +                              max_vq * 128, cpu->sve_max_vq,
> +                              cpu->sve_max_vq * 128);
you could test directly if max_vq < cpu->sve_max_vq too which couldn't
be correct either. But as far as I understand this is caught in *
> +            return;
> +        }
> +
> +        /* Propagate enabled bits down through required powers-of-two. */
> +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> +            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> +                set_bit(vq - 1, cpu->sve_vq_map);
> +            }
> +        }
> +    } else if (cpu->sve_max_vq == 0) {
> +        /*
> +         * No explicit bits enabled, and no implicit bits from sve-max-vq.
> +         */
> +        if (!cpu_isar_feature(aa64_sve, cpu)) {
> +            /* SVE is disabled and so are all vector lengths.  Good. */
> +            return;
> +        }
> +
> +        /* Disabling a power-of-two disables all larger lengths. */
> +        if (test_bit(0, cpu->sve_vq_init)) {> +            error_setg(errp, "cannot disable sve128");
> +            error_append_hint(errp, "Disabling sve128 results in all vector "
> +                              "lengths being disabled.\n");
> +            error_append_hint(errp, "With SVE enabled, at least one vector "
> +                              "length must be enabled.\n");
> +            return;
> +        }
> +        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> +            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> +                break;
> +            }
> +        }
> +        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> +
> +        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> +        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
> +    }
> +
> +    /*
> +     * Process the sve-max-vq property.
> +     * Note that we know from the above that no bit above
> +     * sve-max-vq is currently set.
> +     */
> +    if (cpu->sve_max_vq != 0) {
> +        max_vq = cpu->sve_max_vq;
> +
> +        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
> +            test_bit(max_vq - 1, cpu->sve_vq_init)) {
> +            error_setg(errp, "cannot disable sve%d", max_vq * 128);
> +            error_append_hint(errp, "The maximum vector length must be "
> +                              "enabled, sve-max-vq=%d (%d bits)\n",
> +                              max_vq, max_vq * 128);
> +            return;
> +        }
> +
> +        /* Set all bits not explicitly set within sve-max-vq. */
> +        bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
> +        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> +    }
> +
> +    /*
> +     * We should know what max-vq is now.  Also, as we're done
> +     * manipulating sve-vq-map, we ensure any bits above max-vq
> +     * are clear, just in case anybody looks.
> +     */
> +    assert(max_vq != 0);
> +    bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
> +
> +    /* Ensure all required powers-of-two are enabled. */
> +    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> +        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> +            error_setg(errp, "cannot disable sve%d", vq * 128);
> +            error_append_hint(errp, "sve%d is required as it "
> +                              "is a power-of-two length smaller than "
> +                              "the maximum, sve%d\n",
> +                              vq * 128, max_vq * 128);
* I think this will also catches the case where ,sve512=on,sve-max-vq=5
where the end-user did not explicitly disabled anything
> +            return;
> +        }
> +    }
> +
> +    /* From now on sve_max_vq is the actual maximum supported length. */
> +    cpu->sve_max_vq = max_vq;
> +}
> +
> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> +{
> +    uint32_t bitnum;
> +
> +    /*
> +     * We allow vq == ARM_MAX_VQ + 1 to be input because the caller may want
> +     * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
> +     * function always returns the next smaller than the input.
> +     */
> +    assert(vq && vq <= ARM_MAX_VQ + 1);
> +
> +    bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
> +    return bitnum == vq - 1 ? 0 : bitnum + 1;
> +}
> +
>  static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
>                                     void *opaque, Error **errp)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
> -    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
> +    uint32_t value;
Shouldn't it be part of the previous patch?
> +
> +    /* All vector lengths are disabled when SVE is off. */
> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> +        value = 0;
> +    } else {
> +        value = cpu->sve_max_vq;
> +    }
> +    visit_type_uint32(v, name, &value, errp);
>  }
>  
>  static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> @@ -279,6 +420,44 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
Independently on this patch I noticed that if sve_max_vq is out of
scope, an error is propagated but still the cpu->sve-max_vq is set.
>      error_propagate(errp, err);
>  }
>  
> +static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> +                               void *opaque, Error **errp)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +    uint32_t vq = atoi(&name[3]) / 128;
> +    bool value;
> +
> +    /* All vector lengths are disabled when SVE is off. */
> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> +        value = false;
> +    } else {
> +        value = test_bit(vq - 1, cpu->sve_vq_map);
> +    }
> +    visit_type_bool(v, name, &value, errp);
> +}
> +
> +static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
> +                               void *opaque, Error **errp)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +    uint32_t vq = atoi(&name[3]) / 128;
> +    Error *err = NULL;
> +    bool value;
> +
> +    visit_type_bool(v, name, &value, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    if (value) {
> +        set_bit(vq - 1, cpu->sve_vq_map);
> +    } else {
> +        clear_bit(vq - 1, cpu->sve_vq_map);
> +    }
> +    set_bit(vq - 1, cpu->sve_vq_init);
> +}
> +
>  static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
>                              void *opaque, Error **errp)
>  {
> @@ -315,6 +494,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>  static void aarch64_max_initfn(Object *obj)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
> +    uint32_t vq;
>  
>      if (kvm_enabled()) {
>          kvm_arm_set_cpu_features_from_host(cpu);
> @@ -418,11 +598,17 @@ static void aarch64_max_initfn(Object *obj)
>          cpu->dcz_blocksize = 7; /*  512 bytes */
>  #endif
>  
> -        cpu->sve_max_vq = ARM_MAX_VQ;
>          object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>                              cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
>          object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
>                              cpu_arm_set_sve, NULL, NULL, &error_fatal);
> +
> +        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> +            char name[8];
> +            sprintf(name, "sve%d", vq * 128);
> +            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> +                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> +        }
>      }
>  }
>  
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 507026c9154b..f33284c247d5 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -5351,6 +5351,13 @@ int sve_exception_el(CPUARMState *env, int el)
>      return 0;
>  }
>  
> +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
> +{
> +    uint32_t start_vq = (start_len & 0xf) + 1;
> +
> +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
> +}
> +
>  /*
>   * Given that SVE is enabled, return the vector length for EL.
>   */
> @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
>      uint32_t zcr_len = cpu->sve_max_vq - 1;
>  
>      if (el <= 1) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
>      }
>      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
>      }
>      if (arm_feature(env, ARM_FEATURE_EL3)) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
>      }
>      return zcr_len;
>  }
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index 4fddb6c252a3..e912ed2cefa0 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -90,6 +90,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>      return head;
>  }
>  
> +QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
> +
>  /*
>   * These are cpu model features we want to advertise. The order here
>   * matters as this is the order in which qmp_query_cpu_model_expansion
> @@ -98,6 +100,9 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>   */
>  static const char *cpu_model_advertised_features[] = {
>      "aarch64", "pmu", "sve",
> +    "sve128", "sve256", "sve384", "sve512",
> +    "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
> +    "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
>      NULL
>  };
>  
> @@ -185,6 +190,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>          if (!err) {
>              visit_check_struct(visitor, &err);
>          }
> +        if (!err) {
> +            arm_cpu_finalize_features(ARM_CPU(obj), &err);
> +        }
>          visit_end_struct(visitor, NULL);
>          visit_free(visitor);
>          if (err) {
> @@ -192,6 +200,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>              error_propagate(errp, err);
>              return NULL;
>          }
> +    } else {
> +        Error *err = NULL;
> +        arm_cpu_finalize_features(ARM_CPU(obj), &err);
> +        assert(err == NULL);
>      }
>  
>      expansion_info = g_new0(CpuModelExpansionInfo, 1);
> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> index 202bc0e3e823..9a2dd402b769 100644
> --- a/tests/arm-cpu-features.c
> +++ b/tests/arm-cpu-features.c
> @@ -13,6 +13,18 @@
>  #include "qapi/qmp/qdict.h"
>  #include "qapi/qmp/qjson.h"
>  
> +#if __SIZEOF_LONG__ == 8
> +#define BIT(n) (1UL << (n))
> +#else
> +#define BIT(n) (1ULL << (n))
> +#endif
> +
> +/*
> + * We expect the SVE max-vq to be 16. Also it must be <= 64
> + * for our test code, otherwise 'vls' can't just be a uint64_t.
> + */
> +#define SVE_MAX_VQ 16
> +
>  #define MACHINE    "-machine virt,gic-version=max "
>  #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
>                       "'arguments': { 'type': 'full', "
> @@ -157,6 +169,173 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type)
>      qobject_unref(resp);
>  }
>  
> +static uint64_t resp_get_sve_vls(QDict *resp)
> +{
> +    QDict *props;
> +    const QDictEntry *e;
> +    uint64_t vls = 0;
> +    int n = 0;
> +
> +    g_assert(resp);
> +    g_assert(resp_has_props(resp));
> +
> +    props = resp_get_props(resp);
> +
> +    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
> +        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
> +            g_ascii_isdigit(e->key[3])) {
> +            char *endptr;
> +            int bits;
> +
> +            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
> +            if (!bits || *endptr != '\0') {
> +                continue;
> +            }
> +
> +            if (qdict_get_bool(props, e->key)) {
> +                vls |= BIT((bits / 128) - 1);
> +            }
> +            ++n;
> +        }
> +    }
> +
> +    g_assert(n == SVE_MAX_VQ);
> +
> +    return vls;
> +}
> +
> +#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
> +({                                                                     \
> +    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
> +    g_assert(_resp);                                                   \
> +    g_assert(resp_has_props(_resp));                                   \
> +    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
> +    qobject_unref(_resp);                                              \
> +})
> +
> +static void sve_tests_default(QTestState *qts, const char *cpu_type)
> +{
> +    /*
> +     * With no sve-max-vq or sve<N> properties on the command line
> +     * the default is to have all vector lengths enabled. This also
> +     * tests that 'sve' is 'on' by default.
> +     */
> +    assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL);
> +
> +    /* With SVE off, all vector lengths should also be off. */
> +    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
> +
> +    /* With SVE on, we must have at least one vector length enabled. */
> +    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
> +
> +    /*
> +     * ---------------------------------------------------------------------
> +     *               power-of-two(vq)   all-power-            can      can
> +     *                                  of-two(< vq)        enable   disable
> +     * ---------------------------------------------------------------------
> +     * vq < max_vq      no                MUST*              yes      yes
> +     * vq < max_vq      yes               MUST*              yes      no
> +     * ---------------------------------------------------------------------
> +     * vq == max_vq     n/a               MUST*              yes**    yes**
> +     * ---------------------------------------------------------------------
> +     * vq > max_vq      n/a               no                 no       yes
> +     * vq > max_vq      n/a               yes                yes      yes
> +     * ---------------------------------------------------------------------
> +     *
> +     * [*] "MUST" means this requirement must already be satisfied,
> +     *     otherwise 'max_vq' couldn't itself be enabled.
> +     *
> +     * [**] Not testable with the QMP interface, only with the command line.
> +     */
> +
> +    /* max_vq := 8 */
> +    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
> +
> +    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
> +    assert_sve_vls(qts, cpu_type, 0x8f,
> +                   "{ 'sve1024': true, 'sve384': true }");
> +    assert_sve_vls(qts, cpu_type, 0x8b,
> +                   "{ 'sve1024': true, 'sve384': false }");
> +
> +    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
> +    assert_sve_vls(qts, cpu_type, 0x8b,
> +                   "{ 'sve1024': true, 'sve256': true }");
> +    assert_error(qts, cpu_type, "cannot disable sve256",
> +                 "{ 'sve1024': true, 'sve256': false }");
> +
> +    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
> +    assert_error(qts, cpu_type, "cannot disable sve512",
> +                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
> +
> +    /*
> +     * We can disable power-of-two vector lengths when all larger lengths
> +     * are also disabled. We only need to disable the power-of-two length,
> +     * as all non-enabled larger lengths will then be auto-disabled.
> +     */
> +    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
> +
> +    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
> +    assert_sve_vls(qts, cpu_type, 0x1f,
> +                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
> +    assert_sve_vls(qts, cpu_type, 0xf,
> +                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
> +}
> +
> +static void sve_tests_sve_max_vq_8(const void *data)
> +{
> +    QTestState *qts;
> +
> +    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
> +
> +    assert_sve_vls(qts, "max", BIT(8) - 1, NULL);
> +
> +    /*
> +     * Disabling the max-vq set by sve-max-vq is not allowed, but
> +     * of course enabling it is OK.
> +     */
> +    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
> +
> +    /*
> +     * Enabling anything larger than max-vq set by sve-max-vq is not
> +     * allowed, but of course disabling everything larger is OK.
> +     */
> +    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
> +
> +    /*
> +     * We can disable non power-of-two lengths smaller than the max-vq
> +     * set by sve-max-vq, but not power-of-two lengths.
> +     */
> +    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
you can also test ,sve384=on => 0x7
> +    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
> +
> +    qtest_quit(qts);
> +}
> +
> +static void sve_tests_sve_off(const void *data)
> +{
> +    QTestState *qts;
> +
> +    qts = qtest_init(MACHINE "-cpu max,sve=off");
> +
> +    /* SVE is off, so the map should be empty. */
> +    assert_sve_vls(qts, "max", 0, NULL);
> +
> +    /* The map stays empty even if we turn lengths on or off. */
> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': true }");
> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> +
> +    /* With SVE re-enabled we should get all vector lengths enabled. */
> +    assert_sve_vls(qts, "max", BIT(SVE_MAX_VQ) - 1, "{ 'sve': true }");
> +
> +    /* Or enable SVE with just specific vector lengths. */
> +    assert_sve_vls(qts, "max", 0x3,
> +                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
> +
> +    qtest_quit(qts);
> +}
> +
>  static void test_query_cpu_model_expansion(const void *data)
>  {
>      QTestState *qts;
> @@ -180,9 +359,12 @@ static void test_query_cpu_model_expansion(const void *data)
>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
>          assert_has_feature(qts, "max", "aarch64");
>          assert_has_feature(qts, "max", "sve");
> +        assert_has_feature(qts, "max", "sve128");
>          assert_has_feature(qts, "cortex-a57", "pmu");
>          assert_has_feature(qts, "cortex-a57", "aarch64");
>  
> +        sve_tests_default(qts, "max");
> +
>          /* Test that features that depend on KVM generate errors without. */
>          assert_error(qts, "max",
>                       "'aarch64' feature cannot be disabled "
> @@ -234,6 +416,13 @@ int main(int argc, char **argv)
>      qtest_add_data_func("/arm/query-cpu-model-expansion",
>                          NULL, test_query_cpu_model_expansion);
>  
> +    if (g_str_equal(qtest_get_arch(), "aarch64")) {
> +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
> +                            NULL, sve_tests_sve_max_vq_8);
> +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
> +                            NULL, sve_tests_sve_off);
> +    }
> +
>      if (kvm_available) {
>          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
>                              NULL, test_query_cpu_model_expansion_kvm);
> 
Thanks

Eric


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
@ 2019-09-25 13:58   ` Auger Eric
  2019-09-27 13:00   ` Andrew Jones
  2019-10-01  6:53   ` Andrew Jones
  2 siblings, 0 replies; 32+ messages in thread
From: Auger Eric @ 2019-09-25 13:58 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:31 PM, Andrew Jones wrote:
> These are the SVE equivalents to kvm_arch_get/put_fpsimd. Note, the
> swabbing is different than it is for fpsmid because the vector format
> is a little-endian stream of words.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric
> ---
>  target/arm/kvm64.c | 137 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 133 insertions(+), 4 deletions(-)
> 
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index 28f6db57d5ee..ea454c613919 100644
> --- a/target/arm/kvm64.c
> +++ b/target/arm/kvm64.c
> @@ -671,11 +671,12 @@ int kvm_arch_destroy_vcpu(CPUState *cs)
>  bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
>  {
>      /* Return true if the regidx is a register we should synchronize
> -     * via the cpreg_tuples array (ie is not a core reg we sync by
> -     * hand in kvm_arch_get/put_registers())
> +     * via the cpreg_tuples array (ie is not a core or sve reg that
> +     * we sync by hand in kvm_arch_get/put_registers())
>       */
>      switch (regidx & KVM_REG_ARM_COPROC_MASK) {
>      case KVM_REG_ARM_CORE:
> +    case KVM_REG_ARM64_SVE:
>          return false;
>      default:
>          return true;
> @@ -761,6 +762,78 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
>      return 0;
>  }
>  
> +/*
> + * SVE registers are encoded in KVM's memory in an endianness-invariant format.
> + * The byte at offset i from the start of the in-memory representation contains
> + * the bits [(7 + 8 * i) : (8 * i)] of the register value. As this means the
> + * lowest offsets are stored in the lowest memory addresses, then that nearly
> + * matches QEMU's representation, which is to use an array of host-endian
> + * uint64_t's, where the lower offsets are at the lower indices. To complete
> + * the translation we just need to byte swap the uint64_t's on big-endian hosts.
> + */
> +static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
> +{
> +#ifdef HOST_WORDS_BIGENDIAN
> +    int i;
> +
> +    for (i = 0; i < nr; ++i) {
> +        dst[i] = bswap64(src[i]);
> +    }
> +
> +    return dst;
> +#else
> +    return src;
> +#endif
> +}
> +
> +/*
> + * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
> + * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
> + * code the slice index to zero for now as it's unlikely we'll need more than
> + * one slice for quite some time.
> + */
> +static int kvm_arch_put_sve(CPUState *cs)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    uint64_t tmp[ARM_MAX_VQ * 2];
> +    uint64_t *r;
> +    struct kvm_one_reg reg;
> +    int n, ret;
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
> +        r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2);
> +        reg.addr = (uintptr_t)r;
> +        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
> +        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
> +        r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0],
> +                        DIV_ROUND_UP(cpu->sve_max_vq, 8));
> +        reg.addr = (uintptr_t)r;
> +        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
> +        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    r = sve_bswap64(tmp, &env->vfp.pregs[FFR_PRED_NUM].p[0],
> +                    DIV_ROUND_UP(cpu->sve_max_vq, 8));
> +    reg.addr = (uintptr_t)r;
> +    reg.id = KVM_REG_ARM64_SVE_FFR(0);
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
>  int kvm_arch_put_registers(CPUState *cs, int level)
>  {
>      struct kvm_one_reg reg;
> @@ -855,7 +928,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>          }
>      }
>  
> -    ret = kvm_arch_put_fpsimd(cs);
> +    if (cpu_isar_feature(aa64_sve, cpu)) {
> +        ret = kvm_arch_put_sve(cs);
> +    } else {
> +        ret = kvm_arch_put_fpsimd(cs);
> +    }
>      if (ret) {
>          return ret;
>      }
> @@ -918,6 +995,54 @@ static int kvm_arch_get_fpsimd(CPUState *cs)
>      return 0;
>  }
>  
> +/*
> + * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
> + * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
> + * code the slice index to zero for now as it's unlikely we'll need more than
> + * one slice for quite some time.
> + */
> +static int kvm_arch_get_sve(CPUState *cs)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    struct kvm_one_reg reg;
> +    uint64_t *r;
> +    int n, ret;
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
> +        r = &env->vfp.zregs[n].d[0];
> +        reg.addr = (uintptr_t)r;
> +        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
> +        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +        sve_bswap64(r, r, cpu->sve_max_vq * 2);
> +    }
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
> +        r = &env->vfp.pregs[n].p[0];
> +        reg.addr = (uintptr_t)r;
> +        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
> +        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +        sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
> +    }
> +
> +    r = &env->vfp.pregs[FFR_PRED_NUM].p[0];
> +    reg.addr = (uintptr_t)r;
> +    reg.id = KVM_REG_ARM64_SVE_FFR(0);
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +    sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
> +
> +    return 0;
> +}
> +
>  int kvm_arch_get_registers(CPUState *cs)
>  {
>      struct kvm_one_reg reg;
> @@ -1012,7 +1137,11 @@ int kvm_arch_get_registers(CPUState *cs)
>          env->spsr = env->banked_spsr[i];
>      }
>  
> -    ret = kvm_arch_get_fpsimd(cs);
> +    if (cpu_isar_feature(aa64_sve, cpu)) {
> +        ret = kvm_arch_get_sve(cs);
> +    } else {
> +        ret = kvm_arch_get_fpsimd(cs);
> +    }
>      if (ret) {
>          return ret;
>      }
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-24 11:31 ` [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
@ 2019-09-26  6:52   ` Auger Eric
  2019-09-26  8:41     ` Andrew Jones
  0 siblings, 1 reply; 32+ messages in thread
From: Auger Eric @ 2019-09-26  6:52 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:31 PM, Andrew Jones wrote:
> Extend the SVE vq map initialization and validation with KVM's
> supported vector lengths when KVM is enabled. In order to determine
> and select supported lengths we add two new KVM functions for getting
> and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.
> 
> This patch has been co-authored with Richard Henderson, who reworked
> the target/arm/cpu64.c changes in order to push all the validation and
> auto-enabling/disabling steps into the finalizer, resulting in a nice
> LOC reduction.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  docs/arm-cpu-features.rst |  36 +++++---
>  target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
>  target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
>  target/arm/kvm_arm.h      |  12 +++
>  tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
>  5 files changed, 368 insertions(+), 52 deletions(-)
> 
> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> index 1262fddc6201..939366f959cf 100644
> --- a/docs/arm-cpu-features.rst
> +++ b/docs/arm-cpu-features.rst
> @@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
>  
>    1) At least one vector length must be enabled when `sve` is enabled.
>  
> -  2) If a vector length `N` is enabled, then all power-of-two vector
> -     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> -     is enabled, then `sve128` and `sve256` must also be enabled,
> -     but `sve384` is not required.
> +  2) If a vector length `N` is enabled, then, when KVM is enabled, all
> +     smaller, host supported vector lengths must also be enabled.  If
> +     KVM is not enabled, then only all the smaller, power-of-two vector
> +     lengths must be enabled.  E.g. with KVM if the host supports all
> +     vector lengths up to 512-bits (128, 256, 384, 512), then if
> +     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
> +     be enabled. Without KVM, `sve384` would not be required.
> +
> +  3) If KVM is enabled then only vector lengths that the host CPU type
> +     support may be enabled.  If SVE is not supported by the host, then
> +     no `sve*` properties may be enabled.
>  
>  SVE CPU Property Parsing Semantics
>  ----------------------------------
> @@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
>       disable the last enabled vector length (see constraint (1) of "SVE
>       CPU Property Dependencies and Constraints").
>  
> -  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> +  4) When KVM is enabled, if the host does not support SVE, then an error
> +     is generated when attempting to enable any `sve*` properties.
> +
> +  5) When KVM is enabled, if the host does support SVE, then an error is
> +     generated when attempting to enable any vector lengths not supported
> +     by the host.
> +
> +  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>       CPU properties are set `on`, then the specified vector lengths are
>       disabled but the default for any unspecified lengths remains enabled.
> -     Disabling a power-of-two vector length also disables all vector
> -     lengths larger than the power-of-two length (see constraint (2) of
> -     "SVE CPU Property Dependencies and Constraints").
> +     When KVM is not enabled, disabling a power-of-two vector length also
> +     disables all vector lengths larger than the power-of-two length.
> +     When KVM is enabled, then disabling any supported vector length also
> +     disables all larger vector lengths (see constraint (2) of "SVE CPU
> +     Property Dependencies and Constraints").
>  
> -  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> +  7) If one or more `sve<N>` CPU properties are set to `on`, then they
>       are enabled and all unspecified lengths default to disabled, except
>       for the required lengths per constraint (2) of "SVE CPU Property
>       Dependencies and Constraints", which will even be auto-enabled if
>       they were not explicitly enabled.
>  
> -  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> +  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>       explicitly disabled (i.e. avoiding the error specified in (3) of
>       "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
>       provided an error will be generated.  To avoid this error, one must
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index b7eff4e1e107..18dd5e24ec61 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>       * any of the above.  Finally, if SVE is not disabled, then at least one
>       * vector length must be enabled.
>       */
> +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
>      DECLARE_BITMAP(tmp, ARM_MAX_VQ);
>      uint32_t vq, max_vq = 0;
>  
> +    /* Collect the set of vector lengths supported by KVM. */
> +    bitmap_zero(kvm_supported, ARM_MAX_VQ);
> +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
> +        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
> +    } else if (kvm_enabled()) {
> +        assert(!cpu_isar_feature(aa64_sve, cpu));
why not set an error and propagate it instead?
> +    }
> +
>      /*
>       * Process explicit sve<N> properties.
>       * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> @@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>              return;
>          }
>  
> -        /* Propagate enabled bits down through required powers-of-two. */
> -        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> -            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> -                set_bit(vq - 1, cpu->sve_vq_map);
> +        if (kvm_enabled()) {
> +            /*
> +             * For KVM we have to automatically enable all supported unitialized
> +             * lengths, even when the smaller lengths are not all powers-of-two.
> +             */
> +            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
> +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> +        } else {
> +            /* Propagate enabled bits down through required powers-of-two. */
> +            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> +                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> +                    set_bit(vq - 1, cpu->sve_vq_map);
> +                }
>              }
>          }
>      } else if (cpu->sve_max_vq == 0) {
> @@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>              return;
>          }
>  
> -        /* Disabling a power-of-two disables all larger lengths. */
> -        if (test_bit(0, cpu->sve_vq_init)) {
> -            error_setg(errp, "cannot disable sve128");
> -            error_append_hint(errp, "Disabling sve128 results in all vector "
> -                              "lengths being disabled.\n");
> -            error_append_hint(errp, "With SVE enabled, at least one vector "
> -                              "length must be enabled.\n");
> -            return;
> -        }
> -        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> -            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> -                break;
> +        if (kvm_enabled()) {
> +            /* Disabling a supported length disables all larger lengths. */
> +            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> +                if (test_bit(vq - 1, cpu->sve_vq_init) &&
> +                    test_bit(vq - 1, kvm_supported)) {
> +                    break;
> +                }
> +            }
> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
> +                          cpu->sve_vq_init, max_vq);
> +            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
> +                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
> +                error_setg(errp, "cannot disable sve%d", vq * 128);
isn't the one disabled max_vq? Do you really need to re-compute vq?
> +                error_append_hint(errp, "Disabling sve%d results in all "
> +                                  "vector lengths being disabled.\n",
> +                                  vq * 128);
> +                error_append_hint(errp, "With SVE enabled, at least one "
> +                                  "vector length must be enabled.\n");
> +                return;> +            }
> +        } else {
> +            /* Disabling a power-of-two disables all larger lengths. */
> +            if (test_bit(0, cpu->sve_vq_init)) {
> +                error_setg(errp, "cannot disable sve128");
> +                error_append_hint(errp, "Disabling sve128 results in all "
> +                                  "vector lengths being disabled.\n");
> +                error_append_hint(errp, "With SVE enabled, at least one "
> +                                  "vector length must be enabled.\n");
> +                return;
> +            }
> +            for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> +                if (test_bit(vq - 1, cpu->sve_vq_init)) {
> +                    break;
> +                }
>              }
> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> +            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
>          }
> -        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>  
> -        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
>          max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
>      }
>  
> @@ -358,16 +399,48 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>      assert(max_vq != 0);
>      bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
>  
> -    /* Ensure all required powers-of-two are enabled. */
> -    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> -        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> -            error_setg(errp, "cannot disable sve%d", vq * 128);
> -            error_append_hint(errp, "sve%d is required as it "
> -                              "is a power-of-two length smaller than "
> -                              "the maximum, sve%d\n",
> -                              vq * 128, max_vq * 128);
> +    if (kvm_enabled()) {
> +        /* Ensure the set of lengths matches what KVM supports. */
> +        bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
> +        if (!bitmap_empty(tmp, max_vq)) {
> +            vq = find_last_bit(tmp, max_vq) + 1;
> +            if (test_bit(vq - 1, cpu->sve_vq_map)) {
> +                if (cpu->sve_max_vq) {
> +                    error_setg(errp, "cannot set sve-max-vq=%d",
> +                               cpu->sve_max_vq);
> +                    error_append_hint(errp, "This KVM host does not support "
> +                                      "the vector length %d-bits.\n",
> +                                      vq * 128);
> +                    error_append_hint(errp, "It may not be possible to use "
> +                                      "sve-max-vq with this KVM host. Try "
> +                                      "using only sve<N> properties.\n");
> +                } else {
> +                    error_setg(errp, "cannot enable sve%d", vq * 128);
> +                    error_append_hint(errp, "This KVM host does not support "
> +                                      "the vector length %d-bits.\n",
> +                                      vq * 128);
> +                }
> +            } else {
> +                error_setg(errp, "cannot disable sve%d", vq * 128);
I am not sure about the above message. what is the vq value supposed to
be? For instance if we previously entered the
"if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {" path
> +                error_append_hint(errp, "The KVM host requires all "
> +                                  "supported vector lengths smaller "
> +                                  "than %d bits to also be enabled.\n",
> +                                  max_vq * 128);
> +            }
>              return;
>          }
> +    } else {
> +        /* Ensure all required powers-of-two are enabled. */
> +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> +            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> +                error_setg(errp, "cannot disable sve%d", vq * 128);
> +                error_append_hint(errp, "sve%d is required as it "
> +                                  "is a power-of-two length smaller than "
> +                                  "the maximum, sve%d\n",
> +                                  vq * 128, max_vq * 128);
> +                return;
> +            }
> +        }
>      }
>  
>      /* From now on sve_max_vq is the actual maximum supported length. */
> @@ -411,13 +484,22 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>      Error *err = NULL;
>  
>      visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
>  
> -    if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) {
> -        error_setg(&err, "unsupported SVE vector length");
> -        error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n",
> +    if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
> +        error_setg(errp, "cannot set sve-max-vq");
> +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
> +        return;
> +    }
> +
> +    if (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ) {
> +        error_setg(errp, "unsupported SVE vector length");
> +        error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n",
>                            ARM_MAX_VQ);
>      }
> -    error_propagate(errp, err);
>  }
>  
>  static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> @@ -450,6 +532,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
>          return;
>      }
>  
> +    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
> +        error_setg(errp, "cannot enable %s", name);
> +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
> +        return;
> +    }
> +
>      if (value) {
>          set_bit(vq - 1, cpu->sve_vq_map);
>      } else {
> @@ -607,20 +695,19 @@ static void aarch64_max_initfn(Object *obj)
>          cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
>          cpu->dcz_blocksize = 7; /*  512 bytes */
>  #endif
> -
> -        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> -                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> -
> -        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -            char name[8];
> -            sprintf(name, "sve%d", vq * 128);
> -            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> -                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> -        }
>      }
>  
>      object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
>                          cpu_arm_set_sve, NULL, NULL, &error_fatal);
> +    object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> +                        cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> +
> +    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> +        char name[8];
> +        sprintf(name, "sve%d", vq * 128);
> +        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> +                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> +    }
>  }
>  
>  struct ARMCPUInfo {
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index f96649ae0349..cff4217a8469 100644
> --- a/target/arm/kvm64.c
> +++ b/target/arm/kvm64.c
> @@ -613,6 +613,100 @@ bool kvm_arm_sve_supported(CPUState *cpu)
>      return kvm_check_extension(s, KVM_CAP_ARM_SVE);
>  }
>  
> +QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
> +
> +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
> +{
> +    /* Only call this function if kvm_arm_sve_supported() returns true. */
> +    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
> +    static bool probed;
> +    uint32_t vq = 0;
> +    int i, j;
> +
> +    bitmap_clear(map, 0, ARM_MAX_VQ);
> +
> +    /*
> +     * KVM ensures all host CPUs support the same set of vector lengths.
> +     * So we only need to create the scratch VCPUs once and then cache
> +     * the results.
> +     */
> +    if (!probed) {
> +        struct kvm_vcpu_init init = {
> +            .target = -1,
> +            .features[0] = (1 << KVM_ARM_VCPU_SVE),
> +        };
> +        struct kvm_one_reg reg = {
> +            .id = KVM_REG_ARM64_SVE_VLS,
> +            .addr = (uint64_t)&vls[0],
> +        };
> +        int fdarray[3], ret;
> +
> +        probed = true;
> +
> +        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
> +            error_report("failed to create scratch VCPU with SVE enabled");
> +            abort();
> +        }
> +        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
> +        kvm_arm_destroy_scratch_host_vcpu(fdarray);
> +        if (ret) {
> +            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
> +                         strerror(errno));
> +            abort();
> +        }
> +
> +        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
> +            if (vls[i]) {
> +                vq = 64 - clz64(vls[i]) + i * 64;
> +                break;
> +            }
> +        }
> +        if (vq > ARM_MAX_VQ) {
> +            warn_report("KVM supports vector lengths larger than "
> +                        "QEMU can enable");
> +        }
> +    }
> +
> +    for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) {
> +        if (!vls[i]) {
> +            continue;
> +        }
> +        for (j = 1; j <= 64; ++j) {
> +            vq = j + i * 64;
> +            if (vq > ARM_MAX_VQ) {
> +                return;
> +            }
> +            if (vls[i] & (1UL << (j - 1))) {
> +                set_bit(vq - 1, map);
> +            }
> +        }
> +    }
> +}
> +
> +static int kvm_arm_sve_set_vls(CPUState *cs)
> +{
> +    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0};
> +    struct kvm_one_reg reg = {
> +        .id = KVM_REG_ARM64_SVE_VLS,
> +        .addr = (uint64_t)&vls[0],
> +    };
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    uint32_t vq;
> +    int i, j;
> +
> +    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
> +
> +    for (vq = 1; vq <= cpu->sve_max_vq; ++vq) {
> +        if (test_bit(vq - 1, cpu->sve_vq_map)) {
> +            i = (vq - 1) / 64;
> +            j = (vq - 1) % 64;
> +            vls[i] |= 1UL << j;
> +        }
> +    }
> +
> +    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +}
> +
>  #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
>  
>  int kvm_arch_init_vcpu(CPUState *cs)
> @@ -624,7 +718,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
>  
>      if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
>          !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
> -        fprintf(stderr, "KVM is not supported for this guest CPU type\n");
> +        error_report("KVM is not supported for this guest CPU type");
>          return -EINVAL;
>      }
>  
> @@ -660,6 +754,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>      }
>  
>      if (cpu_isar_feature(aa64_sve, cpu)) {
> +        ret = kvm_arm_sve_set_vls(cs);
> +        if (ret) {
> +            return ret;
> +        }
>          ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
>          if (ret) {
>              return ret;
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index 1151877f97ea..a1cc6513f72b 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -212,6 +212,17 @@ typedef struct ARMHostCPUFeatures {
>   */
>  bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
>  
> +/**
> + * kvm_arm_sve_get_vls:
> + * @cs: CPUState
> + * @map: bitmap to fill in
> + *
> + * Get all the SVE vector lengths supported by the KVM host, setting
> + * the bits corresponding to their length in quadwords minus one
> + * (vq - 1) in @map up to ARM_MAX_VQ.
> + */
> +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
> +
>  /**
>   * kvm_arm_set_cpu_features_from_host:
>   * @cpu: ARMCPU to set the features for
> @@ -315,6 +326,7 @@ static inline int kvm_arm_vgic_probe(void)
>  static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
>  static inline void kvm_arm_pmu_init(CPUState *cs) {}
>  
> +static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) {}
>  #endif
>  
>  static inline const char *gic_class_name(void)
> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> index d50f98cb6aea..a0129aebf409 100644
> --- a/tests/arm-cpu-features.c
> +++ b/tests/arm-cpu-features.c
> @@ -117,6 +117,17 @@ static QDict *resp_get_props(QDict *resp)
>      return qdict;
>  }
>  
> +static bool resp_get_feature(QDict *resp, const char *feature)
> +{
> +    QDict *props;
> +
> +    g_assert(resp);
> +    g_assert(resp_has_props(resp));
> +    props = resp_get_props(resp);
> +    g_assert(qdict_get(props, feature));
> +    return qdict_get_bool(props, feature);
> +}
> +
>  #define assert_has_feature(qts, cpu_type, feature)                     \
>  ({                                                                     \
>      QDict *_resp = do_query_no_props(qts, cpu_type);                   \
> @@ -336,6 +347,25 @@ static void sve_tests_sve_off(const void *data)
>      qtest_quit(qts);
>  }
>  
> +static void sve_tests_sve_off_kvm(const void *data)
> +{
> +    QTestState *qts;
> +
> +    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
> +
> +    /*
> +     * We don't know if this host supports SVE so we don't
> +     * attempt to test enabling anything. We only test that
> +     * everything is disabled (as it should be with sve=off)
> +     * and that using sve<N>=off to explicitly disable vector
> +     * lengths is OK too.
> +     */
> +    assert_sve_vls(qts, "max", 0, NULL);
> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> +
> +    qtest_quit(qts);
> +}
> +
>  static void test_query_cpu_model_expansion(const void *data)
>  {
>      QTestState *qts;
> @@ -385,12 +415,81 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>      assert_has_feature(qts, "host", "pmu");
>  
>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
> +        bool kvm_supports_sve;
> +        char max_name[8], name[8];
> +        uint32_t max_vq, vq;
> +        uint64_t vls;
> +        QDict *resp;
> +        char *error;
> +
>          assert_has_feature(qts, "host", "aarch64");
> -        assert_has_feature(qts, "max", "sve");
>  
>          assert_error(qts, "cortex-a15",
>              "We cannot guarantee the CPU type 'cortex-a15' works "
>              "with KVM on this host", NULL);
> +
> +        assert_has_feature(qts, "max", "sve");
> +        resp = do_query_no_props(qts, "max");
> +        kvm_supports_sve = resp_get_feature(resp, "sve");
> +        vls = resp_get_sve_vls(resp);
> +        qobject_unref(resp);
> +
> +        if (kvm_supports_sve) {
> +            g_assert(vls != 0);
> +            max_vq = 64 - __builtin_clzll(vls);
> +            sprintf(max_name, "sve%d", max_vq * 128);
> +
> +            /* Enabling a supported length is of course fine. */
> +            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
> +
> +            /* Get the next supported length smaller than max-vq. */
> +            vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
> +            if (vq) {
> +                /*
> +                 * We have at least one length smaller than max-vq,
> +                 * so we can disable max-vq.
> +                 */
> +                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
> +                               "{ %s: false }", max_name);
> +
> +                /*
> +                 * Smaller, supported vector lengths cannot be disabled
> +                 * unless all larger, supported vector lengths are also
> +                 * disabled.
> +                 */
> +                sprintf(name, "sve%d", vq * 128);
> +                error = g_strdup_printf("cannot disable %s", name);
> +                assert_error(qts, "max", error,
> +                             "{ %s: true, %s: false }",
> +                             max_name, name);
> +                g_free(error);
> +            }
> +
> +            /*
> +             * The smallest, supported vector length is required, because
> +             * we need at least one vector length enabled.
> +             */
> +            vq = __builtin_ffsll(vls);
> +            sprintf(name, "sve%d", vq * 128);
> +            error = g_strdup_printf("cannot disable %s", name);
> +            assert_error(qts, "max", error, "{ %s: false }", name);
> +            g_free(error);
> +
> +            /* Get an unsupported length. */
> +            for (vq = 1; vq <= max_vq; ++vq) {
> +                if (!(vls & BIT(vq - 1))) {
> +                    break;
> +                }
> +            }
> +            if (vq <= SVE_MAX_VQ) {
> +                sprintf(name, "sve%d", vq * 128);
> +                error = g_strdup_printf("cannot enable %s", name);
> +                assert_error(qts, "max", error, "{ %s: true }", name);
> +                g_free(error);
> +            }
> +        } else {
> +            g_assert(vls == 0);
> +        }
>      } else {
>          assert_error(qts, "host",
>                       "'pmu' feature not supported by KVM on this host",
> @@ -427,6 +526,10 @@ int main(int argc, char **argv)
>      if (kvm_available) {
>          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
>                              NULL, test_query_cpu_model_expansion_kvm);
> +        if (g_str_equal(qtest_get_arch(), "aarch64")) {
> +            qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
> +                                NULL, sve_tests_sve_off_kvm);
> +        }
>      }
>  
>      return g_test_run();
> 
Besides,
Reviewed-by: Eric Auger <eric.auger@redhat.com>


Thanks

Eric




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available
  2019-09-24 11:31 ` [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
@ 2019-09-26  6:53   ` Auger Eric
  0 siblings, 0 replies; 32+ messages in thread
From: Auger Eric @ 2019-09-26  6:53 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:31 PM, Andrew Jones wrote:
> Enable SVE in the KVM guest when the 'max' cpu type is configured
> and KVM supports it. KVM SVE requires use of the new finalize
> vcpu ioctl, so we add that now too. For starters SVE can only be
> turned on or off, getting all vector lengths the host CPU supports
> when on. We'll add the other SVE CPU properties in later patches.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric

> ---
>  target/arm/cpu64.c       | 17 ++++++++++++++---
>  target/arm/kvm.c         |  5 +++++
>  target/arm/kvm64.c       | 20 +++++++++++++++++++-
>  target/arm/kvm_arm.h     | 27 +++++++++++++++++++++++++++
>  tests/arm-cpu-features.c |  1 +
>  5 files changed, 66 insertions(+), 4 deletions(-)
> 
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 606e3eceb9c0..b7eff4e1e107 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -481,6 +481,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>          return;
>      }
>  
> +    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
> +        error_setg(errp, "'sve' feature not supported by KVM on this host");
> +        return;
> +    }
> +
>      t = cpu->isar.id_aa64pfr0;
>      t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
>      cpu->isar.id_aa64pfr0 = t;
> @@ -495,11 +500,16 @@ static void aarch64_max_initfn(Object *obj)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      uint32_t vq;
> +    uint64_t t;
>  
>      if (kvm_enabled()) {
>          kvm_arm_set_cpu_features_from_host(cpu);
> +        if (kvm_arm_sve_supported(CPU(cpu))) {
> +            t = cpu->isar.id_aa64pfr0;
> +            t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
> +            cpu->isar.id_aa64pfr0 = t;
> +        }
>      } else {
> -        uint64_t t;
>          uint32_t u;
>          aarch64_a57_initfn(obj);
>  
> @@ -600,8 +610,6 @@ static void aarch64_max_initfn(Object *obj)
>  
>          object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>                              cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> -        object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> -                            cpu_arm_set_sve, NULL, NULL, &error_fatal);
>  
>          for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>              char name[8];
> @@ -610,6 +618,9 @@ static void aarch64_max_initfn(Object *obj)
>                                  cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
>          }
>      }
> +
> +    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> +                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
>  }
>  
>  struct ARMCPUInfo {
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index b2eaa50b8df9..72569f71236e 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -51,6 +51,11 @@ int kvm_arm_vcpu_init(CPUState *cs)
>      return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
>  }
>  
> +int kvm_arm_vcpu_finalize(CPUState *cs, int feature)
> +{
> +    return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_FINALIZE, &feature);
> +}
> +
>  void kvm_arm_init_serror_injection(CPUState *cs)
>  {
>      cap_has_inject_serror_esr = kvm_check_extension(cs->kvm_state,
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index ea454c613919..fc62bab8684e 100644
> --- a/target/arm/kvm64.c
> +++ b/target/arm/kvm64.c
> @@ -602,6 +602,13 @@ bool kvm_arm_aarch32_supported(CPUState *cpu)
>      return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT);
>  }
>  
> +bool kvm_arm_sve_supported(CPUState *cpu)
> +{
> +    KVMState *s = KVM_STATE(current_machine->accelerator);
> +
> +    return kvm_check_extension(s, KVM_CAP_ARM_SVE);
> +}
> +
>  #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
>  
>  int kvm_arch_init_vcpu(CPUState *cs)
> @@ -630,13 +637,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
>      }
>      if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
> -            cpu->has_pmu = false;
> +        cpu->has_pmu = false;
>      }
>      if (cpu->has_pmu) {
>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
>      } else {
>          unset_feature(&env->features, ARM_FEATURE_PMU);
>      }
> +    if (cpu_isar_feature(aa64_sve, cpu)) {
> +        assert(kvm_arm_sve_supported(cs));
> +        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE;
> +    }
>  
>      /* Do KVM_ARM_VCPU_INIT ioctl */
>      ret = kvm_arm_vcpu_init(cs);
> @@ -644,6 +655,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
>          return ret;
>      }
>  
> +    if (cpu_isar_feature(aa64_sve, cpu)) {
> +        ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
>      /*
>       * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
>       * Currently KVM has its own idea about MPIDR assignment, so we
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index b3106c8600af..1151877f97ea 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -27,6 +27,20 @@
>   */
>  int kvm_arm_vcpu_init(CPUState *cs);
>  
> +/**
> + * kvm_arm_vcpu_finalize
> + * @cs: CPUState
> + * @feature: int
> + *
> + * Finalizes the configuration of the specified VCPU feature by
> + * invoking the KVM_ARM_VCPU_FINALIZE ioctl. Features requiring
> + * this are documented in the "KVM_ARM_VCPU_FINALIZE" section of
> + * KVM's API documentation.
> + *
> + * Returns: 0 if success else < 0 error code
> + */
> +int kvm_arm_vcpu_finalize(CPUState *cs, int feature);
> +
>  /**
>   * kvm_arm_register_device:
>   * @mr: memory region for this device
> @@ -225,6 +239,14 @@ bool kvm_arm_aarch32_supported(CPUState *cs);
>   */
>  bool kvm_arm_pmu_supported(CPUState *cs);
>  
> +/**
> + * bool kvm_arm_sve_supported:
> + * @cs: CPUState
> + *
> + * Returns true if the KVM VCPU can enable SVE and false otherwise.
> + */
> +bool kvm_arm_sve_supported(CPUState *cs);
> +
>  /**
>   * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the
>   * IPA address space supported by KVM
> @@ -275,6 +297,11 @@ static inline bool kvm_arm_pmu_supported(CPUState *cs)
>      return false;
>  }
>  
> +static inline bool kvm_arm_sve_supported(CPUState *cs)
> +{
> +    return false;
> +}
> +
>  static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
>  {
>      return -ENOENT;
> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> index 9a2dd402b769..d50f98cb6aea 100644
> --- a/tests/arm-cpu-features.c
> +++ b/tests/arm-cpu-features.c
> @@ -386,6 +386,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>  
>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
>          assert_has_feature(qts, "host", "aarch64");
> +        assert_has_feature(qts, "max", "sve");
>  
>          assert_error(qts, "cortex-a15",
>              "We cannot guarantee the CPU type 'cortex-a15' works "
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties
  2019-09-24 11:31 ` [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties Andrew Jones
@ 2019-09-26  7:07   ` Auger Eric
  2019-09-26  8:53     ` Andrew Jones
  0 siblings, 1 reply; 32+ messages in thread
From: Auger Eric @ 2019-09-26  7:07 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, imammedo, alex.bennee,
	Dave.Martin

Hi Drew,

On 9/24/19 1:31 PM, Andrew Jones wrote:
> Allow cpu 'host' to enable SVE when it's available, unless the
> user chooses to disable it with the added 'sve=off' cpu property.
> Also give the user the ability to select vector lengths with the
> sve<N> properties. We don't adopt 'max' cpu's other sve property,
> sve-max-vq, because that property is difficult to use with KVM.
> That property assumes all vector lengths in the range from 1 up
> to and including the specified maximum length are supported, but
> there may be optional lengths not supported by the host in that
> range. With KVM one must be more specific when enabling vector
> lengths.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  docs/arm-cpu-features.rst | 19 ++++++++++++-------
>  target/arm/cpu.c          |  3 +++
>  target/arm/cpu.h          |  2 ++
>  target/arm/cpu64.c        | 33 +++++++++++++++++----------------
>  target/arm/kvm64.c        | 14 +++++++++++++-
>  tests/arm-cpu-features.c  | 21 +++++++++++----------
>  6 files changed, 58 insertions(+), 34 deletions(-)
> 
> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> index 939366f959cf..0c16eef7c8c2 100644
> --- a/docs/arm-cpu-features.rst
> +++ b/docs/arm-cpu-features.rst
> @@ -256,31 +256,36 @@ SVE CPU Property Examples
>  
>       $ qemu-system-aarch64 -M virt -cpu max
>  
> -  3) Only enable the 128-bit vector length::
> +  3) When KVM is enabled, implicitly enable all host CPU supported vector
> +     lengths with the `host` CPU type::
> +
> +     $ qemu-system-aarch64 -M virt,accel=kvm -cpu host
> +
> +  4) Only enable the 128-bit vector length::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve128=on
>  
> -  4) Disable the 256-bit vector length and all larger vector lengths
> +  5) Disable the 256-bit vector length and all larger vector lengths
>       since 256 is a power-of-two (this results in only the 128-bit length
>       being enabled)::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve256=off
>  
> -  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> +  6) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
>  
> -  6) The same as (5), but since the 128-bit and 256-bit vector
> +  7) The same as (6), but since the 128-bit and 256-bit vector
>       lengths are required for the 512-bit vector length to be enabled,
>       then allow them to be auto-enabled::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve512=on
>  
> -  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
> +  8) Do the same as (7), but by first disabling SVE and then re-enabling it::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on
>  
> -  8) Force errors regarding the last vector length::
> +  9) Force errors regarding the last vector length::
>  
>       $ qemu-system-aarch64 -M virt -cpu max,sve128=off
>       $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
> @@ -292,5 +297,5 @@ The examples in "SVE CPU Property Examples" exhibit many ways to select
>  vector lengths which developers may find useful in order to avoid overly
>  verbose command lines.  However, the recommended way to select vector
>  lengths is to explicitly enable each desired length.  Therefore only
> -example's (1), (3), and (5) exhibit recommended uses of the properties.
> +example's (1), (4), and (6) exhibit recommended uses of the properties.
>  
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 522fed95b339..7695ae551218 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -2671,6 +2671,9 @@ static void arm_host_initfn(Object *obj)
>      ARMCPU *cpu = ARM_CPU(obj);
>  
>      kvm_arm_set_cpu_features_from_host(cpu);
> +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> +        aarch64_add_sve_properties(obj);
> +    }
>      arm_cpu_post_init(obj);
>  }
>  
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 11162484465a..5b9c3e4cd73d 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -974,11 +974,13 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>  void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
>  void aarch64_sve_change_el(CPUARMState *env, int old_el,
>                             int new_el, bool el0_a64);
> +void aarch64_add_sve_properties(Object *obj);
>  #else
>  static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { }
>  static inline void aarch64_sve_change_el(CPUARMState *env, int o,
>                                           int n, bool a)
>  { }
> +static inline void aarch64_add_sve_properties(Object *obj) { }
>  #endif
>  
>  #if !defined(CONFIG_TCG)
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 18dd5e24ec61..e7cd420faa9d 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -579,6 +579,21 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>      cpu->isar.id_aa64pfr0 = t;
>  }
>  
> +void aarch64_add_sve_properties(Object *obj)
> +{
> +    uint32_t vq;
> +
> +    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> +                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
> +
> +    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> +        char name[8];
line needed
> +        sprintf(name, "sve%d", vq * 128);
> +        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> +                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> +    }
> +}
> +
>  /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
>   * otherwise, a CPU with as many features enabled as our emulation supports.
>   * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
> @@ -587,17 +602,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>  static void aarch64_max_initfn(Object *obj)
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
> -    uint32_t vq;
> -    uint64_t t;
>  
>      if (kvm_enabled()) {
>          kvm_arm_set_cpu_features_from_host(cpu);
> -        if (kvm_arm_sve_supported(CPU(cpu))) {
> -            t = cpu->isar.id_aa64pfr0;
> -            t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
> -            cpu->isar.id_aa64pfr0 = t;
> -        }
>      } else {
> +        uint64_t t;
>          uint32_t u;
>          aarch64_a57_initfn(obj);
>  
> @@ -697,17 +706,9 @@ static void aarch64_max_initfn(Object *obj)
>  #endif
>      }
>  
> -    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> -                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
> +    aarch64_add_sve_properties(obj);
>      object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>                          cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> -
> -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -        char name[8];
> -        sprintf(name, "sve%d", vq * 128);
> -        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> -                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> -    }
>  }
>  
>  struct ARMCPUInfo {
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index cff4217a8469..2da366ba113e 100644
> --- a/target/arm/kvm64.c
> +++ b/target/arm/kvm64.c
> @@ -488,7 +488,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
>       * and then query that CPU for the relevant ID registers.
>       */
>      int fdarray[3];
> +    bool sve_supported;
>      uint64_t features = 0;
> +    uint64_t t;
t can stay local to the block below
>      int err;
>  
>      /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
> @@ -578,13 +580,23 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
>                                ARM64_SYS_REG(3, 0, 0, 3, 2));
>      }
>  
> +    sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0;
!ioctl?
> +
>      kvm_arm_destroy_scratch_host_vcpu(fdarray);
>  
>      if (err < 0) {
>          return false;
>      }
>  
> -   /* We can assume any KVM supporting CPU is at least a v8
> +    /* Add feature bits that can't appear until after VCPU init. */
> +    if (sve_supported) {
> +        t = ahcf->isar.id_aa64pfr0;
> +        t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
> +        ahcf->isar.id_aa64pfr0 = t;
> +    }
> +
> +    /*
> +     * We can assume any KVM supporting CPU is at least a v8
>       * with VFPv4+Neon; this in turn implies most of the other
>       * feature bits.
>       */
> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> index a0129aebf409..4dc067fb5558 100644
> --- a/tests/arm-cpu-features.c
> +++ b/tests/arm-cpu-features.c
> @@ -351,7 +351,7 @@ static void sve_tests_sve_off_kvm(const void *data)
>  {
>      QTestState *qts;
>  
> -    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
> +    qts = qtest_init(MACHINE "-accel kvm -cpu host,sve=off");
>  
>      /*
>       * We don't know if this host supports SVE so we don't
> @@ -360,8 +360,8 @@ static void sve_tests_sve_off_kvm(const void *data)
>       * and that using sve<N>=off to explicitly disable vector
>       * lengths is OK too.
>       */
> -    assert_sve_vls(qts, "max", 0, NULL);
> -    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> +    assert_sve_vls(qts, "host", 0, NULL);
> +    assert_sve_vls(qts, "host", 0, "{ 'sve128': false }");
>  
>      qtest_quit(qts);
>  }
> @@ -428,8 +428,8 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>              "We cannot guarantee the CPU type 'cortex-a15' works "
>              "with KVM on this host", NULL);
>  
> -        assert_has_feature(qts, "max", "sve");
> -        resp = do_query_no_props(qts, "max");
> +        assert_has_feature(qts, "host", "sve");
> +        resp = do_query_no_props(qts, "host");
>          kvm_supports_sve = resp_get_feature(resp, "sve");
>          vls = resp_get_sve_vls(resp);
>          qobject_unref(resp);
> @@ -440,7 +440,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>              sprintf(max_name, "sve%d", max_vq * 128);
>  
>              /* Enabling a supported length is of course fine. */
> -            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
> +            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
>  
>              /* Get the next supported length smaller than max-vq. */
>              vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
> @@ -449,7 +449,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>                   * We have at least one length smaller than max-vq,
>                   * so we can disable max-vq.
>                   */
> -                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
> +                assert_sve_vls(qts, "host", (vls & ~BIT(max_vq - 1)),
>                                 "{ %s: false }", max_name);
>  
>                  /*
> @@ -459,7 +459,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>                   */
>                  sprintf(name, "sve%d", vq * 128);
>                  error = g_strdup_printf("cannot disable %s", name);
> -                assert_error(qts, "max", error,
> +                assert_error(qts, "host", error,
>                               "{ %s: true, %s: false }",
>                               max_name, name);
>                  g_free(error);
> @@ -472,7 +472,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>              vq = __builtin_ffsll(vls);
>              sprintf(name, "sve%d", vq * 128);
>              error = g_strdup_printf("cannot disable %s", name);
> -            assert_error(qts, "max", error, "{ %s: false }", name);
> +            assert_error(qts, "host", error, "{ %s: false }", name);
>              g_free(error);
>  
>              /* Get an unsupported length. */
> @@ -484,13 +484,14 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>              if (vq <= SVE_MAX_VQ) {
>                  sprintf(name, "sve%d", vq * 128);
>                  error = g_strdup_printf("cannot enable %s", name);
> -                assert_error(qts, "max", error, "{ %s: true }", name);
> +                assert_error(qts, "host", error, "{ %s: true }", name);
>                  g_free(error);
>              }
>          } else {
>              g_assert(vls == 0);
>          }
>      } else {
> +        assert_has_not_feature(qts, "host", "sve");
>          assert_error(qts, "host",
>                       "'pmu' feature not supported by KVM on this host",
>                       "{ 'pmu': true }");
> 
Besides
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-25 13:53   ` Auger Eric
@ 2019-09-26  8:21     ` Andrew Jones
  2019-09-26  9:34       ` Auger Eric
  0 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-26  8:21 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Wed, Sep 25, 2019 at 03:53:42PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 9/24/19 1:31 PM, Andrew Jones wrote:
> > Introduce cpu properties to give fine control over SVE vector lengths.
> > We introduce a property for each valid length up to the current
> > maximum supported, which is 2048-bits. The properties are named, e.g.
> > sve128, sve256, sve384, sve512, ..., where the number is the number of
> > bits. See the updates to docs/arm-cpu-features.rst for a description
> > of the semantics and for example uses.
> > 
> > Note, as sve-max-vq is still present and we'd like to be able to
> > support qmp_query_cpu_model_expansion with guests launched with e.g.
> > -cpu max,sve-max-vq=8 on their command lines, then we do allow
> > sve-max-vq and sve<N> properties to be provided at the same time, but
> > this is not recommended, and is why sve-max-vq is not mentioned in the
> > document.  If sve-max-vq is provided then it enables all lengths smaller
> > than and including the max and disables all lengths larger. It also has
> > the side-effect that no larger lengths may be enabled and that the max
> > itself cannot be disabled. Smaller non-power-of-two lengths may,
> > however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
> > guest the vector lengths 128, 256, and 512 bits.
> > 
> > This patch has been co-authored with Richard Henderson, who reworked
> > the target/arm/cpu64.c changes in order to push all the validation and
> > auto-enabling/disabling steps into the finalizer, resulting in a nice
> > LOC reduction.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  docs/arm-cpu-features.rst | 157 +++++++++++++++++++++++++++++--
> >  target/arm/cpu.c          |  19 ++++
> >  target/arm/cpu.h          |  19 ++++
> >  target/arm/cpu64.c        | 190 +++++++++++++++++++++++++++++++++++++-
> >  target/arm/helper.c       |  13 ++-
> >  target/arm/monitor.c      |  12 +++
> >  tests/arm-cpu-features.c  | 189 +++++++++++++++++++++++++++++++++++++
> >  7 files changed, 587 insertions(+), 12 deletions(-)
> > 
> > diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> > index c79dcffb5556..1262fddc6201 100644
> > --- a/docs/arm-cpu-features.rst
> > +++ b/docs/arm-cpu-features.rst
> > @@ -48,18 +48,28 @@ block in the script for usage) is used to issue the QMP commands.
> >        (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
> >        { "return": {
> >          "model": { "name": "max", "props": {
> > -        "pmu": true, "aarch64": true
> > +        "sve1664": true, "pmu": true, "sve1792": true, "sve1920": true,
> > +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> > +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> > +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> > +        "sve896": true, "sve1280": true, "sve2048": true
> I don't really understand why this gets printed unsorted as you
> registered them in the logical order, any clue?

Maybe qdict hashing? qmp-shell could probably be patched to sort them,
but it's probably not worth it.

> 
> Note: This example is given with TCG or KVM with all those vectors
> supported by the host.

You want this note to be added? I don't think it's necessary, as it's just
an example. A different configuration or different CPU model expansion
will have different results, as we explain exhaustively in this document.

> >        }}}}
> >  
> > -We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
> > -We also see that the CPU features are enabled, as they are all `true`.
> > +We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many
> > +`sve<N>` CPU features.  We also see that all the CPU features are
> > +enabled, as they are all `true`.  (The `sve<N>` CPU features are all
> > +optional SVE vector lengths.  See "SVE CPU Properties".)
> >  
> >  (2) Let's try to disable the PMU::
> >  
> >        (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
> >        { "return": {
> >          "model": { "name": "max", "props": {
> > -        "pmu": false, "aarch64": true
> > +        "sve1664": true, "pmu": false, "sve1792": true, "sve1920": true,
> > +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> > +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> > +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> > +        "sve896": true, "sve1280": true, "sve2048": true
> >        }}}}
> >  
> >  We see it worked, as `pmu` is now `false`.
> > @@ -75,7 +85,22 @@ We see it worked, as `pmu` is now `false`.
> >  It looks like this feature is limited to a configuration we do not
> >  currently have.
> >  
> > -(4) Let's try probing CPU features for the Cortex-A15 CPU type::
> > +(4) Let's disable `sve` and see what happens to all the optional SVE
> > +    vector lengths::
> > +
> > +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}}
> > +      { "return": {
> > +        "model": { "name": "max", "props": {
> > +        "sve1664": false, "pmu": true, "sve1792": false, "sve1920": false,
> > +        "sve128": false, "aarch64": true, "sve1024": false, "sve": false,
> > +        "sve640": false, "sve768": false, "sve1408": false, "sve256": false,
> > +        "sve1152": false, "sve512": false, "sve384": false, "sve1536": false,
> > +        "sve896": false, "sve1280": false, "sve2048": false
> > +      }}}}
> > +
> > +As expected they are now all `false`.
> > +
> > +(5) Let's try probing CPU features for the Cortex-A15 CPU type::
> >  
> >        (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
> >        {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
> > @@ -131,7 +156,125 @@ After determining which CPU features are available and supported for a
> >  given CPU type, then they may be selectively enabled or disabled on the
> >  QEMU command line with that CPU type::
> >  
> > -  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
> > +  $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on
> > +
> > +The example above disables the PMU and enables the first two SVE vector
> > +lengths for the `max` CPU type.  Note, the `sve=on` isn't actually
> > +necessary, because, as we observed above with our probe of the `max` CPU
> > +type, `sve` is already on by default.
> 
> This holds with TCG and not KVM.

It also holds with KVM, as long as the host supports SVE. But that doesn't
matter, because we're speaking specifically about the example above here,
where we see that sve=on is the default. 

> 
> Also, based on our probe of
> > +defaults, it would seem we need to disable many SVE vector lengths, rather
> > +than only enabling the two we want.  This isn't the case, because, as
> > +disabling many SVE vector lengths would be quite verbose, the `sve<N>` CPU
> > +properties have special semantics (see "SVE CPU Property Parsing
> > +Semantics").
> > +
> > +SVE CPU Properties
> > +==================
> > +
> > +There are two types of SVE CPU properties: `sve` and `sve<N>`.  The first
> > +is used to enable or disable the entire SVE feature, just as the `pmu`
> > +CPU property completely enables or disables the PMU.  The second type
> > +is used to enable or disable specific vector lengths, where `N` is the
> > +number of bits of the length.  The `sve<N>` CPU properties have special
> > +dependencies and constraints, see "SVE CPU Property Dependencies and
> > +Constraints" below.  Additionally, as we want all supported vector lengths
> > +to be enabled by default, then, in order to avoid overly verbose command
> > +lines (command lines full of `sve<N>=off`, for all `N` not wanted), we
> > +provide the parsing semantics listed in "SVE CPU Property Parsing
> > +Semantics".
> > +
> > +SVE CPU Property Dependencies and Constraints
> > +---------------------------------------------
> > +
> > +  1) At least one vector length must be enabled when `sve` is enabled.> +
> > +  2) If a vector length `N` is enabled, then all power-of-two vector
> > +     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> > +     is enabled, then `sve128` and `sve256` must also be enabled,
> > +     but `sve384` is not required.
> I would remove the eg. part. reading that I tend to understand that the
> user must pass ,sve128=on, sve256=on and sve512=on whereas example 6
> says only sve512=on can be set and other lower ^2 values are auto-enabled.

I'll keep the example, but instead of using the property names, I'll
change to using "the 128-bit vector length", 256-bit ..., etc.

> > +
> > +SVE CPU Property Parsing Semantics
> > +----------------------------------
> > +
> > +  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
> > +     are enabled or disabled is irrelevant to the guest, as the entire
> > +     SVE feature is disabled and that disables all vector lengths for
> > +     the guest.  However QEMU will still track any `sve<N>` CPU
> > +     properties provided by the user.  If later an `sve=on` is provided,
> > +     then the guest will get only the enabled lengths.
> > +
> > +  2) If SVE is enabled (`sve=on`), but no `sve<N>` CPU properties are
> > +     provided, then all supported vector lengths are enabled.
> I understand from the code it also includes non ^2 values which is not
> obvious.

Yes, the default is to have *all* supported vector lengths enabled, not
just the power-of-two. As we already use the word 'all' here, then how
can we further clarify this?

> > +
> > +  3) If SVE is enabled, then an error is generated when attempting to
> > +     disable the last enabled vector length (see constraint (1) of "SVE
> > +     CPU Property Dependencies and Constraints").
> the same happens if you attempt to disabled any lower ^2 value

That should be another bullet, which I appear to be missing, and will add.

> > +
> > +  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> > +     CPU properties are set `on`, then the specified vector lengths are
> > +     disabled but the default for any unspecified lengths remains enabled.
> > +     Disabling a power-of-two vector length also disables all vector
> > +     lengths larger than the power-of-two length (see constraint (2) of
> > +     "SVE CPU Property Dependencies and Constraints").
> So rephasing it:
> disabling a non ^2 value only disable that one
> disabling a ^2 value disables all larger lengths too
> is that correct?

That's correct. We auto-disable all uninitialized larger lengths when a
power-of-two dependency length is explicitly disabled.

> 
> > +
> > +  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> > +     are enabled and all unspecified lengths default to disabled, except
> > +     for the required lengths per constraint (2) of "SVE CPU Property
> > +     Dependencies and Constraints", which will even be auto-enabled if
> > +     they were not explicitly enabled.
> > +
> > +  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> > +     explicitly disabled (i.e. avoiding the error specified in (3) of
> > +     "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
> > +     provided an error will be generated.  To avoid this error, one must
> > +     enable at least one vector length prior to enabling SVE.
> > +
> > +SVE CPU Property Examples
> > +-------------------------
> > +
> > +  1) Disable SVE::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve=off
> > +
> > +  2) Implicitly enable all vector lengths for the `max` CPU type::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max
> > +
> > +  3) Only enable the 128-bit vector length::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on
> > +
> > +  4) Disable the 256-bit vector length and all larger vector lengths
> > +     since 256 is a power-of-two (this results in only the 128-bit length
> > +     being enabled)::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve256=off
> > +
> > +  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
> > +
> > +  6) The same as (5), but since the 128-bit and 256-bit vector
> > +     lengths are required for the 512-bit vector length to be enabled,
> > +     then allow them to be auto-enabled::> +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve512=on
> 
> You should also document
> $ qemu-system-aarch64 -M virt -cpu max,sve512=off
> as in that case this result in 128, 256 and 384. the fact you get non ^2
> values is not obvious here because if you enable a ^2 value you onlt get
> <= ^2 values.

I can change (4) above to use 512 instead of 256.

> > +
> > +  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on> +
> > +  8) Force errors regarding the last vector length::
> You mean those commands will generate errors, right?

Yes

> > +
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve128=off
> > +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
> > +
> > +SVE CPU Property Recommendations
> > +--------------------------------
> >  
> > -The example above disables the PMU for the `max` CPU type.
> > +The examples in "SVE CPU Property Examples" exhibit many ways to select
> > +vector lengths which developers may find useful in order to avoid overly
> > +verbose command lines.  However, the recommended way to select vector
> > +lengths is to explicitly enable each desired length.  Therefore only
> > +example's (1), (3), and (5) exhibit recommended uses of the properties.
> >  
> > diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> > index 73be2ebfdd39..522fed95b339 100644
> > --- a/target/arm/cpu.c
> > +++ b/target/arm/cpu.c
> > @@ -1199,6 +1199,19 @@ static void arm_cpu_finalizefn(Object *obj)
> >  #endif
> >  }
> >  
> > +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
> > +{
> > +    Error *local_err = NULL;
> > +
> > +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> > +        arm_cpu_sve_finalize(cpu, &local_err);
> > +        if (local_err != NULL) {
> nit: !local_err
> > +            error_propagate(errp, local_err);
> > +            return;
> not needed

Yet. I expect a chain of finalizers to go here, so we'll want the 'return'
when we get the next one. As it doesn't hurt, it might as well go in now.

> > +        }
> > +    }
> > +}
> > +
> >  static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
> >  {
> >      CPUState *cs = CPU(dev);
> > @@ -1255,6 +1268,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
> >          return;
> >      }
> >  
> > +    arm_cpu_finalize_features(cpu, &local_err);
> > +    if (local_err != NULL) {
> same
> > +        error_propagate(errp, local_err);
> > +        return;> +    }
> > +
> >      if (arm_feature(env, ARM_FEATURE_AARCH64) &&
> >          cpu->has_vfp != cpu->has_neon) {
> >          /*
> > diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> > index 297ad5e47ad8..11162484465a 100644
> > --- a/target/arm/cpu.h
> > +++ b/target/arm/cpu.h
> > @@ -184,8 +184,13 @@ typedef struct {
> >  
> >  #ifdef TARGET_AARCH64
> >  # define ARM_MAX_VQ    16
> > +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
> > +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
> >  #else
> >  # define ARM_MAX_VQ    1
> > +static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
> > +static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> > +{ return 0; }
> >  #endif
> >  
> >  typedef struct ARMVectorReg {
> > @@ -915,6 +920,18 @@ struct ARMCPU {
> >  
> >      /* Used to set the maximum vector length the cpu will support.  */
> >      uint32_t sve_max_vq;
> > +
> > +    /*
> > +     * In sve_vq_map each set bit is a supported vector length of
> > +     * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
> > +     * length in quadwords.
> > +     *
> > +     * While processing properties during initialization, corresponding
> > +     * sve_vq_init bits are set for bits in sve_vq_map that have been
> > +     * set by properties.
> > +     */
> > +    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
> > +    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
> >  };
> >  
> >  void arm_cpu_post_init(Object *obj);
> > @@ -1834,6 +1851,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
> >      return (env->features & (1ULL << feature)) != 0;
> >  }
> >  
> > +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
> > +
> >  #if !defined(CONFIG_USER_ONLY)
> >  /* Return true if exception levels below EL3 are in secure state,
> >   * or would be following an exception return to that level.
> > diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> > index 8cdb0c79fa7a..606e3eceb9c0 100644
> > --- a/target/arm/cpu64.c
> > +++ b/target/arm/cpu64.c
> > @@ -256,11 +256,152 @@ static void aarch64_a72_initfn(Object *obj)
> >      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
> >  }
> >  
> > +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> > +{
> > +    /*
> > +     * If any vector lengths are explicitly enabled with sve<N> properties,
> > +     * then all other lengths are implicitly disabled.  If sve-max-vq is
> > +     * specified then it is the same as explicitly enabling all lengths
> > +     * up to and including the specified maximum, which means all larger
> > +     * lengths will be implicitly disabled.  If no sve<N> properties
> > +     * are enabled and sve-max-vq is not specified, then all lengths not
> > +     * explicitly disabled will be enabled.  Additionally, all power-of-two
> > +     * vector lengths less than the maximum enabled length will be
> > +     * automatically enabled and all vector lengths larger than the largest
> > +     * disabled power-of-two vector length will be automatically disabled.
> > +     * Errors are generated if the user provided input that interferes with
> > +     * any of the above.  Finally, if SVE is not disabled, then at least one
> > +     * vector length must be enabled.
> > +     */
> > +    DECLARE_BITMAP(tmp, ARM_MAX_VQ);
> > +    uint32_t vq, max_vq = 0;
> > +
> > +    /*
> > +     * Process explicit sve<N> properties.
> > +     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> > +     * Check first for any sve<N> enabled.
> > +     */
> > +    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
> > +        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
> > +
> > +        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
> > +            error_setg(errp, "cannot enable sve%d", max_vq * 128);
> > +            error_append_hint(errp, "sve%d is larger than the maximum vector "
> > +                              "length, sve-max-vq=%d (%d bits)\n",
> > +                              max_vq * 128, cpu->sve_max_vq,
> > +                              cpu->sve_max_vq * 128);
> you could test directly if max_vq < cpu->sve_max_vq too which couldn't

That's not an error. Here max_vq is the maximum enabled with sve<N>
properties. We haven't considered cpu->sve_max_vq yet, except for
ensuring we don't enable something larger than it.

> be correct either. But as far as I understand this is caught in *
> > +            return;
> > +        }
> > +
> > +        /* Propagate enabled bits down through required powers-of-two. */
> > +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > +            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> > +                set_bit(vq - 1, cpu->sve_vq_map);
> > +            }
> > +        }
> > +    } else if (cpu->sve_max_vq == 0) {
> > +        /*
> > +         * No explicit bits enabled, and no implicit bits from sve-max-vq.
> > +         */
> > +        if (!cpu_isar_feature(aa64_sve, cpu)) {
> > +            /* SVE is disabled and so are all vector lengths.  Good. */
> > +            return;
> > +        }
> > +
> > +        /* Disabling a power-of-two disables all larger lengths. */
> > +        if (test_bit(0, cpu->sve_vq_init)) {> +            error_setg(errp, "cannot disable sve128");
> > +            error_append_hint(errp, "Disabling sve128 results in all vector "
> > +                              "lengths being disabled.\n");
> > +            error_append_hint(errp, "With SVE enabled, at least one vector "
> > +                              "length must be enabled.\n");
> > +            return;
> > +        }
> > +        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> > +            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> > +                break;
> > +            }
> > +        }
> > +        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> > +
> > +        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> > +        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
> > +    }
> > +
> > +    /*
> > +     * Process the sve-max-vq property.
> > +     * Note that we know from the above that no bit above
> > +     * sve-max-vq is currently set.
> > +     */
> > +    if (cpu->sve_max_vq != 0) {
> > +        max_vq = cpu->sve_max_vq;
> > +
> > +        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
> > +            test_bit(max_vq - 1, cpu->sve_vq_init)) {
> > +            error_setg(errp, "cannot disable sve%d", max_vq * 128);
> > +            error_append_hint(errp, "The maximum vector length must be "
> > +                              "enabled, sve-max-vq=%d (%d bits)\n",
> > +                              max_vq, max_vq * 128);
> > +            return;
> > +        }
> > +
> > +        /* Set all bits not explicitly set within sve-max-vq. */
> > +        bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
> > +        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> > +    }
> > +
> > +    /*
> > +     * We should know what max-vq is now.  Also, as we're done
> > +     * manipulating sve-vq-map, we ensure any bits above max-vq
> > +     * are clear, just in case anybody looks.
> > +     */
> > +    assert(max_vq != 0);
> > +    bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
> > +
> > +    /* Ensure all required powers-of-two are enabled. */
> > +    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > +        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> > +            error_setg(errp, "cannot disable sve%d", vq * 128);
> > +            error_append_hint(errp, "sve%d is required as it "
> > +                              "is a power-of-two length smaller than "
> > +                              "the maximum, sve%d\n",
> > +                              vq * 128, max_vq * 128);
> * I think this will also catches the case where ,sve512=on,sve-max-vq=5
> where the end-user did not explicitly disabled anything

As stated above, 'sve512=on,sve-max-vq=5' isn't an error. It doesn't hurt
to enable vector lengths explicitly that would be enabled automatically
anyway with the sve-max-vq property.


> > +            return;
> > +        }
> > +    }
> > +
> > +    /* From now on sve_max_vq is the actual maximum supported length. */
> > +    cpu->sve_max_vq = max_vq;
> > +}
> > +
> > +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> > +{
> > +    uint32_t bitnum;
> > +
> > +    /*
> > +     * We allow vq == ARM_MAX_VQ + 1 to be input because the caller may want
> > +     * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
> > +     * function always returns the next smaller than the input.
> > +     */
> > +    assert(vq && vq <= ARM_MAX_VQ + 1);
> > +
> > +    bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
> > +    return bitnum == vq - 1 ? 0 : bitnum + 1;
> > +}
> > +
> >  static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
> >                                     void *opaque, Error **errp)
> >  {
> >      ARMCPU *cpu = ARM_CPU(obj);
> > -    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
> > +    uint32_t value;
> Shouldn't it be part of the previous patch?

Yes. Will fix for v5.

> > +
> > +    /* All vector lengths are disabled when SVE is off. */
> > +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> > +        value = 0;
> > +    } else {
> > +        value = cpu->sve_max_vq;
> > +    }
> > +    visit_type_uint32(v, name, &value, errp);
> >  }
> >  
> >  static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> > @@ -279,6 +420,44 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> Independently on this patch I noticed that if sve_max_vq is out of
> scope, an error is propagated but still the cpu->sve-max_vq is set.

I'll sneak that fix into patch 8/9 where we touch the function anyway.

> >      error_propagate(errp, err);
> >  }
> >  
> > +static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> > +                               void *opaque, Error **errp)
> > +{
> > +    ARMCPU *cpu = ARM_CPU(obj);
> > +    uint32_t vq = atoi(&name[3]) / 128;
> > +    bool value;
> > +
> > +    /* All vector lengths are disabled when SVE is off. */
> > +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> > +        value = false;
> > +    } else {
> > +        value = test_bit(vq - 1, cpu->sve_vq_map);
> > +    }
> > +    visit_type_bool(v, name, &value, errp);
> > +}
> > +
> > +static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
> > +                               void *opaque, Error **errp)
> > +{
> > +    ARMCPU *cpu = ARM_CPU(obj);
> > +    uint32_t vq = atoi(&name[3]) / 128;
> > +    Error *err = NULL;
> > +    bool value;
> > +
> > +    visit_type_bool(v, name, &value, &err);
> > +    if (err) {
> > +        error_propagate(errp, err);
> > +        return;
> > +    }
> > +
> > +    if (value) {
> > +        set_bit(vq - 1, cpu->sve_vq_map);
> > +    } else {
> > +        clear_bit(vq - 1, cpu->sve_vq_map);
> > +    }
> > +    set_bit(vq - 1, cpu->sve_vq_init);
> > +}
> > +
> >  static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
> >                              void *opaque, Error **errp)
> >  {
> > @@ -315,6 +494,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
> >  static void aarch64_max_initfn(Object *obj)
> >  {
> >      ARMCPU *cpu = ARM_CPU(obj);
> > +    uint32_t vq;
> >  
> >      if (kvm_enabled()) {
> >          kvm_arm_set_cpu_features_from_host(cpu);
> > @@ -418,11 +598,17 @@ static void aarch64_max_initfn(Object *obj)
> >          cpu->dcz_blocksize = 7; /*  512 bytes */
> >  #endif
> >  
> > -        cpu->sve_max_vq = ARM_MAX_VQ;
> >          object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> >                              cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> >          object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> >                              cpu_arm_set_sve, NULL, NULL, &error_fatal);
> > +
> > +        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > +            char name[8];
> > +            sprintf(name, "sve%d", vq * 128);
> > +            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> > +                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> > +        }
> >      }
> >  }
> >  
> > diff --git a/target/arm/helper.c b/target/arm/helper.c
> > index 507026c9154b..f33284c247d5 100644
> > --- a/target/arm/helper.c
> > +++ b/target/arm/helper.c
> > @@ -5351,6 +5351,13 @@ int sve_exception_el(CPUARMState *env, int el)
> >      return 0;
> >  }
> >  
> > +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
> > +{
> > +    uint32_t start_vq = (start_len & 0xf) + 1;
> > +
> > +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
> > +}
> > +
> >  /*
> >   * Given that SVE is enabled, return the vector length for EL.
> >   */
> > @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
> >      uint32_t zcr_len = cpu->sve_max_vq - 1;
> >  
> >      if (el <= 1) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
> >      }
> >      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
> >      }
> >      if (arm_feature(env, ARM_FEATURE_EL3)) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
> >      }
> >      return zcr_len;
> >  }
> > diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> > index 4fddb6c252a3..e912ed2cefa0 100644
> > --- a/target/arm/monitor.c
> > +++ b/target/arm/monitor.c
> > @@ -90,6 +90,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
> >      return head;
> >  }
> >  
> > +QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
> > +
> >  /*
> >   * These are cpu model features we want to advertise. The order here
> >   * matters as this is the order in which qmp_query_cpu_model_expansion
> > @@ -98,6 +100,9 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
> >   */
> >  static const char *cpu_model_advertised_features[] = {
> >      "aarch64", "pmu", "sve",
> > +    "sve128", "sve256", "sve384", "sve512",
> > +    "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
> > +    "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
> >      NULL
> >  };
> >  
> > @@ -185,6 +190,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> >          if (!err) {
> >              visit_check_struct(visitor, &err);
> >          }
> > +        if (!err) {
> > +            arm_cpu_finalize_features(ARM_CPU(obj), &err);
> > +        }
> >          visit_end_struct(visitor, NULL);
> >          visit_free(visitor);
> >          if (err) {
> > @@ -192,6 +200,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> >              error_propagate(errp, err);
> >              return NULL;
> >          }
> > +    } else {
> > +        Error *err = NULL;
> > +        arm_cpu_finalize_features(ARM_CPU(obj), &err);
> > +        assert(err == NULL);
> >      }
> >  
> >      expansion_info = g_new0(CpuModelExpansionInfo, 1);
> > diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> > index 202bc0e3e823..9a2dd402b769 100644
> > --- a/tests/arm-cpu-features.c
> > +++ b/tests/arm-cpu-features.c
> > @@ -13,6 +13,18 @@
> >  #include "qapi/qmp/qdict.h"
> >  #include "qapi/qmp/qjson.h"
> >  
> > +#if __SIZEOF_LONG__ == 8
> > +#define BIT(n) (1UL << (n))
> > +#else
> > +#define BIT(n) (1ULL << (n))
> > +#endif
> > +
> > +/*
> > + * We expect the SVE max-vq to be 16. Also it must be <= 64
> > + * for our test code, otherwise 'vls' can't just be a uint64_t.
> > + */
> > +#define SVE_MAX_VQ 16
> > +
> >  #define MACHINE    "-machine virt,gic-version=max "
> >  #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
> >                       "'arguments': { 'type': 'full', "
> > @@ -157,6 +169,173 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type)
> >      qobject_unref(resp);
> >  }
> >  
> > +static uint64_t resp_get_sve_vls(QDict *resp)
> > +{
> > +    QDict *props;
> > +    const QDictEntry *e;
> > +    uint64_t vls = 0;
> > +    int n = 0;
> > +
> > +    g_assert(resp);
> > +    g_assert(resp_has_props(resp));
> > +
> > +    props = resp_get_props(resp);
> > +
> > +    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
> > +        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
> > +            g_ascii_isdigit(e->key[3])) {
> > +            char *endptr;
> > +            int bits;
> > +
> > +            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
> > +            if (!bits || *endptr != '\0') {
> > +                continue;
> > +            }
> > +
> > +            if (qdict_get_bool(props, e->key)) {
> > +                vls |= BIT((bits / 128) - 1);
> > +            }
> > +            ++n;
> > +        }
> > +    }
> > +
> > +    g_assert(n == SVE_MAX_VQ);
> > +
> > +    return vls;
> > +}
> > +
> > +#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
> > +({                                                                     \
> > +    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
> > +    g_assert(_resp);                                                   \
> > +    g_assert(resp_has_props(_resp));                                   \
> > +    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
> > +    qobject_unref(_resp);                                              \
> > +})
> > +
> > +static void sve_tests_default(QTestState *qts, const char *cpu_type)
> > +{
> > +    /*
> > +     * With no sve-max-vq or sve<N> properties on the command line
> > +     * the default is to have all vector lengths enabled. This also
> > +     * tests that 'sve' is 'on' by default.
> > +     */
> > +    assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL);
> > +
> > +    /* With SVE off, all vector lengths should also be off. */
> > +    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
> > +
> > +    /* With SVE on, we must have at least one vector length enabled. */
> > +    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
> > +
> > +    /*
> > +     * ---------------------------------------------------------------------
> > +     *               power-of-two(vq)   all-power-            can      can
> > +     *                                  of-two(< vq)        enable   disable
> > +     * ---------------------------------------------------------------------
> > +     * vq < max_vq      no                MUST*              yes      yes
> > +     * vq < max_vq      yes               MUST*              yes      no
> > +     * ---------------------------------------------------------------------
> > +     * vq == max_vq     n/a               MUST*              yes**    yes**
> > +     * ---------------------------------------------------------------------
> > +     * vq > max_vq      n/a               no                 no       yes
> > +     * vq > max_vq      n/a               yes                yes      yes
> > +     * ---------------------------------------------------------------------
> > +     *
> > +     * [*] "MUST" means this requirement must already be satisfied,
> > +     *     otherwise 'max_vq' couldn't itself be enabled.
> > +     *
> > +     * [**] Not testable with the QMP interface, only with the command line.
> > +     */
> > +
> > +    /* max_vq := 8 */
> > +    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
> > +
> > +    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
> > +    assert_sve_vls(qts, cpu_type, 0x8f,
> > +                   "{ 'sve1024': true, 'sve384': true }");
> > +    assert_sve_vls(qts, cpu_type, 0x8b,
> > +                   "{ 'sve1024': true, 'sve384': false }");
> > +
> > +    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
> > +    assert_sve_vls(qts, cpu_type, 0x8b,
> > +                   "{ 'sve1024': true, 'sve256': true }");
> > +    assert_error(qts, cpu_type, "cannot disable sve256",
> > +                 "{ 'sve1024': true, 'sve256': false }");
> > +
> > +    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
> > +    assert_error(qts, cpu_type, "cannot disable sve512",
> > +                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
> > +
> > +    /*
> > +     * We can disable power-of-two vector lengths when all larger lengths
> > +     * are also disabled. We only need to disable the power-of-two length,
> > +     * as all non-enabled larger lengths will then be auto-disabled.
> > +     */
> > +    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
> > +
> > +    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
> > +    assert_sve_vls(qts, cpu_type, 0x1f,
> > +                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
> > +    assert_sve_vls(qts, cpu_type, 0xf,
> > +                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
> > +}
> > +
> > +static void sve_tests_sve_max_vq_8(const void *data)
> > +{
> > +    QTestState *qts;
> > +
> > +    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
> > +
> > +    assert_sve_vls(qts, "max", BIT(8) - 1, NULL);
> > +
> > +    /*
> > +     * Disabling the max-vq set by sve-max-vq is not allowed, but
> > +     * of course enabling it is OK.
> > +     */
> > +    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
> > +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
> > +
> > +    /*
> > +     * Enabling anything larger than max-vq set by sve-max-vq is not
> > +     * allowed, but of course disabling everything larger is OK.
> > +     */
> > +    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
> > +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
> > +
> > +    /*
> > +     * We can disable non power-of-two lengths smaller than the max-vq
> > +     * set by sve-max-vq, but not power-of-two lengths.
> > +     */
> > +    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
> you can also test ,sve384=on => 0x7

We wouldn't get 0x7, we'd get 0xff. I could still add the test to ensure
we can enable smaller vector lengths without an error though.

> > +    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
> > +
> > +    qtest_quit(qts);
> > +}
> > +
> > +static void sve_tests_sve_off(const void *data)
> > +{
> > +    QTestState *qts;
> > +
> > +    qts = qtest_init(MACHINE "-cpu max,sve=off");
> > +
> > +    /* SVE is off, so the map should be empty. */
> > +    assert_sve_vls(qts, "max", 0, NULL);
> > +
> > +    /* The map stays empty even if we turn lengths on or off. */
> > +    assert_sve_vls(qts, "max", 0, "{ 'sve128': true }");
> > +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> > +
> > +    /* With SVE re-enabled we should get all vector lengths enabled. */
> > +    assert_sve_vls(qts, "max", BIT(SVE_MAX_VQ) - 1, "{ 'sve': true }");
> > +
> > +    /* Or enable SVE with just specific vector lengths. */
> > +    assert_sve_vls(qts, "max", 0x3,
> > +                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
> > +
> > +    qtest_quit(qts);
> > +}
> > +
> >  static void test_query_cpu_model_expansion(const void *data)
> >  {
> >      QTestState *qts;
> > @@ -180,9 +359,12 @@ static void test_query_cpu_model_expansion(const void *data)
> >      if (g_str_equal(qtest_get_arch(), "aarch64")) {
> >          assert_has_feature(qts, "max", "aarch64");
> >          assert_has_feature(qts, "max", "sve");
> > +        assert_has_feature(qts, "max", "sve128");
> >          assert_has_feature(qts, "cortex-a57", "pmu");
> >          assert_has_feature(qts, "cortex-a57", "aarch64");
> >  
> > +        sve_tests_default(qts, "max");
> > +
> >          /* Test that features that depend on KVM generate errors without. */
> >          assert_error(qts, "max",
> >                       "'aarch64' feature cannot be disabled "
> > @@ -234,6 +416,13 @@ int main(int argc, char **argv)
> >      qtest_add_data_func("/arm/query-cpu-model-expansion",
> >                          NULL, test_query_cpu_model_expansion);
> >  
> > +    if (g_str_equal(qtest_get_arch(), "aarch64")) {
> > +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
> > +                            NULL, sve_tests_sve_max_vq_8);
> > +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
> > +                            NULL, sve_tests_sve_off);
> > +    }
> > +
> >      if (kvm_available) {
> >          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
> >                              NULL, test_query_cpu_model_expansion_kvm);
> > 
> Thanks
> 
> Eric
>

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-26  6:52   ` Auger Eric
@ 2019-09-26  8:41     ` Andrew Jones
  2019-09-26 10:01       ` Auger Eric
  0 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-26  8:41 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Sep 26, 2019 at 08:52:55AM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 9/24/19 1:31 PM, Andrew Jones wrote:
> > Extend the SVE vq map initialization and validation with KVM's
> > supported vector lengths when KVM is enabled. In order to determine
> > and select supported lengths we add two new KVM functions for getting
> > and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.
> > 
> > This patch has been co-authored with Richard Henderson, who reworked
> > the target/arm/cpu64.c changes in order to push all the validation and
> > auto-enabling/disabling steps into the finalizer, resulting in a nice
> > LOC reduction.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  docs/arm-cpu-features.rst |  36 +++++---
> >  target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
> >  target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
> >  target/arm/kvm_arm.h      |  12 +++
> >  tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
> >  5 files changed, 368 insertions(+), 52 deletions(-)
> > 
> > diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> > index 1262fddc6201..939366f959cf 100644
> > --- a/docs/arm-cpu-features.rst
> > +++ b/docs/arm-cpu-features.rst
> > @@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
> >  
> >    1) At least one vector length must be enabled when `sve` is enabled.
> >  
> > -  2) If a vector length `N` is enabled, then all power-of-two vector
> > -     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> > -     is enabled, then `sve128` and `sve256` must also be enabled,
> > -     but `sve384` is not required.
> > +  2) If a vector length `N` is enabled, then, when KVM is enabled, all
> > +     smaller, host supported vector lengths must also be enabled.  If
> > +     KVM is not enabled, then only all the smaller, power-of-two vector
> > +     lengths must be enabled.  E.g. with KVM if the host supports all
> > +     vector lengths up to 512-bits (128, 256, 384, 512), then if
> > +     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
> > +     be enabled. Without KVM, `sve384` would not be required.
> > +
> > +  3) If KVM is enabled then only vector lengths that the host CPU type
> > +     support may be enabled.  If SVE is not supported by the host, then
> > +     no `sve*` properties may be enabled.
> >  
> >  SVE CPU Property Parsing Semantics
> >  ----------------------------------
> > @@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
> >       disable the last enabled vector length (see constraint (1) of "SVE
> >       CPU Property Dependencies and Constraints").
> >  
> > -  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> > +  4) When KVM is enabled, if the host does not support SVE, then an error
> > +     is generated when attempting to enable any `sve*` properties.
> > +
> > +  5) When KVM is enabled, if the host does support SVE, then an error is
> > +     generated when attempting to enable any vector lengths not supported
> > +     by the host.
> > +
> > +  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> >       CPU properties are set `on`, then the specified vector lengths are
> >       disabled but the default for any unspecified lengths remains enabled.
> > -     Disabling a power-of-two vector length also disables all vector
> > -     lengths larger than the power-of-two length (see constraint (2) of
> > -     "SVE CPU Property Dependencies and Constraints").
> > +     When KVM is not enabled, disabling a power-of-two vector length also
> > +     disables all vector lengths larger than the power-of-two length.
> > +     When KVM is enabled, then disabling any supported vector length also
> > +     disables all larger vector lengths (see constraint (2) of "SVE CPU
> > +     Property Dependencies and Constraints").
> >  
> > -  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> > +  7) If one or more `sve<N>` CPU properties are set to `on`, then they
> >       are enabled and all unspecified lengths default to disabled, except
> >       for the required lengths per constraint (2) of "SVE CPU Property
> >       Dependencies and Constraints", which will even be auto-enabled if
> >       they were not explicitly enabled.
> >  
> > -  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> > +  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> >       explicitly disabled (i.e. avoiding the error specified in (3) of
> >       "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
> >       provided an error will be generated.  To avoid this error, one must
> > diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> > index b7eff4e1e107..18dd5e24ec61 100644
> > --- a/target/arm/cpu64.c
> > +++ b/target/arm/cpu64.c
> > @@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >       * any of the above.  Finally, if SVE is not disabled, then at least one
> >       * vector length must be enabled.
> >       */
> > +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
> >      DECLARE_BITMAP(tmp, ARM_MAX_VQ);
> >      uint32_t vq, max_vq = 0;
> >  
> > +    /* Collect the set of vector lengths supported by KVM. */
> > +    bitmap_zero(kvm_supported, ARM_MAX_VQ);
> > +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
> > +        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
> > +    } else if (kvm_enabled()) {
> > +        assert(!cpu_isar_feature(aa64_sve, cpu));
> why not set an error and propagate it instead?

This should never happen. We shouldn't be here if KVM is enabled and SVE
isn't supported. The question is how defensive do we want QEMU code?
We could just drop the check altogether if we don't want the assert, but
I'd rather keep it.

> > +    }
> > +
> >      /*
> >       * Process explicit sve<N> properties.
> >       * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> > @@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >              return;
> >          }
> >  
> > -        /* Propagate enabled bits down through required powers-of-two. */
> > -        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > -            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> > -                set_bit(vq - 1, cpu->sve_vq_map);
> > +        if (kvm_enabled()) {
> > +            /*
> > +             * For KVM we have to automatically enable all supported unitialized
> > +             * lengths, even when the smaller lengths are not all powers-of-two.
> > +             */
> > +            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
> > +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> > +        } else {
> > +            /* Propagate enabled bits down through required powers-of-two. */
> > +            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > +                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> > +                    set_bit(vq - 1, cpu->sve_vq_map);
> > +                }
> >              }
> >          }
> >      } else if (cpu->sve_max_vq == 0) {
> > @@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >              return;
> >          }
> >  
> > -        /* Disabling a power-of-two disables all larger lengths. */
> > -        if (test_bit(0, cpu->sve_vq_init)) {
> > -            error_setg(errp, "cannot disable sve128");
> > -            error_append_hint(errp, "Disabling sve128 results in all vector "
> > -                              "lengths being disabled.\n");
> > -            error_append_hint(errp, "With SVE enabled, at least one vector "
> > -                              "length must be enabled.\n");
> > -            return;
> > -        }
> > -        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> > -            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> > -                break;
> > +        if (kvm_enabled()) {
> > +            /* Disabling a supported length disables all larger lengths. */
> > +            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > +                if (test_bit(vq - 1, cpu->sve_vq_init) &&
> > +                    test_bit(vq - 1, kvm_supported)) {
> > +                    break;
> > +                }
> > +            }
> > +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> > +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
> > +                          cpu->sve_vq_init, max_vq);
> > +            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
> > +                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
> > +                error_setg(errp, "cannot disable sve%d", vq * 128);
> isn't the one disabled max_vq? Do you really need to re-compute vq?

We're not looking for max_vq with find_next_bit(), we're looking for
"min_vq". Here we're checking that we always have at least one vector
length enabled. You can't disable the minimum, because that's the last
one.

> > +                error_append_hint(errp, "Disabling sve%d results in all "
> > +                                  "vector lengths being disabled.\n",
> > +                                  vq * 128);
> > +                error_append_hint(errp, "With SVE enabled, at least one "
> > +                                  "vector length must be enabled.\n");
> > +                return;> +            }
> > +        } else {
> > +            /* Disabling a power-of-two disables all larger lengths. */
> > +            if (test_bit(0, cpu->sve_vq_init)) {
> > +                error_setg(errp, "cannot disable sve128");
> > +                error_append_hint(errp, "Disabling sve128 results in all "
> > +                                  "vector lengths being disabled.\n");
> > +                error_append_hint(errp, "With SVE enabled, at least one "
> > +                                  "vector length must be enabled.\n");
> > +                return;
> > +            }
> > +            for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> > +                if (test_bit(vq - 1, cpu->sve_vq_init)) {
> > +                    break;
> > +                }
> >              }
> > +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> > +            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> >          }
> > -        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> >  
> > -        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> >          max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
> >      }
> >  
> > @@ -358,16 +399,48 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >      assert(max_vq != 0);
> >      bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
> >  
> > -    /* Ensure all required powers-of-two are enabled. */
> > -    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > -        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> > -            error_setg(errp, "cannot disable sve%d", vq * 128);
> > -            error_append_hint(errp, "sve%d is required as it "
> > -                              "is a power-of-two length smaller than "
> > -                              "the maximum, sve%d\n",
> > -                              vq * 128, max_vq * 128);
> > +    if (kvm_enabled()) {
> > +        /* Ensure the set of lengths matches what KVM supports. */
> > +        bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
> > +        if (!bitmap_empty(tmp, max_vq)) {
> > +            vq = find_last_bit(tmp, max_vq) + 1;
> > +            if (test_bit(vq - 1, cpu->sve_vq_map)) {
> > +                if (cpu->sve_max_vq) {
> > +                    error_setg(errp, "cannot set sve-max-vq=%d",
> > +                               cpu->sve_max_vq);
> > +                    error_append_hint(errp, "This KVM host does not support "
> > +                                      "the vector length %d-bits.\n",
> > +                                      vq * 128);
> > +                    error_append_hint(errp, "It may not be possible to use "
> > +                                      "sve-max-vq with this KVM host. Try "
> > +                                      "using only sve<N> properties.\n");
> > +                } else {
> > +                    error_setg(errp, "cannot enable sve%d", vq * 128);
> > +                    error_append_hint(errp, "This KVM host does not support "
> > +                                      "the vector length %d-bits.\n",
> > +                                      vq * 128);
> > +                }
> > +            } else {
> > +                error_setg(errp, "cannot disable sve%d", vq * 128);
> I am not sure about the above message. what is the vq value supposed to
> be? For instance if we previously entered the
> "if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {" path

'vq' here should be enabled because it's a dependency for the max-vq.
If the user had enabled it or left it uninitialized (allowing it to
be auto-enabled) then we wouldn't be here. To get here the user must
have explicitly disabled it. Hence the 'cannot disable' message.

> > +                error_append_hint(errp, "The KVM host requires all "
> > +                                  "supported vector lengths smaller "
> > +                                  "than %d bits to also be enabled.\n",
> > +                                  max_vq * 128);
> > +            }
> >              return;
> >          }
> > +    } else {
> > +        /* Ensure all required powers-of-two are enabled. */
> > +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> > +            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> > +                error_setg(errp, "cannot disable sve%d", vq * 128);
> > +                error_append_hint(errp, "sve%d is required as it "
> > +                                  "is a power-of-two length smaller than "
> > +                                  "the maximum, sve%d\n",
> > +                                  vq * 128, max_vq * 128);
> > +                return;
> > +            }
> > +        }
> >      }
> >  
> >      /* From now on sve_max_vq is the actual maximum supported length. */
> > @@ -411,13 +484,22 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> >      Error *err = NULL;
> >  
> >      visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
> > +    if (err) {
> > +        error_propagate(errp, err);
> > +        return;
> > +    }
> >  
> > -    if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) {
> > -        error_setg(&err, "unsupported SVE vector length");
> > -        error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n",
> > +    if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
> > +        error_setg(errp, "cannot set sve-max-vq");
> > +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
> > +        return;
> > +    }
> > +
> > +    if (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ) {
> > +        error_setg(errp, "unsupported SVE vector length");
> > +        error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n",
> >                            ARM_MAX_VQ);
> >      }
> > -    error_propagate(errp, err);
> >  }
> >  
> >  static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> > @@ -450,6 +532,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
> >          return;
> >      }
> >  
> > +    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
> > +        error_setg(errp, "cannot enable %s", name);
> > +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
> > +        return;
> > +    }
> > +
> >      if (value) {
> >          set_bit(vq - 1, cpu->sve_vq_map);
> >      } else {
> > @@ -607,20 +695,19 @@ static void aarch64_max_initfn(Object *obj)
> >          cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
> >          cpu->dcz_blocksize = 7; /*  512 bytes */
> >  #endif
> > -
> > -        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> > -                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> > -
> > -        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > -            char name[8];
> > -            sprintf(name, "sve%d", vq * 128);
> > -            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> > -                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> > -        }
> >      }
> >  
> >      object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> >                          cpu_arm_set_sve, NULL, NULL, &error_fatal);
> > +    object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> > +                        cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> > +
> > +    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > +        char name[8];
> > +        sprintf(name, "sve%d", vq * 128);
> > +        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> > +                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> > +    }
> >  }
> >  
> >  struct ARMCPUInfo {
> > diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> > index f96649ae0349..cff4217a8469 100644
> > --- a/target/arm/kvm64.c
> > +++ b/target/arm/kvm64.c
> > @@ -613,6 +613,100 @@ bool kvm_arm_sve_supported(CPUState *cpu)
> >      return kvm_check_extension(s, KVM_CAP_ARM_SVE);
> >  }
> >  
> > +QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
> > +
> > +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
> > +{
> > +    /* Only call this function if kvm_arm_sve_supported() returns true. */
> > +    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
> > +    static bool probed;
> > +    uint32_t vq = 0;
> > +    int i, j;
> > +
> > +    bitmap_clear(map, 0, ARM_MAX_VQ);
> > +
> > +    /*
> > +     * KVM ensures all host CPUs support the same set of vector lengths.
> > +     * So we only need to create the scratch VCPUs once and then cache
> > +     * the results.
> > +     */
> > +    if (!probed) {
> > +        struct kvm_vcpu_init init = {
> > +            .target = -1,
> > +            .features[0] = (1 << KVM_ARM_VCPU_SVE),
> > +        };
> > +        struct kvm_one_reg reg = {
> > +            .id = KVM_REG_ARM64_SVE_VLS,
> > +            .addr = (uint64_t)&vls[0],
> > +        };
> > +        int fdarray[3], ret;
> > +
> > +        probed = true;
> > +
> > +        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
> > +            error_report("failed to create scratch VCPU with SVE enabled");
> > +            abort();
> > +        }
> > +        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
> > +        kvm_arm_destroy_scratch_host_vcpu(fdarray);
> > +        if (ret) {
> > +            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
> > +                         strerror(errno));
> > +            abort();
> > +        }
> > +
> > +        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
> > +            if (vls[i]) {
> > +                vq = 64 - clz64(vls[i]) + i * 64;
> > +                break;
> > +            }
> > +        }
> > +        if (vq > ARM_MAX_VQ) {
> > +            warn_report("KVM supports vector lengths larger than "
> > +                        "QEMU can enable");
> > +        }
> > +    }
> > +
> > +    for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) {
> > +        if (!vls[i]) {
> > +            continue;
> > +        }
> > +        for (j = 1; j <= 64; ++j) {
> > +            vq = j + i * 64;
> > +            if (vq > ARM_MAX_VQ) {
> > +                return;
> > +            }
> > +            if (vls[i] & (1UL << (j - 1))) {
> > +                set_bit(vq - 1, map);
> > +            }
> > +        }
> > +    }
> > +}
> > +
> > +static int kvm_arm_sve_set_vls(CPUState *cs)
> > +{
> > +    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0};
> > +    struct kvm_one_reg reg = {
> > +        .id = KVM_REG_ARM64_SVE_VLS,
> > +        .addr = (uint64_t)&vls[0],
> > +    };
> > +    ARMCPU *cpu = ARM_CPU(cs);
> > +    uint32_t vq;
> > +    int i, j;
> > +
> > +    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
> > +
> > +    for (vq = 1; vq <= cpu->sve_max_vq; ++vq) {
> > +        if (test_bit(vq - 1, cpu->sve_vq_map)) {
> > +            i = (vq - 1) / 64;
> > +            j = (vq - 1) % 64;
> > +            vls[i] |= 1UL << j;
> > +        }
> > +    }
> > +
> > +    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> > +}
> > +
> >  #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
> >  
> >  int kvm_arch_init_vcpu(CPUState *cs)
> > @@ -624,7 +718,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
> >  
> >      if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
> >          !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
> > -        fprintf(stderr, "KVM is not supported for this guest CPU type\n");
> > +        error_report("KVM is not supported for this guest CPU type");
> >          return -EINVAL;
> >      }
> >  
> > @@ -660,6 +754,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
> >      }
> >  
> >      if (cpu_isar_feature(aa64_sve, cpu)) {
> > +        ret = kvm_arm_sve_set_vls(cs);
> > +        if (ret) {
> > +            return ret;
> > +        }
> >          ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
> >          if (ret) {
> >              return ret;
> > diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> > index 1151877f97ea..a1cc6513f72b 100644
> > --- a/target/arm/kvm_arm.h
> > +++ b/target/arm/kvm_arm.h
> > @@ -212,6 +212,17 @@ typedef struct ARMHostCPUFeatures {
> >   */
> >  bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
> >  
> > +/**
> > + * kvm_arm_sve_get_vls:
> > + * @cs: CPUState
> > + * @map: bitmap to fill in
> > + *
> > + * Get all the SVE vector lengths supported by the KVM host, setting
> > + * the bits corresponding to their length in quadwords minus one
> > + * (vq - 1) in @map up to ARM_MAX_VQ.
> > + */
> > +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
> > +
> >  /**
> >   * kvm_arm_set_cpu_features_from_host:
> >   * @cpu: ARMCPU to set the features for
> > @@ -315,6 +326,7 @@ static inline int kvm_arm_vgic_probe(void)
> >  static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
> >  static inline void kvm_arm_pmu_init(CPUState *cs) {}
> >  
> > +static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) {}
> >  #endif
> >  
> >  static inline const char *gic_class_name(void)
> > diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> > index d50f98cb6aea..a0129aebf409 100644
> > --- a/tests/arm-cpu-features.c
> > +++ b/tests/arm-cpu-features.c
> > @@ -117,6 +117,17 @@ static QDict *resp_get_props(QDict *resp)
> >      return qdict;
> >  }
> >  
> > +static bool resp_get_feature(QDict *resp, const char *feature)
> > +{
> > +    QDict *props;
> > +
> > +    g_assert(resp);
> > +    g_assert(resp_has_props(resp));
> > +    props = resp_get_props(resp);
> > +    g_assert(qdict_get(props, feature));
> > +    return qdict_get_bool(props, feature);
> > +}
> > +
> >  #define assert_has_feature(qts, cpu_type, feature)                     \
> >  ({                                                                     \
> >      QDict *_resp = do_query_no_props(qts, cpu_type);                   \
> > @@ -336,6 +347,25 @@ static void sve_tests_sve_off(const void *data)
> >      qtest_quit(qts);
> >  }
> >  
> > +static void sve_tests_sve_off_kvm(const void *data)
> > +{
> > +    QTestState *qts;
> > +
> > +    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
> > +
> > +    /*
> > +     * We don't know if this host supports SVE so we don't
> > +     * attempt to test enabling anything. We only test that
> > +     * everything is disabled (as it should be with sve=off)
> > +     * and that using sve<N>=off to explicitly disable vector
> > +     * lengths is OK too.
> > +     */
> > +    assert_sve_vls(qts, "max", 0, NULL);
> > +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> > +
> > +    qtest_quit(qts);
> > +}
> > +
> >  static void test_query_cpu_model_expansion(const void *data)
> >  {
> >      QTestState *qts;
> > @@ -385,12 +415,81 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >      assert_has_feature(qts, "host", "pmu");
> >  
> >      if (g_str_equal(qtest_get_arch(), "aarch64")) {
> > +        bool kvm_supports_sve;
> > +        char max_name[8], name[8];
> > +        uint32_t max_vq, vq;
> > +        uint64_t vls;
> > +        QDict *resp;
> > +        char *error;
> > +
> >          assert_has_feature(qts, "host", "aarch64");
> > -        assert_has_feature(qts, "max", "sve");
> >  
> >          assert_error(qts, "cortex-a15",
> >              "We cannot guarantee the CPU type 'cortex-a15' works "
> >              "with KVM on this host", NULL);
> > +
> > +        assert_has_feature(qts, "max", "sve");
> > +        resp = do_query_no_props(qts, "max");
> > +        kvm_supports_sve = resp_get_feature(resp, "sve");
> > +        vls = resp_get_sve_vls(resp);
> > +        qobject_unref(resp);
> > +
> > +        if (kvm_supports_sve) {
> > +            g_assert(vls != 0);
> > +            max_vq = 64 - __builtin_clzll(vls);
> > +            sprintf(max_name, "sve%d", max_vq * 128);
> > +
> > +            /* Enabling a supported length is of course fine. */
> > +            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
> > +
> > +            /* Get the next supported length smaller than max-vq. */
> > +            vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
> > +            if (vq) {
> > +                /*
> > +                 * We have at least one length smaller than max-vq,
> > +                 * so we can disable max-vq.
> > +                 */
> > +                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
> > +                               "{ %s: false }", max_name);
> > +
> > +                /*
> > +                 * Smaller, supported vector lengths cannot be disabled
> > +                 * unless all larger, supported vector lengths are also
> > +                 * disabled.
> > +                 */
> > +                sprintf(name, "sve%d", vq * 128);
> > +                error = g_strdup_printf("cannot disable %s", name);
> > +                assert_error(qts, "max", error,
> > +                             "{ %s: true, %s: false }",
> > +                             max_name, name);
> > +                g_free(error);
> > +            }
> > +
> > +            /*
> > +             * The smallest, supported vector length is required, because
> > +             * we need at least one vector length enabled.
> > +             */
> > +            vq = __builtin_ffsll(vls);
> > +            sprintf(name, "sve%d", vq * 128);
> > +            error = g_strdup_printf("cannot disable %s", name);
> > +            assert_error(qts, "max", error, "{ %s: false }", name);
> > +            g_free(error);
> > +
> > +            /* Get an unsupported length. */
> > +            for (vq = 1; vq <= max_vq; ++vq) {
> > +                if (!(vls & BIT(vq - 1))) {
> > +                    break;
> > +                }
> > +            }
> > +            if (vq <= SVE_MAX_VQ) {
> > +                sprintf(name, "sve%d", vq * 128);
> > +                error = g_strdup_printf("cannot enable %s", name);
> > +                assert_error(qts, "max", error, "{ %s: true }", name);
> > +                g_free(error);
> > +            }
> > +        } else {
> > +            g_assert(vls == 0);
> > +        }
> >      } else {
> >          assert_error(qts, "host",
> >                       "'pmu' feature not supported by KVM on this host",
> > @@ -427,6 +526,10 @@ int main(int argc, char **argv)
> >      if (kvm_available) {
> >          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
> >                              NULL, test_query_cpu_model_expansion_kvm);
> > +        if (g_str_equal(qtest_get_arch(), "aarch64")) {
> > +            qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
> > +                                NULL, sve_tests_sve_off_kvm);
> > +        }
> >      }
> >  
> >      return g_test_run();
> > 
> Besides,
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> 
>

Thanks!

drew 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties
  2019-09-26  7:07   ` Auger Eric
@ 2019-09-26  8:53     ` Andrew Jones
  0 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-26  8:53 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Sep 26, 2019 at 09:07:36AM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 9/24/19 1:31 PM, Andrew Jones wrote:
> > Allow cpu 'host' to enable SVE when it's available, unless the
> > user chooses to disable it with the added 'sve=off' cpu property.
> > Also give the user the ability to select vector lengths with the
> > sve<N> properties. We don't adopt 'max' cpu's other sve property,
> > sve-max-vq, because that property is difficult to use with KVM.
> > That property assumes all vector lengths in the range from 1 up
> > to and including the specified maximum length are supported, but
> > there may be optional lengths not supported by the host in that
> > range. With KVM one must be more specific when enabling vector
> > lengths.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  docs/arm-cpu-features.rst | 19 ++++++++++++-------
> >  target/arm/cpu.c          |  3 +++
> >  target/arm/cpu.h          |  2 ++
> >  target/arm/cpu64.c        | 33 +++++++++++++++++----------------
> >  target/arm/kvm64.c        | 14 +++++++++++++-
> >  tests/arm-cpu-features.c  | 21 +++++++++++----------
> >  6 files changed, 58 insertions(+), 34 deletions(-)
> > 
> > diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> > index 939366f959cf..0c16eef7c8c2 100644
> > --- a/docs/arm-cpu-features.rst
> > +++ b/docs/arm-cpu-features.rst
> > @@ -256,31 +256,36 @@ SVE CPU Property Examples
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max
> >  
> > -  3) Only enable the 128-bit vector length::
> > +  3) When KVM is enabled, implicitly enable all host CPU supported vector
> > +     lengths with the `host` CPU type::
> > +
> > +     $ qemu-system-aarch64 -M virt,accel=kvm -cpu host
> > +
> > +  4) Only enable the 128-bit vector length::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve128=on
> >  
> > -  4) Disable the 256-bit vector length and all larger vector lengths
> > +  5) Disable the 256-bit vector length and all larger vector lengths
> >       since 256 is a power-of-two (this results in only the 128-bit length
> >       being enabled)::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve256=off
> >  
> > -  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> > +  6) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
> >  
> > -  6) The same as (5), but since the 128-bit and 256-bit vector
> > +  7) The same as (6), but since the 128-bit and 256-bit vector
> >       lengths are required for the 512-bit vector length to be enabled,
> >       then allow them to be auto-enabled::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve512=on
> >  
> > -  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
> > +  8) Do the same as (7), but by first disabling SVE and then re-enabling it::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on
> >  
> > -  8) Force errors regarding the last vector length::
> > +  9) Force errors regarding the last vector length::
> >  
> >       $ qemu-system-aarch64 -M virt -cpu max,sve128=off
> >       $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
> > @@ -292,5 +297,5 @@ The examples in "SVE CPU Property Examples" exhibit many ways to select
> >  vector lengths which developers may find useful in order to avoid overly
> >  verbose command lines.  However, the recommended way to select vector
> >  lengths is to explicitly enable each desired length.  Therefore only
> > -example's (1), (3), and (5) exhibit recommended uses of the properties.
> > +example's (1), (4), and (6) exhibit recommended uses of the properties.
> >  
> > diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> > index 522fed95b339..7695ae551218 100644
> > --- a/target/arm/cpu.c
> > +++ b/target/arm/cpu.c
> > @@ -2671,6 +2671,9 @@ static void arm_host_initfn(Object *obj)
> >      ARMCPU *cpu = ARM_CPU(obj);
> >  
> >      kvm_arm_set_cpu_features_from_host(cpu);
> > +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> > +        aarch64_add_sve_properties(obj);
> > +    }
> >      arm_cpu_post_init(obj);
> >  }
> >  
> > diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> > index 11162484465a..5b9c3e4cd73d 100644
> > --- a/target/arm/cpu.h
> > +++ b/target/arm/cpu.h
> > @@ -974,11 +974,13 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> >  void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
> >  void aarch64_sve_change_el(CPUARMState *env, int old_el,
> >                             int new_el, bool el0_a64);
> > +void aarch64_add_sve_properties(Object *obj);
> >  #else
> >  static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { }
> >  static inline void aarch64_sve_change_el(CPUARMState *env, int o,
> >                                           int n, bool a)
> >  { }
> > +static inline void aarch64_add_sve_properties(Object *obj) { }
> >  #endif
> >  
> >  #if !defined(CONFIG_TCG)
> > diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> > index 18dd5e24ec61..e7cd420faa9d 100644
> > --- a/target/arm/cpu64.c
> > +++ b/target/arm/cpu64.c
> > @@ -579,6 +579,21 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
> >      cpu->isar.id_aa64pfr0 = t;
> >  }
> >  
> > +void aarch64_add_sve_properties(Object *obj)
> > +{
> > +    uint32_t vq;
> > +
> > +    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> > +                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
> > +
> > +    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > +        char name[8];
> line needed

checkpatch doesn't complain and I prefer this simple block to be more dense.

> > +        sprintf(name, "sve%d", vq * 128);
> > +        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> > +                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> > +    }
> > +}
> > +
> >  /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
> >   * otherwise, a CPU with as many features enabled as our emulation supports.
> >   * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
> > @@ -587,17 +602,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
> >  static void aarch64_max_initfn(Object *obj)
> >  {
> >      ARMCPU *cpu = ARM_CPU(obj);
> > -    uint32_t vq;
> > -    uint64_t t;
> >  
> >      if (kvm_enabled()) {
> >          kvm_arm_set_cpu_features_from_host(cpu);
> > -        if (kvm_arm_sve_supported(CPU(cpu))) {
> > -            t = cpu->isar.id_aa64pfr0;
> > -            t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
> > -            cpu->isar.id_aa64pfr0 = t;
> > -        }
> >      } else {
> > +        uint64_t t;
> >          uint32_t u;
> >          aarch64_a57_initfn(obj);
> >  
> > @@ -697,17 +706,9 @@ static void aarch64_max_initfn(Object *obj)
> >  #endif
> >      }
> >  
> > -    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> > -                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
> > +    aarch64_add_sve_properties(obj);
> >      object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> >                          cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> > -
> > -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> > -        char name[8];
> > -        sprintf(name, "sve%d", vq * 128);
> > -        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> > -                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> > -    }
> >  }
> >  
> >  struct ARMCPUInfo {
> > diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> > index cff4217a8469..2da366ba113e 100644
> > --- a/target/arm/kvm64.c
> > +++ b/target/arm/kvm64.c
> > @@ -488,7 +488,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> >       * and then query that CPU for the relevant ID registers.
> >       */
> >      int fdarray[3];
> > +    bool sve_supported;
> >      uint64_t features = 0;
> > +    uint64_t t;
> t can stay local to the block below

I made its scope function-wide because it's unlikely this will be the
only feature we enable this way. We could start it with a smaller scope
and move it when necessary, but as it doesn't hurt to make it function-
wide now, I did it now.

> >      int err;
> >  
> >      /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
> > @@ -578,13 +580,23 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> >                                ARM64_SYS_REG(3, 0, 0, 3, 2));
> >      }
> >  
> > +    sve_supported = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0;
> !ioctl?

!ioctl should be safe with KVM_CHECK_EXTENSION (according to the API
documentation), but nowhere in QEMU do we assume that. We always check
for the possibility of a negative (error) return value.

> > +
> >      kvm_arm_destroy_scratch_host_vcpu(fdarray);
> >  
> >      if (err < 0) {
> >          return false;
> >      }
> >  
> > -   /* We can assume any KVM supporting CPU is at least a v8
> > +    /* Add feature bits that can't appear until after VCPU init. */
> > +    if (sve_supported) {
> > +        t = ahcf->isar.id_aa64pfr0;
> > +        t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
> > +        ahcf->isar.id_aa64pfr0 = t;
> > +    }
> > +
> > +    /*
> > +     * We can assume any KVM supporting CPU is at least a v8
> >       * with VFPv4+Neon; this in turn implies most of the other
> >       * feature bits.
> >       */
> > diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> > index a0129aebf409..4dc067fb5558 100644
> > --- a/tests/arm-cpu-features.c
> > +++ b/tests/arm-cpu-features.c
> > @@ -351,7 +351,7 @@ static void sve_tests_sve_off_kvm(const void *data)
> >  {
> >      QTestState *qts;
> >  
> > -    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
> > +    qts = qtest_init(MACHINE "-accel kvm -cpu host,sve=off");
> >  
> >      /*
> >       * We don't know if this host supports SVE so we don't
> > @@ -360,8 +360,8 @@ static void sve_tests_sve_off_kvm(const void *data)
> >       * and that using sve<N>=off to explicitly disable vector
> >       * lengths is OK too.
> >       */
> > -    assert_sve_vls(qts, "max", 0, NULL);
> > -    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
> > +    assert_sve_vls(qts, "host", 0, NULL);
> > +    assert_sve_vls(qts, "host", 0, "{ 'sve128': false }");
> >  
> >      qtest_quit(qts);
> >  }
> > @@ -428,8 +428,8 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >              "We cannot guarantee the CPU type 'cortex-a15' works "
> >              "with KVM on this host", NULL);
> >  
> > -        assert_has_feature(qts, "max", "sve");
> > -        resp = do_query_no_props(qts, "max");
> > +        assert_has_feature(qts, "host", "sve");
> > +        resp = do_query_no_props(qts, "host");
> >          kvm_supports_sve = resp_get_feature(resp, "sve");
> >          vls = resp_get_sve_vls(resp);
> >          qobject_unref(resp);
> > @@ -440,7 +440,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >              sprintf(max_name, "sve%d", max_vq * 128);
> >  
> >              /* Enabling a supported length is of course fine. */
> > -            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
> > +            assert_sve_vls(qts, "host", vls, "{ %s: true }", max_name);
> >  
> >              /* Get the next supported length smaller than max-vq. */
> >              vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
> > @@ -449,7 +449,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >                   * We have at least one length smaller than max-vq,
> >                   * so we can disable max-vq.
> >                   */
> > -                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
> > +                assert_sve_vls(qts, "host", (vls & ~BIT(max_vq - 1)),
> >                                 "{ %s: false }", max_name);
> >  
> >                  /*
> > @@ -459,7 +459,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >                   */
> >                  sprintf(name, "sve%d", vq * 128);
> >                  error = g_strdup_printf("cannot disable %s", name);
> > -                assert_error(qts, "max", error,
> > +                assert_error(qts, "host", error,
> >                               "{ %s: true, %s: false }",
> >                               max_name, name);
> >                  g_free(error);
> > @@ -472,7 +472,7 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >              vq = __builtin_ffsll(vls);
> >              sprintf(name, "sve%d", vq * 128);
> >              error = g_strdup_printf("cannot disable %s", name);
> > -            assert_error(qts, "max", error, "{ %s: false }", name);
> > +            assert_error(qts, "host", error, "{ %s: false }", name);
> >              g_free(error);
> >  
> >              /* Get an unsupported length. */
> > @@ -484,13 +484,14 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
> >              if (vq <= SVE_MAX_VQ) {
> >                  sprintf(name, "sve%d", vq * 128);
> >                  error = g_strdup_printf("cannot enable %s", name);
> > -                assert_error(qts, "max", error, "{ %s: true }", name);
> > +                assert_error(qts, "host", error, "{ %s: true }", name);
> >                  g_free(error);
> >              }
> >          } else {
> >              g_assert(vls == 0);
> >          }
> >      } else {
> > +        assert_has_not_feature(qts, "host", "sve");
> >          assert_error(qts, "host",
> >                       "'pmu' feature not supported by KVM on this host",
> >                       "{ 'pmu': true }");
> > 
> Besides
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>

Thanks!

drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-26  8:21     ` Andrew Jones
@ 2019-09-26  9:34       ` Auger Eric
  2019-09-26 11:14         ` Andrew Jones
  0 siblings, 1 reply; 32+ messages in thread
From: Auger Eric @ 2019-09-26  9:34 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin



On 9/26/19 10:21 AM, Andrew Jones wrote:
> On Wed, Sep 25, 2019 at 03:53:42PM +0200, Auger Eric wrote:
>> Hi Drew,
>>
>> On 9/24/19 1:31 PM, Andrew Jones wrote:
>>> Introduce cpu properties to give fine control over SVE vector lengths.
>>> We introduce a property for each valid length up to the current
>>> maximum supported, which is 2048-bits. The properties are named, e.g.
>>> sve128, sve256, sve384, sve512, ..., where the number is the number of
>>> bits. See the updates to docs/arm-cpu-features.rst for a description
>>> of the semantics and for example uses.
>>>
>>> Note, as sve-max-vq is still present and we'd like to be able to
>>> support qmp_query_cpu_model_expansion with guests launched with e.g.
>>> -cpu max,sve-max-vq=8 on their command lines, then we do allow
>>> sve-max-vq and sve<N> properties to be provided at the same time, but
>>> this is not recommended, and is why sve-max-vq is not mentioned in the
>>> document.  If sve-max-vq is provided then it enables all lengths smaller
>>> than and including the max and disables all lengths larger. It also has
>>> the side-effect that no larger lengths may be enabled and that the max
>>> itself cannot be disabled. Smaller non-power-of-two lengths may,
>>> however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
>>> guest the vector lengths 128, 256, and 512 bits.
>>>
>>> This patch has been co-authored with Richard Henderson, who reworked
>>> the target/arm/cpu64.c changes in order to push all the validation and
>>> auto-enabling/disabling steps into the finalizer, resulting in a nice
>>> LOC reduction.
>>>
>>> Signed-off-by: Andrew Jones <drjones@redhat.com>
>>> ---
>>>  docs/arm-cpu-features.rst | 157 +++++++++++++++++++++++++++++--
>>>  target/arm/cpu.c          |  19 ++++
>>>  target/arm/cpu.h          |  19 ++++
>>>  target/arm/cpu64.c        | 190 +++++++++++++++++++++++++++++++++++++-
>>>  target/arm/helper.c       |  13 ++-
>>>  target/arm/monitor.c      |  12 +++
>>>  tests/arm-cpu-features.c  | 189 +++++++++++++++++++++++++++++++++++++
>>>  7 files changed, 587 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
>>> index c79dcffb5556..1262fddc6201 100644
>>> --- a/docs/arm-cpu-features.rst
>>> +++ b/docs/arm-cpu-features.rst
>>> @@ -48,18 +48,28 @@ block in the script for usage) is used to issue the QMP commands.
>>>        (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
>>>        { "return": {
>>>          "model": { "name": "max", "props": {
>>> -        "pmu": true, "aarch64": true
>>> +        "sve1664": true, "pmu": true, "sve1792": true, "sve1920": true,
>>> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
>>> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
>>> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
>>> +        "sve896": true, "sve1280": true, "sve2048": true
>> I don't really understand why this gets printed unsorted as you
>> registered them in the logical order, any clue?
> 
> Maybe qdict hashing? qmp-shell could probably be patched to sort them,
> but it's probably not worth it.
OK. Anyway beyond the scope of the series but that's unpractical.
> 
>>
>> Note: This example is given with TCG or KVM with all those vectors
>> supported by the host.
> 
> You want this note to be added? I don't think it's necessary, as it's just
> an example. A different configuration or different CPU model expansion
> will have different results, as we explain exhaustively in this document.
a reader may understand that along with max cpu type whatever the state
of KVM all sve<N> are supported by default, which is not true in KVM
case. Maybe add TCG case.
> 
>>>        }}}}
>>>  
>>> -We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
>>> -We also see that the CPU features are enabled, as they are all `true`.
>>> +We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many
>>> +`sve<N>` CPU features.  We also see that all the CPU features are
>>> +enabled, as they are all `true`.  (The `sve<N>` CPU features are all
>>> +optional SVE vector lengths.  See "SVE CPU Properties".)
>>>  
>>>  (2) Let's try to disable the PMU::
>>>  
>>>        (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
>>>        { "return": {
>>>          "model": { "name": "max", "props": {
>>> -        "pmu": false, "aarch64": true
>>> +        "sve1664": true, "pmu": false, "sve1792": true, "sve1920": true,
>>> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
>>> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
>>> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
>>> +        "sve896": true, "sve1280": true, "sve2048": true
>>>        }}}}
>>>  
>>>  We see it worked, as `pmu` is now `false`.
>>> @@ -75,7 +85,22 @@ We see it worked, as `pmu` is now `false`.
>>>  It looks like this feature is limited to a configuration we do not
>>>  currently have.
>>>  
>>> -(4) Let's try probing CPU features for the Cortex-A15 CPU type::
>>> +(4) Let's disable `sve` and see what happens to all the optional SVE
>>> +    vector lengths::
>>> +
>>> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}}
>>> +      { "return": {
>>> +        "model": { "name": "max", "props": {
>>> +        "sve1664": false, "pmu": true, "sve1792": false, "sve1920": false,
>>> +        "sve128": false, "aarch64": true, "sve1024": false, "sve": false,
>>> +        "sve640": false, "sve768": false, "sve1408": false, "sve256": false,
>>> +        "sve1152": false, "sve512": false, "sve384": false, "sve1536": false,
>>> +        "sve896": false, "sve1280": false, "sve2048": false
>>> +      }}}}
>>> +
>>> +As expected they are now all `false`.
>>> +
>>> +(5) Let's try probing CPU features for the Cortex-A15 CPU type::
>>>  
>>>        (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
>>>        {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
>>> @@ -131,7 +156,125 @@ After determining which CPU features are available and supported for a
>>>  given CPU type, then they may be selectively enabled or disabled on the
>>>  QEMU command line with that CPU type::
>>>  
>>> -  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
>>> +  $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on
>>> +
>>> +The example above disables the PMU and enables the first two SVE vector
>>> +lengths for the `max` CPU type.  Note, the `sve=on` isn't actually
>>> +necessary, because, as we observed above with our probe of the `max` CPU
>>> +type, `sve` is already on by default.

>>
>> This holds with TCG and not KVM.
> 
> It also holds with KVM, as long as the host supports SVE.
as long as the hist supports SVE: Yes that's what I meant

maybe add, as we observed abovewith our probe of the `max` CPU
>>> +type, in this TCG case, `sve` is already on by default

 But that doesn't
> matter, because we're speaking specifically about the example above here,
> where we see that sve=on is the default. 
> 
>>
>> Also, based on our probe of
>>> +defaults, it would seem we need to disable many SVE vector lengths, rather
>>> +than only enabling the two we want.  This isn't the case, because, as
>>> +disabling many SVE vector lengths would be quite verbose, the `sve<N>` CPU
>>> +properties have special semantics (see "SVE CPU Property Parsing
>>> +Semantics").
>>> +
>>> +SVE CPU Properties
>>> +==================
>>> +
>>> +There are two types of SVE CPU properties: `sve` and `sve<N>`.  The first
>>> +is used to enable or disable the entire SVE feature, just as the `pmu`
>>> +CPU property completely enables or disables the PMU.  The second type
>>> +is used to enable or disable specific vector lengths, where `N` is the
>>> +number of bits of the length.  The `sve<N>` CPU properties have special
>>> +dependencies and constraints, see "SVE CPU Property Dependencies and
>>> +Constraints" below.  Additionally, as we want all supported vector lengths
>>> +to be enabled by default, then, in order to avoid overly verbose command
>>> +lines (command lines full of `sve<N>=off`, for all `N` not wanted), we
>>> +provide the parsing semantics listed in "SVE CPU Property Parsing
>>> +Semantics".
>>> +
>>> +SVE CPU Property Dependencies and Constraints
>>> +---------------------------------------------
>>> +
>>> +  1) At least one vector length must be enabled when `sve` is enabled.> +
>>> +  2) If a vector length `N` is enabled, then all power-of-two vector
>>> +     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
>>> +     is enabled, then `sve128` and `sve256` must also be enabled,
>>> +     but `sve384` is not required.
>> I would remove the eg. part. reading that I tend to understand that the
>> user must pass ,sve128=on, sve256=on and sve512=on whereas example 6
>> says only sve512=on can be set and other lower ^2 values are auto-enabled.
> 
> I'll keep the example, but instead of using the property names, I'll
> change to using "the 128-bit vector length", 256-bit ..., etc.
ok
> 
>>> +
>>> +SVE CPU Property Parsing Semantics
>>> +----------------------------------
>>> +
>>> +  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
>>> +     are enabled or disabled is irrelevant to the guest, as the entire
>>> +     SVE feature is disabled and that disables all vector lengths for
>>> +     the guest.  However QEMU will still track any `sve<N>` CPU
>>> +     properties provided by the user.  If later an `sve=on` is provided,
>>> +     then the guest will get only the enabled lengths.
>>> +
>>> +  2) If SVE is enabled (`sve=on`), but no `sve<N>` CPU properties are
>>> +     provided, then all supported vector lengths are enabled.
>> I understand from the code it also includes non ^2 values which is not
>> obvious.
> 
> Yes, the default is to have *all* supported vector lengths enabled, not
> just the power-of-two. As we already use the word 'all' here, then how
> can we further clarify this?
I would simply add "including non ^2 values".
> 
>>> +
>>> +  3) If SVE is enabled, then an error is generated when attempting to
>>> +     disable the last enabled vector length (see constraint (1) of "SVE
>>> +     CPU Property Dependencies and Constraints").
>> the same happens if you attempt to disabled any lower ^2 value
> 
> That should be another bullet, which I appear to be missing, and will add.
> 
>>> +
>>> +  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>>> +     CPU properties are set `on`, then the specified vector lengths are
>>> +     disabled but the default for any unspecified lengths remains enabled.
>>> +     Disabling a power-of-two vector length also disables all vector
>>> +     lengths larger than the power-of-two length (see constraint (2) of
>>> +     "SVE CPU Property Dependencies and Constraints").
>> So rephasing it:
>> disabling a non ^2 value only disable that one
>> disabling a ^2 value disables all larger lengths too
>> is that correct?
> 
> That's correct. We auto-disable all uninitialized larger lengths when a
> power-of-two dependency length is explicitly disabled.
> 
>>
>>> +
>>> +  5) If one or more `sve<N>` CPU properties are set to `on`, then they
>>> +     are enabled and all unspecified lengths default to disabled, except
>>> +     for the required lengths per constraint (2) of "SVE CPU Property
>>> +     Dependencies and Constraints", which will even be auto-enabled if
>>> +     they were not explicitly enabled.
>>> +
>>> +  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>>> +     explicitly disabled (i.e. avoiding the error specified in (3) of
>>> +     "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
>>> +     provided an error will be generated.  To avoid this error, one must
>>> +     enable at least one vector length prior to enabling SVE.
>>> +
>>> +SVE CPU Property Examples
>>> +-------------------------
>>> +
>>> +  1) Disable SVE::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off
>>> +
>>> +  2) Implicitly enable all vector lengths for the `max` CPU type::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max
>>> +
>>> +  3) Only enable the 128-bit vector length::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on
>>> +
>>> +  4) Disable the 256-bit vector length and all larger vector lengths
>>> +     since 256 is a power-of-two (this results in only the 128-bit length
>>> +     being enabled)::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve256=off
>>> +
>>> +  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
>>> +
>>> +  6) The same as (5), but since the 128-bit and 256-bit vector
>>> +     lengths are required for the 512-bit vector length to be enabled,
>>> +     then allow them to be auto-enabled::> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve512=on
>>
>> You should also document
>> $ qemu-system-aarch64 -M virt -cpu max,sve512=off
>> as in that case this result in 128, 256 and 384. the fact you get non ^2
>> values is not obvious here because if you enable a ^2 value you onlt get
>> <= ^2 values.
yep.
> 
> I can change (4) above to use 512 instead of 256.
> 
>>> +
>>> +  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on> +
>>> +  8) Force errors regarding the last vector length::
>> You mean those commands will generate errors, right?
> 
> Yes
> 
>>> +
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=off
>>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
>>> +
>>> +SVE CPU Property Recommendations
>>> +--------------------------------
>>>  
>>> -The example above disables the PMU for the `max` CPU type.
>>> +The examples in "SVE CPU Property Examples" exhibit many ways to select
>>> +vector lengths which developers may find useful in order to avoid overly
>>> +verbose command lines.  However, the recommended way to select vector
>>> +lengths is to explicitly enable each desired length.  Therefore only
>>> +example's (1), (3), and (5) exhibit recommended uses of the properties.
>>>  
>>> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
>>> index 73be2ebfdd39..522fed95b339 100644
>>> --- a/target/arm/cpu.c
>>> +++ b/target/arm/cpu.c
>>> @@ -1199,6 +1199,19 @@ static void arm_cpu_finalizefn(Object *obj)
>>>  #endif
>>>  }
>>>  
>>> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
>>> +{
>>> +    Error *local_err = NULL;
>>> +
>>> +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>>> +        arm_cpu_sve_finalize(cpu, &local_err);
>>> +        if (local_err != NULL) {
>> nit: !local_err
>>> +            error_propagate(errp, local_err);
>>> +            return;
>> not needed
> 
> Yet. I expect a chain of finalizers to go here, so we'll want the 'return'
> when we get the next one. As it doesn't hurt, it might as well go in now.
> 
>>> +        }
>>> +    }
>>> +}
>>> +
>>>  static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>>>  {
>>>      CPUState *cs = CPU(dev);
>>> @@ -1255,6 +1268,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>>>          return;
>>>      }
>>>  
>>> +    arm_cpu_finalize_features(cpu, &local_err);
>>> +    if (local_err != NULL) {
>> same
>>> +        error_propagate(errp, local_err);
>>> +        return;> +    }
>>> +
>>>      if (arm_feature(env, ARM_FEATURE_AARCH64) &&
>>>          cpu->has_vfp != cpu->has_neon) {
>>>          /*
>>> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
>>> index 297ad5e47ad8..11162484465a 100644
>>> --- a/target/arm/cpu.h
>>> +++ b/target/arm/cpu.h
>>> @@ -184,8 +184,13 @@ typedef struct {
>>>  
>>>  #ifdef TARGET_AARCH64
>>>  # define ARM_MAX_VQ    16
>>> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
>>> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
>>>  #else
>>>  # define ARM_MAX_VQ    1
>>> +static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
>>> +static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
>>> +{ return 0; }
>>>  #endif
>>>  
>>>  typedef struct ARMVectorReg {
>>> @@ -915,6 +920,18 @@ struct ARMCPU {
>>>  
>>>      /* Used to set the maximum vector length the cpu will support.  */
>>>      uint32_t sve_max_vq;
>>> +
>>> +    /*
>>> +     * In sve_vq_map each set bit is a supported vector length of
>>> +     * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
>>> +     * length in quadwords.
>>> +     *
>>> +     * While processing properties during initialization, corresponding
>>> +     * sve_vq_init bits are set for bits in sve_vq_map that have been
>>> +     * set by properties.
>>> +     */
>>> +    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
>>> +    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
>>>  };
>>>  
>>>  void arm_cpu_post_init(Object *obj);
>>> @@ -1834,6 +1851,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
>>>      return (env->features & (1ULL << feature)) != 0;
>>>  }
>>>  
>>> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
>>> +
>>>  #if !defined(CONFIG_USER_ONLY)
>>>  /* Return true if exception levels below EL3 are in secure state,
>>>   * or would be following an exception return to that level.
>>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>>> index 8cdb0c79fa7a..606e3eceb9c0 100644
>>> --- a/target/arm/cpu64.c
>>> +++ b/target/arm/cpu64.c
>>> @@ -256,11 +256,152 @@ static void aarch64_a72_initfn(Object *obj)
>>>      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
>>>  }
>>>  
>>> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>> +{
>>> +    /*
>>> +     * If any vector lengths are explicitly enabled with sve<N> properties,
>>> +     * then all other lengths are implicitly disabled.  If sve-max-vq is
>>> +     * specified then it is the same as explicitly enabling all lengths
>>> +     * up to and including the specified maximum, which means all larger
>>> +     * lengths will be implicitly disabled.  If no sve<N> properties
>>> +     * are enabled and sve-max-vq is not specified, then all lengths not
>>> +     * explicitly disabled will be enabled.  Additionally, all power-of-two
>>> +     * vector lengths less than the maximum enabled length will be
>>> +     * automatically enabled and all vector lengths larger than the largest
>>> +     * disabled power-of-two vector length will be automatically disabled.
>>> +     * Errors are generated if the user provided input that interferes with
>>> +     * any of the above.  Finally, if SVE is not disabled, then at least one
>>> +     * vector length must be enabled.
>>> +     */
>>> +    DECLARE_BITMAP(tmp, ARM_MAX_VQ);
>>> +    uint32_t vq, max_vq = 0;
>>> +
>>> +    /*
>>> +     * Process explicit sve<N> properties.
>>> +     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
>>> +     * Check first for any sve<N> enabled.
>>> +     */
>>> +    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
>>> +        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
>>> +
>>> +        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
>>> +            error_setg(errp, "cannot enable sve%d", max_vq * 128);
>>> +            error_append_hint(errp, "sve%d is larger than the maximum vector "
>>> +                              "length, sve-max-vq=%d (%d bits)\n",
>>> +                              max_vq * 128, cpu->sve_max_vq,
>>> +                              cpu->sve_max_vq * 128);
>> you could test directly if max_vq < cpu->sve_max_vq too which couldn't
> 
> That's not an error. Here max_vq is the maximum enabled with sve<N>
> properties. We haven't considered cpu->sve_max_vq yet, except for
> ensuring we don't enable something larger than it.
Oh ok I had in mind sve512=on,sve-max-vq=5 was an error but reading the
code again it is indeed value. My original thought was setting sve<n>
was disabling larger values but that's only valid with sve-max-vq unset.
> 
>> be correct either. But as far as I understand this is caught in *
>>> +            return;
>>> +        }
>>> +
>>> +        /* Propagate enabled bits down through required powers-of-two. */
>>> +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> +            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
>>> +                set_bit(vq - 1, cpu->sve_vq_map);
>>> +            }
>>> +        }
>>> +    } else if (cpu->sve_max_vq == 0) {
>>> +        /*
>>> +         * No explicit bits enabled, and no implicit bits from sve-max-vq.
>>> +         */
>>> +        if (!cpu_isar_feature(aa64_sve, cpu)) {
>>> +            /* SVE is disabled and so are all vector lengths.  Good. */
>>> +            return;
>>> +        }
>>> +
>>> +        /* Disabling a power-of-two disables all larger lengths. */
>>> +        if (test_bit(0, cpu->sve_vq_init)) {> +            error_setg(errp, "cannot disable sve128");
>>> +            error_append_hint(errp, "Disabling sve128 results in all vector "
>>> +                              "lengths being disabled.\n");
>>> +            error_append_hint(errp, "With SVE enabled, at least one vector "
>>> +                              "length must be enabled.\n");
>>> +            return;
>>> +        }
>>> +        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
>>> +            if (test_bit(vq - 1, cpu->sve_vq_init)) {
>>> +                break;
>>> +            }
>>> +        }
>>> +        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>>> +
>>> +        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
>>> +        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
>>> +    }
>>> +
>>> +    /*
>>> +     * Process the sve-max-vq property.
>>> +     * Note that we know from the above that no bit above
>>> +     * sve-max-vq is currently set.
>>> +     */
>>> +    if (cpu->sve_max_vq != 0) {
>>> +        max_vq = cpu->sve_max_vq;
>>> +
>>> +        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
>>> +            test_bit(max_vq - 1, cpu->sve_vq_init)) {
>>> +            error_setg(errp, "cannot disable sve%d", max_vq * 128);
>>> +            error_append_hint(errp, "The maximum vector length must be "
>>> +                              "enabled, sve-max-vq=%d (%d bits)\n",
>>> +                              max_vq, max_vq * 128);
>>> +            return;
>>> +        }
>>> +
>>> +        /* Set all bits not explicitly set within sve-max-vq. */
>>> +        bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
>>> +        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
>>> +    }
>>> +
>>> +    /*
>>> +     * We should know what max-vq is now.  Also, as we're done
>>> +     * manipulating sve-vq-map, we ensure any bits above max-vq
>>> +     * are clear, just in case anybody looks.
>>> +     */
>>> +    assert(max_vq != 0);
>>> +    bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
>>> +
>>> +    /* Ensure all required powers-of-two are enabled. */
>>> +    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> +        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
>>> +            error_setg(errp, "cannot disable sve%d", vq * 128);
>>> +            error_append_hint(errp, "sve%d is required as it "
>>> +                              "is a power-of-two length smaller than "
>>> +                              "the maximum, sve%d\n",
>>> +                              vq * 128, max_vq * 128);
>> * I think this will also catches the case where ,sve512=on,sve-max-vq=5
>> where the end-user did not explicitly disabled anything
> 
> As stated above, 'sve512=on,sve-max-vq=5' isn't an error. It doesn't hurt
> to enable vector lengths explicitly that would be enabled automatically
> anyway with the sve-max-vq property.
Now understood.
> 
> 
>>> +            return;
>>> +        }
>>> +    }
>>> +
>>> +    /* From now on sve_max_vq is the actual maximum supported length. */
>>> +    cpu->sve_max_vq = max_vq;
>>> +}
>>> +
>>> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
>>> +{
>>> +    uint32_t bitnum;
>>> +
>>> +    /*
>>> +     * We allow vq == ARM_MAX_VQ + 1 to be input because the caller may want
>>> +     * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
>>> +     * function always returns the next smaller than the input.
>>> +     */
>>> +    assert(vq && vq <= ARM_MAX_VQ + 1);
>>> +
>>> +    bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
>>> +    return bitnum == vq - 1 ? 0 : bitnum + 1;
>>> +}
>>> +
>>>  static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
>>>                                     void *opaque, Error **errp)
>>>  {
>>>      ARMCPU *cpu = ARM_CPU(obj);
>>> -    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
>>> +    uint32_t value;
>> Shouldn't it be part of the previous patch?
> 
> Yes. Will fix for v5.
> 
>>> +
>>> +    /* All vector lengths are disabled when SVE is off. */
>>> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
>>> +        value = 0;
>>> +    } else {
>>> +        value = cpu->sve_max_vq;
>>> +    }
>>> +    visit_type_uint32(v, name, &value, errp);
>>>  }
>>>  
>>>  static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>>> @@ -279,6 +420,44 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>> Independently on this patch I noticed that if sve_max_vq is out of
>> scope, an error is propagated but still the cpu->sve-max_vq is set.
> 
> I'll sneak that fix into patch 8/9 where we touch the function anyway.
> 
>>>      error_propagate(errp, err);
>>>  }
>>>  
>>> +static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
>>> +                               void *opaque, Error **errp)
>>> +{
>>> +    ARMCPU *cpu = ARM_CPU(obj);
>>> +    uint32_t vq = atoi(&name[3]) / 128;
>>> +    bool value;
>>> +
>>> +    /* All vector lengths are disabled when SVE is off. */
>>> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
>>> +        value = false;
>>> +    } else {
>>> +        value = test_bit(vq - 1, cpu->sve_vq_map);
>>> +    }
>>> +    visit_type_bool(v, name, &value, errp);
>>> +}
>>> +
>>> +static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
>>> +                               void *opaque, Error **errp)
>>> +{
>>> +    ARMCPU *cpu = ARM_CPU(obj);
>>> +    uint32_t vq = atoi(&name[3]) / 128;
>>> +    Error *err = NULL;
>>> +    bool value;
>>> +
>>> +    visit_type_bool(v, name, &value, &err);
>>> +    if (err) {
>>> +        error_propagate(errp, err);
>>> +        return;
>>> +    }
>>> +
>>> +    if (value) {
>>> +        set_bit(vq - 1, cpu->sve_vq_map);
>>> +    } else {
>>> +        clear_bit(vq - 1, cpu->sve_vq_map);
>>> +    }
>>> +    set_bit(vq - 1, cpu->sve_vq_init);
>>> +}
>>> +
>>>  static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
>>>                              void *opaque, Error **errp)
>>>  {
>>> @@ -315,6 +494,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>>>  static void aarch64_max_initfn(Object *obj)
>>>  {
>>>      ARMCPU *cpu = ARM_CPU(obj);
>>> +    uint32_t vq;
>>>  
>>>      if (kvm_enabled()) {
>>>          kvm_arm_set_cpu_features_from_host(cpu);
>>> @@ -418,11 +598,17 @@ static void aarch64_max_initfn(Object *obj)
>>>          cpu->dcz_blocksize = 7; /*  512 bytes */
>>>  #endif
>>>  
>>> -        cpu->sve_max_vq = ARM_MAX_VQ;
>>>          object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>>>                              cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
>>>          object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
>>>                              cpu_arm_set_sve, NULL, NULL, &error_fatal);
>>> +
>>> +        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>>> +            char name[8];
>>> +            sprintf(name, "sve%d", vq * 128);
>>> +            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
>>> +                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
>>> +        }
>>>      }
>>>  }
>>>  
>>> diff --git a/target/arm/helper.c b/target/arm/helper.c
>>> index 507026c9154b..f33284c247d5 100644
>>> --- a/target/arm/helper.c
>>> +++ b/target/arm/helper.c
>>> @@ -5351,6 +5351,13 @@ int sve_exception_el(CPUARMState *env, int el)
>>>      return 0;
>>>  }
>>>  
>>> +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
>>> +{
>>> +    uint32_t start_vq = (start_len & 0xf) + 1;
>>> +
>>> +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
>>> +}
>>> +
>>>  /*
>>>   * Given that SVE is enabled, return the vector length for EL.
>>>   */
>>> @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
>>>      uint32_t zcr_len = cpu->sve_max_vq - 1;
>>>  
>>>      if (el <= 1) {
>>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
>>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
>>>      }
>>>      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
>>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
>>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
>>>      }
>>>      if (arm_feature(env, ARM_FEATURE_EL3)) {
>>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
>>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
>>>      }
>>>      return zcr_len;
>>>  }
>>> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
>>> index 4fddb6c252a3..e912ed2cefa0 100644
>>> --- a/target/arm/monitor.c
>>> +++ b/target/arm/monitor.c
>>> @@ -90,6 +90,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>>>      return head;
>>>  }
>>>  
>>> +QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
>>> +
>>>  /*
>>>   * These are cpu model features we want to advertise. The order here
>>>   * matters as this is the order in which qmp_query_cpu_model_expansion
>>> @@ -98,6 +100,9 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
>>>   */
>>>  static const char *cpu_model_advertised_features[] = {
>>>      "aarch64", "pmu", "sve",
>>> +    "sve128", "sve256", "sve384", "sve512",
>>> +    "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
>>> +    "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
>>>      NULL
>>>  };
>>>  
>>> @@ -185,6 +190,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>>>          if (!err) {
>>>              visit_check_struct(visitor, &err);
>>>          }
>>> +        if (!err) {
>>> +            arm_cpu_finalize_features(ARM_CPU(obj), &err);
>>> +        }
>>>          visit_end_struct(visitor, NULL);
>>>          visit_free(visitor);
>>>          if (err) {
>>> @@ -192,6 +200,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>>>              error_propagate(errp, err);
>>>              return NULL;
>>>          }
>>> +    } else {
>>> +        Error *err = NULL;
>>> +        arm_cpu_finalize_features(ARM_CPU(obj), &err);
>>> +        assert(err == NULL);
>>>      }
>>>  
>>>      expansion_info = g_new0(CpuModelExpansionInfo, 1);
>>> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
>>> index 202bc0e3e823..9a2dd402b769 100644
>>> --- a/tests/arm-cpu-features.c
>>> +++ b/tests/arm-cpu-features.c
>>> @@ -13,6 +13,18 @@
>>>  #include "qapi/qmp/qdict.h"
>>>  #include "qapi/qmp/qjson.h"
>>>  
>>> +#if __SIZEOF_LONG__ == 8
>>> +#define BIT(n) (1UL << (n))
>>> +#else
>>> +#define BIT(n) (1ULL << (n))
>>> +#endif
>>> +
>>> +/*
>>> + * We expect the SVE max-vq to be 16. Also it must be <= 64
>>> + * for our test code, otherwise 'vls' can't just be a uint64_t.
>>> + */
>>> +#define SVE_MAX_VQ 16
>>> +
>>>  #define MACHINE    "-machine virt,gic-version=max "
>>>  #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
>>>                       "'arguments': { 'type': 'full', "
>>> @@ -157,6 +169,173 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type)
>>>      qobject_unref(resp);
>>>  }
>>>  
>>> +static uint64_t resp_get_sve_vls(QDict *resp)
>>> +{
>>> +    QDict *props;
>>> +    const QDictEntry *e;
>>> +    uint64_t vls = 0;
>>> +    int n = 0;
>>> +
>>> +    g_assert(resp);
>>> +    g_assert(resp_has_props(resp));
>>> +
>>> +    props = resp_get_props(resp);
>>> +
>>> +    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
>>> +        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
>>> +            g_ascii_isdigit(e->key[3])) {
>>> +            char *endptr;
>>> +            int bits;
>>> +
>>> +            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
>>> +            if (!bits || *endptr != '\0') {
>>> +                continue;
>>> +            }
>>> +
>>> +            if (qdict_get_bool(props, e->key)) {
>>> +                vls |= BIT((bits / 128) - 1);
>>> +            }
>>> +            ++n;
>>> +        }
>>> +    }
>>> +
>>> +    g_assert(n == SVE_MAX_VQ);
>>> +
>>> +    return vls;
>>> +}
>>> +
>>> +#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
>>> +({                                                                     \
>>> +    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
>>> +    g_assert(_resp);                                                   \
>>> +    g_assert(resp_has_props(_resp));                                   \
>>> +    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
>>> +    qobject_unref(_resp);                                              \
>>> +})
>>> +
>>> +static void sve_tests_default(QTestState *qts, const char *cpu_type)
>>> +{
>>> +    /*
>>> +     * With no sve-max-vq or sve<N> properties on the command line
>>> +     * the default is to have all vector lengths enabled. This also
>>> +     * tests that 'sve' is 'on' by default.
>>> +     */
>>> +    assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL);
>>> +
>>> +    /* With SVE off, all vector lengths should also be off. */
>>> +    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
>>> +
>>> +    /* With SVE on, we must have at least one vector length enabled. */
>>> +    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
>>> +
>>> +    /*
>>> +     * ---------------------------------------------------------------------
>>> +     *               power-of-two(vq)   all-power-            can      can
>>> +     *                                  of-two(< vq)        enable   disable
>>> +     * ---------------------------------------------------------------------
>>> +     * vq < max_vq      no                MUST*              yes      yes
>>> +     * vq < max_vq      yes               MUST*              yes      no
>>> +     * ---------------------------------------------------------------------
>>> +     * vq == max_vq     n/a               MUST*              yes**    yes**
>>> +     * ---------------------------------------------------------------------
>>> +     * vq > max_vq      n/a               no                 no       yes
>>> +     * vq > max_vq      n/a               yes                yes      yes
>>> +     * ---------------------------------------------------------------------
>>> +     *
>>> +     * [*] "MUST" means this requirement must already be satisfied,
>>> +     *     otherwise 'max_vq' couldn't itself be enabled.
>>> +     *
>>> +     * [**] Not testable with the QMP interface, only with the command line.
>>> +     */
>>> +
>>> +    /* max_vq := 8 */
>>> +    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
>>> +
>>> +    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
>>> +    assert_sve_vls(qts, cpu_type, 0x8f,
>>> +                   "{ 'sve1024': true, 'sve384': true }");
>>> +    assert_sve_vls(qts, cpu_type, 0x8b,
>>> +                   "{ 'sve1024': true, 'sve384': false }");
>>> +
>>> +    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
>>> +    assert_sve_vls(qts, cpu_type, 0x8b,
>>> +                   "{ 'sve1024': true, 'sve256': true }");
>>> +    assert_error(qts, cpu_type, "cannot disable sve256",
>>> +                 "{ 'sve1024': true, 'sve256': false }");
>>> +
>>> +    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
>>> +    assert_error(qts, cpu_type, "cannot disable sve512",
>>> +                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
>>> +
>>> +    /*
>>> +     * We can disable power-of-two vector lengths when all larger lengths
>>> +     * are also disabled. We only need to disable the power-of-two length,
>>> +     * as all non-enabled larger lengths will then be auto-disabled.
>>> +     */
>>> +    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
>>> +
>>> +    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
>>> +    assert_sve_vls(qts, cpu_type, 0x1f,
>>> +                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
>>> +    assert_sve_vls(qts, cpu_type, 0xf,
>>> +                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
>>> +}
>>> +
>>> +static void sve_tests_sve_max_vq_8(const void *data)
>>> +{
>>> +    QTestState *qts;
>>> +
>>> +    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
>>> +
>>> +    assert_sve_vls(qts, "max", BIT(8) - 1, NULL);
>>> +
>>> +    /*
>>> +     * Disabling the max-vq set by sve-max-vq is not allowed, but
>>> +     * of course enabling it is OK.
>>> +     */
>>> +    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
>>> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
>>> +
>>> +    /*
>>> +     * Enabling anything larger than max-vq set by sve-max-vq is not
>>> +     * allowed, but of course disabling everything larger is OK.
>>> +     */
>>> +    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
>>> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
>>> +
>>> +    /*
>>> +     * We can disable non power-of-two lengths smaller than the max-vq
>>> +     * set by sve-max-vq, but not power-of-two lengths.
>>> +     */
>>> +    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
>> you can also test ,sve384=on => 0x7
> 
> We wouldn't get 0x7, we'd get 0xff. I could still add the test to ensure
> we can enable smaller vector lengths without an error though.
Oh yes because you have the sve-max-vq=8
I rather meant in sve_tests_default then

Eric
> 
>>> +    assert_error(qts, "max", "cannot disable sve256", "{ 'sve256': false }");
>>> +
>>> +    qtest_quit(qts);
>>> +}
>>> +
>>> +static void sve_tests_sve_off(const void *data)
>>> +{
>>> +    QTestState *qts;
>>> +
>>> +    qts = qtest_init(MACHINE "-cpu max,sve=off");
>>> +
>>> +    /* SVE is off, so the map should be empty. */
>>> +    assert_sve_vls(qts, "max", 0, NULL);
>>> +
>>> +    /* The map stays empty even if we turn lengths on or off. */
>>> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': true }");
>>> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
>>> +
>>> +    /* With SVE re-enabled we should get all vector lengths enabled. */
>>> +    assert_sve_vls(qts, "max", BIT(SVE_MAX_VQ) - 1, "{ 'sve': true }");
>>> +
>>> +    /* Or enable SVE with just specific vector lengths. */
>>> +    assert_sve_vls(qts, "max", 0x3,
>>> +                   "{ 'sve': true, 'sve128': true, 'sve256': true }");
>>> +
>>> +    qtest_quit(qts);
>>> +}
>>> +
>>>  static void test_query_cpu_model_expansion(const void *data)
>>>  {
>>>      QTestState *qts;
>>> @@ -180,9 +359,12 @@ static void test_query_cpu_model_expansion(const void *data)
>>>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
>>>          assert_has_feature(qts, "max", "aarch64");
>>>          assert_has_feature(qts, "max", "sve");
>>> +        assert_has_feature(qts, "max", "sve128");
>>>          assert_has_feature(qts, "cortex-a57", "pmu");
>>>          assert_has_feature(qts, "cortex-a57", "aarch64");
>>>  
>>> +        sve_tests_default(qts, "max");
>>> +
>>>          /* Test that features that depend on KVM generate errors without. */
>>>          assert_error(qts, "max",
>>>                       "'aarch64' feature cannot be disabled "
>>> @@ -234,6 +416,13 @@ int main(int argc, char **argv)
>>>      qtest_add_data_func("/arm/query-cpu-model-expansion",
>>>                          NULL, test_query_cpu_model_expansion);
>>>  
>>> +    if (g_str_equal(qtest_get_arch(), "aarch64")) {
>>> +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8",
>>> +                            NULL, sve_tests_sve_max_vq_8);
>>> +        qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off",
>>> +                            NULL, sve_tests_sve_off);
>>> +    }
>>> +
>>>      if (kvm_available) {
>>>          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
>>>                              NULL, test_query_cpu_model_expansion_kvm);
>>>
>> Thanks
>>
>> Eric
>>
> 
> Thanks,
> drew
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-26  8:41     ` Andrew Jones
@ 2019-09-26 10:01       ` Auger Eric
  2019-09-26 11:40         ` Andrew Jones
  0 siblings, 1 reply; 32+ messages in thread
From: Auger Eric @ 2019-09-26 10:01 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin



On 9/26/19 10:41 AM, Andrew Jones wrote:
> On Thu, Sep 26, 2019 at 08:52:55AM +0200, Auger Eric wrote:
>> Hi Drew,
>>
>> On 9/24/19 1:31 PM, Andrew Jones wrote:
>>> Extend the SVE vq map initialization and validation with KVM's
>>> supported vector lengths when KVM is enabled. In order to determine
>>> and select supported lengths we add two new KVM functions for getting
>>> and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.
>>>
>>> This patch has been co-authored with Richard Henderson, who reworked
>>> the target/arm/cpu64.c changes in order to push all the validation and
>>> auto-enabling/disabling steps into the finalizer, resulting in a nice
>>> LOC reduction.
>>>
>>> Signed-off-by: Andrew Jones <drjones@redhat.com>
>>> ---
>>>  docs/arm-cpu-features.rst |  36 +++++---
>>>  target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
>>>  target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
>>>  target/arm/kvm_arm.h      |  12 +++
>>>  tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
>>>  5 files changed, 368 insertions(+), 52 deletions(-)
>>>
>>> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
>>> index 1262fddc6201..939366f959cf 100644
>>> --- a/docs/arm-cpu-features.rst
>>> +++ b/docs/arm-cpu-features.rst
>>> @@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
>>>  
>>>    1) At least one vector length must be enabled when `sve` is enabled.
>>>  
>>> -  2) If a vector length `N` is enabled, then all power-of-two vector
>>> -     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
>>> -     is enabled, then `sve128` and `sve256` must also be enabled,
>>> -     but `sve384` is not required.
>>> +  2) If a vector length `N` is enabled, then, when KVM is enabled, all
>>> +     smaller, host supported vector lengths must also be enabled.  If
>>> +     KVM is not enabled, then only all the smaller, power-of-two vector
>>> +     lengths must be enabled.  E.g. with KVM if the host supports all
>>> +     vector lengths up to 512-bits (128, 256, 384, 512), then if
>>> +     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
>>> +     be enabled. Without KVM, `sve384` would not be required.
>>> +
>>> +  3) If KVM is enabled then only vector lengths that the host CPU type
>>> +     support may be enabled.  If SVE is not supported by the host, then
>>> +     no `sve*` properties may be enabled.
>>>  
>>>  SVE CPU Property Parsing Semantics
>>>  ----------------------------------
>>> @@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
>>>       disable the last enabled vector length (see constraint (1) of "SVE
>>>       CPU Property Dependencies and Constraints").
>>>  
>>> -  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>>> +  4) When KVM is enabled, if the host does not support SVE, then an error
>>> +     is generated when attempting to enable any `sve*` properties.
>>> +
>>> +  5) When KVM is enabled, if the host does support SVE, then an error is
>>> +     generated when attempting to enable any vector lengths not supported
>>> +     by the host.
>>> +
>>> +  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>>>       CPU properties are set `on`, then the specified vector lengths are
>>>       disabled but the default for any unspecified lengths remains enabled.
>>> -     Disabling a power-of-two vector length also disables all vector
>>> -     lengths larger than the power-of-two length (see constraint (2) of
>>> -     "SVE CPU Property Dependencies and Constraints").
>>> +     When KVM is not enabled, disabling a power-of-two vector length also
>>> +     disables all vector lengths larger than the power-of-two length.
>>> +     When KVM is enabled, then disabling any supported vector length also
>>> +     disables all larger vector lengths (see constraint (2) of "SVE CPU
>>> +     Property Dependencies and Constraints").
>>>  
>>> -  5) If one or more `sve<N>` CPU properties are set to `on`, then they
>>> +  7) If one or more `sve<N>` CPU properties are set to `on`, then they
>>>       are enabled and all unspecified lengths default to disabled, except
>>>       for the required lengths per constraint (2) of "SVE CPU Property
>>>       Dependencies and Constraints", which will even be auto-enabled if
>>>       they were not explicitly enabled.
>>>  
>>> -  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>>> +  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>>>       explicitly disabled (i.e. avoiding the error specified in (3) of
>>>       "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
>>>       provided an error will be generated.  To avoid this error, one must
>>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>>> index b7eff4e1e107..18dd5e24ec61 100644
>>> --- a/target/arm/cpu64.c
>>> +++ b/target/arm/cpu64.c
>>> @@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>       * any of the above.  Finally, if SVE is not disabled, then at least one
>>>       * vector length must be enabled.
>>>       */
>>> +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
>>>      DECLARE_BITMAP(tmp, ARM_MAX_VQ);
>>>      uint32_t vq, max_vq = 0;
>>>  
>>> +    /* Collect the set of vector lengths supported by KVM. */
>>> +    bitmap_zero(kvm_supported, ARM_MAX_VQ);
>>> +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
>>> +        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
>>> +    } else if (kvm_enabled()) {
>>> +        assert(!cpu_isar_feature(aa64_sve, cpu));
>> why not set an error and propagate it instead?
> 
> This should never happen. We shouldn't be here if KVM is enabled and SVE
> isn't supported. The question is how defensive do we want QEMU code?
> We could just drop the check altogether if we don't want the assert, but
> I'd rather keep it.
> 
>>> +    }
>>> +
>>>      /*
>>>       * Process explicit sve<N> properties.
>>>       * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
>>> @@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>              return;
>>>          }
>>>  
>>> -        /* Propagate enabled bits down through required powers-of-two. */
>>> -        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> -            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
>>> -                set_bit(vq - 1, cpu->sve_vq_map);
>>> +        if (kvm_enabled()) {
>>> +            /*
>>> +             * For KVM we have to automatically enable all supported unitialized
>>> +             * lengths, even when the smaller lengths are not all powers-of-two.
>>> +             */
>>> +            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
>>> +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
>>> +        } else {
>>> +            /* Propagate enabled bits down through required powers-of-two. */
>>> +            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> +                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
>>> +                    set_bit(vq - 1, cpu->sve_vq_map);
>>> +                }
>>>              }
>>>          }
>>>      } else if (cpu->sve_max_vq == 0) {
>>> @@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>              return;
>>>          }
>>>  
>>> -        /* Disabling a power-of-two disables all larger lengths. */
>>> -        if (test_bit(0, cpu->sve_vq_init)) {
>>> -            error_setg(errp, "cannot disable sve128");
>>> -            error_append_hint(errp, "Disabling sve128 results in all vector "
>>> -                              "lengths being disabled.\n");
>>> -            error_append_hint(errp, "With SVE enabled, at least one vector "
>>> -                              "length must be enabled.\n");
>>> -            return;
>>> -        }
>>> -        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
>>> -            if (test_bit(vq - 1, cpu->sve_vq_init)) {
>>> -                break;
>>> +        if (kvm_enabled()) {
>>> +            /* Disabling a supported length disables all larger lengths. */
>>> +            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>>> +                if (test_bit(vq - 1, cpu->sve_vq_init) &&
>>> +                    test_bit(vq - 1, kvm_supported)) {
>>> +                    break;
>>> +                }
the above loop looks for the 1st disabled vq that is also supported, right?
>>> +            }
>>> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>>> +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
>>> +                          cpu->sve_vq_init, max_vq);
>>> +            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
here we don't have anything enabled below the disabled one. So don't we
have the culprit already?
>>> +                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
>>> +                error_setg(errp, "cannot disable sve%d", vq * 128);
>> isn't the one disabled max_vq? Do you really need to re-compute vq?
> 
> We're not looking for max_vq with find_next_bit(), we're looking for
> "min_vq". Here we're checking that we always have at least one vector
> length enabled. You can't disable the minimum, because that's the last
> one.
> 
>>> +                error_append_hint(errp, "Disabling sve%d results in all "
>>> +                                  "vector lengths being disabled.\n",
>>> +                                  vq * 128);
>>> +                error_append_hint(errp, "With SVE enabled, at least one "
>>> +                                  "vector length must be enabled.\n");
>>> +                return;> +            }
>>> +        } else {
>>> +            /* Disabling a power-of-two disables all larger lengths. */
>>> +            if (test_bit(0, cpu->sve_vq_init)) {
>>> +                error_setg(errp, "cannot disable sve128");
>>> +                error_append_hint(errp, "Disabling sve128 results in all "
>>> +                                  "vector lengths being disabled.\n");
>>> +                error_append_hint(errp, "With SVE enabled, at least one "
>>> +                                  "vector length must be enabled.\n");
>>> +                return;
>>> +            }
>>> +            for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
>>> +                if (test_bit(vq - 1, cpu->sve_vq_init)) {
>>> +                    break;
>>> +                }
>>>              }
>>> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>>> +            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
>>>          }
>>> -        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>>>  
>>> -        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
>>>          max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
>>>      }
>>>  
>>> @@ -358,16 +399,48 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>      assert(max_vq != 0);
>>>      bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
>>>  
>>> -    /* Ensure all required powers-of-two are enabled. */
>>> -    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> -        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
>>> -            error_setg(errp, "cannot disable sve%d", vq * 128);
>>> -            error_append_hint(errp, "sve%d is required as it "
>>> -                              "is a power-of-two length smaller than "
>>> -                              "the maximum, sve%d\n",
>>> -                              vq * 128, max_vq * 128);
>>> +    if (kvm_enabled()) {
>>> +        /* Ensure the set of lengths matches what KVM supports. */
>>> +        bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
>>> +        if (!bitmap_empty(tmp, max_vq)) {
>>> +            vq = find_last_bit(tmp, max_vq) + 1;
>>> +            if (test_bit(vq - 1, cpu->sve_vq_map)) {
>>> +                if (cpu->sve_max_vq) {
>>> +                    error_setg(errp, "cannot set sve-max-vq=%d",
>>> +                               cpu->sve_max_vq);
>>> +                    error_append_hint(errp, "This KVM host does not support "
>>> +                                      "the vector length %d-bits.\n",
>>> +                                      vq * 128);
>>> +                    error_append_hint(errp, "It may not be possible to use "
>>> +                                      "sve-max-vq with this KVM host. Try "
>>> +                                      "using only sve<N> properties.\n");
>>> +                } else {
>>> +                    error_setg(errp, "cannot enable sve%d", vq * 128);
>>> +                    error_append_hint(errp, "This KVM host does not support "
>>> +                                      "the vector length %d-bits.\n",
>>> +                                      vq * 128);
>>> +                }
>>> +            } else {
>>> +                error_setg(errp, "cannot disable sve%d", vq * 128);
>> I am not sure about the above message. what is the vq value supposed to
>> be? For instance if we previously entered the
>> "if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {" path
> 
> 'vq' here should be enabled because it's a dependency for the max-vq.
> If the user had enabled it or left it uninitialized (allowing it to
> be auto-enabled) then we wouldn't be here. To get here the user must
> have explicitly disabled it. Hence the 'cannot disable' message.
OK you're right. Got it.

Eric

> 
>>> +                error_append_hint(errp, "The KVM host requires all "
>>> +                                  "supported vector lengths smaller "
>>> +                                  "than %d bits to also be enabled.\n",
>>> +                                  max_vq * 128);
>>> +            }
>>>              return;
>>>          }
>>> +    } else {
>>> +        /* Ensure all required powers-of-two are enabled. */
>>> +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>> +            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
>>> +                error_setg(errp, "cannot disable sve%d", vq * 128);
>>> +                error_append_hint(errp, "sve%d is required as it "
>>> +                                  "is a power-of-two length smaller than "
>>> +                                  "the maximum, sve%d\n",
>>> +                                  vq * 128, max_vq * 128);
>>> +                return;
>>> +            }
>>> +        }
>>>      }
>>>  
>>>      /* From now on sve_max_vq is the actual maximum supported length. */
>>> @@ -411,13 +484,22 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>>>      Error *err = NULL;
>>>  
>>>      visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
>>> +    if (err) {
>>> +        error_propagate(errp, err);
>>> +        return;
>>> +    }
>>>  
>>> -    if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) {
>>> -        error_setg(&err, "unsupported SVE vector length");
>>> -        error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n",
>>> +    if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
>>> +        error_setg(errp, "cannot set sve-max-vq");
>>> +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
>>> +        return;
>>> +    }
>>> +
>>> +    if (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ) {
>>> +        error_setg(errp, "unsupported SVE vector length");
>>> +        error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n",
>>>                            ARM_MAX_VQ);
>>>      }
>>> -    error_propagate(errp, err);
>>>  }
>>>  
>>>  static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
>>> @@ -450,6 +532,12 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
>>>          return;
>>>      }
>>>  
>>> +    if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
>>> +        error_setg(errp, "cannot enable %s", name);
>>> +        error_append_hint(errp, "SVE not supported by KVM on this host\n");
>>> +        return;
>>> +    }
>>> +
>>>      if (value) {
>>>          set_bit(vq - 1, cpu->sve_vq_map);
>>>      } else {
>>> @@ -607,20 +695,19 @@ static void aarch64_max_initfn(Object *obj)
>>>          cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
>>>          cpu->dcz_blocksize = 7; /*  512 bytes */
>>>  #endif
>>> -
>>> -        object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>>> -                            cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
>>> -
>>> -        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>>> -            char name[8];
>>> -            sprintf(name, "sve%d", vq * 128);
>>> -            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
>>> -                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
>>> -        }
>>>      }
>>>  
>>>      object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
>>>                          cpu_arm_set_sve, NULL, NULL, &error_fatal);
>>> +    object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
>>> +                        cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
>>> +
>>> +    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>>> +        char name[8];
>>> +        sprintf(name, "sve%d", vq * 128);
>>> +        object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
>>> +                            cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
>>> +    }
>>>  }
>>>  
>>>  struct ARMCPUInfo {
>>> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
>>> index f96649ae0349..cff4217a8469 100644
>>> --- a/target/arm/kvm64.c
>>> +++ b/target/arm/kvm64.c
>>> @@ -613,6 +613,100 @@ bool kvm_arm_sve_supported(CPUState *cpu)
>>>      return kvm_check_extension(s, KVM_CAP_ARM_SVE);
>>>  }
>>>  
>>> +QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
>>> +
>>> +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
>>> +{
>>> +    /* Only call this function if kvm_arm_sve_supported() returns true. */
>>> +    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
>>> +    static bool probed;
>>> +    uint32_t vq = 0;
>>> +    int i, j;
>>> +
>>> +    bitmap_clear(map, 0, ARM_MAX_VQ);
>>> +
>>> +    /*
>>> +     * KVM ensures all host CPUs support the same set of vector lengths.
>>> +     * So we only need to create the scratch VCPUs once and then cache
>>> +     * the results.
>>> +     */
>>> +    if (!probed) {
>>> +        struct kvm_vcpu_init init = {
>>> +            .target = -1,
>>> +            .features[0] = (1 << KVM_ARM_VCPU_SVE),
>>> +        };
>>> +        struct kvm_one_reg reg = {
>>> +            .id = KVM_REG_ARM64_SVE_VLS,
>>> +            .addr = (uint64_t)&vls[0],
>>> +        };
>>> +        int fdarray[3], ret;
>>> +
>>> +        probed = true;
>>> +
>>> +        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
>>> +            error_report("failed to create scratch VCPU with SVE enabled");
>>> +            abort();
>>> +        }
>>> +        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
>>> +        kvm_arm_destroy_scratch_host_vcpu(fdarray);
>>> +        if (ret) {
>>> +            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
>>> +                         strerror(errno));
>>> +            abort();
>>> +        }
>>> +
>>> +        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
>>> +            if (vls[i]) {
>>> +                vq = 64 - clz64(vls[i]) + i * 64;
>>> +                break;
>>> +            }
>>> +        }
>>> +        if (vq > ARM_MAX_VQ) {
>>> +            warn_report("KVM supports vector lengths larger than "
>>> +                        "QEMU can enable");
>>> +        }
>>> +    }
>>> +
>>> +    for (i = 0; i < KVM_ARM64_SVE_VLS_WORDS; ++i) {
>>> +        if (!vls[i]) {
>>> +            continue;
>>> +        }
>>> +        for (j = 1; j <= 64; ++j) {
>>> +            vq = j + i * 64;
>>> +            if (vq > ARM_MAX_VQ) {
>>> +                return;
>>> +            }
>>> +            if (vls[i] & (1UL << (j - 1))) {
>>> +                set_bit(vq - 1, map);
>>> +            }
>>> +        }
>>> +    }
>>> +}
>>> +
>>> +static int kvm_arm_sve_set_vls(CPUState *cs)
>>> +{
>>> +    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = {0};
>>> +    struct kvm_one_reg reg = {
>>> +        .id = KVM_REG_ARM64_SVE_VLS,
>>> +        .addr = (uint64_t)&vls[0],
>>> +    };
>>> +    ARMCPU *cpu = ARM_CPU(cs);
>>> +    uint32_t vq;
>>> +    int i, j;
>>> +
>>> +    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
>>> +
>>> +    for (vq = 1; vq <= cpu->sve_max_vq; ++vq) {
>>> +        if (test_bit(vq - 1, cpu->sve_vq_map)) {
>>> +            i = (vq - 1) / 64;
>>> +            j = (vq - 1) % 64;
>>> +            vls[i] |= 1UL << j;
>>> +        }
>>> +    }
>>> +
>>> +    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
>>> +}
>>> +
>>>  #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
>>>  
>>>  int kvm_arch_init_vcpu(CPUState *cs)
>>> @@ -624,7 +718,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
>>>  
>>>      if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
>>>          !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
>>> -        fprintf(stderr, "KVM is not supported for this guest CPU type\n");
>>> +        error_report("KVM is not supported for this guest CPU type");
>>>          return -EINVAL;
>>>      }
>>>  
>>> @@ -660,6 +754,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>>>      }
>>>  
>>>      if (cpu_isar_feature(aa64_sve, cpu)) {
>>> +        ret = kvm_arm_sve_set_vls(cs);
>>> +        if (ret) {
>>> +            return ret;
>>> +        }
>>>          ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
>>>          if (ret) {
>>>              return ret;
>>> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
>>> index 1151877f97ea..a1cc6513f72b 100644
>>> --- a/target/arm/kvm_arm.h
>>> +++ b/target/arm/kvm_arm.h
>>> @@ -212,6 +212,17 @@ typedef struct ARMHostCPUFeatures {
>>>   */
>>>  bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
>>>  
>>> +/**
>>> + * kvm_arm_sve_get_vls:
>>> + * @cs: CPUState
>>> + * @map: bitmap to fill in
>>> + *
>>> + * Get all the SVE vector lengths supported by the KVM host, setting
>>> + * the bits corresponding to their length in quadwords minus one
>>> + * (vq - 1) in @map up to ARM_MAX_VQ.
>>> + */
>>> +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
>>> +
>>>  /**
>>>   * kvm_arm_set_cpu_features_from_host:
>>>   * @cpu: ARMCPU to set the features for
>>> @@ -315,6 +326,7 @@ static inline int kvm_arm_vgic_probe(void)
>>>  static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
>>>  static inline void kvm_arm_pmu_init(CPUState *cs) {}
>>>  
>>> +static inline void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map) {}
>>>  #endif
>>>  
>>>  static inline const char *gic_class_name(void)
>>> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
>>> index d50f98cb6aea..a0129aebf409 100644
>>> --- a/tests/arm-cpu-features.c
>>> +++ b/tests/arm-cpu-features.c
>>> @@ -117,6 +117,17 @@ static QDict *resp_get_props(QDict *resp)
>>>      return qdict;
>>>  }
>>>  
>>> +static bool resp_get_feature(QDict *resp, const char *feature)
>>> +{
>>> +    QDict *props;
>>> +
>>> +    g_assert(resp);
>>> +    g_assert(resp_has_props(resp));
>>> +    props = resp_get_props(resp);
>>> +    g_assert(qdict_get(props, feature));
>>> +    return qdict_get_bool(props, feature);
>>> +}
>>> +
>>>  #define assert_has_feature(qts, cpu_type, feature)                     \
>>>  ({                                                                     \
>>>      QDict *_resp = do_query_no_props(qts, cpu_type);                   \
>>> @@ -336,6 +347,25 @@ static void sve_tests_sve_off(const void *data)
>>>      qtest_quit(qts);
>>>  }
>>>  
>>> +static void sve_tests_sve_off_kvm(const void *data)
>>> +{
>>> +    QTestState *qts;
>>> +
>>> +    qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off");
>>> +
>>> +    /*
>>> +     * We don't know if this host supports SVE so we don't
>>> +     * attempt to test enabling anything. We only test that
>>> +     * everything is disabled (as it should be with sve=off)
>>> +     * and that using sve<N>=off to explicitly disable vector
>>> +     * lengths is OK too.
>>> +     */
>>> +    assert_sve_vls(qts, "max", 0, NULL);
>>> +    assert_sve_vls(qts, "max", 0, "{ 'sve128': false }");
>>> +
>>> +    qtest_quit(qts);
>>> +}
>>> +
>>>  static void test_query_cpu_model_expansion(const void *data)
>>>  {
>>>      QTestState *qts;
>>> @@ -385,12 +415,81 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
>>>      assert_has_feature(qts, "host", "pmu");
>>>  
>>>      if (g_str_equal(qtest_get_arch(), "aarch64")) {
>>> +        bool kvm_supports_sve;
>>> +        char max_name[8], name[8];
>>> +        uint32_t max_vq, vq;
>>> +        uint64_t vls;
>>> +        QDict *resp;
>>> +        char *error;
>>> +
>>>          assert_has_feature(qts, "host", "aarch64");
>>> -        assert_has_feature(qts, "max", "sve");
>>>  
>>>          assert_error(qts, "cortex-a15",
>>>              "We cannot guarantee the CPU type 'cortex-a15' works "
>>>              "with KVM on this host", NULL);
>>> +
>>> +        assert_has_feature(qts, "max", "sve");
>>> +        resp = do_query_no_props(qts, "max");
>>> +        kvm_supports_sve = resp_get_feature(resp, "sve");
>>> +        vls = resp_get_sve_vls(resp);
>>> +        qobject_unref(resp);
>>> +
>>> +        if (kvm_supports_sve) {
>>> +            g_assert(vls != 0);
>>> +            max_vq = 64 - __builtin_clzll(vls);
>>> +            sprintf(max_name, "sve%d", max_vq * 128);
>>> +
>>> +            /* Enabling a supported length is of course fine. */
>>> +            assert_sve_vls(qts, "max", vls, "{ %s: true }", max_name);
>>> +
>>> +            /* Get the next supported length smaller than max-vq. */
>>> +            vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
>>> +            if (vq) {
>>> +                /*
>>> +                 * We have at least one length smaller than max-vq,
>>> +                 * so we can disable max-vq.
>>> +                 */
>>> +                assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
>>> +                               "{ %s: false }", max_name);
>>> +
>>> +                /*
>>> +                 * Smaller, supported vector lengths cannot be disabled
>>> +                 * unless all larger, supported vector lengths are also
>>> +                 * disabled.
>>> +                 */
>>> +                sprintf(name, "sve%d", vq * 128);
>>> +                error = g_strdup_printf("cannot disable %s", name);
>>> +                assert_error(qts, "max", error,
>>> +                             "{ %s: true, %s: false }",
>>> +                             max_name, name);
>>> +                g_free(error);
>>> +            }
>>> +
>>> +            /*
>>> +             * The smallest, supported vector length is required, because
>>> +             * we need at least one vector length enabled.
>>> +             */
>>> +            vq = __builtin_ffsll(vls);
>>> +            sprintf(name, "sve%d", vq * 128);
>>> +            error = g_strdup_printf("cannot disable %s", name);
>>> +            assert_error(qts, "max", error, "{ %s: false }", name);
>>> +            g_free(error);
>>> +
>>> +            /* Get an unsupported length. */
>>> +            for (vq = 1; vq <= max_vq; ++vq) {
>>> +                if (!(vls & BIT(vq - 1))) {
>>> +                    break;
>>> +                }
>>> +            }
>>> +            if (vq <= SVE_MAX_VQ) {
>>> +                sprintf(name, "sve%d", vq * 128);
>>> +                error = g_strdup_printf("cannot enable %s", name);
>>> +                assert_error(qts, "max", error, "{ %s: true }", name);
>>> +                g_free(error);
>>> +            }
>>> +        } else {
>>> +            g_assert(vls == 0);
>>> +        }
>>>      } else {
>>>          assert_error(qts, "host",
>>>                       "'pmu' feature not supported by KVM on this host",
>>> @@ -427,6 +526,10 @@ int main(int argc, char **argv)
>>>      if (kvm_available) {
>>>          qtest_add_data_func("/arm/kvm/query-cpu-model-expansion",
>>>                              NULL, test_query_cpu_model_expansion_kvm);
>>> +        if (g_str_equal(qtest_get_arch(), "aarch64")) {
>>> +            qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off",
>>> +                                NULL, sve_tests_sve_off_kvm);
>>> +        }
>>>      }
>>>  
>>>      return g_test_run();
>>>
>> Besides,
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>
>>
> 
> Thanks!
> 
> drew 
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-26  9:34       ` Auger Eric
@ 2019-09-26 11:14         ` Andrew Jones
  0 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-26 11:14 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Sep 26, 2019 at 11:34:45AM +0200, Auger Eric wrote:
> 
> 
> On 9/26/19 10:21 AM, Andrew Jones wrote:
> > On Wed, Sep 25, 2019 at 03:53:42PM +0200, Auger Eric wrote:
> >> Hi Drew,
> >>
> >> On 9/24/19 1:31 PM, Andrew Jones wrote:
> >>> Introduce cpu properties to give fine control over SVE vector lengths.
> >>> We introduce a property for each valid length up to the current
> >>> maximum supported, which is 2048-bits. The properties are named, e.g.
> >>> sve128, sve256, sve384, sve512, ..., where the number is the number of
> >>> bits. See the updates to docs/arm-cpu-features.rst for a description
> >>> of the semantics and for example uses.
> >>>
> >>> Note, as sve-max-vq is still present and we'd like to be able to
> >>> support qmp_query_cpu_model_expansion with guests launched with e.g.
> >>> -cpu max,sve-max-vq=8 on their command lines, then we do allow
> >>> sve-max-vq and sve<N> properties to be provided at the same time, but
> >>> this is not recommended, and is why sve-max-vq is not mentioned in the
> >>> document.  If sve-max-vq is provided then it enables all lengths smaller
> >>> than and including the max and disables all lengths larger. It also has
> >>> the side-effect that no larger lengths may be enabled and that the max
> >>> itself cannot be disabled. Smaller non-power-of-two lengths may,
> >>> however, be disabled, e.g. -cpu max,sve-max-vq=4,sve384=off provides a
> >>> guest the vector lengths 128, 256, and 512 bits.
> >>>
> >>> This patch has been co-authored with Richard Henderson, who reworked
> >>> the target/arm/cpu64.c changes in order to push all the validation and
> >>> auto-enabling/disabling steps into the finalizer, resulting in a nice
> >>> LOC reduction.
> >>>
> >>> Signed-off-by: Andrew Jones <drjones@redhat.com>
> >>> ---
> >>>  docs/arm-cpu-features.rst | 157 +++++++++++++++++++++++++++++--
> >>>  target/arm/cpu.c          |  19 ++++
> >>>  target/arm/cpu.h          |  19 ++++
> >>>  target/arm/cpu64.c        | 190 +++++++++++++++++++++++++++++++++++++-
> >>>  target/arm/helper.c       |  13 ++-
> >>>  target/arm/monitor.c      |  12 +++
> >>>  tests/arm-cpu-features.c  | 189 +++++++++++++++++++++++++++++++++++++
> >>>  7 files changed, 587 insertions(+), 12 deletions(-)
> >>>
> >>> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> >>> index c79dcffb5556..1262fddc6201 100644
> >>> --- a/docs/arm-cpu-features.rst
> >>> +++ b/docs/arm-cpu-features.rst
> >>> @@ -48,18 +48,28 @@ block in the script for usage) is used to issue the QMP commands.
> >>>        (QEMU) query-cpu-model-expansion type=full model={"name":"max"}
> >>>        { "return": {
> >>>          "model": { "name": "max", "props": {
> >>> -        "pmu": true, "aarch64": true
> >>> +        "sve1664": true, "pmu": true, "sve1792": true, "sve1920": true,
> >>> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> >>> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> >>> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> >>> +        "sve896": true, "sve1280": true, "sve2048": true
> >> I don't really understand why this gets printed unsorted as you
> >> registered them in the logical order, any clue?
> > 
> > Maybe qdict hashing? qmp-shell could probably be patched to sort them,
> > but it's probably not worth it.
> OK. Anyway beyond the scope of the series but that's unpractical.
> > 
> >>
> >> Note: This example is given with TCG or KVM with all those vectors
> >> supported by the host.
> > 
> > You want this note to be added? I don't think it's necessary, as it's just
> > an example. A different configuration or different CPU model expansion
> > will have different results, as we explain exhaustively in this document.
> a reader may understand that along with max cpu type whatever the state
> of KVM all sve<N> are supported by default, which is not true in KVM
> case. Maybe add TCG case.

I'll mention above where we have "we started QEMU with
qemu-system-aarch64" that it's using TCG. If I can find some place
where it doesn't break the flow too much, then I'll add a statement
that says all lengths being 'true' is unlikely when KVM is in use.

> > 
> >>>        }}}}
> >>>  
> >>> -We see that the `max` CPU type has the `pmu` and `aarch64` CPU features.
> >>> -We also see that the CPU features are enabled, as they are all `true`.
> >>> +We see that the `max` CPU type has the `pmu`, `aarch64`, `sve`, and many
> >>> +`sve<N>` CPU features.  We also see that all the CPU features are
> >>> +enabled, as they are all `true`.  (The `sve<N>` CPU features are all
> >>> +optional SVE vector lengths.  See "SVE CPU Properties".)
> >>>  
> >>>  (2) Let's try to disable the PMU::
> >>>  
> >>>        (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"pmu":false}}
> >>>        { "return": {
> >>>          "model": { "name": "max", "props": {
> >>> -        "pmu": false, "aarch64": true
> >>> +        "sve1664": true, "pmu": false, "sve1792": true, "sve1920": true,
> >>> +        "sve128": true, "aarch64": true, "sve1024": true, "sve": true,
> >>> +        "sve640": true, "sve768": true, "sve1408": true, "sve256": true,
> >>> +        "sve1152": true, "sve512": true, "sve384": true, "sve1536": true,
> >>> +        "sve896": true, "sve1280": true, "sve2048": true
> >>>        }}}}
> >>>  
> >>>  We see it worked, as `pmu` is now `false`.
> >>> @@ -75,7 +85,22 @@ We see it worked, as `pmu` is now `false`.
> >>>  It looks like this feature is limited to a configuration we do not
> >>>  currently have.
> >>>  
> >>> -(4) Let's try probing CPU features for the Cortex-A15 CPU type::
> >>> +(4) Let's disable `sve` and see what happens to all the optional SVE
> >>> +    vector lengths::
> >>> +
> >>> +      (QEMU) query-cpu-model-expansion type=full model={"name":"max","props":{"sve":false}}
> >>> +      { "return": {
> >>> +        "model": { "name": "max", "props": {
> >>> +        "sve1664": false, "pmu": true, "sve1792": false, "sve1920": false,
> >>> +        "sve128": false, "aarch64": true, "sve1024": false, "sve": false,
> >>> +        "sve640": false, "sve768": false, "sve1408": false, "sve256": false,
> >>> +        "sve1152": false, "sve512": false, "sve384": false, "sve1536": false,
> >>> +        "sve896": false, "sve1280": false, "sve2048": false
> >>> +      }}}}
> >>> +
> >>> +As expected they are now all `false`.
> >>> +
> >>> +(5) Let's try probing CPU features for the Cortex-A15 CPU type::
> >>>  
> >>>        (QEMU) query-cpu-model-expansion type=full model={"name":"cortex-a15"}
> >>>        {"return": {"model": {"name": "cortex-a15", "props": {"pmu": true}}}}
> >>> @@ -131,7 +156,125 @@ After determining which CPU features are available and supported for a
> >>>  given CPU type, then they may be selectively enabled or disabled on the
> >>>  QEMU command line with that CPU type::
> >>>  
> >>> -  $ qemu-system-aarch64 -M virt -cpu max,pmu=off
> >>> +  $ qemu-system-aarch64 -M virt -cpu max,pmu=off,sve=on,sve128=on,sve256=on
> >>> +
> >>> +The example above disables the PMU and enables the first two SVE vector
> >>> +lengths for the `max` CPU type.  Note, the `sve=on` isn't actually
> >>> +necessary, because, as we observed above with our probe of the `max` CPU
> >>> +type, `sve` is already on by default.
> 
> >>
> >> This holds with TCG and not KVM.
> > 
> > It also holds with KVM, as long as the host supports SVE.
> as long as the hist supports SVE: Yes that's what I meant
> 
> maybe add, as we observed abovewith our probe of the `max` CPU
> >>> +type, in this TCG case, `sve` is already on by default

But "in this TCG case, `sve` is already on by default" implies that it
won't be on by default with KVM. However it will be, when KVM supports
the feature. I don't like adding "but ..., if ..."'s everywhere because
then readers can't get through a paragraph without having to double
think everything. We're presenting a single example here, so we shouldn't
try to introduce another example (the same thing, but with KVM, when KVM
supports the feature) in its description. If you think we should add
another example for KVM, then we should do it separately. I'd argue it's
not really necessary to do though. Although a couple sentences at the top
that emphasize this is a single TCG example, and with KVM things are
different, might be good.

> 
>  But that doesn't
> > matter, because we're speaking specifically about the example above here,
> > where we see that sve=on is the default. 
> > 
> >>
> >> Also, based on our probe of
> >>> +defaults, it would seem we need to disable many SVE vector lengths, rather
> >>> +than only enabling the two we want.  This isn't the case, because, as
> >>> +disabling many SVE vector lengths would be quite verbose, the `sve<N>` CPU
> >>> +properties have special semantics (see "SVE CPU Property Parsing
> >>> +Semantics").
> >>> +
> >>> +SVE CPU Properties
> >>> +==================
> >>> +
> >>> +There are two types of SVE CPU properties: `sve` and `sve<N>`.  The first
> >>> +is used to enable or disable the entire SVE feature, just as the `pmu`
> >>> +CPU property completely enables or disables the PMU.  The second type
> >>> +is used to enable or disable specific vector lengths, where `N` is the
> >>> +number of bits of the length.  The `sve<N>` CPU properties have special
> >>> +dependencies and constraints, see "SVE CPU Property Dependencies and
> >>> +Constraints" below.  Additionally, as we want all supported vector lengths
> >>> +to be enabled by default, then, in order to avoid overly verbose command
> >>> +lines (command lines full of `sve<N>=off`, for all `N` not wanted), we
> >>> +provide the parsing semantics listed in "SVE CPU Property Parsing
> >>> +Semantics".
> >>> +
> >>> +SVE CPU Property Dependencies and Constraints
> >>> +---------------------------------------------
> >>> +
> >>> +  1) At least one vector length must be enabled when `sve` is enabled.> +
> >>> +  2) If a vector length `N` is enabled, then all power-of-two vector
> >>> +     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> >>> +     is enabled, then `sve128` and `sve256` must also be enabled,
> >>> +     but `sve384` is not required.
> >> I would remove the eg. part. reading that I tend to understand that the
> >> user must pass ,sve128=on, sve256=on and sve512=on whereas example 6
> >> says only sve512=on can be set and other lower ^2 values are auto-enabled.
> > 
> > I'll keep the example, but instead of using the property names, I'll
> > change to using "the 128-bit vector length", 256-bit ..., etc.
> ok
> > 
> >>> +
> >>> +SVE CPU Property Parsing Semantics
> >>> +----------------------------------
> >>> +
> >>> +  1) If SVE is disabled (`sve=off`), then which SVE vector lengths
> >>> +     are enabled or disabled is irrelevant to the guest, as the entire
> >>> +     SVE feature is disabled and that disables all vector lengths for
> >>> +     the guest.  However QEMU will still track any `sve<N>` CPU
> >>> +     properties provided by the user.  If later an `sve=on` is provided,
> >>> +     then the guest will get only the enabled lengths.
> >>> +
> >>> +  2) If SVE is enabled (`sve=on`), but no `sve<N>` CPU properties are
> >>> +     provided, then all supported vector lengths are enabled.
> >> I understand from the code it also includes non ^2 values which is not
> >> obvious.
> > 
> > Yes, the default is to have *all* supported vector lengths enabled, not
> > just the power-of-two. As we already use the word 'all' here, then how
> > can we further clarify this?
> I would simply add "including non ^2 values".

OK, but these precise descriptions get pretty long, especially when you
add KVM. For TCG it's just 'including the non power-of-two lengths', but
then when we add KVM, which from QEMU's point of view decides what's
supported and power-of-two's have nothing to do with it, we get

 ...all supported vector lengths, which when KVM is not in use means
 including the non power-of-two lengths, and, when KVM is in use,
 it means all vector lengths supported by the host processor.

I'll add that for v5. I just hope people don't end up always 'tl;dr'ing
this document...

> > 
> >>> +
> >>> +  3) If SVE is enabled, then an error is generated when attempting to
> >>> +     disable the last enabled vector length (see constraint (1) of "SVE
> >>> +     CPU Property Dependencies and Constraints").
> >> the same happens if you attempt to disabled any lower ^2 value
> > 
> > That should be another bullet, which I appear to be missing, and will add.
> > 
> >>> +
> >>> +  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> >>> +     CPU properties are set `on`, then the specified vector lengths are
> >>> +     disabled but the default for any unspecified lengths remains enabled.
> >>> +     Disabling a power-of-two vector length also disables all vector
> >>> +     lengths larger than the power-of-two length (see constraint (2) of
> >>> +     "SVE CPU Property Dependencies and Constraints").
> >> So rephasing it:
> >> disabling a non ^2 value only disable that one
> >> disabling a ^2 value disables all larger lengths too
> >> is that correct?
> > 
> > That's correct. We auto-disable all uninitialized larger lengths when a
> > power-of-two dependency length is explicitly disabled.
> > 
> >>
> >>> +
> >>> +  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> >>> +     are enabled and all unspecified lengths default to disabled, except
> >>> +     for the required lengths per constraint (2) of "SVE CPU Property
> >>> +     Dependencies and Constraints", which will even be auto-enabled if
> >>> +     they were not explicitly enabled.
> >>> +
> >>> +  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> >>> +     explicitly disabled (i.e. avoiding the error specified in (3) of
> >>> +     "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
> >>> +     provided an error will be generated.  To avoid this error, one must
> >>> +     enable at least one vector length prior to enabling SVE.
> >>> +
> >>> +SVE CPU Property Examples
> >>> +-------------------------
> >>> +
> >>> +  1) Disable SVE::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off
> >>> +
> >>> +  2) Implicitly enable all vector lengths for the `max` CPU type::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max
> >>> +
> >>> +  3) Only enable the 128-bit vector length::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on
> >>> +
> >>> +  4) Disable the 256-bit vector length and all larger vector lengths
> >>> +     since 256 is a power-of-two (this results in only the 128-bit length
> >>> +     being enabled)::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve256=off
> >>> +
> >>> +  5) Enable the 128-bit, 256-bit, and 512-bit vector lengths::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=on,sve256=on,sve512=on
> >>> +
> >>> +  6) The same as (5), but since the 128-bit and 256-bit vector
> >>> +     lengths are required for the 512-bit vector length to be enabled,
> >>> +     then allow them to be auto-enabled::> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve512=on
> >>
> >> You should also document
> >> $ qemu-system-aarch64 -M virt -cpu max,sve512=off
> >> as in that case this result in 128, 256 and 384. the fact you get non ^2
> >> values is not obvious here because if you enable a ^2 value you onlt get
> >> <= ^2 values.
> yep.
> > 
> > I can change (4) above to use 512 instead of 256.
> > 
> >>> +
> >>> +  7) Do the same as (6), but by first disabling SVE and then re-enabling it::
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve512=on,sve=on> +
> >>> +  8) Force errors regarding the last vector length::
> >> You mean those commands will generate errors, right?
> > 
> > Yes
> > 
> >>> +
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve128=off
> >>> +     $ qemu-system-aarch64 -M virt -cpu max,sve=off,sve128=off,sve=on
> >>> +
> >>> +SVE CPU Property Recommendations
> >>> +--------------------------------
> >>>  
> >>> -The example above disables the PMU for the `max` CPU type.
> >>> +The examples in "SVE CPU Property Examples" exhibit many ways to select
> >>> +vector lengths which developers may find useful in order to avoid overly
> >>> +verbose command lines.  However, the recommended way to select vector
> >>> +lengths is to explicitly enable each desired length.  Therefore only
> >>> +example's (1), (3), and (5) exhibit recommended uses of the properties.
> >>>  
> >>> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> >>> index 73be2ebfdd39..522fed95b339 100644
> >>> --- a/target/arm/cpu.c
> >>> +++ b/target/arm/cpu.c
> >>> @@ -1199,6 +1199,19 @@ static void arm_cpu_finalizefn(Object *obj)
> >>>  #endif
> >>>  }
> >>>  
> >>> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
> >>> +{
> >>> +    Error *local_err = NULL;
> >>> +
> >>> +    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> >>> +        arm_cpu_sve_finalize(cpu, &local_err);
> >>> +        if (local_err != NULL) {
> >> nit: !local_err
> >>> +            error_propagate(errp, local_err);
> >>> +            return;
> >> not needed
> > 
> > Yet. I expect a chain of finalizers to go here, so we'll want the 'return'
> > when we get the next one. As it doesn't hurt, it might as well go in now.
> > 
> >>> +        }
> >>> +    }
> >>> +}
> >>> +
> >>>  static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
> >>>  {
> >>>      CPUState *cs = CPU(dev);
> >>> @@ -1255,6 +1268,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
> >>>          return;
> >>>      }
> >>>  
> >>> +    arm_cpu_finalize_features(cpu, &local_err);
> >>> +    if (local_err != NULL) {
> >> same
> >>> +        error_propagate(errp, local_err);
> >>> +        return;> +    }
> >>> +
> >>>      if (arm_feature(env, ARM_FEATURE_AARCH64) &&
> >>>          cpu->has_vfp != cpu->has_neon) {
> >>>          /*
> >>> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> >>> index 297ad5e47ad8..11162484465a 100644
> >>> --- a/target/arm/cpu.h
> >>> +++ b/target/arm/cpu.h
> >>> @@ -184,8 +184,13 @@ typedef struct {
> >>>  
> >>>  #ifdef TARGET_AARCH64
> >>>  # define ARM_MAX_VQ    16
> >>> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
> >>> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq);
> >>>  #else
> >>>  # define ARM_MAX_VQ    1
> >>> +static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
> >>> +static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> >>> +{ return 0; }
> >>>  #endif
> >>>  
> >>>  typedef struct ARMVectorReg {
> >>> @@ -915,6 +920,18 @@ struct ARMCPU {
> >>>  
> >>>      /* Used to set the maximum vector length the cpu will support.  */
> >>>      uint32_t sve_max_vq;
> >>> +
> >>> +    /*
> >>> +     * In sve_vq_map each set bit is a supported vector length of
> >>> +     * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
> >>> +     * length in quadwords.
> >>> +     *
> >>> +     * While processing properties during initialization, corresponding
> >>> +     * sve_vq_init bits are set for bits in sve_vq_map that have been
> >>> +     * set by properties.
> >>> +     */
> >>> +    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
> >>> +    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
> >>>  };
> >>>  
> >>>  void arm_cpu_post_init(Object *obj);
> >>> @@ -1834,6 +1851,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
> >>>      return (env->features & (1ULL << feature)) != 0;
> >>>  }
> >>>  
> >>> +void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
> >>> +
> >>>  #if !defined(CONFIG_USER_ONLY)
> >>>  /* Return true if exception levels below EL3 are in secure state,
> >>>   * or would be following an exception return to that level.
> >>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> >>> index 8cdb0c79fa7a..606e3eceb9c0 100644
> >>> --- a/target/arm/cpu64.c
> >>> +++ b/target/arm/cpu64.c
> >>> @@ -256,11 +256,152 @@ static void aarch64_a72_initfn(Object *obj)
> >>>      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
> >>>  }
> >>>  
> >>> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >>> +{
> >>> +    /*
> >>> +     * If any vector lengths are explicitly enabled with sve<N> properties,
> >>> +     * then all other lengths are implicitly disabled.  If sve-max-vq is
> >>> +     * specified then it is the same as explicitly enabling all lengths
> >>> +     * up to and including the specified maximum, which means all larger
> >>> +     * lengths will be implicitly disabled.  If no sve<N> properties
> >>> +     * are enabled and sve-max-vq is not specified, then all lengths not
> >>> +     * explicitly disabled will be enabled.  Additionally, all power-of-two
> >>> +     * vector lengths less than the maximum enabled length will be
> >>> +     * automatically enabled and all vector lengths larger than the largest
> >>> +     * disabled power-of-two vector length will be automatically disabled.
> >>> +     * Errors are generated if the user provided input that interferes with
> >>> +     * any of the above.  Finally, if SVE is not disabled, then at least one
> >>> +     * vector length must be enabled.
> >>> +     */
> >>> +    DECLARE_BITMAP(tmp, ARM_MAX_VQ);
> >>> +    uint32_t vq, max_vq = 0;
> >>> +
> >>> +    /*
> >>> +     * Process explicit sve<N> properties.
> >>> +     * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> >>> +     * Check first for any sve<N> enabled.
> >>> +     */
> >>> +    if (!bitmap_empty(cpu->sve_vq_map, ARM_MAX_VQ)) {
> >>> +        max_vq = find_last_bit(cpu->sve_vq_map, ARM_MAX_VQ) + 1;
> >>> +
> >>> +        if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) {
> >>> +            error_setg(errp, "cannot enable sve%d", max_vq * 128);
> >>> +            error_append_hint(errp, "sve%d is larger than the maximum vector "
> >>> +                              "length, sve-max-vq=%d (%d bits)\n",
> >>> +                              max_vq * 128, cpu->sve_max_vq,
> >>> +                              cpu->sve_max_vq * 128);
> >> you could test directly if max_vq < cpu->sve_max_vq too which couldn't
> > 
> > That's not an error. Here max_vq is the maximum enabled with sve<N>
> > properties. We haven't considered cpu->sve_max_vq yet, except for
> > ensuring we don't enable something larger than it.
> Oh ok I had in mind sve512=on,sve-max-vq=5 was an error but reading the
> code again it is indeed value. My original thought was setting sve<n>
> was disabling larger values but that's only valid with sve-max-vq unset.
> > 
> >> be correct either. But as far as I understand this is caught in *
> >>> +            return;
> >>> +        }
> >>> +
> >>> +        /* Propagate enabled bits down through required powers-of-two. */
> >>> +        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> >>> +            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> >>> +                set_bit(vq - 1, cpu->sve_vq_map);
> >>> +            }
> >>> +        }
> >>> +    } else if (cpu->sve_max_vq == 0) {
> >>> +        /*
> >>> +         * No explicit bits enabled, and no implicit bits from sve-max-vq.
> >>> +         */
> >>> +        if (!cpu_isar_feature(aa64_sve, cpu)) {
> >>> +            /* SVE is disabled and so are all vector lengths.  Good. */
> >>> +            return;
> >>> +        }
> >>> +
> >>> +        /* Disabling a power-of-two disables all larger lengths. */
> >>> +        if (test_bit(0, cpu->sve_vq_init)) {> +            error_setg(errp, "cannot disable sve128");
> >>> +            error_append_hint(errp, "Disabling sve128 results in all vector "
> >>> +                              "lengths being disabled.\n");
> >>> +            error_append_hint(errp, "With SVE enabled, at least one vector "
> >>> +                              "length must be enabled.\n");
> >>> +            return;
> >>> +        }
> >>> +        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> >>> +            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> >>> +                break;
> >>> +            }
> >>> +        }
> >>> +        max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> >>> +
> >>> +        bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> >>> +        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
> >>> +    }
> >>> +
> >>> +    /*
> >>> +     * Process the sve-max-vq property.
> >>> +     * Note that we know from the above that no bit above
> >>> +     * sve-max-vq is currently set.
> >>> +     */
> >>> +    if (cpu->sve_max_vq != 0) {
> >>> +        max_vq = cpu->sve_max_vq;
> >>> +
> >>> +        if (!test_bit(max_vq - 1, cpu->sve_vq_map) &&
> >>> +            test_bit(max_vq - 1, cpu->sve_vq_init)) {
> >>> +            error_setg(errp, "cannot disable sve%d", max_vq * 128);
> >>> +            error_append_hint(errp, "The maximum vector length must be "
> >>> +                              "enabled, sve-max-vq=%d (%d bits)\n",
> >>> +                              max_vq, max_vq * 128);
> >>> +            return;
> >>> +        }
> >>> +
> >>> +        /* Set all bits not explicitly set within sve-max-vq. */
> >>> +        bitmap_complement(tmp, cpu->sve_vq_init, max_vq);
> >>> +        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> >>> +    }
> >>> +
> >>> +    /*
> >>> +     * We should know what max-vq is now.  Also, as we're done
> >>> +     * manipulating sve-vq-map, we ensure any bits above max-vq
> >>> +     * are clear, just in case anybody looks.
> >>> +     */
> >>> +    assert(max_vq != 0);
> >>> +    bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
> >>> +
> >>> +    /* Ensure all required powers-of-two are enabled. */
> >>> +    for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> >>> +        if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> >>> +            error_setg(errp, "cannot disable sve%d", vq * 128);
> >>> +            error_append_hint(errp, "sve%d is required as it "
> >>> +                              "is a power-of-two length smaller than "
> >>> +                              "the maximum, sve%d\n",
> >>> +                              vq * 128, max_vq * 128);
> >> * I think this will also catches the case where ,sve512=on,sve-max-vq=5
> >> where the end-user did not explicitly disabled anything
> > 
> > As stated above, 'sve512=on,sve-max-vq=5' isn't an error. It doesn't hurt
> > to enable vector lengths explicitly that would be enabled automatically
> > anyway with the sve-max-vq property.
> Now understood.
> > 
> > 
> >>> +            return;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    /* From now on sve_max_vq is the actual maximum supported length. */
> >>> +    cpu->sve_max_vq = max_vq;
> >>> +}
> >>> +
> >>> +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
> >>> +{
> >>> +    uint32_t bitnum;
> >>> +
> >>> +    /*
> >>> +     * We allow vq == ARM_MAX_VQ + 1 to be input because the caller may want
> >>> +     * to find the maximum vq enabled, which may be ARM_MAX_VQ, but this
> >>> +     * function always returns the next smaller than the input.
> >>> +     */
> >>> +    assert(vq && vq <= ARM_MAX_VQ + 1);
> >>> +
> >>> +    bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
> >>> +    return bitnum == vq - 1 ? 0 : bitnum + 1;
> >>> +}
> >>> +
> >>>  static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
> >>>                                     void *opaque, Error **errp)
> >>>  {
> >>>      ARMCPU *cpu = ARM_CPU(obj);
> >>> -    visit_type_uint32(v, name, &cpu->sve_max_vq, errp);
> >>> +    uint32_t value;
> >> Shouldn't it be part of the previous patch?
> > 
> > Yes. Will fix for v5.
> > 
> >>> +
> >>> +    /* All vector lengths are disabled when SVE is off. */
> >>> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> >>> +        value = 0;
> >>> +    } else {
> >>> +        value = cpu->sve_max_vq;
> >>> +    }
> >>> +    visit_type_uint32(v, name, &value, errp);
> >>>  }
> >>>  
> >>>  static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> >>> @@ -279,6 +420,44 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
> >> Independently on this patch I noticed that if sve_max_vq is out of
> >> scope, an error is propagated but still the cpu->sve-max_vq is set.
> > 
> > I'll sneak that fix into patch 8/9 where we touch the function anyway.
> > 
> >>>      error_propagate(errp, err);
> >>>  }
> >>>  
> >>> +static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> >>> +                               void *opaque, Error **errp)
> >>> +{
> >>> +    ARMCPU *cpu = ARM_CPU(obj);
> >>> +    uint32_t vq = atoi(&name[3]) / 128;
> >>> +    bool value;
> >>> +
> >>> +    /* All vector lengths are disabled when SVE is off. */
> >>> +    if (!cpu_isar_feature(aa64_sve, cpu)) {
> >>> +        value = false;
> >>> +    } else {
> >>> +        value = test_bit(vq - 1, cpu->sve_vq_map);
> >>> +    }
> >>> +    visit_type_bool(v, name, &value, errp);
> >>> +}
> >>> +
> >>> +static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
> >>> +                               void *opaque, Error **errp)
> >>> +{
> >>> +    ARMCPU *cpu = ARM_CPU(obj);
> >>> +    uint32_t vq = atoi(&name[3]) / 128;
> >>> +    Error *err = NULL;
> >>> +    bool value;
> >>> +
> >>> +    visit_type_bool(v, name, &value, &err);
> >>> +    if (err) {
> >>> +        error_propagate(errp, err);
> >>> +        return;
> >>> +    }
> >>> +
> >>> +    if (value) {
> >>> +        set_bit(vq - 1, cpu->sve_vq_map);
> >>> +    } else {
> >>> +        clear_bit(vq - 1, cpu->sve_vq_map);
> >>> +    }
> >>> +    set_bit(vq - 1, cpu->sve_vq_init);
> >>> +}
> >>> +
> >>>  static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
> >>>                              void *opaque, Error **errp)
> >>>  {
> >>> @@ -315,6 +494,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
> >>>  static void aarch64_max_initfn(Object *obj)
> >>>  {
> >>>      ARMCPU *cpu = ARM_CPU(obj);
> >>> +    uint32_t vq;
> >>>  
> >>>      if (kvm_enabled()) {
> >>>          kvm_arm_set_cpu_features_from_host(cpu);
> >>> @@ -418,11 +598,17 @@ static void aarch64_max_initfn(Object *obj)
> >>>          cpu->dcz_blocksize = 7; /*  512 bytes */
> >>>  #endif
> >>>  
> >>> -        cpu->sve_max_vq = ARM_MAX_VQ;
> >>>          object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
> >>>                              cpu_max_set_sve_max_vq, NULL, NULL, &error_fatal);
> >>>          object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
> >>>                              cpu_arm_set_sve, NULL, NULL, &error_fatal);
> >>> +
> >>> +        for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> >>> +            char name[8];
> >>> +            sprintf(name, "sve%d", vq * 128);
> >>> +            object_property_add(obj, name, "bool", cpu_arm_get_sve_vq,
> >>> +                                cpu_arm_set_sve_vq, NULL, NULL, &error_fatal);
> >>> +        }
> >>>      }
> >>>  }
> >>>  
> >>> diff --git a/target/arm/helper.c b/target/arm/helper.c
> >>> index 507026c9154b..f33284c247d5 100644
> >>> --- a/target/arm/helper.c
> >>> +++ b/target/arm/helper.c
> >>> @@ -5351,6 +5351,13 @@ int sve_exception_el(CPUARMState *env, int el)
> >>>      return 0;
> >>>  }
> >>>  
> >>> +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
> >>> +{
> >>> +    uint32_t start_vq = (start_len & 0xf) + 1;
> >>> +
> >>> +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
> >>> +}
> >>> +
> >>>  /*
> >>>   * Given that SVE is enabled, return the vector length for EL.
> >>>   */
> >>> @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
> >>>      uint32_t zcr_len = cpu->sve_max_vq - 1;
> >>>  
> >>>      if (el <= 1) {
> >>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
> >>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
> >>>      }
> >>>      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
> >>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
> >>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
> >>>      }
> >>>      if (arm_feature(env, ARM_FEATURE_EL3)) {
> >>> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
> >>> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
> >>>      }
> >>>      return zcr_len;
> >>>  }
> >>> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> >>> index 4fddb6c252a3..e912ed2cefa0 100644
> >>> --- a/target/arm/monitor.c
> >>> +++ b/target/arm/monitor.c
> >>> @@ -90,6 +90,8 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
> >>>      return head;
> >>>  }
> >>>  
> >>> +QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
> >>> +
> >>>  /*
> >>>   * These are cpu model features we want to advertise. The order here
> >>>   * matters as this is the order in which qmp_query_cpu_model_expansion
> >>> @@ -98,6 +100,9 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
> >>>   */
> >>>  static const char *cpu_model_advertised_features[] = {
> >>>      "aarch64", "pmu", "sve",
> >>> +    "sve128", "sve256", "sve384", "sve512",
> >>> +    "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
> >>> +    "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
> >>>      NULL
> >>>  };
> >>>  
> >>> @@ -185,6 +190,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> >>>          if (!err) {
> >>>              visit_check_struct(visitor, &err);
> >>>          }
> >>> +        if (!err) {
> >>> +            arm_cpu_finalize_features(ARM_CPU(obj), &err);
> >>> +        }
> >>>          visit_end_struct(visitor, NULL);
> >>>          visit_free(visitor);
> >>>          if (err) {
> >>> @@ -192,6 +200,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> >>>              error_propagate(errp, err);
> >>>              return NULL;
> >>>          }
> >>> +    } else {
> >>> +        Error *err = NULL;
> >>> +        arm_cpu_finalize_features(ARM_CPU(obj), &err);
> >>> +        assert(err == NULL);
> >>>      }
> >>>  
> >>>      expansion_info = g_new0(CpuModelExpansionInfo, 1);
> >>> diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
> >>> index 202bc0e3e823..9a2dd402b769 100644
> >>> --- a/tests/arm-cpu-features.c
> >>> +++ b/tests/arm-cpu-features.c
> >>> @@ -13,6 +13,18 @@
> >>>  #include "qapi/qmp/qdict.h"
> >>>  #include "qapi/qmp/qjson.h"
> >>>  
> >>> +#if __SIZEOF_LONG__ == 8
> >>> +#define BIT(n) (1UL << (n))
> >>> +#else
> >>> +#define BIT(n) (1ULL << (n))
> >>> +#endif
> >>> +
> >>> +/*
> >>> + * We expect the SVE max-vq to be 16. Also it must be <= 64
> >>> + * for our test code, otherwise 'vls' can't just be a uint64_t.
> >>> + */
> >>> +#define SVE_MAX_VQ 16
> >>> +
> >>>  #define MACHINE    "-machine virt,gic-version=max "
> >>>  #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \
> >>>                       "'arguments': { 'type': 'full', "
> >>> @@ -157,6 +169,173 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type)
> >>>      qobject_unref(resp);
> >>>  }
> >>>  
> >>> +static uint64_t resp_get_sve_vls(QDict *resp)
> >>> +{
> >>> +    QDict *props;
> >>> +    const QDictEntry *e;
> >>> +    uint64_t vls = 0;
> >>> +    int n = 0;
> >>> +
> >>> +    g_assert(resp);
> >>> +    g_assert(resp_has_props(resp));
> >>> +
> >>> +    props = resp_get_props(resp);
> >>> +
> >>> +    for (e = qdict_first(props); e; e = qdict_next(props, e)) {
> >>> +        if (strlen(e->key) > 3 && !strncmp(e->key, "sve", 3) &&
> >>> +            g_ascii_isdigit(e->key[3])) {
> >>> +            char *endptr;
> >>> +            int bits;
> >>> +
> >>> +            bits = g_ascii_strtoll(&e->key[3], &endptr, 10);
> >>> +            if (!bits || *endptr != '\0') {
> >>> +                continue;
> >>> +            }
> >>> +
> >>> +            if (qdict_get_bool(props, e->key)) {
> >>> +                vls |= BIT((bits / 128) - 1);
> >>> +            }
> >>> +            ++n;
> >>> +        }
> >>> +    }
> >>> +
> >>> +    g_assert(n == SVE_MAX_VQ);
> >>> +
> >>> +    return vls;
> >>> +}
> >>> +
> >>> +#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...)          \
> >>> +({                                                                     \
> >>> +    QDict *_resp = do_query(qts, cpu_type, fmt, ##__VA_ARGS__);        \
> >>> +    g_assert(_resp);                                                   \
> >>> +    g_assert(resp_has_props(_resp));                                   \
> >>> +    g_assert(resp_get_sve_vls(_resp) == expected_vls);                 \
> >>> +    qobject_unref(_resp);                                              \
> >>> +})
> >>> +
> >>> +static void sve_tests_default(QTestState *qts, const char *cpu_type)
> >>> +{
> >>> +    /*
> >>> +     * With no sve-max-vq or sve<N> properties on the command line
> >>> +     * the default is to have all vector lengths enabled. This also
> >>> +     * tests that 'sve' is 'on' by default.
> >>> +     */
> >>> +    assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL);
> >>> +
> >>> +    /* With SVE off, all vector lengths should also be off. */
> >>> +    assert_sve_vls(qts, cpu_type, 0, "{ 'sve': false }");
> >>> +
> >>> +    /* With SVE on, we must have at least one vector length enabled. */
> >>> +    assert_error(qts, cpu_type, "cannot disable sve128", "{ 'sve128': false }");
> >>> +
> >>> +    /*
> >>> +     * ---------------------------------------------------------------------
> >>> +     *               power-of-two(vq)   all-power-            can      can
> >>> +     *                                  of-two(< vq)        enable   disable
> >>> +     * ---------------------------------------------------------------------
> >>> +     * vq < max_vq      no                MUST*              yes      yes
> >>> +     * vq < max_vq      yes               MUST*              yes      no
> >>> +     * ---------------------------------------------------------------------
> >>> +     * vq == max_vq     n/a               MUST*              yes**    yes**
> >>> +     * ---------------------------------------------------------------------
> >>> +     * vq > max_vq      n/a               no                 no       yes
> >>> +     * vq > max_vq      n/a               yes                yes      yes
> >>> +     * ---------------------------------------------------------------------
> >>> +     *
> >>> +     * [*] "MUST" means this requirement must already be satisfied,
> >>> +     *     otherwise 'max_vq' couldn't itself be enabled.
> >>> +     *
> >>> +     * [**] Not testable with the QMP interface, only with the command line.
> >>> +     */
> >>> +
> >>> +    /* max_vq := 8 */
> >>> +    assert_sve_vls(qts, cpu_type, 0x8b, "{ 'sve1024': true }");
> >>> +
> >>> +    /* max_vq := 8, vq < max_vq, !power-of-two(vq) */
> >>> +    assert_sve_vls(qts, cpu_type, 0x8f,
> >>> +                   "{ 'sve1024': true, 'sve384': true }");
> >>> +    assert_sve_vls(qts, cpu_type, 0x8b,
> >>> +                   "{ 'sve1024': true, 'sve384': false }");
> >>> +
> >>> +    /* max_vq := 8, vq < max_vq, power-of-two(vq) */
> >>> +    assert_sve_vls(qts, cpu_type, 0x8b,
> >>> +                   "{ 'sve1024': true, 'sve256': true }");
> >>> +    assert_error(qts, cpu_type, "cannot disable sve256",
> >>> +                 "{ 'sve1024': true, 'sve256': false }");
> >>> +
> >>> +    /* max_vq := 3, vq > max_vq, !all-power-of-two(< vq) */
> >>> +    assert_error(qts, cpu_type, "cannot disable sve512",
> >>> +                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
> >>> +
> >>> +    /*
> >>> +     * We can disable power-of-two vector lengths when all larger lengths
> >>> +     * are also disabled. We only need to disable the power-of-two length,
> >>> +     * as all non-enabled larger lengths will then be auto-disabled.
> >>> +     */
> >>> +    assert_sve_vls(qts, cpu_type, 0x7, "{ 'sve512': false }");
> >>> +
> >>> +    /* max_vq := 3, vq > max_vq, all-power-of-two(< vq) */
> >>> +    assert_sve_vls(qts, cpu_type, 0x1f,
> >>> +                   "{ 'sve384': true, 'sve512': true, 'sve640': true }");
> >>> +    assert_sve_vls(qts, cpu_type, 0xf,
> >>> +                   "{ 'sve384': true, 'sve512': true, 'sve640': false }");
> >>> +}
> >>> +
> >>> +static void sve_tests_sve_max_vq_8(const void *data)
> >>> +{
> >>> +    QTestState *qts;
> >>> +
> >>> +    qts = qtest_init(MACHINE "-cpu max,sve-max-vq=8");
> >>> +
> >>> +    assert_sve_vls(qts, "max", BIT(8) - 1, NULL);
> >>> +
> >>> +    /*
> >>> +     * Disabling the max-vq set by sve-max-vq is not allowed, but
> >>> +     * of course enabling it is OK.
> >>> +     */
> >>> +    assert_error(qts, "max", "cannot disable sve1024", "{ 'sve1024': false }");
> >>> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1024': true }");
> >>> +
> >>> +    /*
> >>> +     * Enabling anything larger than max-vq set by sve-max-vq is not
> >>> +     * allowed, but of course disabling everything larger is OK.
> >>> +     */
> >>> +    assert_error(qts, "max", "cannot enable sve1152", "{ 'sve1152': true }");
> >>> +    assert_sve_vls(qts, "max", 0xff, "{ 'sve1152': false }");
> >>> +
> >>> +    /*
> >>> +     * We can disable non power-of-two lengths smaller than the max-vq
> >>> +     * set by sve-max-vq, but not power-of-two lengths.
> >>> +     */
> >>> +    assert_sve_vls(qts, "max", 0xfb, "{ 'sve384': false }");
> >> you can also test ,sve384=on => 0x7
> > 
> > We wouldn't get 0x7, we'd get 0xff. I could still add the test to ensure
> > we can enable smaller vector lengths without an error though.
> Oh yes because you have the sve-max-vq=8
> I rather meant in sve_tests_default then

I can add to both.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-26 10:01       ` Auger Eric
@ 2019-09-26 11:40         ` Andrew Jones
  2019-09-26 11:50           ` Auger Eric
  0 siblings, 1 reply; 32+ messages in thread
From: Andrew Jones @ 2019-09-26 11:40 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Sep 26, 2019 at 12:01:36PM +0200, Auger Eric wrote:
> 
> 
> On 9/26/19 10:41 AM, Andrew Jones wrote:
> > On Thu, Sep 26, 2019 at 08:52:55AM +0200, Auger Eric wrote:
> >> Hi Drew,
> >>
> >> On 9/24/19 1:31 PM, Andrew Jones wrote:
> >>> Extend the SVE vq map initialization and validation with KVM's
> >>> supported vector lengths when KVM is enabled. In order to determine
> >>> and select supported lengths we add two new KVM functions for getting
> >>> and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.
> >>>
> >>> This patch has been co-authored with Richard Henderson, who reworked
> >>> the target/arm/cpu64.c changes in order to push all the validation and
> >>> auto-enabling/disabling steps into the finalizer, resulting in a nice
> >>> LOC reduction.
> >>>
> >>> Signed-off-by: Andrew Jones <drjones@redhat.com>
> >>> ---
> >>>  docs/arm-cpu-features.rst |  36 +++++---
> >>>  target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
> >>>  target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
> >>>  target/arm/kvm_arm.h      |  12 +++
> >>>  tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
> >>>  5 files changed, 368 insertions(+), 52 deletions(-)
> >>>
> >>> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
> >>> index 1262fddc6201..939366f959cf 100644
> >>> --- a/docs/arm-cpu-features.rst
> >>> +++ b/docs/arm-cpu-features.rst
> >>> @@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
> >>>  
> >>>    1) At least one vector length must be enabled when `sve` is enabled.
> >>>  
> >>> -  2) If a vector length `N` is enabled, then all power-of-two vector
> >>> -     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
> >>> -     is enabled, then `sve128` and `sve256` must also be enabled,
> >>> -     but `sve384` is not required.
> >>> +  2) If a vector length `N` is enabled, then, when KVM is enabled, all
> >>> +     smaller, host supported vector lengths must also be enabled.  If
> >>> +     KVM is not enabled, then only all the smaller, power-of-two vector
> >>> +     lengths must be enabled.  E.g. with KVM if the host supports all
> >>> +     vector lengths up to 512-bits (128, 256, 384, 512), then if
> >>> +     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
> >>> +     be enabled. Without KVM, `sve384` would not be required.
> >>> +
> >>> +  3) If KVM is enabled then only vector lengths that the host CPU type
> >>> +     support may be enabled.  If SVE is not supported by the host, then
> >>> +     no `sve*` properties may be enabled.
> >>>  
> >>>  SVE CPU Property Parsing Semantics
> >>>  ----------------------------------
> >>> @@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
> >>>       disable the last enabled vector length (see constraint (1) of "SVE
> >>>       CPU Property Dependencies and Constraints").
> >>>  
> >>> -  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> >>> +  4) When KVM is enabled, if the host does not support SVE, then an error
> >>> +     is generated when attempting to enable any `sve*` properties.
> >>> +
> >>> +  5) When KVM is enabled, if the host does support SVE, then an error is
> >>> +     generated when attempting to enable any vector lengths not supported
> >>> +     by the host.
> >>> +
> >>> +  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
> >>>       CPU properties are set `on`, then the specified vector lengths are
> >>>       disabled but the default for any unspecified lengths remains enabled.
> >>> -     Disabling a power-of-two vector length also disables all vector
> >>> -     lengths larger than the power-of-two length (see constraint (2) of
> >>> -     "SVE CPU Property Dependencies and Constraints").
> >>> +     When KVM is not enabled, disabling a power-of-two vector length also
> >>> +     disables all vector lengths larger than the power-of-two length.
> >>> +     When KVM is enabled, then disabling any supported vector length also
> >>> +     disables all larger vector lengths (see constraint (2) of "SVE CPU
> >>> +     Property Dependencies and Constraints").
> >>>  
> >>> -  5) If one or more `sve<N>` CPU properties are set to `on`, then they
> >>> +  7) If one or more `sve<N>` CPU properties are set to `on`, then they
> >>>       are enabled and all unspecified lengths default to disabled, except
> >>>       for the required lengths per constraint (2) of "SVE CPU Property
> >>>       Dependencies and Constraints", which will even be auto-enabled if
> >>>       they were not explicitly enabled.
> >>>  
> >>> -  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> >>> +  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
> >>>       explicitly disabled (i.e. avoiding the error specified in (3) of
> >>>       "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
> >>>       provided an error will be generated.  To avoid this error, one must
> >>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> >>> index b7eff4e1e107..18dd5e24ec61 100644
> >>> --- a/target/arm/cpu64.c
> >>> +++ b/target/arm/cpu64.c
> >>> @@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >>>       * any of the above.  Finally, if SVE is not disabled, then at least one
> >>>       * vector length must be enabled.
> >>>       */
> >>> +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
> >>>      DECLARE_BITMAP(tmp, ARM_MAX_VQ);
> >>>      uint32_t vq, max_vq = 0;
> >>>  
> >>> +    /* Collect the set of vector lengths supported by KVM. */
> >>> +    bitmap_zero(kvm_supported, ARM_MAX_VQ);
> >>> +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
> >>> +        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
> >>> +    } else if (kvm_enabled()) {
> >>> +        assert(!cpu_isar_feature(aa64_sve, cpu));
> >> why not set an error and propagate it instead?
> > 
> > This should never happen. We shouldn't be here if KVM is enabled and SVE
> > isn't supported. The question is how defensive do we want QEMU code?
> > We could just drop the check altogether if we don't want the assert, but
> > I'd rather keep it.
> > 
> >>> +    }
> >>> +
> >>>      /*
> >>>       * Process explicit sve<N> properties.
> >>>       * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
> >>> @@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >>>              return;
> >>>          }
> >>>  
> >>> -        /* Propagate enabled bits down through required powers-of-two. */
> >>> -        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> >>> -            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> >>> -                set_bit(vq - 1, cpu->sve_vq_map);
> >>> +        if (kvm_enabled()) {
> >>> +            /*
> >>> +             * For KVM we have to automatically enable all supported unitialized
> >>> +             * lengths, even when the smaller lengths are not all powers-of-two.
> >>> +             */
> >>> +            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
> >>> +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
> >>> +        } else {
> >>> +            /* Propagate enabled bits down through required powers-of-two. */
> >>> +            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
> >>> +                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
> >>> +                    set_bit(vq - 1, cpu->sve_vq_map);
> >>> +                }
> >>>              }
> >>>          }
> >>>      } else if (cpu->sve_max_vq == 0) {
> >>> @@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> >>>              return;
> >>>          }
> >>>  
> >>> -        /* Disabling a power-of-two disables all larger lengths. */
> >>> -        if (test_bit(0, cpu->sve_vq_init)) {
> >>> -            error_setg(errp, "cannot disable sve128");
> >>> -            error_append_hint(errp, "Disabling sve128 results in all vector "
> >>> -                              "lengths being disabled.\n");
> >>> -            error_append_hint(errp, "With SVE enabled, at least one vector "
> >>> -                              "length must be enabled.\n");
> >>> -            return;
> >>> -        }
> >>> -        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
> >>> -            if (test_bit(vq - 1, cpu->sve_vq_init)) {
> >>> -                break;
> >>> +        if (kvm_enabled()) {
> >>> +            /* Disabling a supported length disables all larger lengths. */
> >>> +            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> >>> +                if (test_bit(vq - 1, cpu->sve_vq_init) &&
> >>> +                    test_bit(vq - 1, kvm_supported)) {
> >>> +                    break;
> >>> +                }
> the above loop looks for the 1st disabled vq that is also supported, right?

Right

> >>> +            }
> >>> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
> >>> +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
> >>> +                          cpu->sve_vq_init, max_vq);
> >>> +            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
> here we don't have anything enabled below the disabled one. So don't we
> have the culprit already?

Oh, you're right. We can drop the find_next_bit call. Thanks for catching
that.

> >>> +                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
> >>> +                error_setg(errp, "cannot disable sve%d", vq * 128);
> >> isn't the one disabled max_vq? Do you really need to re-compute vq?

vq != max_vq here. max_vq is one smaller, even 0 if vq=1. So while vq
is already correct, as you've pointed out, we need to use specifically
that, not max_vq.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-09-26 11:40         ` Andrew Jones
@ 2019-09-26 11:50           ` Auger Eric
  0 siblings, 0 replies; 32+ messages in thread
From: Auger Eric @ 2019-09-26 11:50 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, richard.henderson, qemu-devel, armbru, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

Hi Drew,

On 9/26/19 1:40 PM, Andrew Jones wrote:
> On Thu, Sep 26, 2019 at 12:01:36PM +0200, Auger Eric wrote:
>>
>>
>> On 9/26/19 10:41 AM, Andrew Jones wrote:
>>> On Thu, Sep 26, 2019 at 08:52:55AM +0200, Auger Eric wrote:
>>>> Hi Drew,
>>>>
>>>> On 9/24/19 1:31 PM, Andrew Jones wrote:
>>>>> Extend the SVE vq map initialization and validation with KVM's
>>>>> supported vector lengths when KVM is enabled. In order to determine
>>>>> and select supported lengths we add two new KVM functions for getting
>>>>> and setting the KVM_REG_ARM64_SVE_VLS pseudo-register.
>>>>>
>>>>> This patch has been co-authored with Richard Henderson, who reworked
>>>>> the target/arm/cpu64.c changes in order to push all the validation and
>>>>> auto-enabling/disabling steps into the finalizer, resulting in a nice
>>>>> LOC reduction.
>>>>>
>>>>> Signed-off-by: Andrew Jones <drjones@redhat.com>
>>>>> ---
>>>>>  docs/arm-cpu-features.rst |  36 +++++---
>>>>>  target/arm/cpu64.c        | 167 +++++++++++++++++++++++++++++---------
>>>>>  target/arm/kvm64.c        | 100 ++++++++++++++++++++++-
>>>>>  target/arm/kvm_arm.h      |  12 +++
>>>>>  tests/arm-cpu-features.c  | 105 +++++++++++++++++++++++-
>>>>>  5 files changed, 368 insertions(+), 52 deletions(-)
>>>>>
>>>>> diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
>>>>> index 1262fddc6201..939366f959cf 100644
>>>>> --- a/docs/arm-cpu-features.rst
>>>>> +++ b/docs/arm-cpu-features.rst
>>>>> @@ -188,10 +188,17 @@ SVE CPU Property Dependencies and Constraints
>>>>>  
>>>>>    1) At least one vector length must be enabled when `sve` is enabled.
>>>>>  
>>>>> -  2) If a vector length `N` is enabled, then all power-of-two vector
>>>>> -     lengths smaller than `N` must also be enabled.  E.g. if `sve512`
>>>>> -     is enabled, then `sve128` and `sve256` must also be enabled,
>>>>> -     but `sve384` is not required.
>>>>> +  2) If a vector length `N` is enabled, then, when KVM is enabled, all
>>>>> +     smaller, host supported vector lengths must also be enabled.  If
>>>>> +     KVM is not enabled, then only all the smaller, power-of-two vector
>>>>> +     lengths must be enabled.  E.g. with KVM if the host supports all
>>>>> +     vector lengths up to 512-bits (128, 256, 384, 512), then if
>>>>> +     `sve512` is enabled, `sve128`, `sve256`, and `sve384` must also
>>>>> +     be enabled. Without KVM, `sve384` would not be required.
>>>>> +
>>>>> +  3) If KVM is enabled then only vector lengths that the host CPU type
>>>>> +     support may be enabled.  If SVE is not supported by the host, then
>>>>> +     no `sve*` properties may be enabled.
>>>>>  
>>>>>  SVE CPU Property Parsing Semantics
>>>>>  ----------------------------------
>>>>> @@ -210,20 +217,29 @@ SVE CPU Property Parsing Semantics
>>>>>       disable the last enabled vector length (see constraint (1) of "SVE
>>>>>       CPU Property Dependencies and Constraints").
>>>>>  
>>>>> -  4) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>>>>> +  4) When KVM is enabled, if the host does not support SVE, then an error
>>>>> +     is generated when attempting to enable any `sve*` properties.
>>>>> +
>>>>> +  5) When KVM is enabled, if the host does support SVE, then an error is
>>>>> +     generated when attempting to enable any vector lengths not supported
>>>>> +     by the host.
>>>>> +
>>>>> +  6) If one or more `sve<N>` CPU properties are set `off`, but no `sve<N>`,
>>>>>       CPU properties are set `on`, then the specified vector lengths are
>>>>>       disabled but the default for any unspecified lengths remains enabled.
>>>>> -     Disabling a power-of-two vector length also disables all vector
>>>>> -     lengths larger than the power-of-two length (see constraint (2) of
>>>>> -     "SVE CPU Property Dependencies and Constraints").
>>>>> +     When KVM is not enabled, disabling a power-of-two vector length also
>>>>> +     disables all vector lengths larger than the power-of-two length.
>>>>> +     When KVM is enabled, then disabling any supported vector length also
>>>>> +     disables all larger vector lengths (see constraint (2) of "SVE CPU
>>>>> +     Property Dependencies and Constraints").
>>>>>  
>>>>> -  5) If one or more `sve<N>` CPU properties are set to `on`, then they
>>>>> +  7) If one or more `sve<N>` CPU properties are set to `on`, then they
>>>>>       are enabled and all unspecified lengths default to disabled, except
>>>>>       for the required lengths per constraint (2) of "SVE CPU Property
>>>>>       Dependencies and Constraints", which will even be auto-enabled if
>>>>>       they were not explicitly enabled.
>>>>>  
>>>>> -  6) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>>>>> +  8) If SVE was disabled (`sve=off`), allowing all vector lengths to be
>>>>>       explicitly disabled (i.e. avoiding the error specified in (3) of
>>>>>       "SVE CPU Property Parsing Semantics"), then if later an `sve=on` is
>>>>>       provided an error will be generated.  To avoid this error, one must
>>>>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>>>>> index b7eff4e1e107..18dd5e24ec61 100644
>>>>> --- a/target/arm/cpu64.c
>>>>> +++ b/target/arm/cpu64.c
>>>>> @@ -273,9 +273,18 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>>>       * any of the above.  Finally, if SVE is not disabled, then at least one
>>>>>       * vector length must be enabled.
>>>>>       */
>>>>> +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
>>>>>      DECLARE_BITMAP(tmp, ARM_MAX_VQ);
>>>>>      uint32_t vq, max_vq = 0;
>>>>>  
>>>>> +    /* Collect the set of vector lengths supported by KVM. */
>>>>> +    bitmap_zero(kvm_supported, ARM_MAX_VQ);
>>>>> +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
>>>>> +        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
>>>>> +    } else if (kvm_enabled()) {
>>>>> +        assert(!cpu_isar_feature(aa64_sve, cpu));
>>>> why not set an error and propagate it instead?
>>>
>>> This should never happen. We shouldn't be here if KVM is enabled and SVE
>>> isn't supported. The question is how defensive do we want QEMU code?
>>> We could just drop the check altogether if we don't want the assert, but
>>> I'd rather keep it.
>>>
>>>>> +    }
>>>>> +
>>>>>      /*
>>>>>       * Process explicit sve<N> properties.
>>>>>       * From the properties, sve_vq_map<N> implies sve_vq_init<N>.
>>>>> @@ -293,10 +302,19 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>>>              return;
>>>>>          }
>>>>>  
>>>>> -        /* Propagate enabled bits down through required powers-of-two. */
>>>>> -        for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>>>> -            if (!test_bit(vq - 1, cpu->sve_vq_init)) {
>>>>> -                set_bit(vq - 1, cpu->sve_vq_map);
>>>>> +        if (kvm_enabled()) {
>>>>> +            /*
>>>>> +             * For KVM we have to automatically enable all supported unitialized
>>>>> +             * lengths, even when the smaller lengths are not all powers-of-two.
>>>>> +             */
>>>>> +            bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
>>>>> +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
>>>>> +        } else {
>>>>> +            /* Propagate enabled bits down through required powers-of-two. */
>>>>> +            for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
>>>>> +                if (!test_bit(vq - 1, cpu->sve_vq_init)) {
>>>>> +                    set_bit(vq - 1, cpu->sve_vq_map);
>>>>> +                }
>>>>>              }
>>>>>          }
>>>>>      } else if (cpu->sve_max_vq == 0) {
>>>>> @@ -308,23 +326,46 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>>>>>              return;
>>>>>          }
>>>>>  
>>>>> -        /* Disabling a power-of-two disables all larger lengths. */
>>>>> -        if (test_bit(0, cpu->sve_vq_init)) {
>>>>> -            error_setg(errp, "cannot disable sve128");
>>>>> -            error_append_hint(errp, "Disabling sve128 results in all vector "
>>>>> -                              "lengths being disabled.\n");
>>>>> -            error_append_hint(errp, "With SVE enabled, at least one vector "
>>>>> -                              "length must be enabled.\n");
>>>>> -            return;
>>>>> -        }
>>>>> -        for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
>>>>> -            if (test_bit(vq - 1, cpu->sve_vq_init)) {
>>>>> -                break;
>>>>> +        if (kvm_enabled()) {
>>>>> +            /* Disabling a supported length disables all larger lengths. */
>>>>> +            for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>>>>> +                if (test_bit(vq - 1, cpu->sve_vq_init) &&
>>>>> +                    test_bit(vq - 1, kvm_supported)) {
>>>>> +                    break;
>>>>> +                }
>> the above loop looks for the 1st disabled vq that is also supported, right?
> 
> Right
> 
>>>>> +            }
>>>>> +            max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
>>>>> +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
>>>>> +                          cpu->sve_vq_init, max_vq);
>>>>> +            if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
>> here we don't have anything enabled below the disabled one. So don't we
>> have the culprit already?
> 
> Oh, you're right. We can drop the find_next_bit call. Thanks for catching
> that.
> 
>>>>> +                vq = find_next_bit(kvm_supported, ARM_MAX_VQ, 0) + 1;
>>>>> +                error_setg(errp, "cannot disable sve%d", vq * 128);
>>>> isn't the one disabled max_vq? Do you really need to re-compute vq?
> 
> vq != max_vq here. max_vq is one smaller, even 0 if vq=1. So while vq
> is already correct, as you've pointed out, we need to use specifically
> that, not max_vq.
OK

Thanks

Eric
> 
> Thanks,
> drew
> 


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
  2019-09-24 13:55   ` Andrew Jones
  2019-09-25 13:53   ` Auger Eric
@ 2019-09-26 19:07   ` Richard Henderson
  2019-09-26 23:50     ` Alex Bennée
  2019-09-27  6:45     ` Andrew Jones
  2 siblings, 2 replies; 32+ messages in thread
From: Richard Henderson @ 2019-09-26 19:07 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 9/24/19 4:31 AM, Andrew Jones wrote:
> +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
> +{
> +    uint32_t start_vq = (start_len & 0xf) + 1;
> +
> +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
> +}
> +
>  /*
>   * Given that SVE is enabled, return the vector length for EL.
>   */
> @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
>      uint32_t zcr_len = cpu->sve_max_vq - 1;
>  
>      if (el <= 1) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
>      }
>      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
>      }
>      if (arm_feature(env, ARM_FEATURE_EL3)) {
> -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
> +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);

This has lost the MIN relation between these 3 registers.
One possible solution is to keep these 3 if statements as-is,
but make one call

    zcr_len = arm_cpu_vq_map_next_smaller(cpu, zcr_len);

at the end.

> +#if __SIZEOF_LONG__ == 8
> +#define BIT(n) (1UL << (n))
> +#else
> +#define BIT(n) (1ULL << (n))
> +#endif

There's no reason not to always use 1ULL is there?


r~


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-26 19:07   ` Richard Henderson
@ 2019-09-26 23:50     ` Alex Bennée
  2019-09-27  6:51       ` Andrew Jones
  2019-09-27  6:45     ` Andrew Jones
  1 sibling, 1 reply; 32+ messages in thread
From: Alex Bennée @ 2019-09-26 23:50 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, Andrew Jones, qemu-devel, armbru, eric.auger,
	qemu-arm, imammedo, Dave.Martin


Richard Henderson <richard.henderson@linaro.org> writes:

> On 9/24/19 4:31 AM, Andrew Jones wrote:
<snip>
>
>> +#if __SIZEOF_LONG__ == 8
>> +#define BIT(n) (1UL << (n))
>> +#else
>> +#define BIT(n) (1ULL << (n))
>> +#endif
>
> There's no reason not to always use 1ULL is there?

Also we already have this helper in bitops.h so should just use that.

--
Alex Bennée


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-26 19:07   ` Richard Henderson
  2019-09-26 23:50     ` Alex Bennée
@ 2019-09-27  6:45     ` Andrew Jones
  1 sibling, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-27  6:45 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Sep 26, 2019 at 12:07:54PM -0700, Richard Henderson wrote:
> On 9/24/19 4:31 AM, Andrew Jones wrote:
> > +static uint32_t sve_zcr_get_valid_len(ARMCPU *cpu, uint32_t start_len)
> > +{
> > +    uint32_t start_vq = (start_len & 0xf) + 1;
> > +
> > +    return arm_cpu_vq_map_next_smaller(cpu, start_vq + 1) - 1;
> > +}
> > +
> >  /*
> >   * Given that SVE is enabled, return the vector length for EL.
> >   */
> > @@ -5360,13 +5367,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
> >      uint32_t zcr_len = cpu->sve_max_vq - 1;
> >  
> >      if (el <= 1) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[1]);
> >      }
> >      if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[2]);
> >      }
> >      if (arm_feature(env, ARM_FEATURE_EL3)) {
> > -        zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[3]);
> > +        zcr_len = sve_zcr_get_valid_len(cpu, env->vfp.zcr_el[3]);
> 
> This has lost the MIN relation between these 3 registers.
> One possible solution is to keep these 3 if statements as-is,
> but make one call
> 
>     zcr_len = arm_cpu_vq_map_next_smaller(cpu, zcr_len);
> 
> at the end.

Argh. I obviously didn't look closely enough at this function when I was
modifying it. I must have interpreted it as an if-else-if sequence...

I'll fix this as you suggest.

> 
> > +#if __SIZEOF_LONG__ == 8
> > +#define BIT(n) (1UL << (n))
> > +#else
> > +#define BIT(n) (1ULL << (n))
> > +#endif
> 
> There's no reason not to always use 1ULL is there?

Indeed ULL == UL for AArch64. I'll drop the #if... stuff.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties
  2019-09-26 23:50     ` Alex Bennée
@ 2019-09-27  6:51       ` Andrew Jones
  0 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-27  6:51 UTC (permalink / raw)
  To: Alex Bennée
  Cc: peter.maydell, Richard Henderson, qemu-devel, armbru, eric.auger,
	qemu-arm, imammedo, Dave.Martin

On Fri, Sep 27, 2019 at 12:50:55AM +0100, Alex Bennée wrote:
> 
> Richard Henderson <richard.henderson@linaro.org> writes:
> 
> > On 9/24/19 4:31 AM, Andrew Jones wrote:
> <snip>
> >
> >> +#if __SIZEOF_LONG__ == 8
> >> +#define BIT(n) (1UL << (n))
> >> +#else
> >> +#define BIT(n) (1ULL << (n))
> >> +#endif
> >
> > There's no reason not to always use 1ULL is there?
> 
> Also we already have this helper in bitops.h so should just use that.

bitops.h BIT() uses UL, but we need ULL. FWIW, the kernel has a BIT_ULL()
that we could mimic in QEMU. I guess I could even add that for this patch,
if you'd like.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
  2019-09-25 13:58   ` Auger Eric
@ 2019-09-27 13:00   ` Andrew Jones
  2019-10-01  6:53   ` Andrew Jones
  2 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-09-27 13:00 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

On Tue, Sep 24, 2019 at 01:31:01PM +0200, Andrew Jones wrote:
> These are the SVE equivalents to kvm_arch_get/put_fpsimd. Note, the
> swabbing is different than it is for fpsmid because the vector format
> is a little-endian stream of words.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/kvm64.c | 137 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 133 insertions(+), 4 deletions(-)
>

It looks like I need to add the below changes to this patch as well,
since FPSR and FPCR are still in use with SVE.

Thanks,
drew


diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 2da366ba113e..be31e56a1ab0 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -854,10 +854,8 @@ int kvm_arm_cpreg_level(uint64_t regidx)
 
 static int kvm_arch_put_fpsimd(CPUState *cs)
 {
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
+    CPUARMState *env = &ARM_CPU(cs)->env;
     struct kvm_one_reg reg;
-    uint32_t fpr;
     int i, ret;
 
     for (i = 0; i < 32; i++) {
@@ -875,22 +873,6 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
         }
     }
 
-    reg.addr = (uintptr_t)(&fpr);
-    fpr = vfp_get_fpsr(env);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.addr = (uintptr_t)(&fpr);
-    fpr = vfp_get_fpcr(env);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
     return 0;
 }
 
@@ -970,6 +952,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 {
     struct kvm_one_reg reg;
     uint64_t val;
+    uint32_t fpr;
     int i, ret;
     unsigned int el;
 
@@ -1069,6 +1052,22 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         return ret;
     }
 
+    reg.addr = (uintptr_t)(&fpr);
+    fpr = vfp_get_fpsr(env);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.addr = (uintptr_t)(&fpr);
+    fpr = vfp_get_fpcr(env);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
     ret = kvm_put_vcpu_events(cpu);
     if (ret) {
         return ret;
@@ -1087,10 +1086,8 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 
 static int kvm_arch_get_fpsimd(CPUState *cs)
 {
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
+    CPUARMState *env = &ARM_CPU(cs)->env;
     struct kvm_one_reg reg;
-    uint32_t fpr;
     int i, ret;
 
     for (i = 0; i < 32; i++) {
@@ -1108,22 +1105,6 @@ static int kvm_arch_get_fpsimd(CPUState *cs)
         }
     }
 
-    reg.addr = (uintptr_t)(&fpr);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-    vfp_set_fpsr(env, fpr);
-
-    reg.addr = (uintptr_t)(&fpr);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-    vfp_set_fpcr(env, fpr);
-
     return 0;
 }
 
@@ -1180,6 +1161,7 @@ int kvm_arch_get_registers(CPUState *cs)
     struct kvm_one_reg reg;
     uint64_t val;
     unsigned int el;
+    uint32_t fpr;
     int i, ret;
 
     ARMCPU *cpu = ARM_CPU(cs);
@@ -1278,6 +1260,22 @@ int kvm_arch_get_registers(CPUState *cs)
         return ret;
     }
 
+    reg.addr = (uintptr_t)(&fpr);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpsr(env, fpr);
+
+    reg.addr = (uintptr_t)(&fpr);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpcr(env, fpr);
+
     ret = kvm_get_vcpu_events(cpu);
     if (ret) {
         return ret;


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
  2019-09-25 13:58   ` Auger Eric
  2019-09-27 13:00   ` Andrew Jones
@ 2019-10-01  6:53   ` Andrew Jones
  2 siblings, 0 replies; 32+ messages in thread
From: Andrew Jones @ 2019-10-01  6:53 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

On Tue, Sep 24, 2019 at 01:31:01PM +0200, Andrew Jones wrote:
> These are the SVE equivalents to kvm_arch_get/put_fpsimd. Note, the
> swabbing is different than it is for fpsmid because the vector format
> is a little-endian stream of words.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/kvm64.c | 137 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 133 insertions(+), 4 deletions(-)
> 
> diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
> index 28f6db57d5ee..ea454c613919 100644
> --- a/target/arm/kvm64.c
> +++ b/target/arm/kvm64.c
> @@ -671,11 +671,12 @@ int kvm_arch_destroy_vcpu(CPUState *cs)
>  bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
>  {
>      /* Return true if the regidx is a register we should synchronize
> -     * via the cpreg_tuples array (ie is not a core reg we sync by
> -     * hand in kvm_arch_get/put_registers())
> +     * via the cpreg_tuples array (ie is not a core or sve reg that
> +     * we sync by hand in kvm_arch_get/put_registers())
>       */
>      switch (regidx & KVM_REG_ARM_COPROC_MASK) {
>      case KVM_REG_ARM_CORE:
> +    case KVM_REG_ARM64_SVE:
>          return false;
>      default:
>          return true;
> @@ -761,6 +762,78 @@ static int kvm_arch_put_fpsimd(CPUState *cs)
>      return 0;
>  }
>  
> +/*
> + * SVE registers are encoded in KVM's memory in an endianness-invariant format.
> + * The byte at offset i from the start of the in-memory representation contains
> + * the bits [(7 + 8 * i) : (8 * i)] of the register value. As this means the
> + * lowest offsets are stored in the lowest memory addresses, then that nearly
> + * matches QEMU's representation, which is to use an array of host-endian
> + * uint64_t's, where the lower offsets are at the lower indices. To complete
> + * the translation we just need to byte swap the uint64_t's on big-endian hosts.
> + */
> +static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
> +{
> +#ifdef HOST_WORDS_BIGENDIAN
> +    int i;
> +
> +    for (i = 0; i < nr; ++i) {
> +        dst[i] = bswap64(src[i]);
> +    }
> +
> +    return dst;
> +#else
> +    return src;
> +#endif
> +}
> +
> +/*
> + * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
> + * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
> + * code the slice index to zero for now as it's unlikely we'll need more than
> + * one slice for quite some time.
> + */
> +static int kvm_arch_put_sve(CPUState *cs)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    uint64_t tmp[ARM_MAX_VQ * 2];
> +    uint64_t *r;
> +    struct kvm_one_reg reg;
> +    int n, ret;
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
> +        r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2);
> +        reg.addr = (uintptr_t)r;
> +        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
> +        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +        if (ret) {
> +            return ret;
> +        }
> +    }
> +
> +    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
> +        r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0],
> +                        DIV_ROUND_UP(cpu->sve_max_vq, 8));

I see a bug here that I introduced between v2 and v3 when I switched to
DIV_ROUND_UP. I dropped the '* 2's on all of these. They should be
DIV_ROUND_UP(cpu->sve_max_vq * 2, 8). I'll fix for v5, which I'll be
posting later today.

Thanks,
drew


^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2019-10-01  6:54 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-24 11:30 [PATCH v4 0/9] target/arm/kvm: enable SVE in guests Andrew Jones
2019-09-24 11:30 ` [PATCH v4 1/9] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
2019-09-24 15:06   ` Auger Eric
2019-09-24 11:30 ` [PATCH v4 2/9] tests: arm: Introduce cpu feature tests Andrew Jones
2019-09-24 11:30 ` [PATCH v4 3/9] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
2019-09-24 15:06   ` Auger Eric
2019-09-24 11:31 ` [PATCH v4 4/9] target/arm/cpu64: max cpu: Introduce sve<N> properties Andrew Jones
2019-09-24 13:55   ` Andrew Jones
2019-09-25 13:53   ` Auger Eric
2019-09-26  8:21     ` Andrew Jones
2019-09-26  9:34       ` Auger Eric
2019-09-26 11:14         ` Andrew Jones
2019-09-26 19:07   ` Richard Henderson
2019-09-26 23:50     ` Alex Bennée
2019-09-27  6:51       ` Andrew Jones
2019-09-27  6:45     ` Andrew Jones
2019-09-24 11:31 ` [PATCH v4 5/9] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
2019-09-25 13:58   ` Auger Eric
2019-09-27 13:00   ` Andrew Jones
2019-10-01  6:53   ` Andrew Jones
2019-09-24 11:31 ` [PATCH v4 6/9] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
2019-09-26  6:53   ` Auger Eric
2019-09-24 11:31 ` [PATCH v4 7/9] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
2019-09-24 11:31 ` [PATCH v4 8/9] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
2019-09-26  6:52   ` Auger Eric
2019-09-26  8:41     ` Andrew Jones
2019-09-26 10:01       ` Auger Eric
2019-09-26 11:40         ` Andrew Jones
2019-09-26 11:50           ` Auger Eric
2019-09-24 11:31 ` [PATCH v4 9/9] target/arm/kvm: host cpu: Add support for sve<N> properties Andrew Jones
2019-09-26  7:07   ` Auger Eric
2019-09-26  8:53     ` Andrew Jones

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.