All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
@ 2019-08-02 12:25 Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 01/15] target/arm/cpu64: Ensure kvm really supports aarch64=off Andrew Jones
                   ` (16 more replies)
  0 siblings, 17 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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.

v3:
  - Added documentation (docs/arm-cpu-features.rst)
  - Fixed TCG emulation of ZCR
  - Fixed KVM put/get_sve registers to not forget to bswap FFR
  - Now ensure we never end up with no vector lengths selected and sve=on
  - Now also auto-disable uninitialized larger vector lengths that are
    no longer possible due to disabling a dependent smaller length
  - Now only use cpu_isar_feature(aa64_sve, cpu) to track SVE enablement
  - Now sve-max-vq can come wherever it wants in an sve* property sequence
  - No longer abuse sve_max_vq for additional states; instead use a couple
    new helper functions to determine the same states
  - Changed some error messages
  - Dropped some asserts
  - Added more code comments
  - Churned a good amount of code for refactoring and cleanups
  - Picked up some tags from Eric and Richard


Thanks!
drew

Andrew Jones (15):
  target/arm/cpu64: Ensure kvm really supports aarch64=off
  target/arm/cpu: Ensure we can use the pmu with kvm
  target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  tests: arm: Introduce cpu feature tests
  target/arm/helper: zcr: Add build bug next to value range assumption
  target/arm/cpu: Use div-round-up to determine predicate register array
    size
  target/arm: Allow SVE to be disabled via a CPU property
  target/arm/cpu64: max cpu: Introduce sve<vl-bits> properties
  target/arm/kvm64: Fix error returns
  target/arm/kvm64: Move the get/put of fpsimd registers out
  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<vl-bits> properties

 docs/arm-cpu-features.rst | 301 ++++++++++++++++++++++
 qapi/machine-target.json  |   6 +-
 target/arm/cpu.c          |  38 ++-
 target/arm/cpu.h          |  19 +-
 target/arm/cpu64.c        | 499 +++++++++++++++++++++++++++++++++--
 target/arm/helper.c       |  14 +-
 target/arm/kvm.c          |  32 ++-
 target/arm/kvm32.c        |   6 +-
 target/arm/kvm64.c        | 439 ++++++++++++++++++++++++++-----
 target/arm/kvm_arm.h      |  67 +++++
 target/arm/monitor.c      | 154 +++++++++++
 tests/Makefile.include    |   5 +-
 tests/arm-cpu-features.c  | 529 ++++++++++++++++++++++++++++++++++++++
 13 files changed, 2005 insertions(+), 104 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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 01/15] target/arm/cpu64: Ensure kvm really supports aarch64=off
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 02/15] target/arm/cpu: Ensure we can use the pmu with kvm Andrew Jones
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

If -cpu <cpu>,aarch64=off is used then KVM must also be used, and it
and the host must support running the vcpu in 32-bit mode. Also, if
-cpu <cpu>,aarch64=on is used, then it doesn't matter if kvm is
enabled or not.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
 target/arm/cpu64.c   | 12 ++++++------
 target/arm/kvm64.c   |  9 +++++++++
 target/arm/kvm_arm.h | 14 ++++++++++++++
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 1901997a0645..946994838d8a 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -407,13 +407,13 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp)
      * restriction allows us to avoid fixing up functionality that assumes a
      * uniform execution state like do_interrupt.
      */
-    if (!kvm_enabled()) {
-        error_setg(errp, "'aarch64' feature cannot be disabled "
-                         "unless KVM is enabled");
-        return;
-    }
-
     if (value == false) {
+        if (!kvm_enabled() || !kvm_arm_aarch32_supported(CPU(cpu))) {
+            error_setg(errp, "'aarch64' feature cannot be disabled "
+                             "unless KVM is enabled and 32-bit EL1 "
+                             "is supported");
+            return;
+        }
         unset_feature(&cpu->env, ARM_FEATURE_AARCH64);
     } else {
         set_feature(&cpu->env, ARM_FEATURE_AARCH64);
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 22d19c9aec6f..3d91846beb8f 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -24,7 +24,9 @@
 #include "exec/gdbstub.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
+#include "sysemu/kvm_int.h"
 #include "kvm_arm.h"
+#include "hw/boards.h"
 #include "internals.h"
 
 static bool have_guest_debug;
@@ -593,6 +595,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     return true;
 }
 
+bool kvm_arm_aarch32_supported(CPUState *cpu)
+{
+    KVMState *s = KVM_STATE(current_machine->accelerator);
+
+    return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT);
+}
+
 #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
 
 int kvm_arch_init_vcpu(CPUState *cs)
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 2a07333c615f..98af1050a753 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -207,6 +207,15 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
  */
 void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
 
+/**
+ * kvm_arm_aarch32_supported:
+ * @cs: CPUState
+ *
+ * Returns: true if the KVM VCPU can enable AArch32 mode
+ * and false otherwise.
+ */
+bool kvm_arm_aarch32_supported(CPUState *cs);
+
 /**
  * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the
  * IPA address space supported by KVM
@@ -247,6 +256,11 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
     cpu->host_cpu_probe_failed = true;
 }
 
+static inline bool kvm_arm_aarch32_supported(CPUState *cs)
+{
+    return false;
+}
+
 static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
 {
     return -ENOENT;
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 02/15] target/arm/cpu: Ensure we can use the pmu with kvm
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 01/15] target/arm/cpu64: Ensure kvm really supports aarch64=off Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

We first convert the pmu property from a static property to one with
its own accessors. Then we use the set accessor to check if the PMU is
supported when using KVM. Indeed a 32-bit KVM host does not support
the PMU, so this check will catch an attempt to use it at property-set
time.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
 target/arm/cpu.c     | 30 +++++++++++++++++++++++++-----
 target/arm/kvm.c     |  7 +++++++
 target/arm/kvm_arm.h | 14 ++++++++++++++
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 9eb40ff755f9..8b86ce478fc0 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -986,10 +986,6 @@ static Property arm_cpu_has_el3_property =
 static Property arm_cpu_cfgend_property =
             DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
 
-/* use property name "pmu" to match other archs and virt tools */
-static Property arm_cpu_has_pmu_property =
-            DEFINE_PROP_BOOL("pmu", ARMCPU, has_pmu, true);
-
 static Property arm_cpu_has_vfp_property =
             DEFINE_PROP_BOOL("vfp", ARMCPU, has_vfp, true);
 
@@ -1012,6 +1008,29 @@ static Property arm_cpu_pmsav7_dregion_property =
                                            pmsav7_dregion,
                                            qdev_prop_uint32, uint32_t);
 
+static bool arm_get_pmu(Object *obj, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    return cpu->has_pmu;
+}
+
+static void arm_set_pmu(Object *obj, bool value, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    if (value) {
+        if (kvm_enabled() && !kvm_arm_pmu_supported(CPU(cpu))) {
+            error_setg(errp, "'pmu' feature not supported by KVM on this host");
+            return;
+        }
+        set_feature(&cpu->env, ARM_FEATURE_PMU);
+    } else {
+        unset_feature(&cpu->env, ARM_FEATURE_PMU);
+    }
+    cpu->has_pmu = value;
+}
+
 static void arm_get_init_svtor(Object *obj, Visitor *v, const char *name,
                                void *opaque, Error **errp)
 {
@@ -1086,7 +1105,8 @@ void arm_cpu_post_init(Object *obj)
     }
 
     if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
-        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_pmu_property,
+        cpu->has_pmu = true;
+        object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu,
                                  &error_abort);
     }
 
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index fe4f461d4ef6..bfe3d445e196 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -162,6 +162,13 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
     env->features = arm_host_cpu_features.features;
 }
 
+bool kvm_arm_pmu_supported(CPUState *cpu)
+{
+    KVMState *s = KVM_STATE(current_machine->accelerator);
+
+    return kvm_check_extension(s, KVM_CAP_ARM_PMU_V3);
+}
+
 int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
 {
     KVMState *s = KVM_STATE(ms->accelerator);
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 98af1050a753..b3106c8600af 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -216,6 +216,15 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
  */
 bool kvm_arm_aarch32_supported(CPUState *cs);
 
+/**
+ * bool kvm_arm_pmu_supported:
+ * @cs: CPUState
+ *
+ * Returns: true if the KVM VCPU can enable its PMU
+ * and false otherwise.
+ */
+bool kvm_arm_pmu_supported(CPUState *cs);
+
 /**
  * kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the
  * IPA address space supported by KVM
@@ -261,6 +270,11 @@ static inline bool kvm_arm_aarch32_supported(CPUState *cs)
     return false;
 }
 
+static inline bool kvm_arm_pmu_supported(CPUState *cs)
+{
+    return false;
+}
+
 static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
 {
     return -ENOENT;
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 01/15] target/arm/cpu64: Ensure kvm really supports aarch64=off Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 02/15] target/arm/cpu: Ensure we can use the pmu with kvm Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 16:27   ` Richard Henderson
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 04/15] tests: arm: Introduce cpu feature tests Andrew Jones
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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 their property set accessors fail when invalid
configurations are detected. For vfp we would need something like

 set_vfp()
 {
   if (arm_feature(env, ARM_FEATURE_AARCH64) &&
       cpu->has_vfp != cpu->has_neon)
       error("AArch64 CPUs must have both VFP and Neon or neither")

in its set accessor, and the same for neon, rather than doing that
check at realize time, which isn't executed at qmp query time.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst | 137 +++++++++++++++++++++++++++++++++++++
 qapi/machine-target.json  |   6 +-
 target/arm/monitor.c      | 138 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 278 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 6ec6dd04ac2e..96ada22d9cc7 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -23,7 +23,14 @@
 #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)
 {
@@ -82,3 +89,134 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
 
     return head;
 }
+
+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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 04/15] tests: arm: Introduce cpu feature tests
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (2 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 05/15] target/arm/helper: zcr: Add build bug next to value range assumption Andrew Jones
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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 fd7fdb865862..16257d8bcc59 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -257,6 +257,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)
@@ -264,7 +265,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
@@ -827,6 +829,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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 05/15] target/arm/helper: zcr: Add build bug next to value range assumption
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (3 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 04/15] tests: arm: Introduce cpu feature tests Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size Andrew Jones
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

The current implementation of ZCR_ELx matches the architecture, only
implementing the lower four bits, with the rest RAZ/WI. This puts
a strict limit on ARM_MAX_VQ of 16. Make sure we don't let ARM_MAX_VQ
grow without a corresponding update here.

Suggested-by: Dave Martin <Dave.Martin@arm.com>
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/helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index b74c23a9bc08..3064067c69a6 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5300,6 +5300,7 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     int new_len;
 
     /* Bits other than [3:0] are RAZ/WI.  */
