QEMU does not support disable/enable CPU features in AArch64 for now. This patch series add support for CPU features in AArch64. Firstly, we change the isar struct in ARMCPU to an array for convenience. Secondly, we add support to configure CPU feautres in AArch64 and make sure that the ID registers can be synchronized to KVM so that guest can read the value we configure. Thirdly, we add a mechanism to solve the dependency relationship of some CPU features. Last, we add a KVM_CAP_ARM_CPU_FEATURE to check whether KVM supports to set CPU features in AArch64. Also export CPU features to the result of qmp query-cpu-model-expansion so that libvirt can get the supported CPU features. Update the ID fields to ARMv8.6 and add some CPU features according to the new ID fields. With related KVM patch set[1], we can disable/enable CPU features in AArch64. [1] https://patchwork.kernel.org/cover/11711693/ Signed-off-by: Peng Liang <liangpeng10@huawei.com>
185 lines
7.1 KiB
Diff
185 lines
7.1 KiB
Diff
From da538bb9d1acc22543a2b7b07ae35a62386bf226 Mon Sep 17 00:00:00 2001
|
|
From: Peng Liang <liangpeng10@huawei.com>
|
|
Date: Thu, 6 Aug 2020 16:14:46 +0800
|
|
Subject: [PATCH 5/9] target/arm: introduce CPU feature dependency mechanism
|
|
|
|
Some CPU features are dependent on other CPU features. For example,
|
|
ID_AA64PFR0_EL1.FP field and ID_AA64PFR0_EL1.AdvSIMD must have the same
|
|
value, which means FP and ADVSIMD are dependent on each other, FPHP and
|
|
ADVSIMDHP are dependent on each other.
|
|
|
|
This commit introduces a mechanism for CPU feature dependency in
|
|
AArch64. We build a directed graph from the CPU feature dependency
|
|
relationship, each edge from->to means the `to` CPU feature is dependent
|
|
on the `from` CPU feature. And we will automatically enable/disable CPU
|
|
feature according to the directed graph.
|
|
|
|
For example, a, b, and c CPU features are in relationship a->b->c, which
|
|
means c is dependent on b and b is dependent on a. If c is enabled by
|
|
user, then a and b is enabled automatically. And if a is disabled by
|
|
user, then b and c is disabled automatically.
|
|
|
|
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
|
|
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
|
|
---
|
|
target/arm/cpu.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 129 insertions(+)
|
|
|
|
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
|
|
index 3f63312c..d5576538 100644
|
|
--- a/target/arm/cpu.c
|
|
+++ b/target/arm/cpu.c
|
|
@@ -1306,6 +1306,103 @@ static struct CPUFeatureInfo cpu_features[] = {
|
|
},
|
|
};
|
|
|
|
+typedef struct CPUFeatureDep {
|
|
+ CPUFeatureInfo from, to;
|
|
+} CPUFeatureDep;
|
|
+
|
|
+static const CPUFeatureDep feature_dependencies[] = {
|
|
+ {
|
|
+ .from = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false),
|
|
+ .to = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false),
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("asimd", ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false),
|
|
+ .to = FIELD_INFO("fp", ID_AA64PFR0, FP, true, 0, 0xf, false),
|
|
+ },
|
|
+ {
|
|
+ .from = {
|
|
+ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH,
|
|
+ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1,
|
|
+ .ni_value = 0, .name = "fphp", .is_32bit = false,
|
|
+ },
|
|
+ .to = {
|
|
+ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH,
|
|
+ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1,
|
|
+ .ni_value = 0, .name = "asimdhp", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .from = {
|
|
+ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_ADVSIMD_LENGTH,
|
|
+ .shift = R_ID_AA64PFR0_ADVSIMD_SHIFT, .sign = true, .min_value = 1,
|
|
+ .ni_value = 0, .name = "asimdhp", .is_32bit = false,
|
|
+ },
|
|
+ .to = {
|
|
+ .reg = ID_AA64PFR0, .length = R_ID_AA64PFR0_FP_LENGTH,
|
|
+ .shift = R_ID_AA64PFR0_FP_SHIFT, .sign = true, .min_value = 1,
|
|
+ .ni_value = 0, .name = "fphp", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+
|
|
+ .from = FIELD_INFO("aes", ID_AA64ISAR0, AES, false, 1, 0, false),
|
|
+ .to = {
|
|
+ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_AES_LENGTH,
|
|
+ .shift = R_ID_AA64ISAR0_AES_SHIFT, .sign = false, .min_value = 2,
|
|
+ .ni_value = 1, .name = "pmull", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+
|
|
+ .from = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false),
|
|
+ .to = {
|
|
+ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH,
|
|
+ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2,
|
|
+ .ni_value = 1, .name = "sha512", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("lrcpc", ID_AA64ISAR1, LRCPC, false, 1, 0, false),
|
|
+ .to = {
|
|
+ .reg = ID_AA64ISAR1, .length = R_ID_AA64ISAR1_LRCPC_LENGTH,
|
|
+ .shift = R_ID_AA64ISAR1_LRCPC_SHIFT, .sign = false, .min_value = 2,
|
|
+ .ni_value = 1, .name = "ilrcpc", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false),
|
|
+ .to = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false),
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("sm4", ID_AA64ISAR0, SM4, false, 1, 0, false),
|
|
+ .to = FIELD_INFO("sm3", ID_AA64ISAR0, SM3, false, 1, 0, false),
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false),
|
|
+ .to = FIELD_INFO("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false),
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, false, 1, 0, false),
|
|
+ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false),
|
|
+ },
|
|
+ {
|
|
+ .from = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false),
|
|
+ .to = {
|
|
+ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH,
|
|
+ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2,
|
|
+ .ni_value = 1, .name = "sha512", .is_32bit = false,
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ .from = {
|
|
+ .reg = ID_AA64ISAR0, .length = R_ID_AA64ISAR0_SHA2_LENGTH,
|
|
+ .shift = R_ID_AA64ISAR0_SHA2_SHIFT, .sign = false, .min_value = 2,
|
|
+ .ni_value = 1, .name = "sha512", .is_32bit = false,
|
|
+ },
|
|
+ .to = FIELD_INFO("sha3", ID_AA64ISAR0, SHA3, false, 1, 0, false),
|
|
+ },
|
|
+};
|
|
+
|
|
static void arm_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
void *opaque, Error **errp)
|
|
{
|
|
@@ -1342,13 +1439,45 @@ static void arm_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name,
|
|
}
|
|
|
|
if (value) {
|
|
+ if (object_property_get_bool(obj, feat->name, NULL)) {
|
|
+ return;
|
|
+ }
|
|
isar->regs[feat->reg] = deposit64(isar->regs[feat->reg],
|
|
feat->shift, feat->length,
|
|
feat->min_value);
|
|
+ /* Auto enable the features which current feature is dependent on. */
|
|
+ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) {
|
|
+ const CPUFeatureDep *d = &feature_dependencies[i];
|
|
+ if (strcmp(d->to.name, feat->name) != 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ object_property_set_bool(obj, true, d->from.name, &local_err);
|
|
+ if (local_err) {
|
|
+ error_propagate(errp, local_err);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
} else {
|
|
+ if (!object_property_get_bool(obj, feat->name, NULL)) {
|
|
+ return;
|
|
+ }
|
|
isar->regs[feat->reg] = deposit64(isar->regs[feat->reg],
|
|
feat->shift, feat->length,
|
|
feat->ni_value);
|
|
+ /* Auto disable the features which are dependent on current feature. */
|
|
+ for (int i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) {
|
|
+ const CPUFeatureDep *d = &feature_dependencies[i];
|
|
+ if (strcmp(d->from.name, feat->name) != 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ object_property_set_bool(obj, false, d->to.name, &local_err);
|
|
+ if (local_err) {
|
|
+ error_propagate(errp, local_err);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|
|
--
|
|
2.25.1
|
|
|