From eb4515d3928634a2e944d0bfad25414a79a09ab2 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Thu, 6 Aug 2020 16:14:46 +0800 Subject: [PATCH] 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 Signed-off-by: Peng Liang Signed-off-by: Dongxu Sun --- ...duce-CPU-feature-dependency-mechanis.patch | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 target-arm-introduce-CPU-feature-dependency-mechanis.patch diff --git a/target-arm-introduce-CPU-feature-dependency-mechanis.patch b/target-arm-introduce-CPU-feature-dependency-mechanis.patch new file mode 100644 index 0000000..aecfbf8 --- /dev/null +++ b/target-arm-introduce-CPU-feature-dependency-mechanis.patch @@ -0,0 +1,185 @@ +From 632d58d1b908ee979074b589417f446c0a3be35d Mon Sep 17 00:00:00 2001 +From: Peng Liang +Date: Thu, 6 Aug 2020 16:14:46 +0800 +Subject: [PATCH] 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 +Signed-off-by: Peng Liang +Signed-off-by: Dongxu Sun +--- + target/arm/cpu.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 129 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index c081ecc12b..ee09642dae 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1483,6 +1483,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) + { +@@ -1519,13 +1616,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, d->from.name, true, &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, d->to.name, false, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } + } + } + +-- +2.27.0 +