+    QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
     raw_write(env, ri, value & 0xf);
 
     /*
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (4 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 05/15] target/arm/helper: zcr: Add build bug next to value range assumption Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 16:33   ` Richard Henderson
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Unless we're guaranteed to always increase ARM_MAX_VQ by a multiple of
four, then we should use DIV_ROUND_UP to ensure we get an appropriate
array size.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 target/arm/cpu.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 94c990cddbd8..a3300f3ee7d7 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -195,7 +195,7 @@ typedef struct ARMVectorReg {
 #ifdef TARGET_AARCH64
 /* In AArch32 mode, predicate registers do not exist at all.  */
 typedef struct ARMPredicateReg {
-    uint64_t p[2 * ARM_MAX_VQ / 8] QEMU_ALIGNED(16);
+    uint64_t p[DIV_ROUND_UP(2 * ARM_MAX_VQ, 8)] QEMU_ALIGNED(16);
 } ARMPredicateReg;
 
 /* In AArch32 mode, PAC keys do not exist at all.  */
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (5 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 16:35   ` Richard Henderson
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 08/15] target/arm/cpu64: max cpu: Introduce sve<vl-bits> properties Andrew Jones
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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>
---
 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 8b86ce478fc0..930f4579ccae 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 946994838d8a..e470c34f89ac 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -257,15 +257,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;
@@ -280,6 +280,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;
@@ -373,8 +401,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 96ada22d9cc7..36a86cb83ce5 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -91,7 +91,7 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
 }
 
 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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 08/15] target/arm/cpu64: max cpu: Introduce sve<vl-bits> properties
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (6 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 09/15] target/arm/kvm64: Fix error returns Andrew Jones
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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<vl-bits> 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-2 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.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst | 157 +++++++++++++++++-
 target/arm/cpu.c          |   4 +
 target/arm/cpu.h          |  14 ++
 target/arm/cpu64.c        | 340 +++++++++++++++++++++++++++++++++++++-
 target/arm/helper.c       |  13 +-
 target/arm/monitor.c      |  16 ++
 tests/arm-cpu-features.c  | 197 ++++++++++++++++++++++
 7 files changed, 726 insertions(+), 15 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index c79dcffb5556..aaaed861cda2 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 for the `max` CPU type.
+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-2 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-2 vector length also disables all vector lengths
+     larger than the power-of-2 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-2 (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 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 930f4579ccae..842637ae0c49 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1247,6 +1247,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        arm_cpu_sve_finalize(cpu);
+    }
+
     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 a3300f3ee7d7..c8b96293c5e2 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);
+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) { }
+static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
+{ return 0; }
 #endif
 
 typedef struct ARMVectorReg {
@@ -915,6 +920,15 @@ 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. We need a map size twice the maximum
+     * quadword length though because we use two bits for each vector
+     * length in order to track three states: uninitialized, off, and on.
+     */
+    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ * 2);
 };
 
 void arm_cpu_post_init(Object *obj);
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index e470c34f89ac..c9412a0b71af 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -257,6 +257,150 @@ static void aarch64_a72_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
 }
 
+/*
+ * While we eventually use cpu->sve_vq_map as a typical bitmap, where each vq
+ * has only two states (off/on), until we've finalized the map at realize time
+ * we use an extra bit, at the vq - 1 + ARM_MAX_VQ bit number, to also allow
+ * tracking of the uninitialized state. The arm_vq_state typedef and following
+ * functions allow us to more easily work with the bitmap.
+ */
+typedef enum arm_vq_state {
+    ARM_VQ_OFF,
+    ARM_VQ_ON,
+    ARM_VQ_UNINITIALIZED,
+} arm_vq_state;
+
+static arm_vq_state arm_cpu_vq_map_get(ARMCPU *cpu, uint32_t vq)
+{
+    assert(vq <= ARM_MAX_VQ);
+
+    return test_bit(vq - 1, cpu->sve_vq_map) |
+           test_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map) << 1;
+}
+
+static void arm_cpu_vq_map_set(ARMCPU *cpu, uint32_t vq, arm_vq_state state)
+{
+    assert(vq <= ARM_MAX_VQ);
+    assert(state == ARM_VQ_OFF || state == ARM_VQ_ON);
+
+    clear_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map);
+
+    if (state == ARM_VQ_ON) {
+        set_bit(vq - 1, cpu->sve_vq_map);
+    } else {
+        clear_bit(vq - 1, cpu->sve_vq_map);
+    }
+}
+
+/*
+ * Uninitialized vector lengths need a default value to use in case we need
+ * to query their value prior to map finalization. Additionally map finalizing
+ * itself needs to determine what value to assign uninitialized vector lengths.
+ * The default is determined as follows:
+ *
+ *  * When no vector lengths have been explicitly enabled, i.e. either no
+ *    input has been provided by the user at all, or vector lengths have
+ *    only been disabled, then all uninitialized vector lengths default 'ON'.
+ *
+ *  * When one or more vector lengths have been enabled, then all uninitialized
+ *    vector lengths default 'OFF'. Note, when checking for enabled vector
+ *    lengths we do not discriminate between user-enabled vector lengths and
+ *    auto-enabled vector lengths (which were auto-enabled in order to satisfy
+ *    the user-enabled vector lengths). This implies the default can never
+ *    transition back to 'ON', even if the user-enabled and auto-enabled vector
+ *    lengths that initially transitioned it to 'OFF' are later disabled, as at
+ *    least one vector length must remain enabled unless the SVE feature is
+ *    completely disabled. If SVE is completely disabled then all vector
+ *    lengths are effectively 'OFF'.
+ */
+static bool arm_cpu_vq_map_get_default(ARMCPU *cpu)
+{
+    uint32_t vq;
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * We need to be able to track the number of enabled (or will-be enabled)
+ * vector lengths in order to ensure we never drop to zero. If the default
+ * is 'ON', then we count enabled and uninitialized vector lengths. Otherwise,
+ * if the default is 'OFF', then we only count enabled vector lengths.
+ */
+static int arm_cpu_num_vqs_available(ARMCPU *cpu)
+{
+    uint32_t vq;
+    bool defval;
+    int num = 0;
+
+    defval = arm_cpu_vq_map_get_default(cpu);
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
+
+        if (vq_state == ARM_VQ_ON) {
+            ++num;
+        } else if (defval && vq_state == ARM_VQ_UNINITIALIZED) {
+            ++num;
+        }
+    }
+
+    return num;
+}
+
+static void arm_cpu_vq_map_init(ARMCPU *cpu)
+{
+    /* Set all vq's to 0b10 (ARM_VQ_UNINITIALIZED) */
+    bitmap_clear(cpu->sve_vq_map, 0, ARM_MAX_VQ);
+    bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ);
+}
+
+void arm_cpu_sve_finalize(ARMCPU *cpu)
+{
+    bool defval = arm_cpu_vq_map_get_default(cpu);
+    uint32_t vq, max_vq;
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
+
+        if (vq_state == ARM_VQ_UNINITIALIZED) {
+            if (defval) {
+                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
+            } else {
+                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+            }
+        }
+    }
+
+    max_vq = arm_cpu_vq_map_next_smaller(cpu, ARM_MAX_VQ + 1);
+
+    if (!cpu->sve_max_vq) {
+        cpu->sve_max_vq = max_vq;
+    }
+
+    assert(max_vq && 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 <= 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)
 {
@@ -269,15 +413,178 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     Error *err = NULL;
+    uint32_t vq;
 
     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 (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);
+        return;
+    }
+
+    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
+        if (vq <= cpu->sve_max_vq) {
+            char tmp[8];
+
+            sprintf(tmp, "sve%d", vq * 128);
+            object_property_set_bool(obj, true, tmp, &err);
+            if (err) {
+                error_propagate(errp, err);
+                return;
+            }
+        } else if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
+            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+        }
+    }
+}
+
+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;
+    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
+    bool value;
+
+    if (!cpu_isar_feature(aa64_sve, cpu)) {
+        /* All vector lengths are disabled when SVE is off. */
+        value = false;
+    } else if (vq_state == ARM_VQ_ON) {
+        value = true;
+    } else if (vq_state == ARM_VQ_OFF) {
+        value = false;
+    } else if (arm_cpu_vq_map_get_default(cpu)) {
+        value = true;
+    } else {
+        value = false;
+    }
+
+    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;
+    uint32_t max_vq = 0;
+    Error *err = NULL;
+    bool value;
+
+    visit_type_bool(v, name, &value, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    /*
+     * We need to know the maximum vector length, which may just currently
+     * be the maximum length, in order to validate the enabling/disabling
+     * of this vector length.
+     */
+    if (!cpu->sve_max_vq) {
+        for (max_vq = ARM_MAX_VQ; max_vq >= 1; --max_vq) {
+            if (arm_cpu_vq_map_get(cpu, max_vq) == ARM_VQ_ON) {
+                break;
+            }
+        }
+    }
+
+    if (cpu->sve_max_vq && value && vq > cpu->sve_max_vq) {
+        error_setg(errp, "cannot enable %s", name);
+        error_append_hint(errp, "vq=%d (%d bits) is larger than the "
+                          "maximum vector length, sve-max-vq=%d "
+                          "(%d bits)\n", vq, vq * 128,
+                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
+    } else if (cpu->sve_max_vq && !value && vq == cpu->sve_max_vq) {
+        error_setg(errp, "cannot disable %s", name);
+        error_append_hint(errp, "The maximum vector length must be "
+                          "enabled, sve-max-vq=%d (%d bits)\n",
+                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
+    } else if (cpu->sve_max_vq && !value && vq < cpu->sve_max_vq &&
+               is_power_of_2(vq)) {
+        error_setg(errp, "cannot disable %s", name);
+        error_append_hint(errp, "vq=%d (%d bits) is required as it is a "
+                          "power-of-2 length smaller than the maximum, "
+                          "sve-max-vq=%d (%d bits)\n", vq, vq * 128,
+                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
+    } else if (max_vq && !value && vq < max_vq && is_power_of_2(vq)) {
+        error_setg(errp, "cannot disable %s", name);
+        error_append_hint(errp, "Vector length %d-bits is required as it "
+                          "is a power-of-2 length smaller than another "
+                          "enabled vector length. Disable all larger vector "
+                          "lengths first.\n", vq * 128);
+    } else {
+        uint32_t s;
+
+        if (value) {
+            arm_vq_state vq_state;
+            bool fail = false;
+
+            /*
+             * Enabling a vector length automatically enables all
+             * uninitialized power-of-2 lengths smaller than it, as
+             * per the architecture.
+             */
+            for (s = 1; s < vq; ++s) {
+                if (is_power_of_2(s)) {
+                    vq_state = arm_cpu_vq_map_get(cpu, s);
+                    if (vq_state == ARM_VQ_UNINITIALIZED) {
+                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON);
+                    } else if (vq_state == ARM_VQ_OFF) {
+                        fail = true;
+                        break;
+                    }
+                }
+            }
+
+            if (fail) {
+                error_setg(errp, "cannot enable %s", name);
+                error_append_hint(errp, "Vector length %d-bits is disabled "
+                                  "and is a power-of-2 length smaller than "
+                                  "%s. All power-of-2 vector lengths smaller "
+                                  "than the maximum length are required.\n",
+                                  s * 128, name);
+            } else {
+                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
+            }
+        } else {
+            /*
+             * We would have errored-out already if we were attempting to
+             * disable a power-of-2 vector length less than another enabled
+             * vector length, but there may be uninitialized vector lengths
+             * larger than a power-of-2 vector length that we're disabling.
+             * We disable all of those lengths now too, as they can no longer
+             * be enabled.
+             */
+            if (is_power_of_2(vq)) {
+                for (s = vq + 1; s <= ARM_MAX_VQ; ++s) {
+                    arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
+                }
+            }
+
+            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+
+            /*
+             * We just disabled one or more vector lengths. We need to make
+             * sure we didn't disable them all when SVE is enabled.
+             */
+            if (cpu_isar_feature(aa64_sve, cpu) &&
+                !arm_cpu_num_vqs_available(cpu)) {
+                error_setg(errp, "cannot disable %s", name);
+                error_append_hint(errp, "Disabling %s results in all vector "
+                                  "lengths being disabled.\n", name);
+                error_append_hint(errp, "With SVE enabled, at least one vector "
+                                  "length must be enabled.\n");
+            }
+        }
     }
-    error_propagate(errp, err);
 }
 
 static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
@@ -306,6 +613,16 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
     t = cpu->isar.id_aa64pfr0;
     t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
     cpu->isar.id_aa64pfr0 = t;
+
+    /*
+     * When SVE is enabled ensure that we have at least one vector
+     * length available.
+     */
+    if (cpu_isar_feature(aa64_sve, cpu) && !arm_cpu_num_vqs_available(cpu)) {
+        error_setg(errp, "cannot enable SVE");
+        error_append_hint(errp, "All possible SVE vector lengths have "
+                          "been disabled.\n");
+    }
 }
 
 /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
@@ -316,6 +633,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);
@@ -400,11 +718,23 @@ 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);
+
+        /*
+         * sve_vq_map uses a special state while setting properties, so
+         * we initialize it here with its init function and finalize it
+         * in arm_cpu_realizefn().
+         */
+        arm_cpu_vq_map_init(cpu);
+        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 3064067c69a6..5d38f92eebef 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5272,6 +5272,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.
  */
@@ -5281,13 +5288,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 36a86cb83ce5..f7099917e137 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -90,8 +90,24 @@ 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
+ * will attempt to set them. If there are dependencies between features,
+ * as there are with the sve<vl-bits> features, then the order that
+ * considers those dependencies must be used.
+ *
+ * The sve<vl-bits> features need to be in reverse order in order to
+ * enable/disable the largest vector lengths first, ensuring all
+ * power-of-2 vector lengths smaller can also be enabled/disabled.
+ */
 static const char *cpu_model_advertised_features[] = {
     "aarch64", "pmu", "sve",
+    "sve2048", "sve1920", "sve1792", "sve1664", "sve1536", "sve1408",
+    "sve1280", "sve1152", "sve1024", "sve896", "sve768", "sve640",
+    "sve512", "sve384", "sve256", "sve128",
     NULL
 };
 
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 202bc0e3e823..a0752d000c08 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,181 @@ 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<vl-bits> 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-2(vq)   all-power-            can      can
+     *                                of-2(< 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-2(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-2(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-2(< vq)
+     *
+     * If given sve384=on,sve512=off,sve640=on the command line error would be
+     * "cannot enable sve640", but QMP visits the vector lengths in reverse
+     * order, so we get "cannot disable sve512" instead. The command line would
+     * also give that error if given sve384=on,sve640=on,sve512=off, so this is
+     * all fine. The important thing is that we get an error.
+     */
+    assert_error(qts, cpu_type, "cannot disable sve512",
+                 "{ 'sve384': true, 'sve512': false, 'sve640': true }");
+
+    /*
+     * We can disable power-of-2 vector lengths when all larger lengths
+     * are also disabled. We only need to disable the power-of-2 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-2(< 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-2 lengths smaller than the max-vq
+     * set by sve-max-vq, but not power-of-2 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 +367,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 +424,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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 09/15] target/arm/kvm64: Fix error returns
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (7 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 08/15] target/arm/cpu64: max cpu: Introduce sve<vl-bits> properties Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 10/15] target/arm/kvm64: Move the get/put of fpsimd registers out Andrew Jones
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

A couple return -EINVAL's forgot their '-'s.

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

diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 3d91846beb8f..ddde6268b9d0 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -854,7 +854,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     write_cpustate_to_list(cpu, true);
 
     if (!write_list_to_kvmstate(cpu, level)) {
-        return EINVAL;
+        return -EINVAL;
     }
 
     kvm_arm_sync_mpstate_to_kvm(cpu);
@@ -995,7 +995,7 @@ int kvm_arch_get_registers(CPUState *cs)
     }
 
     if (!write_kvmstate_to_list(cpu)) {
-        return EINVAL;
+        return -EINVAL;
     }
     /* Note that it's OK to have registers which aren't in CPUState,
      * so we can ignore a failure return here.
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 10/15] target/arm/kvm64: Move the get/put of fpsimd registers out
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (8 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 09/15] target/arm/kvm64: Fix error returns Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: peter.maydell, richard.henderson, armbru, eric.auger, imammedo,
	alex.bennee, Dave.Martin

Move the getting/putting of the fpsimd registers out of
kvm_arch_get/put_registers() into their own helper functions
to prepare for alternatively getting/putting SVE registers.

No functional change.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm64.c | 148 +++++++++++++++++++++++++++------------------
 1 file changed, 88 insertions(+), 60 deletions(-)

diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index ddde6268b9d0..0b004d5d3050 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -719,13 +719,53 @@ int kvm_arm_cpreg_level(uint64_t regidx)
 #define AARCH64_SIMD_CTRL_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U32 | \
                  KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
 
+static int kvm_arch_put_fpsimd(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    struct kvm_one_reg reg;
+    uint32_t fpr;
+    int i, ret;
+
+    for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
+#ifdef HOST_WORDS_BIGENDIAN
+        uint64_t fp_val[2] = { q[1], q[0] };
+        reg.addr = (uintptr_t)fp_val;
+#else
+        reg.addr = (uintptr_t)q;
+#endif
+        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            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;
+    }
+
+    return 0;
+}
+
 int kvm_arch_put_registers(CPUState *cs, int level)
 {
     struct kvm_one_reg reg;
-    uint32_t fpr;
     uint64_t val;
-    int i;
-    int ret;
+    int i, ret;
     unsigned int el;
 
     ARMCPU *cpu = ARM_CPU(cs);
@@ -815,33 +855,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         }
     }
 
-    /* Advanced SIMD and FP registers. */
-    for (i = 0; i < 32; i++) {
-        uint64_t *q = aa64_vfp_qreg(env, i);
-#ifdef HOST_WORDS_BIGENDIAN
-        uint64_t fp_val[2] = { q[1], q[0] };
-        reg.addr = (uintptr_t)fp_val;
-#else
-        reg.addr = (uintptr_t)q;
-#endif
-        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            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;
-    }
-
-    fpr = vfp_get_fpcr(env);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    ret = kvm_arch_put_fpsimd(cs);
     if (ret) {
         return ret;
     }
@@ -862,14 +876,54 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     return ret;
 }
 
+static int kvm_arch_get_fpsimd(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    struct kvm_one_reg reg;
+    uint32_t fpr;
+    int i, ret;
+
+    for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
+        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
+        reg.addr = (uintptr_t)q;
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        } else {
+#ifdef HOST_WORDS_BIGENDIAN
+            uint64_t t;
+            t = q[0], q[0] = q[1], q[1] = t;
+#endif
+        }
+    }
+
+    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;
+}
+
 int kvm_arch_get_registers(CPUState *cs)
 {
     struct kvm_one_reg reg;
     uint64_t val;
-    uint32_t fpr;
     unsigned int el;
-    int i;
-    int ret;
+    int i, ret;
 
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
@@ -958,36 +1012,10 @@ int kvm_arch_get_registers(CPUState *cs)
         env->spsr = env->banked_spsr[i];
     }
 
-    /* Advanced SIMD and FP registers */
-    for (i = 0; i < 32; i++) {
-        uint64_t *q = aa64_vfp_qreg(env, i);
-        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        reg.addr = (uintptr_t)q;
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        } else {
-#ifdef HOST_WORDS_BIGENDIAN
-            uint64_t t;
-            t = q[0], q[0] = q[1], q[1] = t;
-#endif
-        }
-    }
-
-    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.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    ret = kvm_arch_get_fpsimd(cs);
     if (ret) {
         return ret;
     }
-    vfp_set_fpcr(env, fpr);
 
     ret = kvm_get_vcpu_events(cpu);
     if (ret) {
-- 
2.20.1



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

* [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (9 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 10/15] target/arm/kvm64: Move the get/put of fpsimd registers out Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 18:07   ` Richard Henderson
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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>
---
 target/arm/kvm64.c | 150 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 146 insertions(+), 4 deletions(-)

diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 0b004d5d3050..f5c99984f25f 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,85 @@ 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.
+ */
+#ifdef HOST_WORDS_BIGENDIAN
+static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
+{
+    int i;
+
+    for (i = 0; i < nr; ++i) {
+        dst[i] = bswap64(src[i]);
+    }
+
+    return dst;
+}
+#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;
+#ifdef HOST_WORDS_BIGENDIAN
+    uint64_t tmp[ARM_MAX_VQ * 2];
+#endif
+    uint64_t *r;
+    struct kvm_one_reg reg;
+    int n, ret;
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
+        r = &env->vfp.zregs[n].d[0];
+#ifdef HOST_WORDS_BIGENDIAN
+        r = sve_bswap64(tmp, r, cpu->sve_max_vq * 2);
+#endif
+        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 = &env->vfp.pregs[n].p[0];
+#ifdef HOST_WORDS_BIGENDIAN
+        r = sve_bswap64(tmp, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+#endif
+        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 = &env->vfp.pregs[FFR_PRED_NUM].p[0];
+#ifdef HOST_WORDS_BIGENDIAN
+    r = sve_bswap64(tmp, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+#endif
+    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 +935,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 +1002,60 @@ 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;
+        }
+#ifdef HOST_WORDS_BIGENDIAN
+        sve_bswap64(r, r, cpu->sve_max_vq * 2);
+#endif
+    }
+
+    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;
+        }
+#ifdef HOST_WORDS_BIGENDIAN
+        sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+#endif
+    }
+
+    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;
+    }
+#ifdef HOST_WORDS_BIGENDIAN
+    sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq, 8));
+#endif
+
+    return 0;
+}
+
 int kvm_arch_get_registers(CPUState *cs)
 {
     struct kvm_one_reg reg;
@@ -1012,7 +1150,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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (10 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 18:20   ` Richard Henderson
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 13/15] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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>
---
 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 c9412a0b71af..f8ed393ed16c 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -610,6 +610,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;
@@ -634,11 +639,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);
 
@@ -720,8 +730,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);
 
         /*
          * sve_vq_map uses a special state while setting properties, so
@@ -736,6 +744,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 bfe3d445e196..ce4e362b3476 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -49,6 +49,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 f5c99984f25f..a6871017d375 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 a0752d000c08..51fbb1739d8e 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -394,6 +394,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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 13/15] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (11 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 14/15] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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 ce4e362b3476..4bf6664a2d63 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -64,7 +64,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) {
@@ -84,7 +84,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) {
@@ -96,10 +103,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;
             }
@@ -107,6 +116,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 51f78f722b18..d007f6bd34d7 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -54,7 +54,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 a6871017d375..48adfc16b3d7 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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 14/15] target/arm/cpu64: max cpu: Support sve properties with KVM
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (12 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 13/15] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 15/15] target/arm/kvm: host cpu: Add support for sve<vl-bits> properties Andrew Jones
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 docs/arm-cpu-features.rst |  36 ++++++---
 target/arm/cpu.h          |   3 +-
 target/arm/cpu64.c        | 159 +++++++++++++++++++++++++++++---------
 target/arm/kvm64.c        | 110 +++++++++++++++++++++++++-
 target/arm/kvm_arm.h      |  12 +++
 target/arm/monitor.c      |   2 +-
 tests/arm-cpu-features.c  |  89 ++++++++++++++++++++-
 7 files changed, 359 insertions(+), 52 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index aaaed861cda2..4181539e06a5 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-2 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-2 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-2 vector length also disables all vector lengths
-     larger than the power-of-2 length (see constraint (2) of "SVE CPU
-     Property Dependencies and Constraints").
+     When KVM is not enabled, disabling a power-of-2 vector length also
+     disables all vector lengths larger than the power-of-2 length.  When
+     KVM is enabled, then disabling any 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/cpu.h b/target/arm/cpu.h
index c8b96293c5e2..b6cd721c91f5 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -926,7 +926,8 @@ struct ARMCPU {
      * (bit-number + 1) * 16 bytes, i.e. each bit number + 1 is the vector
      * length in quadwords. We need a map size twice the maximum
      * quadword length though because we use two bits for each vector
-     * length in order to track three states: uninitialized, off, and on.
+     * length in order to track four states: uninitialized, uninitialized
+     * but supported by KVM, off, and on.
      */
     DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ * 2);
 };
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index f8ed393ed16c..0d0664b24865 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -261,13 +261,19 @@ static void aarch64_a72_initfn(Object *obj)
  * While we eventually use cpu->sve_vq_map as a typical bitmap, where each vq
  * has only two states (off/on), until we've finalized the map at realize time
  * we use an extra bit, at the vq - 1 + ARM_MAX_VQ bit number, to also allow
- * tracking of the uninitialized state. The arm_vq_state typedef and following
- * functions allow us to more easily work with the bitmap.
+ * tracking of the uninitialized state and the uninitialized but supported by
+ * KVM state. The arm_vq_state typedef and following functions allow us to more
+ * easily work with the bitmap.
  */
 typedef enum arm_vq_state {
     ARM_VQ_OFF,
     ARM_VQ_ON,
     ARM_VQ_UNINITIALIZED,
+    ARM_VQ_UNINITIALIZED_KVM_SUPPORTED
+    /*
+     * More states cannot be added without adding bits to sve_vq_map
+     * and modifying its supporting functions.
+     */
 } arm_vq_state;
 
 static arm_vq_state arm_cpu_vq_map_get(ARMCPU *cpu, uint32_t vq)
@@ -292,6 +298,22 @@ static void arm_cpu_vq_map_set(ARMCPU *cpu, uint32_t vq, arm_vq_state state)
     }
 }
 
+static bool arm_cpu_vq_kvm_supported(ARMCPU *cpu, uint32_t vq)
+{
+    return arm_cpu_vq_map_get(cpu, vq) != ARM_VQ_UNINITIALIZED;
+}
+
+static bool arm_cpu_vq_uninitialized(ARMCPU *cpu, uint32_t vq)
+{
+    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
+
+    if (kvm_enabled()) {
+        return vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED;
+    }
+
+    return vq_state == ARM_VQ_UNINITIALIZED;
+}
+
 /*
  * Uninitialized vector lengths need a default value to use in case we need
  * to query their value prior to map finalization. Additionally map finalizing
@@ -341,11 +363,9 @@ static int arm_cpu_num_vqs_available(ARMCPU *cpu)
     defval = arm_cpu_vq_map_get_default(cpu);
 
     for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
-
-        if (vq_state == ARM_VQ_ON) {
+        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
             ++num;
-        } else if (defval && vq_state == ARM_VQ_UNINITIALIZED) {
+        } else if (defval && arm_cpu_vq_uninitialized(cpu, vq)) {
             ++num;
         }
     }
@@ -358,6 +378,18 @@ static void arm_cpu_vq_map_init(ARMCPU *cpu)
     /* Set all vq's to 0b10 (ARM_VQ_UNINITIALIZED) */
     bitmap_clear(cpu->sve_vq_map, 0, ARM_MAX_VQ);
     bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ);
+
+    if (kvm_enabled()) {
+        /*
+         * As the upper bits of the ARM_VQ_UNINITIALIZED_KVM_SUPPORTED (0b11)
+         * states have already been set with the bitmap_set() above, we only
+         * need to OR in the lower bits.
+         */
+        DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
+
+        kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
+        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, kvm_supported, ARM_MAX_VQ);
+    }
 }
 
 void arm_cpu_sve_finalize(ARMCPU *cpu)
@@ -366,9 +398,9 @@ void arm_cpu_sve_finalize(ARMCPU *cpu)
     uint32_t vq, max_vq;
 
     for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
-
-        if (vq_state == ARM_VQ_UNINITIALIZED) {
+        if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
+            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+        } else if (arm_cpu_vq_uninitialized(cpu, vq)) {
             if (defval) {
                 arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
             } else {
@@ -421,6 +453,12 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
         return;
     }
 
+    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",
@@ -435,6 +473,12 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
             sprintf(tmp, "sve%d", vq * 128);
             object_property_set_bool(obj, true, tmp, &err);
             if (err) {
+                if (kvm_enabled()) {
+                    error_append_hint(&err, "It is not possible to use "
+                                      "sve-max-vq with this KVM host. Try "
+                                      "using only sve<vl-bits> "
+                                      "properties.\n");
+                }
                 error_propagate(errp, err);
                 return;
             }
@@ -459,6 +503,8 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
         value = true;
     } else if (vq_state == ARM_VQ_OFF) {
         value = false;
+    } else if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
+        value = false;
     } else if (arm_cpu_vq_map_get_default(cpu)) {
         value = true;
     } else {
@@ -483,6 +529,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;
+    }
+
     /*
      * We need to know the maximum vector length, which may just currently
      * be the maximum length, in order to validate the enabling/disabling
@@ -507,69 +559,101 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
         error_append_hint(errp, "The maximum vector length must be "
                           "enabled, sve-max-vq=%d (%d bits)\n",
                           cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (cpu->sve_max_vq && !value && vq < cpu->sve_max_vq &&
-               is_power_of_2(vq)) {
+    } else if (!kvm_enabled() && cpu->sve_max_vq && !value &&
+               vq < cpu->sve_max_vq && is_power_of_2(vq)) {
         error_setg(errp, "cannot disable %s", name);
         error_append_hint(errp, "vq=%d (%d bits) is required as it is a "
                           "power-of-2 length smaller than the maximum, "
                           "sve-max-vq=%d (%d bits)\n", vq, vq * 128,
                           cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (max_vq && !value && vq < max_vq && is_power_of_2(vq)) {
+    } else if (!kvm_enabled() && max_vq && !value && vq < max_vq &&
+               is_power_of_2(vq)) {
         error_setg(errp, "cannot disable %s", name);
         error_append_hint(errp, "Vector length %d-bits is required as it "
                           "is a power-of-2 length smaller than another "
                           "enabled vector length. Disable all larger vector "
                           "lengths first.\n", vq * 128);
+    } else if (kvm_enabled() && !value && vq < max_vq &&
+                arm_cpu_vq_kvm_supported(cpu, vq)) {
+        error_setg(errp, "cannot disable %s", name);
+        error_append_hint(errp, "Vector length %d-bits is a KVM supported "
+                          "length smaller than another enabled vector "
+                          "length. Disable all larger vector lengths "
+                          "first.\n", vq * 128);
+    } else if (kvm_enabled() && value && !arm_cpu_vq_kvm_supported(cpu, vq)) {
+        error_setg(errp, "cannot enable %s", name);
+        error_append_hint(errp, "This KVM host does not support "
+                          "the vector length %d-bits.\n", vq * 128);
     } else {
         uint32_t s;
 
         if (value) {
-            arm_vq_state vq_state;
             bool fail = false;
 
             /*
              * Enabling a vector length automatically enables all
              * uninitialized power-of-2 lengths smaller than it, as
              * per the architecture.
+             *
+             * For KVM we have to automatically enable all supported,
+             * uninitialized lengths smaller than this length, even
+             * when the smaller lengths are not power-of-2's.
              */
             for (s = 1; s < vq; ++s) {
-                if (is_power_of_2(s)) {
-                    vq_state = arm_cpu_vq_map_get(cpu, s);
-                    if (vq_state == ARM_VQ_UNINITIALIZED) {
+                if (kvm_enabled() || is_power_of_2(s)) {
+                    if (arm_cpu_vq_uninitialized(cpu, s)) {
                         arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON);
-                    } else if (vq_state == ARM_VQ_OFF) {
+                    } else if (arm_cpu_vq_map_get(cpu, s) == ARM_VQ_OFF) {
                         fail = true;
                         break;
                     }
                 }
             }
 
-            if (fail) {
+            if (!kvm_enabled() && fail) {
                 error_setg(errp, "cannot enable %s", name);
                 error_append_hint(errp, "Vector length %d-bits is disabled "
                                   "and is a power-of-2 length smaller than "
                                   "%s. All power-of-2 vector lengths smaller "
                                   "than the maximum length are required.\n",
                                   s * 128, name);
+
+            } else if (fail) {
+                error_setg(errp, "cannot enable %s", name);
+                error_append_hint(errp, "Vector length %d-bits is disabled "
+                                  "and the KVM host requires all supported "
+                                  "vector lengths smaller than %s to also be "
+                                  "enabled.\n", s * 128, name);
             } else {
                 arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
             }
         } else {
             /*
+             * When disabling vector lengths with KVM enabled if the vq wasn't
+             * supported then we leave it in the ARM_VQ_UNINITIALIZED state in
+             * order to keep that unsupported information. It'll be set to OFF
+             * later when we finalize the map.
+             *
              * We would have errored-out already if we were attempting to
              * disable a power-of-2 vector length less than another enabled
              * vector length, but there may be uninitialized vector lengths
              * larger than a power-of-2 vector length that we're disabling.
              * We disable all of those lengths now too, as they can no longer
-             * be enabled.
+             * be enabled. Additionally, for KVM, we have to automatically
+             * disable all supported, uninitialized lengths larger than this
+             * length, even when this length is not a power-of-2.
              */
-            if (is_power_of_2(vq)) {
+            if (kvm_enabled() || is_power_of_2(vq)) {
                 for (s = vq + 1; s <= ARM_MAX_VQ; ++s) {
-                    arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
+                    if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
+                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
+                    }
                 }
             }
 
-            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+            if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
+                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+            }
 
             /*
              * We just disabled one or more vector lengths. We need to make
@@ -727,26 +811,25 @@ 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);
-
-        /*
-         * sve_vq_map uses a special state while setting properties, so
-         * we initialize it here with its init function and finalize it
-         * in arm_cpu_realizefn().
-         */
-        arm_cpu_vq_map_init(cpu);
-        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);
+
+    /*
+     * sve_vq_map uses a special state while setting properties, so
+     * we initialize it here with its init function and finalize it
+     * in arm_cpu_realizefn().
+     */
+    arm_cpu_vq_map_init(cpu);
+    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 48adfc16b3d7..f6e2389f9f29 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -613,6 +613,110 @@ 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)
+{
+    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, NULL)) {
+            error_report("failed to create scratch vcpu");
+            abort();
+        }
+        ret = ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE);
+        kvm_arm_destroy_scratch_host_vcpu(fdarray);
+        if (ret <= 0) {
+            /* The host doesn't support SVE. */
+            return;
+        }
+
+        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
+            error_report("failed to create scratch vcpu");
+            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 +728,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 +764,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/target/arm/monitor.c b/target/arm/monitor.c
index f7099917e137..e2d559c2301a 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -101,7 +101,7 @@ QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
  *
  * The sve<vl-bits> features need to be in reverse order in order to
  * enable/disable the largest vector lengths first, ensuring all
- * power-of-2 vector lengths smaller can also be enabled/disabled.
+ * smaller required vector lengths can also be enabled/disabled.
  */
 static const char *cpu_model_advertised_features[] = {
     "aarch64", "pmu", "sve",
diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 51fbb1739d8e..720741375bc8 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);                   \
@@ -344,6 +355,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<vl-bits>=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;
@@ -393,12 +423,65 @@ 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;
+        uint32_t max_vq, vq;
+        uint64_t vls;
+        char name[8];
+        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);
+
+            /* Enabling a supported length is of course fine. */
+            sprintf(name, "sve%d", max_vq * 128);
+            assert_sve_vls(qts, "max", vls, "{ %s: true }", name);
+
+            /* Also disabling the largest lengths is fine. */
+            assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
+                           "{ %s: false }", name);
+
+            for (vq = 1; vq <= max_vq; ++vq) {
+                if (!(vls & BIT(vq - 1))) {
+                    /* vq is unsupported */
+                    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);
+            }
+
+            if (max_vq > 1) {
+                /*
+                 * Smaller, supported vector lengths cannot be disabled
+                 * unless all larger, supported vector lengths are disabled
+                 * first.
+                 */
+                vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
+                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);
+            }
+        } else {
+            g_assert(vls == 0);
+        }
     } else {
         assert_error(qts, "host",
                      "'pmu' feature not supported by KVM on this host",
@@ -435,6 +518,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] 37+ messages in thread

* [Qemu-devel] [PATCH v3 15/15] target/arm/kvm: host cpu: Add support for sve<vl-bits> properties
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (13 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 14/15] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
@ 2019-08-02 12:25 ` Andrew Jones
  2019-08-10  1:31 ` [Qemu-devel] [PATCH] HACK: Centralize sve property checks Richard Henderson
  2019-08-15  8:31 ` [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Peter Maydell
  16 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-02 12:25 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<vl-bits> 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          |  1 +
 target/arm/cpu.h          |  2 ++
 target/arm/cpu64.c        | 39 +++++++++++++++++++++++----------------
 tests/arm-cpu-features.c  | 15 ++++++++-------
 5 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/docs/arm-cpu-features.rst b/docs/arm-cpu-features.rst
index 4181539e06a5..dbf578ca231c 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-2 (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 842637ae0c49..901ae813563b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2648,6 +2648,7 @@ static void arm_host_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
 
     kvm_arm_set_cpu_features_from_host(cpu);
+    aarch64_add_sve_properties(obj);
     arm_cpu_post_init(obj);
 }
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index b6cd721c91f5..7993085bea28 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -972,11 +972,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 0d0664b24865..0313eec88a66 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -714,6 +714,28 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
     }
 }
 
+void aarch64_add_sve_properties(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    uint32_t vq;
+
+    object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
+                        cpu_arm_set_sve, NULL, NULL, &error_fatal);
+
+    /*
+     * sve_vq_map uses a special state while setting properties, so
+     * we initialize it here with its init function and finalize it
+     * in arm_cpu_realizefn().
+     */
+    arm_cpu_vq_map_init(cpu);
+    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;
@@ -722,7 +744,6 @@ 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()) {
@@ -813,23 +834,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);
-
-    /*
-     * sve_vq_map uses a special state while setting properties, so
-     * we initialize it here with its init function and finalize it
-     * in arm_cpu_realizefn().
-     */
-    arm_cpu_vq_map_init(cpu);
-    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/tests/arm-cpu-features.c b/tests/arm-cpu-features.c
index 720741375bc8..229f3cf64b12 100644
--- a/tests/arm-cpu-features.c
+++ b/tests/arm-cpu-features.c
@@ -359,7 +359,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
@@ -436,8 +436,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);
@@ -448,10 +448,10 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
 
             /* Enabling a supported length is of course fine. */
             sprintf(name, "sve%d", max_vq * 128);
