From patchwork Fri Jun 21 16:34:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120430 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VkxF5dSNz9s5c for ; Sat, 22 Jun 2019 02:42:09 +1000 (AEST) Received: from localhost ([::1]:36752 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMc3-00067l-ST for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:42:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44487) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVH-0001Um-MZ for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVF-0001Gh-MU for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36050) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMV3-0000Ac-MA; Fri, 21 Jun 2019 12:34:55 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3F496C18B2FA; Fri, 21 Jun 2019 16:34:38 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id D07041001DF3; Fri, 21 Jun 2019 16:34:34 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:10 +0200 Message-Id: <20190621163422.6127-3-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Fri, 21 Jun 2019 16:34:38 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 02/14] target/arm/cpu: Ensure we can use the pmu with kvm X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 Reviewed-by: Eric Auger --- target/arm/cpu.c | 30 +++++++++++++++++++++++++----- target/arm/kvm.c | 9 +++++++++ target/arm/kvm_arm.h | 13 +++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 376db154f008..858f668d226e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -759,10 +759,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); @@ -785,6 +781,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) { @@ -859,7 +878,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..69c961a4c62c 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -162,6 +162,15 @@ 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); + int ret; + + ret = kvm_check_extension(s, KVM_CAP_ARM_PMU_V3); + return ret > 0; +} + 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 812125f805a1..e0ded3607996 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -216,6 +216,14 @@ 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 +269,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; From patchwork Fri Jun 21 16:34:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120431 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vkxw0TMYz9s3l for ; Sat, 22 Jun 2019 02:42:38 +1000 (AEST) Received: from localhost ([::1]:36756 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMcR-0006r6-32 for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:42:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44522) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVJ-0001ZF-Gl for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVF-0001G2-Kt for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:40366) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMV3-0000GC-MB; Fri, 21 Jun 2019 12:34:55 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B7530C1EB219; Fri, 21 Jun 2019 16:34:40 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 78F561001DD9; Fri, 21 Jun 2019 16:34:38 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:11 +0200 Message-Id: <20190621163422.6127-4-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 21 Jun 2019 16:34:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 03/14] target/arm/monitor: Introduce qmp_query_cpu_model_expansion X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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. Also, for simplicity, we restrict the list of queryable cpu models to 'max', 'host', or the current type when KVM is in use, even though there may exist KVM hosts where other types would also work. For example on a seattle you could use 'host' for the current type, but then attempt to query 'cortex-a57', which is also a valid CPU type to use with KVM on seattle hosts, but that query will fail with our simplifications. 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. Finally, we only implement expansion type 'full', as Arm does not yet have a "base" CPU type. Below are some example calls and results (to save character clutter they're not in json, but are still json-ish to give the idea) # expand the 'max' CPU model query-cpu-model-expansion: type:full, model:{ name:max } return: model:{ name:max, props:{ 'aarch64': true, 'pmu': true }} # attempt to expand the 'max' CPU model with pmu=off query-cpu-model-expansion: type:full, model:{ name:max, props:{ 'pmu': false }} return: model:{ name:max, props:{ 'aarch64': true, 'pmu': false }} # attempt to expand the 'max' CPU model with aarch64=off query-cpu-model-expansion: type:full, model:{ name:max, props:{ 'aarch64': false }} error: "'aarch64' feature cannot be disabled unless KVM is enabled and 32-bit EL1 is supported" In the last example KVM was not in use so an error was returned. Note1: 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. Note2: 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 --- qapi/target.json | 6 +- target/arm/monitor.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/qapi/target.json b/qapi/target.json index 1d4d54b6002e..edfa2f82b916 100644 --- a/qapi/target.json +++ b/qapi/target.json @@ -408,7 +408,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: @@ -433,7 +433,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 @@ -447,7 +447,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 41b32b94b258..19e3120eef95 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -23,7 +23,13 @@ #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-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 +88,129 @@ 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 definition '%s' requires KVM", model->name); + return NULL; + } + + oc = cpu_class_by_name(TYPE_ARM_CPU, model->name); + if (!oc) { + error_setg(errp, "The CPU definition '%s' is unknown.", 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, "The CPU definition '%s' cannot " + "be used 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; + + visitor = qobject_input_visitor_new(model->props); + visit_start_struct(visitor, NULL, NULL, 0, errp); + if (*errp) { + object_unref(obj); + return NULL; + } + + i = 0; + while ((name = cpu_model_advertised_features[i++]) != NULL) { + if (qdict_get(qdict_in, name)) { + object_property_set(obj, visitor, name, errp); + if (*errp) { + break; + } + } + } + + if (!*errp) { + visit_check_struct(visitor, errp); + } + visit_end_struct(visitor, NULL); + visit_free(visitor); + if (*errp) { + object_unref(obj); + 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) { + QObject *value; + + assert(prop->get); + value = object_property_get_qobject(obj, name, errp); + assert(!*errp); + + 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; +} From patchwork Fri Jun 21 16:34:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120417 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vkqy3dxdz9sBb for ; Sat, 22 Jun 2019 02:37:30 +1000 (AEST) Received: from localhost ([::1]:36716 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMXX-0002EP-0R for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:37:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44524) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVJ-0001ZY-JW for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVF-0001GB-LN for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38632) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMV3-0000MY-M4; Fri, 21 Jun 2019 12:34:55 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BDB9030C318F; Fri, 21 Jun 2019 16:34:43 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id D3C8F1001DE0; Fri, 21 Jun 2019 16:34:40 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:12 +0200 Message-Id: <20190621163422.6127-5-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]); Fri, 21 Jun 2019 16:34:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 04/14] tests: arm: Introduce cpu feature tests X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 Reviewed-by: Eric Auger --- tests/Makefile.include | 5 +- tests/arm-cpu-features.c | 221 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 tests/arm-cpu-features.c diff --git a/tests/Makefile.include b/tests/Makefile.include index db750dd6d09b..d5f43fe03067 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -255,13 +255,15 @@ 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) check-qtest-arm-y += tests/boot-serial-test$(EXESUF) check-qtest-arm-y += tests/hexloader-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 @@ -822,6 +824,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..31b1c15bb979 --- /dev/null +++ b/tests/arm-cpu-features.c @@ -0,0 +1,221 @@ +/* + * Arm CPU feature test cases + * + * Copyright (c) 2019 Red Hat Inc. + * Authors: + * Andrew Jones + * + * 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 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; +} + +static char *get_error(QTestState *qts, const char *cpu_type, + const char *fmt, ...) +{ + QDict *resp; + char *error; + + 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); + } + + g_assert(resp); + error = g_strdup(resp_get_error(resp)); + qobject_unref(resp); + + return error; +} + +#define assert_error(qts, cpu_type, expected_error, fmt, ...) \ +({ \ + char *_error = get_error(qts, cpu_type, fmt, ##__VA_ARGS__); \ + g_assert(_error); \ + g_assert(g_str_equal(_error, expected_error)); \ + g_free(_error); \ +}) + +static QDict *resp_get_props(QDict *resp) +{ + QDict *qdict; + + g_assert(resp); + g_assert(qdict_haskey(resp, "return")); + qdict = qdict_get_qdict(resp, "return"); + g_assert(qdict_haskey(qdict, "model")); + qdict = qdict_get_qdict(qdict, "model"); + g_assert(qdict_haskey(qdict, "props")); + 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(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(!qdict_get(resp_get_props(_resp), feature)); \ + qobject_unref(_resp); \ +}) + +static void assert_type_full(QTestState *qts, const char *cpu_type) +{ + const char *error; + QDict *resp; + + resp = qtest_qmp(qts, "{ 'execute': 'query-cpu-model-expansion', " + "'arguments': { 'type': 'static', " + "'model': { 'name': %s }}}", + cpu_type); + 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, "foo"); + assert_bad_props(qts, "max"); + assert_error(qts, "foo", "The CPU definition 'foo' is unknown.", NULL); + assert_error(qts, "max", "Parameter 'not-a-prop' is unexpected", + "{ 'not-a-prop': false }"); + assert_error(qts, "host", "The CPU definition '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", + "The CPU definition 'cortex-a15' cannot " + "be used 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(); +} From patchwork Fri Jun 21 16:34:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120419 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VksH4lC2z9s3l for ; Sat, 22 Jun 2019 02:38:43 +1000 (AEST) Received: from localhost ([::1]:36734 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMYj-0003ci-MS for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:38:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44490) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVH-0001Ut-N5 for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVF-0001G4-KK for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44950) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMV3-0000hl-M9; Fri, 21 Jun 2019 12:34:55 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5A4BE81F33; Fri, 21 Jun 2019 16:34:50 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id D8AC61001E73; Fri, 21 Jun 2019 16:34:43 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:13 +0200 Message-Id: <20190621163422.6127-6-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Fri, 21 Jun 2019 16:34:50 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 05/14] target/arm/helper: zcr: Add build bug next to value range assumption X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Suggested-by: Dave Martin Signed-off-by: Andrew Jones Reviewed-by: Richard Henderson Reviewed-by: Eric Auger --- target/arm/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index df4276f5f6ca..edba94004e0b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5319,6 +5319,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); /* From patchwork Fri Jun 21 16:34:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120432 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vl0z46j8z9s5c for ; Sat, 22 Jun 2019 02:45:23 +1000 (AEST) Received: from localhost ([::1]:36774 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMfA-0000jC-Vs for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:45:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44619) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVP-0001j1-Su for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVN-0001fB-F8 for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36640) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVF-0000ux-Js; Fri, 21 Jun 2019 12:35:05 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9579B3002E1D; Fri, 21 Jun 2019 16:34:56 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 615211001DE1; Fri, 21 Jun 2019 16:34:50 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:14 +0200 Message-Id: <20190621163422.6127-7-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.43]); Fri, 21 Jun 2019 16:34:56 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 06/14] target/arm: Allow SVE to be disabled via a CPU property X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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_ pattern. Signed-off-by: Andrew Jones Reviewed-by: Philippe Mathieu-Daudé --- target/arm/cpu.c | 10 +++++- target/arm/cpu64.c | 72 ++++++++++++++++++++++++++++++++++------ target/arm/helper.c | 8 +++-- target/arm/monitor.c | 2 +- tests/arm-cpu-features.c | 1 + 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 858f668d226e..f08e178fc84b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -198,7 +198,7 @@ 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->sve_max_vq ? 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]; /* @@ -1129,6 +1129,14 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->isar.mvfr0 = u; } + if (!cpu->sve_max_vq) { + uint64_t t; + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 0); + cpu->isar.id_aa64pfr0 = t; + } + if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) { uint32_t u; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 946994838d8a..02ada65f240c 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -257,27 +257,75 @@ 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; + uint32_t value; - visit_type_uint32(v, name, &cpu->sve_max_vq, &err); + visit_type_uint32(v, name, &value, &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) { + error_setg(errp, "cannot set sve-max-vq"); + error_append_hint(errp, "SVE has been disabled with sve=off\n"); + return; + } + + cpu->sve_max_vq = value; + + if (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ) { + error_setg(errp, "unsupported SVE vector length"); + error_append_hint(errp, "Valid sve-max-vq in range [1-%d]\n", ARM_MAX_VQ); } - error_propagate(errp, err); +} + +static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + bool value = !!cpu->sve_max_vq; + + 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; + + visit_type_bool(v, name, &value, &err); + if (err) { + error_propagate(errp, err); + return; + } + + if (value) { + /* + * We handle the -cpu ,sve=off,sve=on case by reinitializing, + * but otherwise we don't do anything as an sve=on could come after + * a sve-max-vq setting. + */ + if (!cpu->sve_max_vq) { + cpu->sve_max_vq = ARM_MAX_VQ; + } + } else { + cpu->sve_max_vq = 0; + } } /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); @@ -373,8 +421,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/helper.c b/target/arm/helper.c index edba94004e0b..f500ccb6d31b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5314,9 +5314,13 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + ARMCPU *cpu = env_archcpu(env); int cur_el = arm_current_el(env); - int old_len = sve_zcr_len_for_el(env, cur_el); - int new_len; + int old_len, new_len; + + assert(cpu->sve_max_vq); + + old_len = sve_zcr_len_for_el(env, cur_el); /* Bits other than [3:0] are RAZ/WI. */ QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 19e3120eef95..157c487a1551 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -90,7 +90,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 31b1c15bb979..509e458e9c2f 100644 --- a/tests/arm-cpu-features.c +++ b/tests/arm-cpu-features.c @@ -158,6 +158,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"); From patchwork Fri Jun 21 16:34:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vl5b5H2pz9s3l for ; Sat, 22 Jun 2019 02:49:23 +1000 (AEST) Received: from localhost ([::1]:36810 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMj3-0004iO-Oq for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:49:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44721) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVf-0001sq-PF for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVW-0001ye-Dk for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60186) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVF-00011n-Nj; Fri, 21 Jun 2019 12:35:07 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 32A843082B02; Fri, 21 Jun 2019 16:35:01 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id D15CA1001DC7; Fri, 21 Jun 2019 16:34:56 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:15 +0200 Message-Id: <20190621163422.6127-8-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.45]); Fri, 21 Jun 2019 16:35:01 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 07/14] target/arm/cpu64: max cpu: Introduce sve properties X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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, sve512, ..., where the number is the number of bits. It's now possible to do something like -cpu max,sve-max-vq=4,sve384=off to provide a guest vector lengths 128, 256, and 512 bits. The resulting set must conform to the architectural constraint of having all power-of-2 lengths smaller than the maximum length present. It's also possible to only provide sve properties, e.g. -cpu max,sve512=on. That example provides the machine with 128, 256, and 512 bit vector lengths. It doesn't hurt to explicitly ask for all expected vector lengths, which is what, for example, libvirt should do. Note1, it is not possible to use sve properties before sve-max-vq, e.g. -cpu max,sve384=off,sve-max-vq=4, as supporting that overly complicates the user input validation. Note2, while one might expect -cpu max,sve-max-vq=4,sve512=on to be the same as -cpu max,sve512=on, they are not. The former enables all vector lengths 512 bits and smaller, while the latter only sets the 512-bit length and its smaller power-of-2 lengths. It's probably best not to use sve-max-vq with sve properties, but it can't be completely forbidden as we want qmp_query_cpu_model_expansion to work with guests launched with e.g. -cpu max,sve-max-vq=8 on their command line. Signed-off-by: Andrew Jones --- target/arm/cpu.c | 6 + target/arm/cpu.h | 14 ++ target/arm/cpu64.c | 360 ++++++++++++++++++++++++++++++++++++++- target/arm/helper.c | 11 +- target/arm/monitor.c | 16 ++ tests/arm-cpu-features.c | 217 +++++++++++++++++++++++ 6 files changed, 620 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f08e178fc84b..e060a0d9df0e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1019,6 +1019,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) return; } + arm_cpu_sve_finalize(cpu, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu->has_vfp != cpu->has_neon) { /* diff --git a/target/arm/cpu.h b/target/arm/cpu.h index f9da672be575..cbb155cf72a5 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -184,8 +184,13 @@ typedef struct { #ifdef TARGET_AARCH64 # define ARM_MAX_VQ 16 +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq); #else # define ARM_MAX_VQ 1 +static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { } +static inline uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq) +{ return 0; } #endif typedef struct ARMVectorReg { @@ -915,6 +920,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 02ada65f240c..5def82111dee 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -257,6 +257,149 @@ 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. Also, while the map + * is still initializing, sve-max-vq has an additional three states, bringing + * the number of its states to five, which are the following: + * + * sve-max-vq: + * 0: SVE is disabled. The default value for a vq in the map is 'OFF'. + * -1: SVE is enabled, but neither sve-max-vq nor sve properties + * have yet been specified by the user. The default value for a vq in + * the map is 'ON'. + * -2: SVE is enabled and one or more sve properties have been + * set to 'OFF' by the user, but no sve properties have yet + * been set to 'ON'. The user is now blocked from setting sve-max-vq + * and the default value for a vq in the map is 'ON'. + * -3: SVE is enabled and one or more sve properties have been + * set to 'ON' by the user. The user is blocked from setting sve-max-vq + * and the default value for a vq in the map is 'OFF'. sve-max-vq never + * transitions back to -2, even if later inputs disable the vector + * lengths that initially transitioned sve-max-vq to this state. This + * avoids the default values from flip-flopping. + * [1-ARM_MAX_VQ]: SVE is enabled and the user has specified a valid + * sve-max-vq. The sve-max-vq specified vq and all smaller + * vq's will be initially enabled. All larger vq's will have + * a default of 'OFF'. + */ +#define ARM_SVE_INIT -1 +#define ARM_VQ_DEFAULT_ON -2 +#define ARM_VQ_DEFAULT_OFF -3 + +#define arm_sve_have_max_vq(cpu) ((int32_t)(cpu)->sve_max_vq > 0) + +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, int 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, int vq, arm_vq_state state) +{ + assert(state == ARM_VQ_OFF || state == ARM_VQ_ON); + assert(vq <= ARM_MAX_VQ); + + 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 void arm_cpu_vq_map_init(ARMCPU *cpu) +{ + bitmap_zero(cpu->sve_vq_map, ARM_MAX_VQ * 2); + bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ); +} + +static bool arm_cpu_vq_map_is_finalized(ARMCPU *cpu) +{ + DECLARE_BITMAP(map, ARM_MAX_VQ * 2); + + bitmap_zero(map, ARM_MAX_VQ * 2); + bitmap_set(map, ARM_MAX_VQ, ARM_MAX_VQ); + bitmap_and(map, map, cpu->sve_vq_map, ARM_MAX_VQ * 2); + + return bitmap_empty(map, ARM_MAX_VQ * 2); +} + +static void arm_cpu_vq_map_finalize(ARMCPU *cpu) +{ + Error *err = NULL; + char name[8]; + uint32_t vq; + bool value; + + /* + * We use the property get accessor because it knows what default + * values to return for uninitialized vector lengths. + */ + for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { + sprintf(name, "sve%d", vq * 128); + value = object_property_get_bool(OBJECT(cpu), name, &err); + assert(!err); + if (value) { + arm_cpu_vq_map_set(cpu, vq, ARM_VQ_ON); + } else { + arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF); + } + } + + assert(arm_cpu_vq_map_is_finalized(cpu)); +} + +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) +{ + Error *err = NULL; + + if (!cpu->sve_max_vq) { + bitmap_zero(cpu->sve_vq_map, ARM_MAX_VQ * 2); + return; + } + + if (cpu->sve_max_vq == ARM_SVE_INIT) { + object_property_set_uint(OBJECT(cpu), ARM_MAX_VQ, "sve-max-vq", &err); + if (err) { + error_propagate(errp, err); + return; + } + assert(cpu->sve_max_vq == ARM_MAX_VQ); + arm_cpu_vq_map_finalize(cpu); + } else { + arm_cpu_vq_map_finalize(cpu); + if (!arm_sve_have_max_vq(cpu)) { + cpu->sve_max_vq = arm_cpu_vq_map_next_smaller(cpu, ARM_MAX_VQ + 1); + } + } + + assert(cpu->sve_max_vq == arm_cpu_vq_map_next_smaller(cpu, ARM_MAX_VQ + 1)); +} + +uint32_t arm_cpu_vq_map_next_smaller(ARMCPU *cpu, uint32_t vq) +{ + uint32_t bitnum; + + assert(vq <= ARM_MAX_VQ + 1); + assert(arm_cpu_vq_map_is_finalized(cpu)); + + 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) { @@ -283,12 +426,203 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, return; } + /* + * It gets complicated trying to support both sve-max-vq and + * sve properties together, so we mostly don't. We + * do allow both if sve-max-vq is specified first and only once + * though. + */ + if (cpu->sve_max_vq != ARM_SVE_INIT) { + error_setg(errp, "sve in use or sve-max-vq already " + "specified"); + error_append_hint(errp, "sve-max-vq must come before all " + "sve properties and it must only " + "be specified once.\n"); + return; + } + cpu->sve_max_vq = value; 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); + } else { + uint32_t vq; + + for (vq = 1; vq <= cpu->sve_max_vq; ++vq) { + char name[8]; + sprintf(name, "sve%d", vq * 128); + object_property_set_bool(obj, true, name, &err); + if (err) { + error_propagate(errp, err); + return; + } + } + } +} + +static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + int vq = atoi(&name[3]) / 128; + arm_vq_state vq_state; + bool value; + + vq_state = arm_cpu_vq_map_get(cpu, vq); + + if (!cpu->sve_max_vq) { + /* 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 { + /* + * vq is uninitialized. We pick a default here based on the + * the state of sve-max-vq and other sve properties. + */ + if (arm_sve_have_max_vq(cpu)) { + /* + * If we have sve-max-vq, then all remaining uninitialized + * vq's are 'OFF'. + */ + value = false; + } else { + switch (cpu->sve_max_vq) { + case ARM_SVE_INIT: + case ARM_VQ_DEFAULT_ON: + value = true; + break; + case ARM_VQ_DEFAULT_OFF: + value = false; + break; + } + } + } + + 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); + int vq = atoi(&name[3]) / 128; + arm_vq_state vq_state; + Error *err = NULL; + uint32_t max_vq = 0; + bool value; + + visit_type_bool(v, name, &value, &err); + if (err) { + error_propagate(errp, err); + return; + } + + if (value && !cpu->sve_max_vq) { + error_setg(errp, "cannot enable %s", name); + error_append_hint(errp, "SVE has been disabled with sve=off\n"); + return; + } else if (!cpu->sve_max_vq) { + /* + * We don't complain about disabling vector lengths when SVE + * is off, but we don't do anything either. + */ + return; + } + + if (arm_sve_have_max_vq(cpu)) { + max_vq = cpu->sve_max_vq; + } else { + if (value) { + cpu->sve_max_vq = ARM_VQ_DEFAULT_OFF; + } else if (cpu->sve_max_vq != ARM_VQ_DEFAULT_OFF) { + cpu->sve_max_vq = ARM_VQ_DEFAULT_ON; + } + } + + /* + * 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. We use the property get accessor in order to + * get the appropriate default value for any uninitialized lengths. + */ + if (!max_vq) { + char tmp[8]; + bool s; + + for (max_vq = ARM_MAX_VQ; max_vq >= 1; --max_vq) { + sprintf(tmp, "sve%d", max_vq * 128); + s = object_property_get_bool(OBJECT(cpu), tmp, &err); + assert(!err); + if (s) { + break; + } + } + } + + if (arm_sve_have_max_vq(cpu) && 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 (arm_sve_have_max_vq(cpu) && !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 (arm_sve_have_max_vq(cpu) && !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 (!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 (value) { + bool fail = false; + uint32_t s; + + /* + * 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 { + arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF); + } } } @@ -318,10 +652,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, /* * We handle the -cpu ,sve=off,sve=on case by reinitializing, * but otherwise we don't do anything as an sve=on could come after - * a sve-max-vq setting. + * a sve-max-vq or sve setting. */ if (!cpu->sve_max_vq) { - cpu->sve_max_vq = ARM_MAX_VQ; + cpu->sve_max_vq = ARM_SVE_INIT; + arm_cpu_vq_map_init(cpu); } } else { cpu->sve_max_vq = 0; @@ -336,6 +671,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); @@ -420,11 +756,29 @@ static void aarch64_max_initfn(Object *obj) cpu->dcz_blocksize = 7; /* 512 bytes */ #endif - cpu->sve_max_vq = ARM_MAX_VQ; + /* + * sve_max_vq is initially unspecified, but must be initialized to a + * non-zero value (ARM_SVE_INIT) to indicate that this cpu type has + * SVE. It will be finalized in arm_cpu_realizefn(). + */ + cpu->sve_max_vq = ARM_SVE_INIT; 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 f500ccb6d31b..b7b719dba57f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5324,7 +5324,16 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* Bits other than [3:0] are RAZ/WI. */ QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); - raw_write(env, ri, value & 0xf); + value &= 0xf; + + if (value) { + /* get next vq that is smaller than or equal to value's vq */ + uint32_t vq = value + 1; + vq = arm_cpu_vq_map_next_smaller(cpu, vq + 1); + value = vq - 1; + } + + raw_write(env, ri, value); /* * Because we arrived here, we know both FP and SVE are enabled; diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 157c487a1551..1e213906fd8f 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -89,8 +89,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 features, then the order that + * considers those dependencies must be used. + * + * The sve 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 509e458e9c2f..a4bf6aec00df 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', " @@ -137,6 +149,201 @@ static void assert_bad_props(QTestState *qts, const char *cpu_type) qobject_unref(resp); } +static void resp_get_sve_vls(QDict *resp, uint64_t *vls, uint32_t *max_vq) +{ + const QDictEntry *e; + QDict *qdict; + int n = 0; + + *vls = 0; + + qdict = resp_get_props(resp); + + for (e = qdict_first(qdict); e; e = qdict_next(qdict, 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(qdict, e->key)) { + *vls |= BIT((bits / 128) - 1); + } + ++n; + } + } + + g_assert(n == SVE_MAX_VQ); + + *max_vq = !*vls ? 0 : 64 - __builtin_clzll(*vls); +} + +static uint64_t sve_get_vls(QTestState *qts, const char *cpu_type, + const char *fmt, ...) +{ + QDict *resp; + uint64_t vls; + uint32_t max_vq; + + 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); + } + + g_assert(resp); + resp_get_sve_vls(resp, &vls, &max_vq); + qobject_unref(resp); + + return vls; +} + +#define assert_sve_vls(qts, cpu_type, expected_vls, fmt, ...) \ + g_assert(sve_get_vls(qts, cpu_type, fmt, ##__VA_ARGS__) == expected_vls) + +static void sve_tests_default(QTestState *qts, const char *cpu_type) +{ + /* + * With no sve-max-vq or sve properties on the command line + * the default is to have all vector lengths enabled. + */ + assert_sve_vls(qts, cpu_type, BIT(SVE_MAX_VQ) - 1, NULL); + + /* + * ------------------------------------------------------------------- + * 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. The shorter, sve384=on,sve512=off,sve640=off + * works on the command line, but QMP doesn't know that all the + * vector lengths larger than 384-bits will be disabled until it + * sees the enabling of sve384, which comes near the end since it + * visits the lengths in reverse order. So we just have to explicitly + * disable them all. + */ + assert_sve_vls(qts, cpu_type, 0x7, + "{ 'sve384': true, 'sve512': false, 'sve640': false, " + " 'sve768': false, 'sve896': false, 'sve1024': false, " + " 'sve1152': false, 'sve1280': false, 'sve1408': false, " + " 'sve1536': false, 'sve1664': false, 'sve1792': false, " + " 'sve1920': false, 'sve2048': 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); + + /* + * We can't turn anything on, but off is OK. + */ + assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }"); + assert_sve_vls(qts, "max", 0, "{ 'sve128': false }"); + + qtest_quit(qts); +} + static void test_query_cpu_model_expansion(const void *data) { QTestState *qts; @@ -159,9 +366,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 " @@ -213,6 +423,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); From patchwork Fri Jun 21 16:34:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120433 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vl136c5qz9s3l for ; Sat, 22 Jun 2019 02:45:27 +1000 (AEST) Received: from localhost ([::1]:36776 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMfG-00018Q-0O for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:45:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44669) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVW-0001qN-FU for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVS-0001sn-JE for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50248) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVM-0001Vl-4L; Fri, 21 Jun 2019 12:35:13 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BB0E585540; Fri, 21 Jun 2019 16:35:09 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7755E1001DE1; Fri, 21 Jun 2019 16:35:01 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:16 +0200 Message-Id: <20190621163422.6127-9-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Fri, 21 Jun 2019 16:35:09 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 08/14] target/arm/kvm64: Fix error returns X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" A couple return -EINVAL's forgot their '-'s. Signed-off-by: Andrew Jones Reviewed-by: Eric Auger Reviewed-by: Richard Henderson Reviewed-by: Richard Henderson --- 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 45ccda589903..9ca9a0ce821d 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -856,7 +856,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); @@ -997,7 +997,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. From patchwork Fri Jun 21 16:34:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120438 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vl6M3tVTz9s3l for ; Sat, 22 Jun 2019 02:50:03 +1000 (AEST) Received: from localhost ([::1]:36816 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMjh-00059q-IU for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:50:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44751) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVj-0001tq-2V for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVf-0002Ju-3P for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54632) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVQ-0001n1-Lq; Fri, 21 Jun 2019 12:35:18 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D322731628FA; Fri, 21 Jun 2019 16:35:15 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0A9D91001DE0; Fri, 21 Jun 2019 16:35:09 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:17 +0200 Message-Id: <20190621163422.6127-10-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Fri, 21 Jun 2019 16:35:15 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 09/14] target/arm/kvm64: Move the get/put of fpsimd registers out X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 Reviewed-by: Eric Auger Reviewed-by: Richard Henderson --- 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 9ca9a0ce821d..a2485d447e6a 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -721,13 +721,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, ®); + 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, ®); + 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, ®); + 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); @@ -817,33 +857,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, ®); - 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, ®); - 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, ®); + ret = kvm_arch_put_fpsimd(cs); if (ret) { return ret; } @@ -864,14 +878,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, ®); + 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, ®); + 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, ®); + 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; @@ -960,36 +1014,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, ®); - 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, ®); - 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, ®); + ret = kvm_arch_get_fpsimd(cs); if (ret) { return ret; } - vfp_set_fpcr(env, fpr); ret = kvm_get_vcpu_events(cpu); if (ret) { From patchwork Fri Jun 21 16:34:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120439 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VlBm0B3sz9s3l for ; Sat, 22 Jun 2019 02:53:52 +1000 (AEST) Received: from localhost ([::1]:36832 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMnM-00005N-H6 for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:53:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44828) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVm-000214-Og for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVl-0002Yu-18 for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:38 -0400 Received: from mx1.redhat.com ([209.132.183.28]:17071) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVW-0001sK-CY; Fri, 21 Jun 2019 12:35:24 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 31B0D301D680; Fri, 21 Jun 2019 16:35:18 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 207CE1001DC7; Fri, 21 Jun 2019 16:35:15 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:18 +0200 Message-Id: <20190621163422.6127-11-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Fri, 21 Jun 2019 16:35:18 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 10/14] target/arm/kvm64: Add kvm_arch_get/put_sve X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 --- target/arm/kvm64.c | 135 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 4 deletions(-) diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index a2485d447e6a..706541327491 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -673,11 +673,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; @@ -763,6 +764,70 @@ static int kvm_arch_put_fpsimd(CPUState *cs) return 0; } +/* + * If ARM_MAX_VQ is increased to be greater than 16, then we can no + * longer hard code slices to 1 in kvm_arch_put/get_sve(). + */ +QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); + +static int kvm_arch_put_sve(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + struct kvm_one_reg reg; + int slices = 1; + int i, n, ret; + + for (i = 0; i < slices; i++) { + for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) { + uint64_t *q = aa64_vfp_qreg(env, n); +#ifdef HOST_WORDS_BIGENDIAN + uint64_t d[ARM_MAX_VQ * 2]; + int j; + for (j = 0; j < cpu->sve_max_vq * 2; j++) { + d[j] = bswap64(q[j]); + } + reg.addr = (uintptr_t)d; +#else + reg.addr = (uintptr_t)q; +#endif + reg.id = KVM_REG_ARM64_SVE_ZREG(n, i); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) { + uint64_t *q = &env->vfp.pregs[n].p[0]; +#ifdef HOST_WORDS_BIGENDIAN + uint64_t d[ARM_MAX_VQ * 2 / 8]; + int j; + for (j = 0; j < cpu->sve_max_vq * 2 / 8; j++) { + d[j] = bswap64(q[j]); + } + reg.addr = (uintptr_t)d; +#else + reg.addr = (uintptr_t)q; +#endif + reg.id = KVM_REG_ARM64_SVE_PREG(n, i); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0]; + reg.id = KVM_REG_ARM64_SVE_FFR(i); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + return 0; +} + int kvm_arch_put_registers(CPUState *cs, int level) { struct kvm_one_reg reg; @@ -857,7 +922,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) } } - ret = kvm_arch_put_fpsimd(cs); + if (!cpu->sve_max_vq) { + ret = kvm_arch_put_fpsimd(cs); + } else { + ret = kvm_arch_put_sve(cs); + } if (ret) { return ret; } @@ -920,6 +989,60 @@ static int kvm_arch_get_fpsimd(CPUState *cs) return 0; } +static int kvm_arch_get_sve(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + struct kvm_one_reg reg; + int slices = 1; + int i, n, ret; + + for (i = 0; i < slices; i++) { + for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; n++) { + uint64_t *q = aa64_vfp_qreg(env, n); + reg.id = KVM_REG_ARM64_SVE_ZREG(n, i); + reg.addr = (uintptr_t)q; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } else { +#ifdef HOST_WORDS_BIGENDIAN + int j; + for (j = 0; j < cpu->sve_max_vq * 2; j++) { + q[j] = bswap64(q[j]); + } +#endif + } + } + + for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; n++) { + uint64_t *q = &env->vfp.pregs[n].p[0]; + reg.id = KVM_REG_ARM64_SVE_PREG(n, i); + reg.addr = (uintptr_t)q; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } else { +#ifdef HOST_WORDS_BIGENDIAN + int j; + for (j = 0; j < cpu->sve_max_vq * 2 / 8; j++) { + q[j] = bswap64(q[j]); + } +#endif + } + } + + reg.addr = (uintptr_t)&env->vfp.pregs[FFR_PRED_NUM].p[0]; + reg.id = KVM_REG_ARM64_SVE_FFR(i); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret) { + return ret; + } + } + + return 0; +} + int kvm_arch_get_registers(CPUState *cs) { struct kvm_one_reg reg; @@ -1014,7 +1137,11 @@ int kvm_arch_get_registers(CPUState *cs) env->spsr = env->banked_spsr[i]; } - ret = kvm_arch_get_fpsimd(cs); + if (!cpu->sve_max_vq) { + ret = kvm_arch_get_fpsimd(cs); + } else { + ret = kvm_arch_get_sve(cs); + } if (ret) { return ret; } From patchwork Fri Jun 21 16:34:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120440 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VlGJ3vQ5z9s3l for ; Sat, 22 Jun 2019 02:56:56 +1000 (AEST) Received: from localhost ([::1]:36876 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMqM-0003CE-Jj for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:56:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44839) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVn-000222-6N for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVl-0002Z4-1l for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57644) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVZ-000216-KU; Fri, 21 Jun 2019 12:35:29 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A79327F746; Fri, 21 Jun 2019 16:35:22 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 785791001DD9; Fri, 21 Jun 2019 16:35:18 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:19 +0200 Message-Id: <20190621163422.6127-12-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Fri, 21 Jun 2019 16:35:22 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 11/14] target/arm/kvm64: max cpu: Enable SVE when available X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 --- target/arm/cpu64.c | 24 ++++++++++++++++++++++-- target/arm/kvm.c | 5 +++++ target/arm/kvm64.c | 25 ++++++++++++++++++++++++- target/arm/kvm_arm.h | 27 +++++++++++++++++++++++++++ tests/arm-cpu-features.c | 1 + 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 5def82111dee..2e595ad53137 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -371,6 +371,11 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } + /* sve-max-vq and sve properties not yet implemented for KVM */ + if (kvm_enabled()) { + return; + } + if (cpu->sve_max_vq == ARM_SVE_INIT) { object_property_set_uint(OBJECT(cpu), ARM_MAX_VQ, "sve-max-vq", &err); if (err) { @@ -632,6 +637,10 @@ static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name, ARMCPU *cpu = ARM_CPU(obj); bool value = !!cpu->sve_max_vq; + if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + value = false; + } + visit_type_bool(v, name, &value, errp); } @@ -649,6 +658,11 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, } if (value) { + if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + error_setg(errp, "'sve' feature not supported by KVM on this host"); + return; + } + /* * We handle the -cpu ,sve=off,sve=on case by reinitializing, * but otherwise we don't do anything as an sve=on could come after @@ -675,6 +689,11 @@ static void aarch64_max_initfn(Object *obj) if (kvm_enabled()) { kvm_arm_set_cpu_features_from_host(cpu); + /* + * KVM doesn't yet support the sve-max-vq property, but + * setting cpu->sve_max_vq is also used to turn SVE on. + */ + cpu->sve_max_vq = ARM_SVE_INIT; } else { uint64_t t; uint32_t u; @@ -764,8 +783,6 @@ static void aarch64_max_initfn(Object *obj) cpu->sve_max_vq = ARM_SVE_INIT; 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 @@ -780,6 +797,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 69c961a4c62c..60645a196d3d 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 706541327491..9fc7f078cf68 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -604,6 +604,15 @@ bool kvm_arm_aarch32_supported(CPUState *cpu) return ret > 0; } +bool kvm_arm_sve_supported(CPUState *cpu) +{ + KVMState *s = KVM_STATE(current_machine->accelerator); + int ret; + + ret = kvm_check_extension(s, KVM_CAP_ARM_SVE); + return ret > 0; +} + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 int kvm_arch_init_vcpu(CPUState *cs) @@ -632,13 +641,20 @@ 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->sve_max_vq) { + if (!kvm_arm_sve_supported(cs)) { + cpu->sve_max_vq = 0; + } else { + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; + } + } /* Do KVM_ARM_VCPU_INIT ioctl */ ret = kvm_arm_vcpu_init(cs); @@ -646,6 +662,13 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } + if (cpu->sve_max_vq) { + 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 e0ded3607996..2367f8ab78ed 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 @@ -224,6 +238,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 @@ -274,6 +296,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 a4bf6aec00df..67ad5f2b78d5 100644 --- a/tests/arm-cpu-features.c +++ b/tests/arm-cpu-features.c @@ -393,6 +393,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", "The CPU definition 'cortex-a15' cannot " From patchwork Fri Jun 21 16:34:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120441 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VlKf53BDz9s3l for ; Sat, 22 Jun 2019 02:59:50 +1000 (AEST) Received: from localhost ([::1]:36896 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMt4-00057l-Sb for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:59:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44923) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVr-00029s-EX for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVp-0002k0-SW for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36310) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVk-000285-Td; Fri, 21 Jun 2019 12:35:37 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EBCEB30C62A8; Fri, 21 Jun 2019 16:35:25 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id EE0A21001B3F; Fri, 21 Jun 2019 16:35:22 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:20 +0200 Message-Id: <20190621163422.6127-13-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Fri, 21 Jun 2019 16:35:26 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 12/14] target/arm/kvm: scratch vcpu: Preserve input kvm_vcpu_init features X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 Reviewed-by: Richard Henderson Reviewed-by: Eric Auger --- 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 60645a196d3d..66c0c198604a 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 9fc7f078cf68..2821135a4d0e 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; From patchwork Fri Jun 21 16:34:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120435 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vl3x3wXwz9s3l for ; Sat, 22 Jun 2019 02:47:53 +1000 (AEST) Received: from localhost ([::1]:36802 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMha-0003H1-2I for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 12:47:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44957) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVv-0002Fb-Ax for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVr-0002mL-FV for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33176) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVf-0002DR-43; Fri, 21 Jun 2019 12:35:32 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 54205301EA82; Fri, 21 Jun 2019 16:35:28 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3E7BA1001DDE; Fri, 21 Jun 2019 16:35:26 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:21 +0200 Message-Id: <20190621163422.6127-14-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Fri, 21 Jun 2019 16:35:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 13/14] target/arm/cpu64: max cpu: Support sve properties with KVM X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 --- target/arm/cpu.h | 3 +- target/arm/cpu64.c | 171 +++++++++++++++++++++++++++------------ target/arm/kvm64.c | 117 +++++++++++++++++++++++++-- target/arm/kvm_arm.h | 19 +++++ target/arm/monitor.c | 2 +- tests/arm-cpu-features.c | 86 +++++++++++++++++--- 6 files changed, 331 insertions(+), 67 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cbb155cf72a5..8a1c6c66a462 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 2e595ad53137..6e92aa54b9c8 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -261,10 +261,11 @@ 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. Also, while the map - * is still initializing, sve-max-vq has an additional three states, bringing - * the number of its states to five, which are the following: + * 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. Also, while the map is still initializing, + * sve-max-vq has an additional three states, bringing the number of its states + * to five, which are the following: * * sve-max-vq: * 0: SVE is disabled. The default value for a vq in the map is 'OFF'. @@ -296,6 +297,11 @@ 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, int vq) @@ -324,6 +330,23 @@ static void arm_cpu_vq_map_init(ARMCPU *cpu) { bitmap_zero(cpu->sve_vq_map, ARM_MAX_VQ * 2); bitmap_set(cpu->sve_vq_map, ARM_MAX_VQ, ARM_MAX_VQ); + + if (kvm_enabled()) { + DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ); + uint32_t kvm_max_vq; + + bitmap_zero(kvm_supported, ARM_MAX_VQ); + + kvm_arm_sve_get_vls(CPU(cpu), kvm_supported, ARM_MAX_VQ, &kvm_max_vq); + + if (kvm_max_vq > ARM_MAX_VQ) { + warn_report("KVM supports vector lengths larger than " + "QEMU can enable"); + } + + bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, + kvm_supported, ARM_MAX_VQ); + } } static bool arm_cpu_vq_map_is_finalized(ARMCPU *cpu) @@ -371,12 +394,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) return; } - /* sve-max-vq and sve properties not yet implemented for KVM */ - if (kvm_enabled()) { - return; - } - - if (cpu->sve_max_vq == ARM_SVE_INIT) { + if (!kvm_enabled() && cpu->sve_max_vq == ARM_SVE_INIT) { object_property_set_uint(OBJECT(cpu), ARM_MAX_VQ, "sve-max-vq", &err); if (err) { error_propagate(errp, err); @@ -431,6 +449,11 @@ 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, "'sve' feature not supported by KVM on this host"); + return; + } + /* * It gets complicated trying to support both sve-max-vq and * sve properties together, so we mostly don't. We @@ -460,6 +483,12 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, sprintf(name, "sve%d", vq * 128); object_property_set_bool(obj, true, name, &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 " + "properties.\n"); + } error_propagate(errp, err); return; } @@ -484,6 +513,12 @@ 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() && vq_state == ARM_VQ_UNINITIALIZED) { + /* + * When KVM is enabled, anything not supported by the host must have + * 'OFF' for the default. + */ + value = false; } else { /* * vq is uninitialized. We pick a default here based on the @@ -539,6 +574,11 @@ 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, "'sve' feature not supported by KVM on this host"); + return; + } + if (arm_sve_have_max_vq(cpu)) { max_vq = cpu->sve_max_vq; } else { @@ -569,6 +609,8 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, } } + vq_state = arm_cpu_vq_map_get(cpu, vq); + if (arm_sve_have_max_vq(cpu) && 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 " @@ -580,19 +622,31 @@ 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 (arm_sve_have_max_vq(cpu) && !value && vq < cpu->sve_max_vq && - is_power_of_2(vq)) { + } else if (!kvm_enabled() && arm_sve_have_max_vq(cpu) && !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 (!value && vq < max_vq && is_power_of_2(vq)) { + } else if (!kvm_enabled() && !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_state == ARM_VQ_UNINITIALIZED) { + 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 if (kvm_enabled() && !value && vq < max_vq && + (vq_state == ARM_VQ_ON || + vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED)) { + 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 (value) { bool fail = false; @@ -602,31 +656,53 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, * 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 it's not a power-of-2. */ 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; - } + vq_state = arm_cpu_vq_map_get(cpu, s); + if (!kvm_enabled() && is_power_of_2(s) && + vq_state == ARM_VQ_UNINITIALIZED) { + arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON); + } else if (vq_state == ARM_VQ_UNINITIALIZED_KVM_SUPPORTED) { + assert(kvm_enabled()); + arm_cpu_vq_map_set(cpu, s, ARM_VQ_ON); + } else if ((kvm_enabled() || is_power_of_2(s)) && + vq_state == 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 { - arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF); + /* + * For KVM 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. + */ + if (!kvm_enabled() || vq_state != ARM_VQ_UNINITIALIZED) { + arm_cpu_vq_map_set(cpu, vq, ARM_VQ_OFF); + } } } } @@ -689,11 +765,6 @@ static void aarch64_max_initfn(Object *obj) if (kvm_enabled()) { kvm_arm_set_cpu_features_from_host(cpu); - /* - * KVM doesn't yet support the sve-max-vq property, but - * setting cpu->sve_max_vq is also used to turn SVE on. - */ - cpu->sve_max_vq = ARM_SVE_INIT; } else { uint64_t t; uint32_t u; @@ -774,32 +845,32 @@ 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 - - /* - * sve_max_vq is initially unspecified, but must be initialized to a - * non-zero value (ARM_SVE_INIT) to indicate that this cpu type has - * SVE. It will be finalized in arm_cpu_realizefn(). - */ - cpu->sve_max_vq = ARM_SVE_INIT; - 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); + + /* + * sve_max_vq is initially unspecified, but must be initialized to a + * non-zero value (ARM_SVE_INIT) to indicate that this cpu type has + * SVE. It will be finalized in arm_cpu_realizefn(). + */ + cpu->sve_max_vq = ARM_SVE_INIT; + 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 2821135a4d0e..5b0707e1192b 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -617,6 +617,110 @@ bool kvm_arm_sve_supported(CPUState *cpu) return ret > 0; } +QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); + +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map, + uint32_t qemu_max_vq, uint32_t *kvm_max_vq) +{ + static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS]; + static uint32_t host_max_vq = -1; + uint32_t vq; + int i, j; + + bitmap_clear(map, 0, qemu_max_vq); + *kvm_max_vq = 0; + + /* + * KVM ensures all host CPUs support the same set of vector lengths. + * So we only need to create a scratch VCPU once and then cache the + * results. + */ + if (host_max_vq == -1) { + int fdarray[3], ret = -1; + + if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, NULL)) { + error_report("failed to create scratch vcpu"); + abort(); + } + + if (ioctl(fdarray[0], KVM_CHECK_EXTENSION, KVM_CAP_ARM_SVE) > 0) { + 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], + }; + + kvm_arm_destroy_scratch_host_vcpu(fdarray); + + 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, ®); + if (ret) { + error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s", + strerror(errno)); + abort(); + } + } + + kvm_arm_destroy_scratch_host_vcpu(fdarray); + + if (ret) { + /* The host doesn't support SVE. */ + return; + } + } + + for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) { + if (!vls[i]) { + continue; + } + if (host_max_vq == -1) { + host_max_vq = 64 - clz64(vls[i]) + i * 64; + } + for (j = 1; j <= 64; ++j) { + vq = j + i * 64; + if (vq > qemu_max_vq) { + break; + } + if (vls[i] & (1UL << (j - 1))) { + set_bit(vq - 1, map); + } + } + } + + *kvm_max_vq = host_max_vq; +} + +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, ®); +} + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 int kvm_arch_init_vcpu(CPUState *cs) @@ -628,7 +732,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; } @@ -653,11 +757,8 @@ int kvm_arch_init_vcpu(CPUState *cs) unset_feature(&env->features, ARM_FEATURE_PMU); } if (cpu->sve_max_vq) { - if (!kvm_arm_sve_supported(cs)) { - cpu->sve_max_vq = 0; - } else { - cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; - } + assert(kvm_arm_sve_supported(cs)); + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; } /* Do KVM_ARM_VCPU_INIT ioctl */ @@ -667,6 +768,10 @@ int kvm_arch_init_vcpu(CPUState *cs) } if (cpu->sve_max_vq) { + 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 2367f8ab78ed..d5eb341e906d 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -212,6 +212,22 @@ typedef struct ARMHostCPUFeatures { */ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); +/** + * kvm_arm_sve_get_vls: + * @cs: CPUState + * @map: bitmap to fill in + * @qemu_max_vq: the maximum vector length QEMU supports in quadwords + * (size of the bitmap to fill in) + * @kvm_max_vq: the maximum vector length KVM supports in quadwords + * + * 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 @qemu_max_vq. Also assign @kvm_max_vq to the + * maximum vector length the KVM host supports. + */ +void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map, + uint32_t qemu_max_vq, uint32_t *kvm_max_vq); + /** * kvm_arm_set_cpu_features_from_host: * @cpu: ARMCPU to set the features for @@ -314,6 +330,9 @@ 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, + uint32_t qemu_max_vq, + uint32_t *kvm_max_vq) {} #endif static inline const char *gic_class_name(void) diff --git a/target/arm/monitor.c b/target/arm/monitor.c index 1e213906fd8f..284818fb4a51 100644 --- a/target/arm/monitor.c +++ b/target/arm/monitor.c @@ -100,7 +100,7 @@ QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); * * The sve 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 67ad5f2b78d5..349bd0dca6d1 100644 --- a/tests/arm-cpu-features.c +++ b/tests/arm-cpu-features.c @@ -324,23 +324,35 @@ static void sve_tests_sve_max_vq_8(const void *data) qtest_quit(qts); } -static void sve_tests_sve_off(const void *data) +static void sve_tests_off(QTestState *qts, const char *cpu_type) { - 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); + assert_sve_vls(qts, cpu_type, 0, NULL); /* * We can't turn anything on, but off is OK. */ - assert_error(qts, "max", "cannot enable sve128", "{ 'sve128': true }"); - assert_sve_vls(qts, "max", 0, "{ 'sve128': false }"); + assert_error(qts, cpu_type, "cannot enable sve128", "{ 'sve128': true }"); + assert_sve_vls(qts, cpu_type, 0, "{ 'sve128': false }"); +} +static void sve_tests_sve_off(const void *data) +{ + QTestState *qts; + + qts = qtest_init(MACHINE "-cpu max,sve=off"); + sve_tests_off(qts, "max"); + 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"); + sve_tests_off(qts, "max"); qtest_quit(qts); } @@ -392,12 +404,66 @@ 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", "The CPU definition 'cortex-a15' cannot " "be used with KVM on this host", NULL); + + assert_has_feature(qts, "max", "sve"); + resp = do_query_no_props(qts, "max"); + g_assert(resp); + kvm_supports_sve = qdict_get_bool(resp_get_props(resp), "sve"); + qobject_unref(resp); + + if (kvm_supports_sve) { + resp = do_query_no_props(qts, "max"); + resp_get_sve_vls(resp, &vls, &max_vq); + g_assert(max_vq != 0); + qobject_unref(resp); + + /* 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) { + /* The next smaller, supported vq is required */ + 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 { + resp = do_query_no_props(qts, "max"); + resp_get_sve_vls(resp, &vls, &max_vq); + g_assert(max_vq == 0); + qobject_unref(resp); + } } else { assert_error(qts, "host", "'pmu' feature not supported by KVM on this host", @@ -434,6 +500,8 @@ 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); + qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off", + NULL, sve_tests_sve_off_kvm); } return g_test_run(); From patchwork Fri Jun 21 16:34:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 1120443 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VlPV4MDWz9s3l for ; Sat, 22 Jun 2019 03:03:10 +1000 (AEST) Received: from localhost ([::1]:36918 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMwO-0007Ns-F1 for incoming@patchwork.ozlabs.org; Fri, 21 Jun 2019 13:03:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:44943) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1heMVt-0002Dr-Ds for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1heMVq-0002lX-VR for qemu-devel@nongnu.org; Fri, 21 Jun 2019 12:35:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37364) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1heMVl-0002TW-3X; Fri, 21 Jun 2019 12:35:37 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2120FC18B2C4; Fri, 21 Jun 2019 16:35:34 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTP id 979FE1001B1D; Fri, 21 Jun 2019 16:35:28 +0000 (UTC) From: Andrew Jones To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Date: Fri, 21 Jun 2019 18:34:22 +0200 Message-Id: <20190621163422.6127-15-drjones@redhat.com> In-Reply-To: <20190621163422.6127-1-drjones@redhat.com> References: <20190621163422.6127-1-drjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Fri, 21 Jun 2019 16:35:34 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v2 14/14] target/arm/kvm: host cpu: Add support for sve properties X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, richard.henderson@linaro.org, armbru@redhat.com, eric.auger@redhat.com, imammedo@redhat.com, alex.bennee@linaro.org, Dave.Martin@arm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 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 --- target/arm/cpu.c | 1 + target/arm/cpu.h | 2 ++ target/arm/cpu64.c | 47 ++++++++++++++++++++++++++-------------- tests/arm-cpu-features.c | 21 +++++++++--------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index e060a0d9df0e..9d05291cb5f6 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2407,6 +2407,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 8a1c6c66a462..52a6b219b74a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -974,11 +974,13 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el, bool el0_a64); +void aarch64_add_sve_properties(Object *obj); #else static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { } static inline void aarch64_sve_change_el(CPUARMState *env, int o, int n, bool a) { } +static inline void aarch64_add_sve_properties(Object *obj) { } #endif target_ulong do_arm_semihosting(CPUARMState *env); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 6e92aa54b9c8..89396a7729ec 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -753,6 +753,36 @@ 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_max_vq is initially unspecified, but must be initialized to a + * non-zero value (ARM_SVE_INIT) to indicate that this cpu type has + * SVE. It will be finalized in arm_cpu_realizefn(). + */ + assert(!cpu->sve_max_vq || cpu->sve_max_vq == ARM_SVE_INIT); + cpu->sve_max_vq = ARM_SVE_INIT; + + /* + * 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; @@ -761,7 +791,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; if (kvm_enabled()) { kvm_arm_set_cpu_features_from_host(cpu); @@ -847,9 +876,6 @@ 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); - /* * sve_max_vq is initially unspecified, but must be initialized to a * non-zero value (ARM_SVE_INIT) to indicate that this cpu type has @@ -859,18 +885,7 @@ 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); - /* - * 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); - } + aarch64_add_sve_properties(obj); } struct ARMCPUInfo { diff --git a/tests/arm-cpu-features.c b/tests/arm-cpu-features.c index 349bd0dca6d1..dfe83f104b27 100644 --- a/tests/arm-cpu-features.c +++ b/tests/arm-cpu-features.c @@ -351,8 +351,8 @@ static void sve_tests_sve_off_kvm(const void *data) { QTestState *qts; - qts = qtest_init(MACHINE "-accel kvm -cpu max,sve=off"); - sve_tests_off(qts, "max"); + qts = qtest_init(MACHINE "-accel kvm -cpu host,sve=off"); + sve_tests_off(qts, "host"); qtest_quit(qts); } @@ -417,24 +417,24 @@ static void test_query_cpu_model_expansion_kvm(const void *data) "The CPU definition 'cortex-a15' cannot " "be used 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"); g_assert(resp); kvm_supports_sve = qdict_get_bool(resp_get_props(resp), "sve"); qobject_unref(resp); if (kvm_supports_sve) { - resp = do_query_no_props(qts, "max"); + resp = do_query_no_props(qts, "host"); resp_get_sve_vls(resp, &vls, &max_vq); g_assert(max_vq != 0); qobject_unref(resp); /* 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) { @@ -446,7 +446,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); } @@ -455,16 +455,17 @@ 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 { - resp = do_query_no_props(qts, "max"); + resp = do_query_no_props(qts, "host"); resp_get_sve_vls(resp, &vls, &max_vq); g_assert(max_vq == 0); qobject_unref(resp); } } else { + assert_has_not_feature(qts, "host", "sve"); assert_error(qts, "host", "'pmu' feature not supported by KVM on this host", "{ 'pmu': true }");