[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC v2 09/10] target/arm: introduce CPU feature dependency mechanism
From: |
Peng Liang |
Subject: |
[RFC v2 09/10] target/arm: introduce CPU feature dependency mechanism |
Date: |
Thu, 17 Sep 2020 20:14:48 +0800 |
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 and b CPU features are in relationship a->b, which means
b is dependent on a. If b is enabled by user, then a is enabled
automatically. And if a is disabled by user, then b is disabled
automatically.
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
---
target/arm/cpu.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 134 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 36375807e19d..4bb8587e9c53 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1257,6 +1257,107 @@ 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("sha2", ID_AA64ISAR0, SHA2, false, 1, 0, false),
+ .to = FIELD_INFO("sha1", ID_AA64ISAR0, SHA1, 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_feature_prop(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1491,6 +1592,8 @@ static void arm_cpu_finalizefn(Object *obj)
void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
{
+ int i;
+ ARMISARegisters *isar = &cpu->isar;
Error *local_err = NULL;
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
@@ -1500,6 +1603,37 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
return;
}
}
+
+ if (!kvm_enabled() || !kvm_arm_cpu_feature_supported()) {
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(feature_dependencies); ++i) {
+ const CPUFeatureDep *d = &feature_dependencies[i];
+ bool from_explicit = !!(isar->user_mask[d->from.reg] &
+ MAKE_64BIT_MASK(d->from.shift,
d->from.length));
+ bool to_explicit = !!(isar->user_mask[d->to.reg] &
+ MAKE_64BIT_MASK(d->to.shift, d->to.length));
+ bool from_enabled = object_property_get_bool(OBJECT(cpu), d->from.name,
+ &error_abort);
+ bool to_enabled = object_property_get_bool(OBJECT(cpu), d->to.name,
+ &error_abort);
+
+ if (!from_enabled && to_enabled) {
+ if (from_explicit && to_explicit) {
+ error_setg(errp, "The CPU feature '%s' dependes on CPU feature
"
+ "'%s' that is disabled explicitly",
+ d->to.name, d->from.name);
+ return;
+ } else if (from_explicit) {
+ isar->regs[d->to.reg] = deposit64(isar->regs[d->to.reg],
+ d->to.shift, d->to.length, d->to.ni_value);
+ } else if (to_explicit) {
+ isar->regs[d->from.reg] = deposit64(isar->regs[d->from.reg],
+ d->from.shift, d->from.length, d->from.min_value);
+ }
+ }
+ }
}
static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
--
2.26.2
- [RFC v2 00/10] Support disable/enable CPU features for AArch64, Peng Liang, 2020/09/17
- [RFC v2 01/10] linux-header: Introduce KVM_CAP_ARM_CPU_FEATURE, Peng Liang, 2020/09/17
- [RFC v2 03/10] target/arm: only set ID_PFR1_EL1.GIC for AArch32 guest, Peng Liang, 2020/09/17
- [RFC v2 02/10] target/arm: Update ID fields, Peng Liang, 2020/09/17
- [RFC v2 04/10] target/arm: convert isar regs to array, Peng Liang, 2020/09/17
- [RFC v2 05/10] target/arm: Introduce kvm_arm_cpu_feature_supported, Peng Liang, 2020/09/17
- [RFC v2 07/10] target/arm: Allow ID registers to synchronize to KVM, Peng Liang, 2020/09/17
- [RFC v2 08/10] target/arm: Introduce user_mask to indicate whether the feature is set explicitly, Peng Liang, 2020/09/17
- [RFC v2 10/10] target/arm: Add CPU features to query-cpu-model-expansion, Peng Liang, 2020/09/17
- [RFC v2 06/10] target/arm: register CPU features for property, Peng Liang, 2020/09/17
- [RFC v2 09/10] target/arm: introduce CPU feature dependency mechanism,
Peng Liang <=