-            assert_sve_vls(qts, "max", vls, "{ %s: true }", name);
+            assert_sve_vls(qts, "host", vls, "{ %s: true }", name);
 
             /* Also disabling the largest lengths is fine. */
-            assert_sve_vls(qts, "max", (vls & ~BIT(max_vq - 1)),
+            assert_sve_vls(qts, "host", (vls & ~BIT(max_vq - 1)),
                            "{ %s: false }", name);
 
             for (vq = 1; vq <= max_vq; ++vq) {
@@ -463,7 +463,7 @@ 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);
             }
 
@@ -476,13 +476,14 @@ static void test_query_cpu_model_expansion_kvm(const void *data)
                 vq = 64 - __builtin_clzll(vls & ~BIT(max_vq - 1));
                 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);
             }
         } 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] 37+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
@ 2019-08-02 16:27   ` Richard Henderson
  2019-08-03  1:28     ` Richard Henderson
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-02 16:27 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 5:25 AM, Andrew Jones wrote:
> Note, certainly more features may be added to the list of
> advertised features, e.g. 'vfp' and 'neon'. The only requirement
> is that their property set accessors fail when invalid
> configurations are detected. For vfp we would need something like
> 
>  set_vfp()
>  {
>    if (arm_feature(env, ARM_FEATURE_AARCH64) &&
>        cpu->has_vfp != cpu->has_neon)
>        error("AArch64 CPUs must have both VFP and Neon or neither")
> 
> in its set accessor, and the same for neon, rather than doing that
> check at realize time, which isn't executed at qmp query time.

How could this succeed?  Either set_vfp or set_neon would be called first, at
which point the two features are temporarily out of sync, but the error would
trigger anyway.

This would seem to require some separate "qmp validate" step that is processed
after a collection of properties are set.

I was about to say something about this being moot until someone actually wants
to be able to disable vfp+neon on aarch64, but then...

> +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.

... this language makes me think that you've already encountered an ordering
problem that might be better solved with a separate validate step?

The actual code looks good.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size Andrew Jones
@ 2019-08-02 16:33   ` Richard Henderson
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Henderson @ 2019-08-02 16:33 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 5:25 AM, Andrew Jones wrote:
> Unless we're guaranteed to always increase ARM_MAX_VQ by a multiple of
> four, then we should use DIV_ROUND_UP to ensure we get an appropriate
> array size.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  target/arm/cpu.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
@ 2019-08-02 16:35   ` Richard Henderson
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Henderson @ 2019-08-02 16:35 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 5:25 AM, 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>
> ---
>  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(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
@ 2019-08-02 18:07   ` Richard Henderson
  2019-08-06 12:24     ` Andrew Jones
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-02 18:07 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 5:25 AM, Andrew Jones wrote:
> +/*
> + * 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.
> + */
> +#ifdef HOST_WORDS_BIGENDIAN
> +static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
> +{
> +    int i;
> +
> +    for (i = 0; i < nr; ++i) {
> +        dst[i] = bswap64(src[i]);
> +    }
> +
> +    return dst;
> +}
> +#endif

Maybe better as

static uint64_t *sve_bswap64(uint64_t *tmp, uint64_t *src, int nr)
{
#ifdef HOST_WORDS_BIGENDIAN
    int i;

    for (i = 0; i < nr; ++i) {
        tmp[i] = bswap64(src[i]);
    }

    return tmp;
#else
    return src;
#endif
}

and then the rest of the ifdefs can be removed.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
@ 2019-08-02 18:20   ` Richard Henderson
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Henderson @ 2019-08-02 18:20 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 5:25 AM, 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>
> ---
>  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(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-02 16:27   ` Richard Henderson
@ 2019-08-03  1:28     ` Richard Henderson
  2019-08-06 12:21       ` Andrew Jones
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-03  1:28 UTC (permalink / raw)
  To: Andrew Jones, qemu-devel, qemu-arm
  Cc: peter.maydell, armbru, eric.auger, imammedo, alex.bennee, Dave.Martin

On 8/2/19 9:27 AM, Richard Henderson wrote:
> On 8/2/19 5:25 AM, Andrew Jones wrote:
>> Note, certainly more features may be added to the list of
>> advertised features, e.g. 'vfp' and 'neon'. The only requirement
>> is that their property set accessors fail when invalid
>> configurations are detected. For vfp we would need something like
>>
>>  set_vfp()
>>  {
>>    if (arm_feature(env, ARM_FEATURE_AARCH64) &&
>>        cpu->has_vfp != cpu->has_neon)
>>        error("AArch64 CPUs must have both VFP and Neon or neither")
>>
>> in its set accessor, and the same for neon, rather than doing that
>> check at realize time, which isn't executed at qmp query time.
> 
> How could this succeed?  Either set_vfp or set_neon would be called first, at
> which point the two features are temporarily out of sync, but the error would
> trigger anyway.
> 
> This would seem to require some separate "qmp validate" step that is processed
> after a collection of properties are set.
> 
> I was about to say something about this being moot until someone actually wants
> to be able to disable vfp+neon on aarch64, but then...
> 
>> +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.
> 
> ... this language makes me think that you've already encountered an ordering
> problem that might be better solved with a separate validate step?

It appears to me that we can handle both use cases with a single function to
handle validation of the cross-dependent properties.

It would need to be called at the beginning of arm_cpu_realizefn, for the case
in which we are building a cpu that we wish to instantiate, and

> +        if (!err) {
> +            visit_check_struct(visitor, &err);
> +        }

here, inside qmp_query_cpu_model_expansion for the query case.

Looking at the validation code scattered across multiple functions, across 4
patches, convinces me that the code will be smaller and more readable if we
consolidate them into a single validation function.


r~


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-03  1:28     ` Richard Henderson
@ 2019-08-06 12:21       ` Andrew Jones
  2019-08-07 15:22         ` Richard Henderson
  0 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-06 12:21 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Fri, Aug 02, 2019 at 06:28:51PM -0700, Richard Henderson wrote:
> On 8/2/19 9:27 AM, Richard Henderson wrote:
> > On 8/2/19 5:25 AM, Andrew Jones wrote:
> >> Note, certainly more features may be added to the list of
> >> advertised features, e.g. 'vfp' and 'neon'. The only requirement
> >> is that their property set accessors fail when invalid
> >> configurations are detected. For vfp we would need something like
> >>
> >>  set_vfp()
> >>  {
> >>    if (arm_feature(env, ARM_FEATURE_AARCH64) &&
> >>        cpu->has_vfp != cpu->has_neon)
> >>        error("AArch64 CPUs must have both VFP and Neon or neither")
> >>
> >> in its set accessor, and the same for neon, rather than doing that
> >> check at realize time, which isn't executed at qmp query time.
> > 
> > How could this succeed?  Either set_vfp or set_neon would be called first, at
> > which point the two features are temporarily out of sync, but the error would
> > trigger anyway.
> > 
> > This would seem to require some separate "qmp validate" step that is processed
> > after a collection of properties are set.
> > 
> > I was about to say something about this being moot until someone actually wants
> > to be able to disable vfp+neon on aarch64, but then...
> > 
> >> +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.
> > 
> > ... this language makes me think that you've already encountered an ordering
> > problem that might be better solved with a separate validate step?
> 
> It appears to me that we can handle both use cases with a single function to
> handle validation of the cross-dependent properties.
> 
> It would need to be called at the beginning of arm_cpu_realizefn, for the case
> in which we are building a cpu that we wish to instantiate, and
> 
> > +        if (!err) {
> > +            visit_check_struct(visitor, &err);
> > +        }
> 
> here, inside qmp_query_cpu_model_expansion for the query case.
> 
> Looking at the validation code scattered across multiple functions, across 4
> patches, convinces me that the code will be smaller and more readable if we
> consolidate them into a single validation function.
>

That's a reasonable suggestion. I do like having self-contained
validation, self-contained, but when cross-dependencies arise, then
it does make sense to have a master validation function, rather
than interconnecting too much. That said, for this series we only
enable the qmp query for aarch64, pmu, and sve* properties. aarch64
and pmu are independent, and thus self-contained, and I consider
all sve* properties one big entity, so their validation is also
self-contained. If we add vfp and neon, then indeed I was wrong
with my suggestion in the commit message. They would need a later
validation check. Should we just cross that bridge when we get there
though? Or would you like me to see how that would work within this
series?

Thanks,
drew


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

* Re: [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve
  2019-08-02 18:07   ` Richard Henderson
@ 2019-08-06 12:24     ` Andrew Jones
  0 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-06 12:24 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Fri, Aug 02, 2019 at 11:07:54AM -0700, Richard Henderson wrote:
> On 8/2/19 5:25 AM, Andrew Jones wrote:
> > +/*
> > + * 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.
> > + */
> > +#ifdef HOST_WORDS_BIGENDIAN
> > +static uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr)
> > +{
> > +    int i;
> > +
> > +    for (i = 0; i < nr; ++i) {
> > +        dst[i] = bswap64(src[i]);
> > +    }
> > +
> > +    return dst;
> > +}
> > +#endif
> 
> Maybe better as
> 
> static uint64_t *sve_bswap64(uint64_t *tmp, uint64_t *src, int nr)
> {
> #ifdef HOST_WORDS_BIGENDIAN
>     int i;
> 
>     for (i = 0; i < nr; ++i) {
>         tmp[i] = bswap64(src[i]);
>     }
> 
>     return tmp;
> #else
>     return src;
> #endif
> }
> 
> and then the rest of the ifdefs can be removed.

Will do for v4.

> 
> Otherwise,
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

Thanks!

drew


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-06 12:21       ` Andrew Jones
@ 2019-08-07 15:22         ` Richard Henderson
  2019-08-08  8:50           ` Andrew Jones
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-07 15:22 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On 8/6/19 5:21 AM, Andrew Jones wrote:
> That's a reasonable suggestion. I do like having self-contained
> validation, self-contained, but when cross-dependencies arise, then
> it does make sense to have a master validation function, rather
> than interconnecting too much. That said, for this series we only
> enable the qmp query for aarch64, pmu, and sve* properties. aarch64
> and pmu are independent, and thus self-contained...

Agreed.

> and I consider
> all sve* properties one big entity, so their validation is also
> self-contained. If we add vfp and neon, then indeed I was wrong
> with my suggestion in the commit message. They would need a later
> validation check. Should we just cross that bridge when we get there
> though? Or would you like me to see how that would work within this
> series?

While the sve* properties are handled by one function, they are not handled as
"one big entity".  You examine then apply or diagnose the effects of sve384=on
before you separately examine the effects of sve512=on.

I think it would be easiest to merely record facts while processing sve<N> and
sve-max-vq, with no side effects.  Then in the common validation function see
the required side effects and diagnose errors all at once.


r~


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-07 15:22         ` Richard Henderson
@ 2019-08-08  8:50           ` Andrew Jones
  2019-08-08 18:37             ` Richard Henderson
  0 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-08  8:50 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Wed, Aug 07, 2019 at 08:22:07AM -0700, Richard Henderson wrote:
> On 8/6/19 5:21 AM, Andrew Jones wrote:
> > That's a reasonable suggestion. I do like having self-contained
> > validation, self-contained, but when cross-dependencies arise, then
> > it does make sense to have a master validation function, rather
> > than interconnecting too much. That said, for this series we only
> > enable the qmp query for aarch64, pmu, and sve* properties. aarch64
> > and pmu are independent, and thus self-contained...
> 
> Agreed.
> 
> > and I consider
> > all sve* properties one big entity, so their validation is also
> > self-contained. If we add vfp and neon, then indeed I was wrong
> > with my suggestion in the commit message. They would need a later
> > validation check. Should we just cross that bridge when we get there
> > though? Or would you like me to see how that would work within this
> > series?
> 
> While the sve* properties are handled by one function, they are not handled as
> "one big entity".  You examine then apply or diagnose the effects of sve384=on
> before you separately examine the effects of sve512=on.
> 
> I think it would be easiest to merely record facts while processing sve<N> and
> sve-max-vq, with no side effects.  Then in the common validation function see
> the required side effects and diagnose errors all at once.
>

I'm not sure. Of course I'd need to experiment with it to be sure, but
I'm reluctant to go through that exercise, because I believe that a
deferred validation will result in less specific errors messages. For
example, how would the validator know in which order the sve<N> properties
were provided? Which is necessary to complain that one length is not
allowed when another has already been disabled, or vice versa.

Also with deferred validation I think I'd need more vq states, at least
for when KVM is enabled. For example, if 384-bit vector lengths are not
supported on the KVM host, but the user does sve384=on, and all we do
is record that, then we've lost the KVM unsupported information and won't
find out until we attempt to enable it later at kvm vcpu init time. We'd
need a kvm-unsupported-user-enabled state to track that, which also means
we're not blindly recording user input in cpu_arm_set_sve_vq() anymore,
but are instead applying logic to decide which state we transition to.

Thanks,
drew


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-08  8:50           ` Andrew Jones
@ 2019-08-08 18:37             ` Richard Henderson
  2019-08-09 16:09               ` Andrew Jones
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-08 18:37 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On 8/8/19 1:50 AM, Andrew Jones wrote:
> I'm not sure. Of course I'd need to experiment with it to be sure, but
> I'm reluctant to go through that exercise, because I believe that a
> deferred validation will result in less specific errors messages. For
> example, how would the validator know in which order the sve<N> properties
> were provided? Which is necessary to complain that one length is not
> allowed when another has already been disabled, or vice versa.

My point is that we would not *need* to know in which order the properties are
provided, and do not care.  Indeed, removing this ordering malarkey is a
feature not a bug.

The error message would simply state, e.g., that sve256 may not be disabled
while sve512 is enabled.  The error message does not need to reference the
order in which they appeared.

> Also with deferred validation I think I'd need more vq states, at least
> for when KVM is enabled. For example, if 384-bit vector lengths are not
> supported on the KVM host, but the user does sve384=on, and all we do
> is record that, then we've lost the KVM unsupported information and won't
> find out until we attempt to enable it later at kvm vcpu init time. We'd
> need a kvm-unsupported-user-enabled state to track that, which also means
> we're not blindly recording user input in cpu_arm_set_sve_vq() anymore,
> but are instead applying logic to decide which state we transition to.

Or perhaps, less vq states.  You do not need to compute kvm states early.  You
can wait to collect those until validation time and keep them in their own
local bitmap.

bool validate_sve_properties(...)
{
    // Populate uninitialized bits in sve_vq_map from sve_max_vq.
    // Populate uninitialized bits in sve_vq_map from on bits in sve_vq_map.
    // All remaining uninitialized bits are set to off.
    // Reset sve_max_vq to the maximum bit set in sve_vq_map, plus 1.
    // Diagnose off bits in sve_vq_map from on bits in sve_vq_map.

    if (kvm_enabled()) {
        DECLARE_BITMAP(test, ARM_MAX_VQ);
        kvm_arm_sve_get_vls(CPU(cpu), test);
        if (!bitmap_equal(test, s->sve_vq_map, s->sve_max_vq))  {
            bitmap_xor(test, test, s->sve_vq_map, s->sve_max_vq);
            // Diagnose the differences in TEST:
            // test[i] & s->sve_vq_map[i] -> i is unsupported by kvm
            // test[i] & !s->sve_vq_map[i] -> i is required by kvm
        }
    }
}

If you prefer not to experiment with this, then I will.


r~


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

* Re: [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion
  2019-08-08 18:37             ` Richard Henderson
@ 2019-08-09 16:09               ` Andrew Jones
  0 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-09 16:09 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Thu, Aug 08, 2019 at 11:37:01AM -0700, Richard Henderson wrote:
> On 8/8/19 1:50 AM, Andrew Jones wrote:
> > I'm not sure. Of course I'd need to experiment with it to be sure, but
> > I'm reluctant to go through that exercise, because I believe that a
> > deferred validation will result in less specific errors messages. For
> > example, how would the validator know in which order the sve<N> properties
> > were provided? Which is necessary to complain that one length is not
> > allowed when another has already been disabled, or vice versa.
> 
> My point is that we would not *need* to know in which order the properties are
> provided, and do not care.  Indeed, removing this ordering malarkey is a
> feature not a bug.
> 
> The error message would simply state, e.g., that sve256 may not be disabled
> while sve512 is enabled.  The error message does not need to reference the
> order in which they appeared.

OK, I agree it doesn't make much difference to the user whether the error
hint is the generic "sve256 required with sve512" verse

 sve256=off,sve512=on  "cannot enable sve512 with sve256 disabled"

or

 sve512=on,sve256=off  "cannot disable sve256 with sve512 enabled"

> 
> > Also with deferred validation I think I'd need more vq states, at least
> > for when KVM is enabled. For example, if 384-bit vector lengths are not
> > supported on the KVM host, but the user does sve384=on, and all we do
> > is record that, then we've lost the KVM unsupported information and won't
> > find out until we attempt to enable it later at kvm vcpu init time. We'd
> > need a kvm-unsupported-user-enabled state to track that, which also means
> > we're not blindly recording user input in cpu_arm_set_sve_vq() anymore,
> > but are instead applying logic to decide which state we transition to.
> 
> Or perhaps, less vq states.  You do not need to compute kvm states early.  You
> can wait to collect those until validation time and keep them in their own
> local bitmap.
> 
> bool validate_sve_properties(...)
> {
>     // Populate uninitialized bits in sve_vq_map from sve_max_vq.
>     // Populate uninitialized bits in sve_vq_map from on bits in sve_vq_map.

And disable uninitialized bits in sve_vq_map from OFF bits: auto-disabling

Also we can't do these populate uninitialized bits from on/off steps when
KVM is enabled without first getting the kvm-supported map.

>     // All remaining uninitialized bits are set to off.
>     // Reset sve_max_vq to the maximum bit set in sve_vq_map, plus 1.

I wouldn't always do this. If the user explicitly sets a maximum with
sve-max-vq, then we should generate errors when other inputs would change
that maximum. I would only assert they're the same when both input types
are provided. Of course we do the above when only map input is provided
though.

>     // Diagnose off bits in sve_vq_map from on bits in sve_vq_map.
> 
>     if (kvm_enabled()) {
>         DECLARE_BITMAP(test, ARM_MAX_VQ);
>         kvm_arm_sve_get_vls(CPU(cpu), test);
>         if (!bitmap_equal(test, s->sve_vq_map, s->sve_max_vq))  {
>             bitmap_xor(test, test, s->sve_vq_map, s->sve_max_vq);
>             // Diagnose the differences in TEST:
>             // test[i] & s->sve_vq_map[i] -> i is unsupported by kvm
>             // test[i] & !s->sve_vq_map[i] -> i is required by kvm
>         }
>     }
> }
> 
> If you prefer not to experiment with this, then I will.
>

Ah, the ol' I'll do it if you don't motivator... I do see some
potential for a reduction in complexity with this approach, but
I'm not sure we'll save many lines of code. I could do a quick
hack on top of this series, just to see how well the validator
function looks and works, but I can't get to it until midweek
next week. I won't complain if you beat me to it :-)

Thanks,
drew


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

* [Qemu-devel] [PATCH] HACK: Centralize sve property checks
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (14 preceding siblings ...)
  2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 15/15] target/arm/kvm: host cpu: Add support for sve<vl-bits> properties Andrew Jones
@ 2019-08-10  1:31 ` Richard Henderson
  2019-09-04  8:32   ` Andrew Jones
  2019-08-15  8:31 ` [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Peter Maydell
  16 siblings, 1 reply; 37+ messages in thread
From: Richard Henderson @ 2019-08-10  1:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, drjones, armbru, eric.auger, qemu-arm, imammedo,
	alex.bennee, Dave.Martin

As promised, an experiment in unifying the checks.

I believe that I've tested for all of the same conditions, modulo the
timing at which they are emitted.  As before, only one error is reported,
so if multiple errors exist you can't rely on which error is seen.

I think there's value in splitting the sve_map_vq bitmap such that the
initialized state can be easily manipulated with bitmap functions.

The diffstat is promising.  Lemme know what you think.


r~

---
 target/arm/cpu.h     |  16 +-
 target/arm/cpu.c     |  12 +-
 target/arm/cpu64.c   | 502 ++++++++++++++-----------------------------
 target/arm/monitor.c |   7 +
 4 files changed, 190 insertions(+), 347 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 7993085bea..924476480b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -184,11 +184,11 @@ typedef struct {
 
 #ifdef TARGET_AARCH64
 # define ARM_MAX_VQ    16
-void arm_cpu_sve_finalize(ARMCPU *cpu);
+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) { }
+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
@@ -924,12 +924,14 @@ struct ARMCPU {
     /*
      * 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. We need a map size twice the maximum
-     * quadword length though because we use two bits for each vector
-     * length in order to track four states: uninitialized, uninitialized
-     * but supported by KVM, off, and on.
+     * 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 * 2);
+    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
+    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
 };
 
 void arm_cpu_post_init(Object *obj);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 604f5c3651..a113c30def 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1255,8 +1255,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        arm_cpu_sve_finalize(cpu);
+    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+        arm_cpu_sve_finalize(cpu, &local_err);
+        if (local_err != NULL) {
+            error_propagate(errp, local_err);
+            return;
+        }
     }
 
     if (arm_feature(env, ARM_FEATURE_AARCH64) &&
@@ -2656,7 +2660,9 @@ static void arm_host_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
 
     kvm_arm_set_cpu_features_from_host(cpu);
-    aarch64_add_sve_properties(obj);
+    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+        aarch64_add_sve_properties(obj);
+    }
     arm_cpu_post_init(obj);
 }
 
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 0313eec88a..7c7e54ad78 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -257,165 +257,168 @@ static void aarch64_a72_initfn(Object *obj)
     define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
 }
 
-/*
- * While we eventually use cpu->sve_vq_map as a typical bitmap, where each vq
- * has only two states (off/on), until we've finalized the map at realize time
- * we use an extra bit, at the vq - 1 + ARM_MAX_VQ bit number, to also allow
- * tracking of the uninitialized state and the uninitialized but supported by
- * KVM state. The arm_vq_state typedef and following functions allow us to more
- * easily work with the bitmap.
- */
-typedef enum arm_vq_state {
-    ARM_VQ_OFF,
-    ARM_VQ_ON,
-    ARM_VQ_UNINITIALIZED,
-    ARM_VQ_UNINITIALIZED_KVM_SUPPORTED
-    /*
-     * More states cannot be added without adding bits to sve_vq_map
-     * and modifying its supporting functions.
-     */
-} arm_vq_state;
-
-static arm_vq_state arm_cpu_vq_map_get(ARMCPU *cpu, uint32_t vq)
+void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
 {
-    assert(vq <= ARM_MAX_VQ);
-
-    return test_bit(vq - 1, cpu->sve_vq_map) |
-           test_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map) << 1;
-}
-
-static void arm_cpu_vq_map_set(ARMCPU *cpu, uint32_t vq, arm_vq_state state)
-{
-    assert(vq <= ARM_MAX_VQ);
-    assert(state == ARM_VQ_OFF || state == ARM_VQ_ON);
-
-    clear_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map);
-
-    if (state == ARM_VQ_ON) {
-        set_bit(vq - 1, cpu->sve_vq_map);
-    } else {
-        clear_bit(vq - 1, cpu->sve_vq_map);
-    }
-}
-
-static bool arm_cpu_vq_kvm_supported(ARMCPU *cpu, uint32_t vq)
-{
-    return arm_cpu_vq_map_get(cpu, vq) != ARM_VQ_UNINITIALIZED;
-}
-
-static bool arm_cpu_vq_uninitialized(ARMCPU *cpu, uint32_t vq)
-{
-    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
-
-    if (kvm_enabled()) {
-        return vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED;
-    }
-
-    return vq_state == ARM_VQ_UNINITIALIZED;
-}
-
-/*
- * Uninitialized vector lengths need a default value to use in case we need
- * to query their value prior to map finalization. Additionally map finalizing
- * itself needs to determine what value to assign uninitialized vector lengths.
- * The default is determined as follows:
- *
- *  * When no vector lengths have been explicitly enabled, i.e. either no
- *    input has been provided by the user at all, or vector lengths have
- *    only been disabled, then all uninitialized vector lengths default 'ON'.
- *
- *  * When one or more vector lengths have been enabled, then all uninitialized
- *    vector lengths default 'OFF'. Note, when checking for enabled vector
- *    lengths we do not discriminate between user-enabled vector lengths and
- *    auto-enabled vector lengths (which were auto-enabled in order to satisfy
- *    the user-enabled vector lengths). This implies the default can never
- *    transition back to 'ON', even if the user-enabled and auto-enabled vector
- *    lengths that initially transitioned it to 'OFF' are later disabled, as at
- *    least one vector length must remain enabled unless the SVE feature is
- *    completely disabled. If SVE is completely disabled then all vector
- *    lengths are effectively 'OFF'.
- */
-static bool arm_cpu_vq_map_get_default(ARMCPU *cpu)
-{
-    uint32_t vq;
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-/*
- * We need to be able to track the number of enabled (or will-be enabled)
- * vector lengths in order to ensure we never drop to zero. If the default
- * is 'ON', then we count enabled and uninitialized vector lengths. Otherwise,
- * if the default is 'OFF', then we only count enabled vector lengths.
- */
-static int arm_cpu_num_vqs_available(ARMCPU *cpu)
-{
-    uint32_t vq;
-    bool defval;
-    int num = 0;
-
-    defval = arm_cpu_vq_map_get_default(cpu);
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            ++num;
-        } else if (defval && arm_cpu_vq_uninitialized(cpu, vq)) {
-            ++num;
-        }
-    }
-
-    return num;
-}
-
-static void arm_cpu_vq_map_init(ARMCPU *cpu)
-{
-    /* Set all vq's to 0b10 (ARM_VQ_UNINITIALIZED) */
-    bitmap_clear(cpu->sve_vq_map, 0, ARM_MAX_VQ);
-    bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ);
-
-    if (kvm_enabled()) {
-        /*
-         * As the upper bits of the ARM_VQ_UNINITIALIZED_KVM_SUPPORTED (0b11)
-         * states have already been set with the bitmap_set() above, we only
-         * need to OR in the lower bits.
-         */
-        DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
+    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
+    DECLARE_BITMAP(test, ARM_MAX_VQ);
+    uint32_t vq, max_vq = 0;
 
+    /* Collect the set of VQ supported by KVM. */
+    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
         kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
-        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, kvm_supported, ARM_MAX_VQ);
+    } else {
+        bitmap_zero(kvm_supported, ARM_MAX_VQ);
     }
-}
 
-void arm_cpu_sve_finalize(ARMCPU *cpu)
-{
-    bool defval = arm_cpu_vq_map_get_default(cpu);
-    uint32_t vq, max_vq;
+    /*
+     * 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;
 
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-        } else if (arm_cpu_vq_uninitialized(cpu, vq)) {
-            if (defval) {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
-            } else {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
+        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);
+                set_bit(vq - 1, cpu->sve_vq_init);
             }
         }
+
+        /*
+         * For KVM we have to automatically enable all supported unitialized
+         * lengths, even when the smaller lengths are not all powers-of-two.
+         */
+        if (kvm_enabled()) {
+            if (!kvm_arm_sve_supported(CPU(cpu))) {
+                error_setg(errp, "cannot enable sve%d", max_vq);
+                error_append_hint(errp, "SVE not supported by "
+                                  "KVM on this host\n");
+                return;
+            }
+            bitmap_andnot(test, kvm_supported, cpu->sve_vq_init, max_vq);
+            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
+            bitmap_or(cpu->sve_vq_init, cpu->sve_vq_init, test, max_vq);
+        }
+    } 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);
+
+        /* Enable all supported bits other than those explicit disabled. */
+        if (kvm_enabled()) {
+            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
+                          cpu->sve_vq_init, max_vq);
+        } else {
+            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
+        }
+        bitmap_set(cpu->sve_vq_init, 0, max_vq);
+        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
     }
 
-    max_vq = arm_cpu_vq_map_next_smaller(cpu, ARM_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 (!cpu->sve_max_vq) {
-        cpu->sve_max_vq = 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(test, cpu->sve_vq_init, max_vq);
+        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
     }
 
-    assert(max_vq && cpu->sve_max_vq == max_vq);
+    /*
+     * At this point we will have found max_vq.  All bits implied from
+     * other properties are set or clear in cpu->sve_vq_map.
+     * All bits implied from other sve<N> are set in cpu->sve_vq_init.
+     * If sve_vq_map<N> & !sve_vq_init<N>, then the bit must have come
+     * sve-max-vq.
+     */
+    assert(max_vq != 0);
+
+    /* 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-2 length smaller than "
+                              "the maximum, sve%d\n",
+                              vq * 128, max_vq * 128);
+            return;
+        }
+    }
+
+    /* Ensure the set of lengths matches what KVM supports. */
+    if (kvm_enabled()) {
+        bitmap_xor(test, cpu->sve_vq_map, kvm_supported, max_vq);
+        if (!bitmap_empty(test, max_vq)) {
+            vq = find_last_bit(test, max_vq);
+            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
+                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);
+            } else if (test_bit(vq - 1, cpu->sve_vq_init)) {
+                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 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<vl-bits> properties.\n");
+            }
+            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)
@@ -427,6 +430,7 @@ uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
      * 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 > 1);
     assert(vq <= ARM_MAX_VQ + 1);
 
     bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
@@ -437,7 +441,15 @@ 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,
@@ -445,7 +457,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     Error *err = NULL;
-    uint32_t vq;
 
     visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
     if (err) {
@@ -465,27 +476,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
                           ARM_MAX_VQ);
         return;
     }
-
-    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
-        if (vq <= cpu->sve_max_vq) {
-            char tmp[8];
-
-            sprintf(tmp, "sve%d", vq * 128);
-            object_property_set_bool(obj, true, tmp, &err);
-            if (err) {
-                if (kvm_enabled()) {
-                    error_append_hint(&err, "It is not possible to use "
-                                      "sve-max-vq with this KVM host. Try "
-                                      "using only sve<vl-bits> "
-                                      "properties.\n");
-                }
-                error_propagate(errp, err);
-                return;
-            }
-        } else if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
-            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-        }
-    }
 }
 
 static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
@@ -493,24 +483,14 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq = atoi(&name[3]) / 128;
-    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
     bool value;
 
+    /* All vector lengths are disabled when SVE is off. */
     if (!cpu_isar_feature(aa64_sve, cpu)) {
-        /* All vector lengths are disabled when SVE is off. */
         value = false;
-    } else if (vq_state == ARM_VQ_ON) {
-        value = true;
-    } else if (vq_state == ARM_VQ_OFF) {
-        value = false;
-    } else if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-        value = false;
-    } else if (arm_cpu_vq_map_get_default(cpu)) {
-        value = true;
     } else {
-        value = false;
+        value = test_bit(vq - 1, cpu->sve_vq_map);
     }
-
     visit_type_bool(v, name, &value, errp);
 }
 
@@ -519,7 +499,6 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
 {
     ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq = atoi(&name[3]) / 128;
-    uint32_t max_vq = 0;
     Error *err = NULL;
     bool value;
 
@@ -529,146 +508,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;
-    }
-
-    /*
-     * We need to know the maximum vector length, which may just currently
-     * be the maximum length, in order to validate the enabling/disabling
-     * of this vector length.
-     */
-    if (!cpu->sve_max_vq) {
-        for (max_vq = ARM_MAX_VQ; max_vq >= 1; --max_vq) {
-            if (arm_cpu_vq_map_get(cpu, max_vq) == ARM_VQ_ON) {
-                break;
-            }
-        }
-    }
-
-    if (cpu->sve_max_vq && value && vq > cpu->sve_max_vq) {
-        error_setg(errp, "cannot enable %s", name);
-        error_append_hint(errp, "vq=%d (%d bits) is larger than the "
-                          "maximum vector length, sve-max-vq=%d "
-                          "(%d bits)\n", vq, vq * 128,
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (cpu->sve_max_vq && !value && vq == cpu->sve_max_vq) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "The maximum vector length must be "
-                          "enabled, sve-max-vq=%d (%d bits)\n",
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (!kvm_enabled() && cpu->sve_max_vq && !value &&
-               vq < cpu->sve_max_vq && is_power_of_2(vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "vq=%d (%d bits) is required as it is a "
-                          "power-of-2 length smaller than the maximum, "
-                          "sve-max-vq=%d (%d bits)\n", vq, vq * 128,
-                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
-    } else if (!kvm_enabled() && max_vq && !value && vq < max_vq &&
-               is_power_of_2(vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "Vector length %d-bits is required as it "
-                          "is a power-of-2 length smaller than another "
-                          "enabled vector length. Disable all larger vector "
-                          "lengths first.\n", vq * 128);
-    } else if (kvm_enabled() && !value && vq < max_vq &&
-                arm_cpu_vq_kvm_supported(cpu, vq)) {
-        error_setg(errp, "cannot disable %s", name);
-        error_append_hint(errp, "Vector length %d-bits is a KVM supported "
-                          "length smaller than another enabled vector "
-                          "length. Disable all larger vector lengths "
-                          "first.\n", vq * 128);
-    } else if (kvm_enabled() && value && !arm_cpu_vq_kvm_supported(cpu, vq)) {
-        error_setg(errp, "cannot enable %s", name);
-        error_append_hint(errp, "This KVM host does not support "
-                          "the vector length %d-bits.\n", vq * 128);
+    if (value) {
+        set_bit(vq - 1, cpu->sve_vq_map);
     } else {
-        uint32_t s;
-
-        if (value) {
-            bool fail = false;
-
-            /*
-             * Enabling a vector length automatically enables all
-             * uninitialized power-of-2 lengths smaller than it, as
-             * per the architecture.
-             *
-             * For KVM we have to automatically enable all supported,
-             * uninitialized lengths smaller than this length, even
-             * when the smaller lengths are not power-of-2's.
-             */
-            for (s = 1; s < vq; ++s) {
-                if (kvm_enabled() || is_power_of_2(s)) {
-                    if (arm_cpu_vq_uninitialized(cpu, s)) {
-                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON);
-                    } else if (arm_cpu_vq_map_get(cpu, s) == ARM_VQ_OFF) {
-                        fail = true;
-                        break;
-                    }
-                }
-            }
-
-            if (!kvm_enabled() && fail) {
-                error_setg(errp, "cannot enable %s", name);
-                error_append_hint(errp, "Vector length %d-bits is disabled "
-                                  "and is a power-of-2 length smaller than "
-                                  "%s. All power-of-2 vector lengths smaller "
-                                  "than the maximum length are required.\n",
-                                  s * 128, name);
-
-            } else if (fail) {
-                error_setg(errp, "cannot enable %s", name);
-                error_append_hint(errp, "Vector length %d-bits is disabled "
-                                  "and the KVM host requires all supported "
-                                  "vector lengths smaller than %s to also be "
-                                  "enabled.\n", s * 128, name);
-            } else {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
-            }
-        } else {
-            /*
-             * When disabling vector lengths with KVM enabled if the vq wasn't
-             * supported then we leave it in the ARM_VQ_UNINITIALIZED state in
-             * order to keep that unsupported information. It'll be set to OFF
-             * later when we finalize the map.
-             *
-             * We would have errored-out already if we were attempting to
-             * disable a power-of-2 vector length less than another enabled
-             * vector length, but there may be uninitialized vector lengths
-             * larger than a power-of-2 vector length that we're disabling.
-             * We disable all of those lengths now too, as they can no longer
-             * be enabled. Additionally, for KVM, we have to automatically
-             * disable all supported, uninitialized lengths larger than this
-             * length, even when this length is not a power-of-2.
-             */
-            if (kvm_enabled() || is_power_of_2(vq)) {
-                for (s = vq + 1; s <= ARM_MAX_VQ; ++s) {
-                    if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
-                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
-                    }
-                }
-            }
-
-            if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
-                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
-            }
-
-            /*
-             * We just disabled one or more vector lengths. We need to make
-             * sure we didn't disable them all when SVE is enabled.
-             */
-            if (cpu_isar_feature(aa64_sve, cpu) &&
-                !arm_cpu_num_vqs_available(cpu)) {
-                error_setg(errp, "cannot disable %s", name);
-                error_append_hint(errp, "Disabling %s results in all vector "
-                                  "lengths being disabled.\n", name);
-                error_append_hint(errp, "With SVE enabled, at least one vector "
-                                  "length must be enabled.\n");
-            }
-        }
+        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,
@@ -702,32 +547,15 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
     t = cpu->isar.id_aa64pfr0;
     t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
     cpu->isar.id_aa64pfr0 = t;
-
-    /*
-     * When SVE is enabled ensure that we have at least one vector
-     * length available.
-     */
-    if (cpu_isar_feature(aa64_sve, cpu) && !arm_cpu_num_vqs_available(cpu)) {
-        error_setg(errp, "cannot enable SVE");
-        error_append_hint(errp, "All possible SVE vector lengths have "
-                          "been disabled.\n");
-    }
 }
 
 void aarch64_add_sve_properties(Object *obj)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
     uint32_t vq;
 
     object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
                         cpu_arm_set_sve, NULL, NULL, &error_fatal);
 
-    /*
-     * sve_vq_map uses a special state while setting properties, so
-     * we initialize it here with its init function and finalize it
-     * in arm_cpu_realizefn().
-     */
-    arm_cpu_vq_map_init(cpu);
     for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
         char name[8];
         sprintf(name, "sve%d", vq * 128);
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index e2d559c230..433cbe9b53 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -195,6 +195,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         if (!err) {
             visit_check_struct(visitor, &err);
         }
+        if (!err) {
+            arm_cpu_sve_finalize(ARM_CPU(obj), &err);
+        }
         visit_end_struct(visitor, NULL);
         visit_free(visitor);
         if (err) {
@@ -202,6 +205,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
             error_propagate(errp, err);
             return NULL;
         }
+    } else {
+        Error *err = NULL;
+        arm_cpu_sve_finalize(ARM_CPU(obj), &err);
+        assert(err == NULL);
     }
 
     expansion_info = g_new0(CpuModelExpansionInfo, 1);
-- 
2.17.1



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

* Re: [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
  2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
                   ` (15 preceding siblings ...)
  2019-08-10  1:31 ` [Qemu-devel] [PATCH] HACK: Centralize sve property checks Richard Henderson
@ 2019-08-15  8:31 ` Peter Maydell
  2019-08-15  8:45   ` Andrew Jones
  16 siblings, 1 reply; 37+ messages in thread
From: Peter Maydell @ 2019-08-15  8:31 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Richard Henderson, QEMU Developers, Markus Armbruster,
	Eric Auger, qemu-arm, Igor Mammedov, Alex Bennée,
	Dave P Martin

On Fri, 2 Aug 2019 at 13:25, Andrew Jones <drjones@redhat.com> wrote:
>
> 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.

Hi -- I see there have been some review comments on these patches
that mean there'll be a v4. In the meantime, patches 1, 2, 5, 6, 9, 10
seem to me to be independent bugfixes/cleanups that have been reviewed.
Would you like me to take those into target-arm.next to reduce the
size of the patchset for v4, or is that going to make rebasing
painful on your end?

thanks
-- PMM


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

* Re: [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
  2019-08-15  8:31 ` [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Peter Maydell
@ 2019-08-15  8:45   ` Andrew Jones
  0 siblings, 0 replies; 37+ messages in thread
From: Andrew Jones @ 2019-08-15  8:45 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Richard Henderson, QEMU Developers, Markus Armbruster,
	Eric Auger, qemu-arm, Igor Mammedov, Alex Bennée,
	Dave P Martin

On Thu, Aug 15, 2019 at 09:31:35AM +0100, Peter Maydell wrote:
> On Fri, 2 Aug 2019 at 13:25, Andrew Jones <drjones@redhat.com> wrote:
> >
> > 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.
> 
> Hi -- I see there have been some review comments on these patches
> that mean there'll be a v4. In the meantime, patches 1, 2, 5, 6, 9, 10
> seem to me to be independent bugfixes/cleanups that have been reviewed.
> Would you like me to take those into target-arm.next to reduce the
> size of the patchset for v4, or is that going to make rebasing
> painful on your end?
>

Hi Peter,

Please do take the fixups. I think the rebasing should go fine, and indeed
reducing the number of patches in the patchset should reduce some of my
maintenance and also some reviewer strain for v4.

Thanks,
drew


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

* Re: [Qemu-devel] [PATCH] HACK: Centralize sve property checks
  2019-08-10  1:31 ` [Qemu-devel] [PATCH] HACK: Centralize sve property checks Richard Henderson
@ 2019-09-04  8:32   ` Andrew Jones
  2019-09-04 17:17     ` Richard Henderson
  2019-09-04 17:18     ` Richard Henderson
  0 siblings, 2 replies; 37+ messages in thread
From: Andrew Jones @ 2019-09-04  8:32 UTC (permalink / raw)
  To: Richard Henderson
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On Fri, Aug 09, 2019 at 06:31:12PM -0700, Richard Henderson wrote:
> As promised, an experiment in unifying the checks.
> 
> I believe that I've tested for all of the same conditions, modulo the
> timing at which they are emitted.  As before, only one error is reported,
> so if multiple errors exist you can't rely on which error is seen.
> 
> I think there's value in splitting the sve_map_vq bitmap such that the
> initialized state can be easily manipulated with bitmap functions.
> 
> The diffstat is promising.  Lemme know what you think.

Hi Richard,

Thanks for this!

I'm back after a long context switch away from this work. There is indeed
a nice number of lines reduced. I applied this (with a couple minor fixups
for kvm code) and lightly tested it (primarily with tcg, other than the
sve-not-supported-with-this-kvm path). It works for me. I wouldn't say
this approach is less complex, but with the LOC reduction, then I'm happy
to get started on integrating it into the v4 series. How would you suggest
I apply credit for it? I can give you authorship for any patches that
mainly contain your code. Or I can keep authorship and add mentions of
your contributions in the commit messages. Just let me know your
preference.

I also have a couple comments below on the patch.

> 
> 
> r~
> 
> ---
>  target/arm/cpu.h     |  16 +-
>  target/arm/cpu.c     |  12 +-
>  target/arm/cpu64.c   | 502 ++++++++++++++-----------------------------
>  target/arm/monitor.c |   7 +
>  4 files changed, 190 insertions(+), 347 deletions(-)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 7993085bea..924476480b 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -184,11 +184,11 @@ typedef struct {
>  
>  #ifdef TARGET_AARCH64
>  # define ARM_MAX_VQ    16
> -void arm_cpu_sve_finalize(ARMCPU *cpu);
> +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) { }
> +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
> @@ -924,12 +924,14 @@ struct ARMCPU {
>      /*
>       * 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. We need a map size twice the maximum
> -     * quadword length though because we use two bits for each vector
> -     * length in order to track four states: uninitialized, uninitialized
> -     * but supported by KVM, off, and on.
> +     * 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 * 2);
> +    DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
> +    DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
>  };
>  
>  void arm_cpu_post_init(Object *obj);
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 604f5c3651..a113c30def 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -1255,8 +1255,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    if (cpu_isar_feature(aa64_sve, cpu)) {
> -        arm_cpu_sve_finalize(cpu);
> +    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
> +        arm_cpu_sve_finalize(cpu, &local_err);
> +        if (local_err != NULL) {
> +            error_propagate(errp, local_err);
> +            return;
> +        }
>      }
>  
>      if (arm_feature(env, ARM_FEATURE_AARCH64) &&
> @@ -2656,7 +2660,9 @@ static void arm_host_initfn(Object *obj)
>      ARMCPU *cpu = ARM_CPU(obj);
>  
>      kvm_arm_set_cpu_features_from_host(cpu);
> -    aarch64_add_sve_properties(obj);
> +    if (arm_feature(env, ARM_FEATURE_AARCH64)) {

&cpu->env

> +        aarch64_add_sve_properties(obj);
> +    }
>      arm_cpu_post_init(obj);
>  }
>  
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 0313eec88a..7c7e54ad78 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -257,165 +257,168 @@ static void aarch64_a72_initfn(Object *obj)
>      define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
>  }
>  
> -/*
> - * While we eventually use cpu->sve_vq_map as a typical bitmap, where each vq
> - * has only two states (off/on), until we've finalized the map at realize time
> - * we use an extra bit, at the vq - 1 + ARM_MAX_VQ bit number, to also allow
> - * tracking of the uninitialized state and the uninitialized but supported by
> - * KVM state. The arm_vq_state typedef and following functions allow us to more
> - * easily work with the bitmap.
> - */
> -typedef enum arm_vq_state {
> -    ARM_VQ_OFF,
> -    ARM_VQ_ON,
> -    ARM_VQ_UNINITIALIZED,
> -    ARM_VQ_UNINITIALIZED_KVM_SUPPORTED
> -    /*
> -     * More states cannot be added without adding bits to sve_vq_map
> -     * and modifying its supporting functions.
> -     */
> -} arm_vq_state;
> -
> -static arm_vq_state arm_cpu_vq_map_get(ARMCPU *cpu, uint32_t vq)
> +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>  {
> -    assert(vq <= ARM_MAX_VQ);
> -
> -    return test_bit(vq - 1, cpu->sve_vq_map) |
> -           test_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map) << 1;
> -}
> -
> -static void arm_cpu_vq_map_set(ARMCPU *cpu, uint32_t vq, arm_vq_state state)
> -{
> -    assert(vq <= ARM_MAX_VQ);
> -    assert(state == ARM_VQ_OFF || state == ARM_VQ_ON);
> -
> -    clear_bit(vq - 1 + ARM_MAX_VQ, cpu->sve_vq_map);
> -
> -    if (state == ARM_VQ_ON) {
> -        set_bit(vq - 1, cpu->sve_vq_map);
> -    } else {
> -        clear_bit(vq - 1, cpu->sve_vq_map);
> -    }
> -}
> -
> -static bool arm_cpu_vq_kvm_supported(ARMCPU *cpu, uint32_t vq)
> -{
> -    return arm_cpu_vq_map_get(cpu, vq) != ARM_VQ_UNINITIALIZED;
> -}
> -
> -static bool arm_cpu_vq_uninitialized(ARMCPU *cpu, uint32_t vq)
> -{
> -    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
> -
> -    if (kvm_enabled()) {
> -        return vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED;
> -    }
> -
> -    return vq_state == ARM_VQ_UNINITIALIZED;
> -}
> -
> -/*
> - * Uninitialized vector lengths need a default value to use in case we need
> - * to query their value prior to map finalization. Additionally map finalizing
> - * itself needs to determine what value to assign uninitialized vector lengths.
> - * The default is determined as follows:
> - *
> - *  * When no vector lengths have been explicitly enabled, i.e. either no
> - *    input has been provided by the user at all, or vector lengths have
> - *    only been disabled, then all uninitialized vector lengths default 'ON'.
> - *
> - *  * When one or more vector lengths have been enabled, then all uninitialized
> - *    vector lengths default 'OFF'. Note, when checking for enabled vector
> - *    lengths we do not discriminate between user-enabled vector lengths and
> - *    auto-enabled vector lengths (which were auto-enabled in order to satisfy
> - *    the user-enabled vector lengths). This implies the default can never
> - *    transition back to 'ON', even if the user-enabled and auto-enabled vector
> - *    lengths that initially transitioned it to 'OFF' are later disabled, as at
> - *    least one vector length must remain enabled unless the SVE feature is
> - *    completely disabled. If SVE is completely disabled then all vector
> - *    lengths are effectively 'OFF'.
> - */
> -static bool arm_cpu_vq_map_get_default(ARMCPU *cpu)
> -{
> -    uint32_t vq;
> -
> -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
> -            return false;
> -        }
> -    }
> -
> -    return true;
> -}
> -
> -/*
> - * We need to be able to track the number of enabled (or will-be enabled)
> - * vector lengths in order to ensure we never drop to zero. If the default
> - * is 'ON', then we count enabled and uninitialized vector lengths. Otherwise,
> - * if the default is 'OFF', then we only count enabled vector lengths.
> - */
> -static int arm_cpu_num_vqs_available(ARMCPU *cpu)
> -{
> -    uint32_t vq;
> -    bool defval;
> -    int num = 0;
> -
> -    defval = arm_cpu_vq_map_get_default(cpu);
> -
> -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -        if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
> -            ++num;
> -        } else if (defval && arm_cpu_vq_uninitialized(cpu, vq)) {
> -            ++num;
> -        }
> -    }
> -
> -    return num;
> -}
> -
> -static void arm_cpu_vq_map_init(ARMCPU *cpu)
> -{
> -    /* Set all vq's to 0b10 (ARM_VQ_UNINITIALIZED) */
> -    bitmap_clear(cpu->sve_vq_map, 0, ARM_MAX_VQ);
> -    bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ);
> -
> -    if (kvm_enabled()) {
> -        /*
> -         * As the upper bits of the ARM_VQ_UNINITIALIZED_KVM_SUPPORTED (0b11)
> -         * states have already been set with the bitmap_set() above, we only
> -         * need to OR in the lower bits.
> -         */
> -        DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
> +    DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
> +    DECLARE_BITMAP(test, ARM_MAX_VQ);
> +    uint32_t vq, max_vq = 0;
>  
> +    /* Collect the set of VQ supported by KVM. */
> +    if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
>          kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
> -        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, kvm_supported, ARM_MAX_VQ);
> +    } else {
> +        bitmap_zero(kvm_supported, ARM_MAX_VQ);
>      }
> -}
>  
> -void arm_cpu_sve_finalize(ARMCPU *cpu)
> -{
> -    bool defval = arm_cpu_vq_map_get_default(cpu);
> -    uint32_t vq, max_vq;
> +    /*
> +     * 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;
>  
> -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -        if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
> -            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
> -        } else if (arm_cpu_vq_uninitialized(cpu, vq)) {
> -            if (defval) {
> -                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
> -            } else {
> -                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
> +        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);
> +                set_bit(vq - 1, cpu->sve_vq_init);
>              }
>          }

While the architecture requires this, so all hardware should also
require it / depend on it, I would only do this propagation in the
non-KVM path. When KVM is enabled I prefer giving KVM full authority
over what vector lengths may be enabled. The reasoning is for the
unlikely case of KVM possibly trying to workaround some hardware
errata involving power-of-2 vector lengths.

> +
> +        /*
> +         * For KVM we have to automatically enable all supported unitialized
> +         * lengths, even when the smaller lengths are not all powers-of-two.
> +         */
> +        if (kvm_enabled()) {
> +            if (!kvm_arm_sve_supported(CPU(cpu))) {
> +                error_setg(errp, "cannot enable sve%d", max_vq);

max_vq * 128

> +                error_append_hint(errp, "SVE not supported by "
> +                                  "KVM on this host\n");
> +                return;
> +            }
> +            bitmap_andnot(test, kvm_supported, cpu->sve_vq_init, max_vq);
> +            bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
> +            bitmap_or(cpu->sve_vq_init, cpu->sve_vq_init, test, max_vq);
> +        }
> +    } 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);
> +
> +        /* Enable all supported bits other than those explicit disabled. */
> +        if (kvm_enabled()) {
> +            bitmap_andnot(cpu->sve_vq_map, kvm_supported,
> +                          cpu->sve_vq_init, max_vq);
> +        } else {
> +            bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
> +        }
> +        bitmap_set(cpu->sve_vq_init, 0, max_vq);
> +        max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
>      }
>  
> -    max_vq = arm_cpu_vq_map_next_smaller(cpu, ARM_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 (!cpu->sve_max_vq) {
> -        cpu->sve_max_vq = 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(test, cpu->sve_vq_init, max_vq);
> +        bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, test, max_vq);
>      }
>  
> -    assert(max_vq && cpu->sve_max_vq == max_vq);
> +    /*
> +     * At this point we will have found max_vq.  All bits implied from
> +     * other properties are set or clear in cpu->sve_vq_map.
> +     * All bits implied from other sve<N> are set in cpu->sve_vq_init.
> +     * If sve_vq_map<N> & !sve_vq_init<N>, then the bit must have come
> +     * sve-max-vq.
> +     */
> +    assert(max_vq != 0);
> +
> +    /* 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-2 length smaller than "
> +                              "the maximum, sve%d\n",
> +                              vq * 128, max_vq * 128);
> +            return;
> +        }
> +    }
> +
> +    /* Ensure the set of lengths matches what KVM supports. */
> +    if (kvm_enabled()) {
> +        bitmap_xor(test, cpu->sve_vq_map, kvm_supported, max_vq);
> +        if (!bitmap_empty(test, max_vq)) {
> +            vq = find_last_bit(test, max_vq);
> +            if (!test_bit(vq - 1, cpu->sve_vq_map)) {
> +                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);
> +            } else if (test_bit(vq - 1, cpu->sve_vq_init)) {
> +                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 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<vl-bits> properties.\n");
> +            }
> +            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)
> @@ -427,6 +430,7 @@ uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq)
>       * 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 > 1);
>      assert(vq <= ARM_MAX_VQ + 1);
>  
>      bitnum = find_last_bit(cpu->sve_vq_map, vq - 1);
> @@ -437,7 +441,15 @@ 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,
> @@ -445,7 +457,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      Error *err = NULL;
> -    uint32_t vq;
>  
>      visit_type_uint32(v, name, &cpu->sve_max_vq, &err);
>      if (err) {
> @@ -465,27 +476,6 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
>                            ARM_MAX_VQ);
>          return;
>      }
> -
> -    for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
> -        if (vq <= cpu->sve_max_vq) {
> -            char tmp[8];
> -
> -            sprintf(tmp, "sve%d", vq * 128);
> -            object_property_set_bool(obj, true, tmp, &err);
> -            if (err) {
> -                if (kvm_enabled()) {
> -                    error_append_hint(&err, "It is not possible to use "
> -                                      "sve-max-vq with this KVM host. Try "
> -                                      "using only sve<vl-bits> "
> -                                      "properties.\n");
> -                }
> -                error_propagate(errp, err);
> -                return;
> -            }
> -        } else if (arm_cpu_vq_map_get(cpu, vq) == ARM_VQ_ON) {
> -            arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
> -        }
> -    }
>  }
>  
>  static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
> @@ -493,24 +483,14 @@ static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      uint32_t vq = atoi(&name[3]) / 128;
> -    arm_vq_state vq_state = arm_cpu_vq_map_get(cpu, vq);
>      bool value;
>  
> +    /* All vector lengths are disabled when SVE is off. */
>      if (!cpu_isar_feature(aa64_sve, cpu)) {
> -        /* All vector lengths are disabled when SVE is off. */
>          value = false;
> -    } else if (vq_state == ARM_VQ_ON) {
> -        value = true;
> -    } else if (vq_state == ARM_VQ_OFF) {
> -        value = false;
> -    } else if (kvm_enabled() && !arm_cpu_vq_kvm_supported(cpu, vq)) {
> -        value = false;
> -    } else if (arm_cpu_vq_map_get_default(cpu)) {
> -        value = true;
>      } else {
> -        value = false;
> +        value = test_bit(vq - 1, cpu->sve_vq_map);
>      }
> -
>      visit_type_bool(v, name, &value, errp);
>  }
>  
> @@ -519,7 +499,6 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
>  {
>      ARMCPU *cpu = ARM_CPU(obj);
>      uint32_t vq = atoi(&name[3]) / 128;
> -    uint32_t max_vq = 0;
>      Error *err = NULL;
>      bool value;
>  
> @@ -529,146 +508,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;
> -    }
> -
> -    /*
> -     * We need to know the maximum vector length, which may just currently
> -     * be the maximum length, in order to validate the enabling/disabling
> -     * of this vector length.
> -     */
> -    if (!cpu->sve_max_vq) {
> -        for (max_vq = ARM_MAX_VQ; max_vq >= 1; --max_vq) {
> -            if (arm_cpu_vq_map_get(cpu, max_vq) == ARM_VQ_ON) {
> -                break;
> -            }
> -        }
> -    }
> -
> -    if (cpu->sve_max_vq && value && vq > cpu->sve_max_vq) {
> -        error_setg(errp, "cannot enable %s", name);
> -        error_append_hint(errp, "vq=%d (%d bits) is larger than the "
> -                          "maximum vector length, sve-max-vq=%d "
> -                          "(%d bits)\n", vq, vq * 128,
> -                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
> -    } else if (cpu->sve_max_vq && !value && vq == cpu->sve_max_vq) {
> -        error_setg(errp, "cannot disable %s", name);
> -        error_append_hint(errp, "The maximum vector length must be "
> -                          "enabled, sve-max-vq=%d (%d bits)\n",
> -                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
> -    } else if (!kvm_enabled() && cpu->sve_max_vq && !value &&
> -               vq < cpu->sve_max_vq && is_power_of_2(vq)) {
> -        error_setg(errp, "cannot disable %s", name);
> -        error_append_hint(errp, "vq=%d (%d bits) is required as it is a "
> -                          "power-of-2 length smaller than the maximum, "
> -                          "sve-max-vq=%d (%d bits)\n", vq, vq * 128,
> -                          cpu->sve_max_vq, cpu->sve_max_vq * 128);
> -    } else if (!kvm_enabled() && max_vq && !value && vq < max_vq &&
> -               is_power_of_2(vq)) {
> -        error_setg(errp, "cannot disable %s", name);
> -        error_append_hint(errp, "Vector length %d-bits is required as it "
> -                          "is a power-of-2 length smaller than another "
> -                          "enabled vector length. Disable all larger vector "
> -                          "lengths first.\n", vq * 128);
> -    } else if (kvm_enabled() && !value && vq < max_vq &&
> -                arm_cpu_vq_kvm_supported(cpu, vq)) {
> -        error_setg(errp, "cannot disable %s", name);
> -        error_append_hint(errp, "Vector length %d-bits is a KVM supported "
> -                          "length smaller than another enabled vector "
> -                          "length. Disable all larger vector lengths "
> -                          "first.\n", vq * 128);
> -    } else if (kvm_enabled() && value && !arm_cpu_vq_kvm_supported(cpu, vq)) {
> -        error_setg(errp, "cannot enable %s", name);
> -        error_append_hint(errp, "This KVM host does not support "
> -                          "the vector length %d-bits.\n", vq * 128);
> +    if (value) {
> +        set_bit(vq - 1, cpu->sve_vq_map);
>      } else {
> -        uint32_t s;
> -
> -        if (value) {
> -            bool fail = false;
> -
> -            /*
> -             * Enabling a vector length automatically enables all
> -             * uninitialized power-of-2 lengths smaller than it, as
> -             * per the architecture.
> -             *
> -             * For KVM we have to automatically enable all supported,
> -             * uninitialized lengths smaller than this length, even
> -             * when the smaller lengths are not power-of-2's.
> -             */
> -            for (s = 1; s < vq; ++s) {
> -                if (kvm_enabled() || is_power_of_2(s)) {
> -                    if (arm_cpu_vq_uninitialized(cpu, s)) {
> -                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON);
> -                    } else if (arm_cpu_vq_map_get(cpu, s) == ARM_VQ_OFF) {
> -                        fail = true;
> -                        break;
> -                    }
> -                }
> -            }
> -
> -            if (!kvm_enabled() && fail) {
> -                error_setg(errp, "cannot enable %s", name);
> -                error_append_hint(errp, "Vector length %d-bits is disabled "
> -                                  "and is a power-of-2 length smaller than "
> -                                  "%s. All power-of-2 vector lengths smaller "
> -                                  "than the maximum length are required.\n",
> -                                  s * 128, name);
> -
> -            } else if (fail) {
> -                error_setg(errp, "cannot enable %s", name);
> -                error_append_hint(errp, "Vector length %d-bits is disabled "
> -                                  "and the KVM host requires all supported "
> -                                  "vector lengths smaller than %s to also be "
> -                                  "enabled.\n", s * 128, name);
> -            } else {
> -                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON);
> -            }
> -        } else {
> -            /*
> -             * When disabling vector lengths with KVM enabled if the vq wasn't
> -             * supported then we leave it in the ARM_VQ_UNINITIALIZED state in
> -             * order to keep that unsupported information. It'll be set to OFF
> -             * later when we finalize the map.
> -             *
> -             * We would have errored-out already if we were attempting to
> -             * disable a power-of-2 vector length less than another enabled
> -             * vector length, but there may be uninitialized vector lengths
> -             * larger than a power-of-2 vector length that we're disabling.
> -             * We disable all of those lengths now too, as they can no longer
> -             * be enabled. Additionally, for KVM, we have to automatically
> -             * disable all supported, uninitialized lengths larger than this
> -             * length, even when this length is not a power-of-2.
> -             */
> -            if (kvm_enabled() || is_power_of_2(vq)) {
> -                for (s = vq + 1; s <= ARM_MAX_VQ; ++s) {
> -                    if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
> -                        arm_cpu_vq_map_set(cpu, s, ARM_VQ_OFF);
> -                    }
> -                }
> -            }
> -
> -            if (!kvm_enabled() || arm_cpu_vq_kvm_supported(cpu, vq)) {
> -                arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF);
> -            }
> -
> -            /*
> -             * We just disabled one or more vector lengths. We need to make
> -             * sure we didn't disable them all when SVE is enabled.
> -             */
> -            if (cpu_isar_feature(aa64_sve, cpu) &&
> -                !arm_cpu_num_vqs_available(cpu)) {
> -                error_setg(errp, "cannot disable %s", name);
> -                error_append_hint(errp, "Disabling %s results in all vector "
> -                                  "lengths being disabled.\n", name);
> -                error_append_hint(errp, "With SVE enabled, at least one vector "
> -                                  "length must be enabled.\n");
> -            }
> -        }
> +        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,
> @@ -702,32 +547,15 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
>      t = cpu->isar.id_aa64pfr0;
>      t = FIELD_DP64(t, ID_AA64PFR0, SVE, value);
>      cpu->isar.id_aa64pfr0 = t;
> -
> -    /*
> -     * When SVE is enabled ensure that we have at least one vector
> -     * length available.
> -     */
> -    if (cpu_isar_feature(aa64_sve, cpu) && !arm_cpu_num_vqs_available(cpu)) {
> -        error_setg(errp, "cannot enable SVE");
> -        error_append_hint(errp, "All possible SVE vector lengths have "
> -                          "been disabled.\n");
> -    }
>  }
>  
>  void aarch64_add_sve_properties(Object *obj)
>  {
> -    ARMCPU *cpu = ARM_CPU(obj);
>      uint32_t vq;
>  
>      object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
>                          cpu_arm_set_sve, NULL, NULL, &error_fatal);
>  
> -    /*
> -     * sve_vq_map uses a special state while setting properties, so
> -     * we initialize it here with its init function and finalize it
> -     * in arm_cpu_realizefn().
> -     */
> -    arm_cpu_vq_map_init(cpu);
>      for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
>          char name[8];
>          sprintf(name, "sve%d", vq * 128);
> diff --git a/target/arm/monitor.c b/target/arm/monitor.c
> index e2d559c230..433cbe9b53 100644
> --- a/target/arm/monitor.c
> +++ b/target/arm/monitor.c
> @@ -195,6 +195,9 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>          if (!err) {
>              visit_check_struct(visitor, &err);
>          }
> +        if (!err) {
> +            arm_cpu_sve_finalize(ARM_CPU(obj), &err);
> +        }
>          visit_end_struct(visitor, NULL);
>          visit_free(visitor);
>          if (err) {
> @@ -202,6 +205,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>              error_propagate(errp, err);
>              return NULL;
>          }
> +    } else {
> +        Error *err = NULL;
> +        arm_cpu_sve_finalize(ARM_CPU(obj), &err);
> +        assert(err == NULL);
>      }

Should we already introduce a function that will collect all
finalizers together now, rather than sprinkling around 
arm_cpu_sve_finalize() calls? Something like

void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
{
  arm_cpu_sve_finalize(cpu, errp);
}

Of course we can introduce it when/if we add other finalizers
later, but I guess the vfp-neon finalizer should be coming
soon anyway.

>  
>      expansion_info = g_new0(CpuModelExpansionInfo, 1);
> -- 
> 2.17.1
> 
> 

Thanks,
drew


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

* Re: [Qemu-devel] [PATCH] HACK: Centralize sve property checks
  2019-09-04  8:32   ` Andrew Jones
@ 2019-09-04 17:17     ` Richard Henderson
  2019-09-04 17:18     ` Richard Henderson
  1 sibling, 0 replies; 37+ messages in thread
From: Richard Henderson @ 2019-09-04 17:17 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On 9/4/19 1:32 AM, Andrew Jones wrote:
> How would you suggest
> I apply credit for it? I can give you authorship for any patches that
> mainly contain your code. Or I can keep authorship and add mentions of
> your contributions in the commit messages. Just let me know your
> preference.

I don't mind either way.  The latter sounds easier.

r~


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

* Re: [Qemu-devel] [PATCH] HACK: Centralize sve property checks
  2019-09-04  8:32   ` Andrew Jones
  2019-09-04 17:17     ` Richard Henderson
@ 2019-09-04 17:18     ` Richard Henderson
  1 sibling, 0 replies; 37+ messages in thread
From: Richard Henderson @ 2019-09-04 17:18 UTC (permalink / raw)
  To: Andrew Jones
  Cc: peter.maydell, qemu-devel, armbru, eric.auger, qemu-arm,
	imammedo, alex.bennee, Dave.Martin

On 9/4/19 1:32 AM, Andrew Jones wrote:
> Should we already introduce a function that will collect all
> finalizers together now, rather than sprinkling around 
> arm_cpu_sve_finalize() calls? Something like
> 
> void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
> {
>   arm_cpu_sve_finalize(cpu, errp);
> }
> 
> Of course we can introduce it when/if we add other finalizers
> later, but I guess the vfp-neon finalizer should be coming
> soon anyway.

That sounds reasonable.


r~


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

* Re: [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
  2019-08-20  7:53 ` Andrew Jones
@ 2019-08-20  8:45   ` Andrea Bolognani
  0 siblings, 0 replies; 37+ messages in thread
From: Andrea Bolognani @ 2019-08-20  8:45 UTC (permalink / raw)
  To: Andrew Jones, Zhang, Lei
  Cc: Mizuma, Masayoshi, Okamoto, Takayuki, 'qemu-devel@nongnu.org'

On Tue, 2019-08-20 at 09:53 +0200, Andrew Jones wrote:
> On Tue, Aug 20, 2019 at 06:08:04AM +0000, Zhang, Lei wrote:
> > Hi Andrew,
> > 
> > I have tested your patch on kernel- 5.2.7 + QEMU (4.0.94 + patch).
> 
> Thanks for the testing! I guess it's time for me to get back to this
> series and spin a v4 (so we can test some more :-)
> 
> > This patch series works fine for my tests when use qemu-system-aarch64 directly.
> > But I can't startup kvm when I use virsh[1].
> > 
> > Command I executed.
> > # virsh start test1
> > 
> > The error message is [internal error: CPU features not supported by hypervisor for aarch64 architecture.]
> > Do you have any ideas for this error? 
> 
> I've CC'ed Andrea.

I've specifically patched out that check in my series... Are you
sure you're using the modified libvirt version, and that your guest
is configured to use the modified QEMU binary?

Anyway, once v4 has been posted I'll respin the libvirt series as
well, since in the meantime conflicts have popped up and it no longer
applies cleanly on top of master.

-- 
Andrea Bolognani / Red Hat / Virtualization



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

* Re: [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
  2019-08-20  6:08 Zhang, Lei
@ 2019-08-20  7:53 ` Andrew Jones
  2019-08-20  8:45   ` Andrea Bolognani
  0 siblings, 1 reply; 37+ messages in thread
From: Andrew Jones @ 2019-08-20  7:53 UTC (permalink / raw)
  To: Zhang, Lei
  Cc: Mizuma, Masayoshi, Okamoto, Takayuki,
	'qemu-devel@nongnu.org',
	abologna

On Tue, Aug 20, 2019 at 06:08:04AM +0000, Zhang, Lei wrote:
> Hi Andrew,
> 
> I have tested your patch on kernel- 5.2.7 + QEMU (4.0.94 + patch).

Thanks for the testing! I guess it's time for me to get back to this
series and spin a v4 (so we can test some more :-)

> 
> This patch series works fine for my tests when use qemu-system-aarch64 directly.
> But I can't startup kvm when I use virsh[1].
> 
> Command I executed.
> # virsh start test1
> 
> The error message is [internal error: CPU features not supported by hypervisor for aarch64 architecture.]
> Do you have any ideas for this error? 

I've CC'ed Andrea.

Thanks,
drew

> 
> [1]
> https://www.redhat.com/archives/libvir-list/2019-July/msg01524.html
> 
> Best Regards,
> Lei Zhang


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

* [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests
@ 2019-08-20  6:08 Zhang, Lei
  2019-08-20  7:53 ` Andrew Jones
  0 siblings, 1 reply; 37+ messages in thread
From: Zhang, Lei @ 2019-08-20  6:08 UTC (permalink / raw)
  To: 'qemu-devel@nongnu.org', 'drjones@redhat.com'
  Cc: Mizuma, Masayoshi, Okamoto, Takayuki, Zhang, Lei

Hi Andrew,

I have tested your patch on kernel- 5.2.7 + QEMU (4.0.94 + patch).

This patch series works fine for my tests when use qemu-system-aarch64 directly.
But I can't startup kvm when I use virsh[1].

Command I executed.
# virsh start test1

The error message is [internal error: CPU features not supported by hypervisor for aarch64 architecture.]
Do you have any ideas for this error? 

[1]
https://www.redhat.com/archives/libvir-list/2019-July/msg01524.html

Best Regards,
Lei Zhang

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

end of thread, other threads:[~2019-09-04 17:36 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-02 12:25 [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 01/15] target/arm/cpu64: Ensure kvm really supports aarch64=off Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 02/15] target/arm/cpu: Ensure we can use the pmu with kvm Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 03/15] target/arm/monitor: Introduce qmp_query_cpu_model_expansion Andrew Jones
2019-08-02 16:27   ` Richard Henderson
2019-08-03  1:28     ` Richard Henderson
2019-08-06 12:21       ` Andrew Jones
2019-08-07 15:22         ` Richard Henderson
2019-08-08  8:50           ` Andrew Jones
2019-08-08 18:37             ` Richard Henderson
2019-08-09 16:09               ` Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 04/15] tests: arm: Introduce cpu feature tests Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 05/15] target/arm/helper: zcr: Add build bug next to value range assumption Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 06/15] target/arm/cpu: Use div-round-up to determine predicate register array size Andrew Jones
2019-08-02 16:33   ` Richard Henderson
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 07/15] target/arm: Allow SVE to be disabled via a CPU property Andrew Jones
2019-08-02 16:35   ` Richard Henderson
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 08/15] target/arm/cpu64: max cpu: Introduce sve<vl-bits> properties Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 09/15] target/arm/kvm64: Fix error returns Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 10/15] target/arm/kvm64: Move the get/put of fpsimd registers out Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 11/15] target/arm/kvm64: Add kvm_arch_get/put_sve Andrew Jones
2019-08-02 18:07   ` Richard Henderson
2019-08-06 12:24     ` Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 12/15] target/arm/kvm64: max cpu: Enable SVE when available Andrew Jones
2019-08-02 18:20   ` Richard Henderson
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 13/15] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 14/15] target/arm/cpu64: max cpu: Support sve properties with KVM Andrew Jones
2019-08-02 12:25 ` [Qemu-devel] [PATCH v3 15/15] target/arm/kvm: host cpu: Add support for sve<vl-bits> properties Andrew Jones
2019-08-10  1:31 ` [Qemu-devel] [PATCH] HACK: Centralize sve property checks Richard Henderson
2019-09-04  8:32   ` Andrew Jones
2019-09-04 17:17     ` Richard Henderson
2019-09-04 17:18     ` Richard Henderson
2019-08-15  8:31 ` [Qemu-devel] [PATCH v3 00/15] target/arm/kvm: enable SVE in guests Peter Maydell
2019-08-15  8:45   ` Andrew Jones
2019-08-20  6:08 Zhang, Lei
2019-08-20  7:53 ` Andrew Jones
2019-08-20  8:45   ` Andrea Bolognani

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.