Message ID | 20200813102657.2588720-6-liangpeng10@huawei.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Support disable/enable CPU features for AArch64 | expand |
On Thu, Aug 13, 2020 at 06:26:53PM +0800, Peng Liang wrote: > 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. And what if a is mutually exclusive with b? I.e. a and b can both be disabled, but only a or b may be enabled. Thanks, drew
On 8/13/2020 8:48 PM, Andrew Jones wrote: > On Thu, Aug 13, 2020 at 06:26:53PM +0800, Peng Liang wrote: >> 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. > > And what if a is mutually exclusive with b? I.e. a and b can both be > disabled, but only a or b may be enabled. > > Thanks, > drew > > . > Currently, a and b will be both enabled or disabled. For example, a and b are in relationship a->b, which means b is dependent on a. If -cpu host,a=off,b=on, then both a and b are enabled. If -cpu host,b=on,a=off, then both a and b are disabled. Maybe we should report an error to user in this scenario? Thanks, Peng
On Sat, Aug 15, 2020 at 10:19:27AM +0800, Peng Liang wrote: > On 8/13/2020 8:48 PM, Andrew Jones wrote: > > On Thu, Aug 13, 2020 at 06:26:53PM +0800, Peng Liang wrote: > >> 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. > > > > And what if a is mutually exclusive with b? I.e. a and b can both be > > disabled, but only a or b may be enabled. > > > > Thanks, > > drew > > > > . > > > > Currently, a and b will be both enabled or disabled. For example, a and b are > in relationship a->b, which means b is dependent on a. If -cpu host,a=off,b=on, > then both a and b are enabled. If -cpu host,b=on,a=off, then both a and b are > disabled. Maybe we should report an error to user in this scenario? > Right. There are more relationships between features than "depends on", such as "only if not" or "only if value is". The last one points out that just setting the minimum feature value may not be sufficient to control all the features. Also, there could be relationships involving more than two features, such as 'a iff b and c', or 'a iff b and !c'. We really have to take each feature of each ID register one at a time to make sure we handle them appropriately. Exposing them all like this without any checks just pushes all the pain onto the user to figure everything out, and if there's not even errors generated, then how will the user know when they got something wrong until their guest breaks in some mysterious way? Thanks, drew
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 113cf4a9e7..4e67b8f22c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1418,6 +1418,103 @@ static struct CPUFeatureInfo cpu_features[] = { }, }; +typedef struct CPUFeatureDep { + CPUFeatureInfo from, to; +} CPUFeatureDep; + +static const CPUFeatureDep feature_dependencies[] = { + { + .from = FIELD_INFO(ID_AA64PFR0, FP, true, 0, 0xf, false), + .to = FIELD_INFO(ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), + }, + { + .from = FIELD_INFO(ID_AA64PFR0, ADVSIMD, true, 0, 0xf, false), + .to = FIELD_INFO(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 = "ADVSIMDHP", .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 = "ADVSIMDHP", .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(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(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(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(ID_AA64ISAR0, SM3, false, 1, 0, false), + .to = FIELD_INFO(ID_AA64ISAR0, SM4, false, 1, 0, false), + }, + { + .from = FIELD_INFO(ID_AA64ISAR0, SM4, false, 1, 0, false), + .to = FIELD_INFO(ID_AA64ISAR0, SM3, false, 1, 0, false), + }, + { + .from = FIELD_INFO(ID_AA64ISAR0, SHA1, false, 1, 0, false), + .to = FIELD_INFO(ID_AA64ISAR0, SHA2, false, 1, 0, false), + }, + { + .from = FIELD_INFO(ID_AA64ISAR0, SHA1, false, 1, 0, false), + .to = FIELD_INFO(ID_AA64ISAR0, SHA3, false, 1, 0, false), + }, + { + .from = FIELD_INFO(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(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) { @@ -1454,13 +1551,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; + } + } } }