arm64: Add support for FEAT_E2H0, or lack thereof
Marc Zyngier
maintainerv2 cover arm64: Add support for FEAT_E2H0, or lack thereof
Since ARMv8.1, the architecture has grown the VHE feature, which makes EL2 a superset of EL1. With ARMv9.5 (and retroactively allowed from ARMv8.1), the architecture allows implementations to have VHE as the *only* implemented behaviour, meaning that HCR_EL2.E2H can be implemented as RES1. As a follow-up, HCR_EL2.NV1 can also be implemented as RES0, making the VHE-ness of the architecture recursive.
This has a number of consequences, both at boot time and for KVM, though the changes at that level are pretty minor.
The real meat of this series is on the cpufeature front, as FEAT_E2H0 is a *negative* feature, where 0b1111 (-1) represents E2H being RES1 and 0b1110 (-2) additionally indicates that NV1 is RES0. Fun, isn't it?
As a bonus, a popular crop of non-compliant HW gets promoted as the first batch of non-zero E2H0 users, making things easy for KVM.
This series is a prefix for the next drop of NV support.
* From v1:
- Added a SYS_FIELD_VALUE() helper to handle the concatenation of various fields
- Only test for the top bit of ID_AA64MMFR4_EL1.E2H0 to decide whether HCR_EL2.E2H is RES1.
- Picked RBs from Oliver (thanks!)
- Rebased on 6.7-rc2
Marc Zyngier (13):
arm64: Add macro to compose a sysreg field value
arm64: cpufeatures: Correctly handle signed values
arm64: cpufeature: Correctly display signed override values
arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling
arm64: cpufeature: Detect E2H0 not being implemented
arm64: cpufeature: Detect HCR_EL2.NV1 being RES0
arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is
negative
arm64: Add override for ID_AA64MMFR4_EL1.E2H0
arm64: Add MIDR-based override infrastructure
arm64: Add MIDR-based overrides for ID_AA64MMFR4_EL1.E2H0
KVM: arm64: Expose ID_AA64MMFR4_EL1 to guests
KVM: arm64: Force guest's HCR_EL2.E2H RES1 when NV1 is not implemented
arch/arm64/include/asm/cpu.h | 1 + arch/arm64/include/asm/cpufeature.h | 2 + arch/arm64/include/asm/kvm_emulate.h | 3 +- arch/arm64/include/asm/sysreg.h | 7 ++- arch/arm64/kernel/cpufeature.c | 91 +++++++++++++++++++++++++--- arch/arm64/kernel/cpuinfo.c | 1 + arch/arm64/kernel/head.S | 23 ++++--- arch/arm64/kernel/idreg-override.c | 65 ++++++++++++++++++++ arch/arm64/kvm/nested.c | 4 ++ arch/arm64/kvm/sys_regs.c | 17 +++++- arch/arm64/tools/cpucaps | 2 + arch/arm64/tools/sysreg | 37 +++++++++++ 12 files changed, 229 insertions(+), 24 deletions(-)
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 1/13 arm64: Add macro to compose a sysreg field value
A common idiom is to compose a tupple (reg, field, val) into a symbol matching an autogenerated definition.
Add a help performing the concatenation and replace it when open-coded implementations exist.
--- arch/arm64/include/asm/sysreg.h | 5 ++++- arch/arm64/kvm/sys_regs.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-)
arch/arm64/include/asm/sysreg.h +4 -1
@@ -1156,6 +1156,8 @@ par; \ }) +#define SYS_FIELD_VALUE (reg, field, val) reg##_##field##_##val +#define SYS_FIELD_GET (reg, field, val) \ FIELD_GET(reg##_##field##_MASK, val)
@@ -1163,7 +1165,8 @@ FIELD_PREP(reg##_##field##_MASK, val)#define SYS_FIELD_PREP_ENUM (reg, field, val) \ - FIELD_PREP(reg##_##field##_MASK, reg##_##field##_##val) + FIELD_PREP(reg##_##field##_MASK, \ + SYS_FIELD_VALUE(reg, field, val))#endif
arch/arm64/kvm/sys_regs.c +2 -1
@@ -1561,7 +1561,8 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \ (val) &= ~reg##_##field##_MASK; \ (val) |= FIELD_PREP(reg##_##field##_MASK, \ - min(__f_val, (u64)reg##_##field##_##limit)); \ + min(__f_val, \ + (u64)SYS_FIELD_VALUE(reg, field, limit))); \ (val); \ })
Signature · 1 line
2.39.2
Marc Zyngier
maintainerPATCH v2 2/13 arm64: cpufeatures: Correctly handle signed values
In reply to Marc ZyngierAlthough we've had signed values for some features such as PMUv3 and FP, the code that handles the comparaison with some limit has a couple of annoying issues:
- the min_field_value is always unsigned, meaning that we cannot easily compare it with a negative value
- it is not possible to have a range of values, let alone a range of negative values
Fix this by:
- adding an upper limit to the comparison, defaulting to all bits being set to the maximum positive value
- ensuring that the signess of the min and max values are taken into account
A ARM64_CPUID_FIELDS_NEG() macro is provided for signed features, but nothing is using it yet.
--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 66 +++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 9 deletions(-)
arch/arm64/include/asm/cpufeature.h +1 -0
@@ -363,6 +363,7 @@ struct arm64_cpu_capabilities {u8 field_pos;u8 field_width;u8 min_field_value; +u8 max_field_value;u8 hwcap_type;bool sign;unsigned long hwcap;
arch/arm64/kernel/cpufeature.c +57 -9
80 lines not on this page · raw message
Signature · 1 line
2.39.2
Suzuki K Poulose
reviewerRe: [PATCH v2 02/13] arm64: cpufeatures: Correctly handle signed values
Quoted 44 lines · Marc Zyngier
Although we've had signed values for some features such as PMUv3 and FP, the code that handles the comparaison with some limit has a couple of annoying issues:
- the
min_field_valueis always unsigned, meaning that we cannot easily compare it with a negative value- it is not possible to have a range of values, let alone a range of negative values
Fix this by:
- adding an upper limit to the comparison, defaulting to all bits being set to the maximum positive value
- ensuring that the signess of the min and max values are taken into account
A
ARM64_CPUID_FIELDS_NEG()macro is provided for signed features, but nothing is using it yet.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 66 +++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 9 deletions(-)arch/arm64/include/asm/cpufeature.h +1
-0@@ -363,6 +363,7 @@ struct arm64_cpu_capabilities {u8 field_pos;u8 field_width;u8 min_field_value; +u8 max_field_value;u8 hwcap_type;bool sign;unsigned long hwcap;arch/arm64/kernel/cpufeature.c +0
-0
arch/arm64/kernel/cpufeature.c void dump_cpu_features(void) · line 143
Quoted 4 lines
arch/arm64/kernel/cpufeature.c +1
-0@@ -140,12 +140,43 @@ void dump_cpu_features(void)pr_emerg ("0x%*pb\n" ,ARM64_NCAPS , &system_cpucaps); } +#define __ARM64_EXPAND_RFV (reg, field, val) reg##_##field##_##val
We have defined SYS_FIELD_VALUE to be the exact same thing in Patch 1 and we later remove this and switch to using the same in Patch 8. Could we not do this straight away here ? i.e. use the SYS_FIELD_VALUE
instead of adding this ?
Rest looks good to me.
Suzuki
Quoted 77 lines
arch/arm64/kernel/cpufeature.c +56
-9+#define __ARM64_MAX_POSITIVE (reg, field) \ + ((reg##_##field##_SIGNED ? \ + BIT(reg##_##field##_WIDTH - 1) : \ + BIT(reg##_##field##_WIDTH)) - 1) + +#define __ARM64_MIN_NEGATIVE (reg, field) BIT(reg##_##field##_WIDTH - 1) + +#define __ARM64_CPUID_FIELDS (reg, field, min_value, max_value) \ + .sys_reg = SYS_##reg, \ + .field_pos = reg##_##field##_SHIFT, \ + .field_width = reg##_##field##_WIDTH, \ + .sign = reg##_##field##_SIGNED, \ + .min_field_value = min_value, \ + .max_field_value = max_value, + +/* +* ARM64_CPUID_FIELDS() encodes a field with a range from min_value to +* an implicit maximum that depends on the sign-ess of the field. +* +* An unsigned field will be capped at all ones, while a signed field +* will be limited to the positive half only. +*/ #define ARM64_CPUID_FIELDS (reg, field, min_value) \ - .sys_reg = SYS_##reg, \ - .field_pos = reg##_##field##_SHIFT, \ - .field_width = reg##_##field##_WIDTH, \ - .sign = reg##_##field##_SIGNED, \ - .min_field_value = reg##_##field##_##min_value, + __ARM64_CPUID_FIELDS(reg, field, \ + __ARM64_EXPAND_RFV(reg, field, min_value), \ + __ARM64_MAX_POSITIVE(reg, field)) + +/* +* ARM64_CPUID_FIELDS_NEG() encodes a field with a range from an +* implicit minimal value to max_value. This should be used when +* matching a non-implemented property. +*/ +#define ARM64_CPUID_FIELDS_NEG (reg, field, max_value) \ + __ARM64_CPUID_FIELDS(reg, field, \ + __ARM64_MIN_NEGATIVE(reg, field), \ + __ARM64_EXPAND_RFV(reg, field, max_value))#define __ARM64_FTR_BITS (SIGNED ,VISIBLE ,STRICT ,TYPE ,SHIFT ,WIDTH ,SAFE_VAL ) \ { \@@ -1470,11 +1501,28 @@ has_always(const struct arm64_cpu_capabilities *entry, int scope)static bool feature_matches (u64 reg,const struct arm64_cpu_capabilities *entry) { -int val =cpuid_feature_extract_field_width (reg, entry->field_pos, - entry->field_width, - entry->sign); +int val, min, max; +u64 tmp; + + val =cpuid_feature_extract_field_width (reg, entry->field_pos, + entry->field_width, + entry->sign); + + tmp = entry->min_field_value; + tmp <<= entry->field_pos; + + min =cpuid_feature_extract_field_width (tmp, entry->field_pos, + entry->field_width, + entry->sign); + + tmp = entry->max_field_value; + tmp <<= entry->field_pos; + + max =cpuid_feature_extract_field_width (tmp, entry->field_pos, + entry->field_width, + entry->sign); -return val >= entry->min_field_value; +return val >= min && val <= max; } static u64
Marc Zyngier
maintainerRe: [PATCH v2 02/13] arm64: cpufeatures: Correctly handle signed values
Quoted 47 lines · Suzuki K Poulose
Quoted 45 lines · Marc Zyngier
Although we've had signed values for some features such as PMUv3 and FP, the code that handles the comparaison with some limit has a couple of annoying issues:
- the
min_field_valueis always unsigned, meaning that we cannot easily compare it with a negative value- it is not possible to have a range of values, let alone a range of negative values
Fix this by:
- adding an upper limit to the comparison, defaulting to all bits being set to the maximum positive value
- ensuring that the signess of the min and max values are taken into account
A
ARM64_CPUID_FIELDS_NEG()macro is provided for signed features, but nothing is using it yet.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 66 +++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 9 deletions(-)arch/arm64/include/asm/cpufeature.h +1
-0@@ -363,6 +363,7 @@ struct arm64_cpu_capabilities {u8 field_pos;u8 field_width;u8 min_field_value; +u8 max_field_value;u8 hwcap_type;bool sign;unsigned long hwcap;arch/arm64/kernel/cpufeature.c +0
-0@@ -140,12 +140,43 @@ void dump_cpu_features(void)pr_emerg ("0x%*pb\n" ,ARM64_NCAPS , &system_cpucaps);
Quoted 8 lines
Quoted 3 lines
arch/arm64/kernel/cpufeature.c +0
-0} +#define __ARM64_EXPAND_RFV(reg, field, val)reg##_##field##_##val
We have defined
SYS_FIELD_VALUEto be the exact same thing in Patch 1 and we later remove this and switch to using the same in Patch 8. Could we not do this straight away here ? i.e. use theSYS_FIELD_VALUEinstead of adding this ?
Because I'm a moron and updated everything *except* my own patches. Apologies for the noise, I'll fix that shortly.
Quoted 1 line
Rest looks good to me.
Thanks!
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 3/13 arm64: cpufeature: Correctly display signed override values
In reply to Marc ZyngierWhen a field gets overriden, the kernel indicates the result of the override in dmesg. This works well with unsigned fields, but results in a pretty ugly output when the field is signed.
Truncate the field to its width before displaying it.
--- arch/arm64/kernel/cpufeature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/kernel/cpufeature.c +2 -1
@@ -950,7 +950,8 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)pr_warn ("%s[%d:%d]: %s to %llx\n" , reg->name, ftrp->shift + ftrp->width -1 , - ftrp->shift, str, tmp); + ftrp->shift, str, + tmp & (BIT (ftrp->width) -1 )); }else if ((ftr_mask & reg->override->val) == ftr_mask) { reg->override->val &= ~ftr_mask; pr_warn("%s[%d:%d]: impossible override, ignored\n",
Signature · 1 line
2.39.2
Re: [PATCH v2 03/13] arm64: cpufeature: Correctly display signed override values
Quoted 8 lines · Marc Zyngier
When a field gets overriden, the kernel indicates the result of the override in dmesg. This works well with unsigned fields, but results in a pretty ugly output when the field is signed.
Truncate the field to its width before displaying it.
Reviewed-by Oliver Upton <[email protected]>Signed-off-by Marc Zyngier <[email protected]>
Quoted 18 lines
--- arch/arm64/kernel/cpufeature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)arch/arm64/kernel/cpufeature.c +2
-1@@ -950,7 +950,8 @@ static void init_cpu_ftr_reg(u32 sys_reg, u64 new)pr_warn ("%s[%d:%d]: %s to %llx\n" , reg->name, ftrp->shift + ftrp->width -1 , - ftrp->shift, str, tmp); + ftrp->shift, str, + tmp & (BIT (ftrp->width) -1 )); }else if ((ftr_mask & reg->override->val) == ftr_mask) { reg->override->val &= ~ftr_mask; pr_warn("%s[%d:%d]: impossible override, ignored\n",
Marc Zyngier
maintainerPATCH v2 4/13 arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
In reply to Marc ZyngierARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features. Add the corresponding layout.
This is extracted from the public ARM SysReg_xml_A_profile-2023-09 delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
--- arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
arch/arm64/tools/sysreg +37 -0
@@ -1675,6 +1675,43 @@ UnsignedEnum 3:0 TCRX EndEnum EndSysreg +Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4 +Res0 63:40 +UnsignedEnum 39:36 E3DSE + 0b0000 NI + 0b0001 IMP +EndEnum +Res0 35:28 +SignedEnum 27:24 E2H0 + 0b0000 IMP + 0b1110 NI_NV1 + 0b1111 NI +EndEnum +UnsignedEnum 23:20 NV_frac + 0b0000 NV_NV2 + 0b0001 NV2_ONLY +EndEnum +UnsignedEnum 19:16 FGWTE3 + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 15:12 HACDBS + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 11:8 ASID2 + 0b0000 NI + 0b0001 IMP +EndEnum +SignedEnum 7:4 EIESB + 0b0000 NI + 0b0001 ToEL3 + 0b0010 ToELx + 0b1111 ANY +EndEnum +Res0 3:0 +EndSysreg + Sysreg SCTLR_EL1 3 0 1 0 0 Field 63 TIDCP Field 62 SPINTMASK
Signature · 1 line
2.39.2
Re: [PATCH v2 04/13] arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
Quoted 7 lines · Marc Zyngier
ARMv9.5 has infroduced
ID_AA64MMFR4_EL1with a bunch of new features. Add the corresponding layout.This is extracted from the public ARM SysReg_xml_A_profile-2023-09 delivery, timestamped
d55f5af8e09052abe92a02adf820deea2eaed717.Signed-off-by Marc Zyngier <[email protected]>
Matches the definitions.
Quoted 52 lines
--- arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)arch/arm64/tools/sysreg +37
-0@@ -1675,6 +1675,43 @@ UnsignedEnum 3:0 TCRX EndEnum EndSysreg +Sysreg ID_AA64MMFR4_EL1 3 0 0 7 4 +Res0 63:40 +UnsignedEnum 39:36 E3DSE + 0b0000 NI + 0b0001 IMP +EndEnum +Res0 35:28 +SignedEnum 27:24 E2H0 + 0b0000 IMP + 0b1110 NI_NV1 + 0b1111 NI +EndEnum +UnsignedEnum 23:20 NV_frac + 0b0000 NV_NV2 + 0b0001 NV2_ONLY +EndEnum +UnsignedEnum 19:16 FGWTE3 + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 15:12 HACDBS + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 11:8 ASID2 + 0b0000 NI + 0b0001 IMP +EndEnum +SignedEnum 7:4 EIESB + 0b0000 NI + 0b0001 ToEL3 + 0b0010 ToELx + 0b1111 ANY +EndEnum +Res0 3:0 +EndSysreg + Sysreg SCTLR_EL1 3 0 1 0 0 Field 63 TIDCP Field 62 SPINTMASK
Marc Zyngier
maintainerPATCH v2 5/13 arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling
In reply to Marc ZyngierAdd ID_AA64MMFR4_EL1 to the list of idregs the kernel knows about, and describe the E2H0 field.
--- arch/arm64/include/asm/cpu.h | 1 + arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/kernel/cpuinfo.c | 1 + 3 files changed, 9 insertions(+)
arch/arm64/include/asm/cpu.h +1 -0
@@ -57,6 +57,7 @@ struct cpuinfo_arm64 {u64 reg_id_aa64mmfr1;u64 reg_id_aa64mmfr2;u64 reg_id_aa64mmfr3; +u64 reg_id_aa64mmfr4;u64 reg_id_aa64pfr0;u64 reg_id_aa64pfr1;u64 reg_id_aa64zfr0;
arch/arm64/kernel/cpufeature.c +7 -0
@@ -438,6 +438,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr3[] = { ARM64_FTR_END, }; +static const struct arm64_ftr_bits ftr_id_aa64mmfr4[] = { +S_ARM64_FTR_BITS (FTR_HIDDEN ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64MMFR4_EL1_E2H0_SHIFT ,4 ,0 ), +ARM64_FTR_END , +}; +static const struct arm64_ftr_bits ftr_ctr[] = {ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_EXACT ,31 ,1 ,1 ),/* RES1 */ ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,CTR_EL0_DIC_SHIFT ,1 ,1 ),
@@ -755,6 +760,7 @@ static const struct __ftr_reg_entry { &id_aa64mmfr1_override),ARM64_FTR_REG (SYS_ID_AA64MMFR2_EL1 , ftr_id_aa64mmfr2),ARM64_FTR_REG (SYS_ID_AA64MMFR3_EL1 , ftr_id_aa64mmfr3), +ARM64_FTR_REG (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4),/* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),
@@ -1079,6 +1085,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)init_cpu_ftr_reg (SYS_ID_AA64MMFR1_EL1 , info->reg_id_aa64mmfr1);init_cpu_ftr_reg (SYS_ID_AA64MMFR2_EL1 , info->reg_id_aa64mmfr2);init_cpu_ftr_reg (SYS_ID_AA64MMFR3_EL1 , info->reg_id_aa64mmfr3); +init_cpu_ftr_reg (SYS_ID_AA64MMFR4_EL1 , info->reg_id_aa64mmfr4);init_cpu_ftr_reg (SYS_ID_AA64PFR0_EL1 , info->reg_id_aa64pfr0);init_cpu_ftr_reg (SYS_ID_AA64PFR1_EL1 , info->reg_id_aa64pfr1);init_cpu_ftr_reg (SYS_ID_AA64ZFR0_EL1 , info->reg_id_aa64zfr0);
arch/arm64/kernel/cpuinfo.c +1 -0
@@ -452,6 +452,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) info->reg_id_aa64mmfr1 =read_cpuid (ID_AA64MMFR1_EL1 ); info->reg_id_aa64mmfr2 =read_cpuid (ID_AA64MMFR2_EL1 ); info->reg_id_aa64mmfr3 =read_cpuid (ID_AA64MMFR3_EL1 ); + info->reg_id_aa64mmfr4 =read_cpuid (ID_AA64MMFR4_EL1 ); info->reg_id_aa64pfr0 =read_cpuid (ID_AA64PFR0_EL1 ); info->reg_id_aa64pfr1 =read_cpuid (ID_AA64PFR1_EL1 ); info->reg_id_aa64zfr0 =read_cpuid (ID_AA64ZFR0_EL1 );
Signature · 1 line
2.39.2
Re: [PATCH v2 05/13] arm64: cpufeature: Add ID_AA64MMFR4_EL1 handling
Quoted 28 lines · Marc Zyngier
Add
ID_AA64MMFR4_EL1to the list of idregs the kernel knows about, and describe the E2H0 field.Reviewed-by Oliver Upton <[email protected]>Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/include/asm/cpu.h | 1 + arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/kernel/cpuinfo.c | 1 + 3 files changed, 9 insertions(+)arch/arm64/include/asm/cpu.h +1
-0@@ -57,6 +57,7 @@ struct cpuinfo_arm64 {u64 reg_id_aa64mmfr1;u64 reg_id_aa64mmfr2;u64 reg_id_aa64mmfr3; +u64 reg_id_aa64mmfr4;u64 reg_id_aa64pfr0;u64 reg_id_aa64pfr1;u64 reg_id_aa64zfr0;arch/arm64/kernel/cpufeature.c +0
-0
arch/arm64/kernel/cpufeature.c static const struct arm64_ftr_bits ftr_id_aa64mmfr3[] = { · line 442
Quoted 5 lines
arch/arm64/kernel/cpufeature.c +2
-0@@ -438,6 +438,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr3[] = { ARM64_FTR_END, }; +static const struct arm64_ftr_bits ftr_id_aa64mmfr4[] = { +S_ARM64_FTR_BITS (FTR_HIDDEN ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64MMFR4_EL1_E2H0_SHIFT ,4 ,0 ),
It does sound a bit confusing, but FTR_LOWER_SAFE is the correct choice for the feature.
Quoted 34 lines
arch/arm64/kernel/cpufeature.c +5
-0+ ARM64_FTR_END, +}; +static const struct arm64_ftr_bits ftr_ctr[] = {ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_EXACT ,31 ,1 ,1 ),/* RES1 */ ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,CTR_EL0_DIC_SHIFT ,1 ,1 ),@@ -755,6 +760,7 @@ static const struct __ftr_reg_entry { &id_aa64mmfr1_override),ARM64_FTR_REG (SYS_ID_AA64MMFR2_EL1 , ftr_id_aa64mmfr2),ARM64_FTR_REG (SYS_ID_AA64MMFR3_EL1 , ftr_id_aa64mmfr3), +ARM64_FTR_REG (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4),/* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),@@ -1079,6 +1085,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)init_cpu_ftr_reg (SYS_ID_AA64MMFR1_EL1 , info->reg_id_aa64mmfr1);init_cpu_ftr_reg (SYS_ID_AA64MMFR2_EL1 , info->reg_id_aa64mmfr2);init_cpu_ftr_reg (SYS_ID_AA64MMFR3_EL1 , info->reg_id_aa64mmfr3); +init_cpu_ftr_reg (SYS_ID_AA64MMFR4_EL1 , info->reg_id_aa64mmfr4);init_cpu_ftr_reg (SYS_ID_AA64PFR0_EL1 , info->reg_id_aa64pfr0);init_cpu_ftr_reg (SYS_ID_AA64PFR1_EL1 , info->reg_id_aa64pfr1);init_cpu_ftr_reg (SYS_ID_AA64ZFR0_EL1 , info->reg_id_aa64zfr0);arch/arm64/kernel/cpuinfo.c +1
-0@@ -452,6 +452,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) info->reg_id_aa64mmfr1 =read_cpuid (ID_AA64MMFR1_EL1 ); info->reg_id_aa64mmfr2 =read_cpuid (ID_AA64MMFR2_EL1 ); info->reg_id_aa64mmfr3 =read_cpuid (ID_AA64MMFR3_EL1 ); + info->reg_id_aa64mmfr4 =read_cpuid (ID_AA64MMFR4_EL1 ); info->reg_id_aa64pfr0 =read_cpuid (ID_AA64PFR0_EL1 ); info->reg_id_aa64pfr1 =read_cpuid (ID_AA64PFR1_EL1 ); info->reg_id_aa64zfr0 =read_cpuid (ID_AA64ZFR0_EL1 );
Marc Zyngier
maintainerPATCH v2 6/13 arm64: cpufeature: Detect E2H0 not being implemented
In reply to Marc ZyngierFEAT_E2H0 is a new feature that indicates whether or not HCR_EL2.E2H can be set to 0. Amusingly, this feature is set to 0 when implemented, and otherwise negative.
Add a new capability and detection infrastructure to detect the absence of FEAT_E2H0.
--- arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 8 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
@@ -2787,6 +2787,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP) }, + { + .desc = "FEAT_E2H0 not implemented", + .capability = ARM64_HCR_E2H_RES1, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, +ARM64_CPUID_FIELDS_NEG (ID_AA64MMFR4_EL1 ,E2H0 ,NI ) + }, {}, };
arch/arm64/tools/cpucaps +1 -0
@@ -52,6 +52,7 @@ HAS_TIDCP1 HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT +HCR_E2H_RES1 HW_DBM KVM_HVHE KVM_PROTECTED_MODE
Signature · 1 line
2.39.2
Re: [PATCH v2 06/13] arm64: cpufeature: Detect E2H0 not being implemented
Quoted 8 lines · Marc Zyngier
FEAT_E2H0is a new feature that indicates whether or not HCR_EL2.E2H can be set to 0. Amusingly, this feature is set to 0 when implemented, and otherwise negative.Add a new capability and detection infrastructure to detect the absence of
FEAT_E2H0.Signed-off-by Marc Zyngier <[email protected]>
Quoted 35 lines
--- arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 8 insertions(+)arch/arm64/kernel/cpufeature.c +7
-0@@ -2787,6 +2787,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP) }, + { + .desc = "FEAT_E2H0 not implemented", + .capability = ARM64_HCR_E2H_RES1, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, +ARM64_CPUID_FIELDS_NEG (ID_AA64MMFR4_EL1 ,E2H0 ,NI ) + }, {}, };arch/arm64/tools/cpucaps +1
-0@@ -52,6 +52,7 @@ HAS_TIDCP1 HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT +HCR_E2H_RES1 HW_DBM KVM_HVHE KVM_PROTECTED_MODE
Marc Zyngier
maintainerPATCH v2 7/13 arm64: cpufeature: Detect HCR_EL2.NV1 being RES0
In reply to Marc ZyngierA variant of FEAT_E2H0 not being implemented exists in the form of HCR_EL2.E2H being RES1 *and* HCR_EL2.NV1 being RES0 (indicating that only VHE is supported on the host and nested guests).
Add the necessary infrastructure for this new CPU capability.
--- arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 8 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
@@ -2794,6 +2794,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS_NEG(ID_AA64MMFR4_EL1, E2H0, NI) }, + { + .desc = "FEAT_E2H0 not implemented (NV1 RES0)", + .capability = ARM64_HCR_NV1_RES0, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, +ARM64_CPUID_FIELDS_NEG (ID_AA64MMFR4_EL1 ,E2H0 ,NI_NV1 ) + }, {}, };
arch/arm64/tools/cpucaps +1 -0
@@ -53,6 +53,7 @@ HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT HCR_E2H_RES1 +HCR_NV1_RES0 HW_DBM KVM_HVHE KVM_PROTECTED_MODE
Signature · 1 line
2.39.2
Re: [PATCH v2 07/13] arm64: cpufeature: Detect HCR_EL2.NV1 being RES0
Quoted 7 lines · Marc Zyngier
A variant of
FEAT_E2H0not being implemented exists in the form of HCR_EL2.E2H being RES1 *and* HCR_EL2.NV1 being RES0 (indicating that only VHE is supported on the host and nested guests).Add the necessary infrastructure for this new CPU capability.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 35 lines
--- arch/arm64/kernel/cpufeature.c | 7 +++++++ arch/arm64/tools/cpucaps | 1 + 2 files changed, 8 insertions(+)arch/arm64/kernel/cpufeature.c +7
-0@@ -2794,6 +2794,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS_NEG(ID_AA64MMFR4_EL1, E2H0, NI) }, + { + .desc = "FEAT_E2H0 not implemented (NV1 RES0)", + .capability = ARM64_HCR_NV1_RES0, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, +ARM64_CPUID_FIELDS_NEG (ID_AA64MMFR4_EL1 ,E2H0 ,NI_NV1 ) + }, {}, };arch/arm64/tools/cpucaps +1
-0@@ -53,6 +53,7 @@ HAS_TLB_RANGE HAS_VIRT_HOST_EXTN HAS_WFXT HCR_E2H_RES1 +HCR_NV1_RES0 HW_DBM KVM_HVHE KVM_PROTECTED_MODE
Marc Zyngier
maintainerPATCH v2 8/13 arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative
In reply to Marc ZyngierFor CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we already have this path to cope with fruity CPUs.
Tweak init_el2 to look at ID_AA64MMFR4_EL1.E2H0 first.
--- arch/arm64/kernel/cpufeature.c | 5 ++--- arch/arm64/kernel/head.S | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-)
arch/arm64/kernel/cpufeature.c +2 -3
@@ -140,7 +140,6 @@ void dump_cpu_features(void)pr_emerg ("0x%*pb\n" ,ARM64_NCAPS , &system_cpucaps); } -#define __ARM64_EXPAND_RFV (reg, field, val) reg##_##field##_##val#define __ARM64_MAX_POSITIVE (reg, field) \ ((reg##_##field##_SIGNED ? \ BIT(reg##_##field##_WIDTH - 1) : \
@@ -165,7 +164,7 @@ void dump_cpu_features(void)*/ #define ARM64_CPUID_FIELDS (reg, field, min_value) \ __ARM64_CPUID_FIELDS(reg, field, \ - __ARM64_EXPAND_RFV(reg, field, min_value), \ + SYS_FIELD_VALUE(reg, field, min_value), \ __ARM64_MAX_POSITIVE(reg, field))/*
@@ -176,7 +175,7 @@ void dump_cpu_features(void)#define ARM64_CPUID_FIELDS_NEG (reg, field, max_value) \ __ARM64_CPUID_FIELDS(reg, field, \ __ARM64_MIN_NEGATIVE(reg, field), \ - __ARM64_EXPAND_RFV(reg, field, max_value)) + SYS_FIELD_VALUE(reg, field, max_value))#define __ARM64_FTR_BITS (SIGNED ,VISIBLE ,STRICT ,TYPE ,SHIFT ,WIDTH ,SAFE_VAL ) \ { \
arch/arm64/kernel/head.S +15 -8
@@ -584,25 +584,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) mov_q x1, INIT_SCTLR_EL1_MMU_OFF /* - * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, - * making it impossible to start in nVHE mode. Is that - * compliant with the architecture? Absolutely not! + * Compliant CPUs advertise their VHE-onlyness with + * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be + * RES1 in that case. + * + * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but + * don't advertise it (they predate this relaxation). */ + mrs_s x0, SYS_ID_AA64MMFR4_EL1 + ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH + tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f + mrs x0, hcr_el2 and x0, x0, #HCR_E2H - cbz x0, 1f - + cbz x0, 2f +1: /* Set a sane SCTLR_EL1, the VHE way */ pre_disable_mmu_workaround msr_s SYS_SCTLR_EL12, x1 mov x2, #BOOT_CPU_FLAG_E2H - b 2f + b 3f -1: +2: pre_disable_mmu_workaround msr sctlr_el1, x1 mov x2, xzr -2: +3: __init_el2_nvhe_prepare_eret mov w0, #BOOT_CPU_MODE_EL2
Signature · 1 line
2.39.2
Re: [PATCH v2 08/13] arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative
Quoted 34 lines · Marc Zyngier
For CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we already have this path to cope with fruity CPUs.
Tweak
init_el2to look at ID_AA64MMFR4_EL1.E2H0 first.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kernel/cpufeature.c | 5 ++--- arch/arm64/kernel/head.S | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-)arch/arm64/kernel/cpufeature.c +1
-2@@ -140,7 +140,6 @@ void dump_cpu_features(void)pr_emerg ("0x%*pb\n" ,ARM64_NCAPS , &system_cpucaps); } -#define __ARM64_EXPAND_RFV (reg, field, val) reg##_##field##_##val#define __ARM64_MAX_POSITIVE (reg, field) \ ((reg##_##field##_SIGNED ? \ BIT(reg##_##field##_WIDTH - 1) : \@@ -165,7 +164,7 @@ void dump_cpu_features(void)*/ #define ARM64_CPUID_FIELDS (reg, field, min_value) \ __ARM64_CPUID_FIELDS(reg, field, \ - __ARM64_EXPAND_RFV(reg, field, min_value), \ + SYS_FIELD_VALUE(reg, field, min_value), \ __ARM64_MAX_POSITIVE(reg, field))/*
arch/arm64/kernel/cpufeature.c void dump_cpu_features(void) · line 181
Quoted 8 lines
arch/arm64/kernel/cpufeature.c +1
-1@@ -176,7 +175,7 @@ void dump_cpu_features(void)#define ARM64_CPUID_FIELDS_NEG (reg, field, max_value) \ __ARM64_CPUID_FIELDS(reg, field, \ __ARM64_MIN_NEGATIVE(reg, field), \ - __ARM64_EXPAND_RFV(reg, field, max_value)) + SYS_FIELD_VALUE(reg, field, max_value))#define __ARM64_FTR_BITS (SIGNED ,VISIBLE ,STRICT ,TYPE ,SHIFT ,WIDTH ,SAFE_VAL ) \ { \
As agreed on patch 2, With the above removed, rest looks good.
Quoted 45 lines
arch/arm64/kernel/head.S +15
-8@@ -584,25 +584,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) mov_q x1, INIT_SCTLR_EL1_MMU_OFF /* - * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, - * making it impossible to start in nVHE mode. Is that - * compliant with the architecture? Absolutely not! + * Compliant CPUs advertise their VHE-onlyness with + * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be + * RES1 in that case. + * + * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but + * don't advertise it (they predate this relaxation). */ + mrs_s x0, SYS_ID_AA64MMFR4_EL1 + ubfx x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH + tbnz x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f + mrs x0, hcr_el2 and x0, x0, #HCR_E2H - cbz x0, 1f - + cbz x0, 2f +1: /* Set a sane SCTLR_EL1, the VHE way */ pre_disable_mmu_workaround msr_s SYS_SCTLR_EL12, x1 mov x2, #BOOT_CPU_FLAG_E2H - b 2f + b 3f -1: +2: pre_disable_mmu_workaround msr sctlr_el1, x1 mov x2, xzr -2: +3: __init_el2_nvhe_prepare_eret mov w0, #BOOT_CPU_MODE_EL2
Marc Zyngier
maintainerPATCH v2 9/13 arm64: Add override for ID_AA64MMFR4_EL1.E2H0
In reply to Marc ZyngierAllow ID_AA64MMFR4_EL1.E2H0 to be overriden from the command-line. This will subsequently be of use for non-compliant CPUs.
--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 4 +++- arch/arm64/kernel/idreg-override.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-)
arch/arm64/include/asm/cpufeature.h +1 -0
@@ -901,6 +901,7 @@ s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, s64 cur);struct arm64_ftr_reg *get_arm64_ftr_reg (u32 sys_id);extern struct arm64_ftr_override id_aa64mmfr1_override; +extern struct arm64_ftr_override id_aa64mmfr4_override;extern struct arm64_ftr_override id_aa64pfr0_override;extern struct arm64_ftr_override id_aa64pfr1_override;extern struct arm64_ftr_override id_aa64zfr0_override;
arch/arm64/kernel/cpufeature.c +3 -1
@@ -691,6 +691,7 @@ static const struct arm64_ftr_bits ftr_raz[] = { __ARM64_FTR_REG_OVERRIDE(#id, id, table, &no_override)struct arm64_ftr_override __ro_after_init id_aa64mmfr1_override; +struct arm64_ftr_override __ro_after_init id_aa64mmfr4_override;struct arm64_ftr_override __ro_after_init id_aa64pfr0_override;struct arm64_ftr_override __ro_after_init id_aa64pfr1_override;struct arm64_ftr_override __ro_after_init id_aa64zfr0_override;
@@ -759,7 +760,8 @@ static const struct __ftr_reg_entry { &id_aa64mmfr1_override),ARM64_FTR_REG (SYS_ID_AA64MMFR2_EL1 , ftr_id_aa64mmfr2),ARM64_FTR_REG (SYS_ID_AA64MMFR3_EL1 , ftr_id_aa64mmfr3), -ARM64_FTR_REG (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4), +ARM64_FTR_REG_OVERRIDE (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4, + &id_aa64mmfr4_override),/* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),
arch/arm64/kernel/idreg-override.c +10 -0
@@ -55,6 +55,15 @@ static const struct ftr_set_desc mmfr1 __initconst = { }, }; +static const struct ftr_set_desc mmfr4__initconst = { + .name ="id_aa64mmfr4" , + .override = &id_aa64mmfr4_override, + .fields = { +FIELD ("e2h0" ,ID_AA64MMFR4_EL1_E2H0_SHIFT ,NULL ), + {} + }, +}; +static bool __init pfr0_sve_filter (u64 val) {/*
@@ -161,6 +170,7 @@ static const struct ftr_set_desc sw_features __initconst = {static const struct ftr_set_desc *const regs[]__initconst = { &mmfr1, + &mmfr4, &pfr0, &pfr1, &isar1,
Signature · 1 line
2.39.2
Re: [PATCH v2 09/13] arm64: Add override for ID_AA64MMFR4_EL1.E2H0
Quoted 4 lines · Marc Zyngier
Allow ID_AA64MMFR4_EL1.E2H0 to be overriden from the command-line. This will subsequently be of use for non-compliant CPUs.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 68 lines
--- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 4 +++- arch/arm64/kernel/idreg-override.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-)arch/arm64/include/asm/cpufeature.h +1
-0@@ -901,6 +901,7 @@ s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, s64 cur);struct arm64_ftr_reg *get_arm64_ftr_reg (u32 sys_id);extern struct arm64_ftr_override id_aa64mmfr1_override; +extern struct arm64_ftr_override id_aa64mmfr4_override;extern struct arm64_ftr_override id_aa64pfr0_override;extern struct arm64_ftr_override id_aa64pfr1_override;extern struct arm64_ftr_override id_aa64zfr0_override;arch/arm64/kernel/cpufeature.c +3
-1@@ -691,6 +691,7 @@ static const struct arm64_ftr_bits ftr_raz[] = { __ARM64_FTR_REG_OVERRIDE(#id, id, table, &no_override)struct arm64_ftr_override __ro_after_init id_aa64mmfr1_override; +struct arm64_ftr_override __ro_after_init id_aa64mmfr4_override;struct arm64_ftr_override __ro_after_init id_aa64pfr0_override;struct arm64_ftr_override __ro_after_init id_aa64pfr1_override;struct arm64_ftr_override __ro_after_init id_aa64zfr0_override;@@ -759,7 +760,8 @@ static const struct __ftr_reg_entry { &id_aa64mmfr1_override),ARM64_FTR_REG (SYS_ID_AA64MMFR2_EL1 , ftr_id_aa64mmfr2),ARM64_FTR_REG (SYS_ID_AA64MMFR3_EL1 , ftr_id_aa64mmfr3), -ARM64_FTR_REG (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4), +ARM64_FTR_REG_OVERRIDE (SYS_ID_AA64MMFR4_EL1 , ftr_id_aa64mmfr4, + &id_aa64mmfr4_override),/* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),arch/arm64/kernel/idreg-override.c +10
-0@@ -55,6 +55,15 @@ static const struct ftr_set_desc mmfr1 __initconst = { }, }; +static const struct ftr_set_desc mmfr4__initconst = { + .name ="id_aa64mmfr4" , + .override = &id_aa64mmfr4_override, + .fields = { +FIELD ("e2h0" ,ID_AA64MMFR4_EL1_E2H0_SHIFT ,NULL ), + {} + }, +}; +static bool __init pfr0_sve_filter (u64 val) {/* @@ -161,6 +170,7 @@ static const struct ftr_set_desc sw_features __initconst = {static const struct ftr_set_desc *const regs[]__initconst = { &mmfr1, + &mmfr4, &pfr0, &pfr1, &isar1,
Marc Zyngier
maintainerPATCH v2 10/13 arm64: Add MIDR-based override infrastructure
In reply to Marc ZyngierIn order to be able to use the override infrastructure to "fix" CPUs that have deviated from teh architecture spec, add a new pile of hacks on top of the existing one, allowing a feature to be overriden based on matching a MIDR list.
--- arch/arm64/kernel/idreg-override.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
arch/arm64/kernel/idreg-override.c +19 -0
@@ -321,6 +321,23 @@ static __init void parse_cmdline(void)__parse_cmdline (prop, true); } +struct midr_override_data { +const char feature[FTR_ALIAS_OPTION_LEN ]; +const struct midr_range ranges[]; +}; + +static const struct midr_override_data *const midr_ovr_data[]__initconst = { +}; + +static void __init apply_midr_overrides (void ) +{ +const u64 midr =read_cpuid_id (); + +for (int i =0 ; i <ARRAY_SIZE (midr_ovr_data); i++) +if (is_midr_in_range_list (midr, midr_ovr_data[i]->ranges)) +__parse_cmdline (midr_ovr_data[i]->feature, false); +} +/* Keep checkers quiet */ void init_feature_override (u64 boot_status);
@@ -337,6 +354,8 @@ asmlinkage void __init init_feature_override(u64 boot_status) __boot_status = boot_status; +apply_midr_overrides (); +parse_cmdline ();for (i =0 ; i <ARRAY_SIZE (regs); i++) {
Signature · 1 line
2.39.2
Re: [PATCH v2 10/13] arm64: Add MIDR-based override infrastructure
Quoted 6 lines · Marc Zyngier
In order to be able to use the override infrastructure to "fix" CPUs that have deviated from teh architecture spec, add a new pile of hacks on top of the existing one, allowing a feature to be overriden based on matching a MIDR list.
Signed-off-by Marc Zyngier <[email protected]>
Nice idea!
Quoted 41 lines
--- arch/arm64/kernel/idreg-override.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)arch/arm64/kernel/idreg-override.c +19
-0@@ -321,6 +321,23 @@ static __init void parse_cmdline(void)__parse_cmdline (prop, true); } +struct midr_override_data { +const char feature[FTR_ALIAS_OPTION_LEN ]; +const struct midr_range ranges[]; +}; + +static const struct midr_override_data *const midr_ovr_data[]__initconst = { +}; + +static void __init apply_midr_overrides (void ) +{ +const u64 midr =read_cpuid_id (); + +for (int i =0 ; i <ARRAY_SIZE (midr_ovr_data); i++) +if (is_midr_in_range_list (midr, midr_ovr_data[i]->ranges)) +__parse_cmdline (midr_ovr_data[i]->feature, false); +} +/* Keep checkers quiet */ void init_feature_override (u64 boot_status);@@ -337,6 +354,8 @@ asmlinkage void __init init_feature_override(u64 boot_status) __boot_status = boot_status; +apply_midr_overrides (); +parse_cmdline ();for (i =0 ; i <ARRAY_SIZE (regs); i++) {
Marc Zyngier
maintainerPATCH v2 11/13 arm64: Add MIDR-based overrides for ID_AA64MMFR4_EL1.E2H0
In reply to Marc ZyngierNone the Apple M1/M2 CPUs effectively implement E2H=0, and M2 doesn't correctly implement NV1=1 (the EL2 S1 PTW seems to barf on the nVHE format).
Override ID_AA64MMFR4_EL1.E2H0 for these CPUs to reflect what they actually support.
--- arch/arm64/kernel/idreg-override.c | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
arch/arm64/kernel/idreg-override.c +36 -0
@@ -326,7 +326,43 @@ struct midr_override_data {const struct midr_range ranges[]; }; +static const struct midr_override_data e2h0_ni__initconst = { +/* +* These CPUs predate FEAT_E2H0, but have HCR_EL2.E2H RES1 +* anyway. +*/ + .feature ="id_aa64mmfr4.e2h0=0xf" , + .ranges = { +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM_MAX ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM_MAX ), + {} + }, +}; + +static const struct midr_override_data e2h0_nv1_ni__initconst = { +/* +* These CPUs predate FEAT_E2H0, but have both HCR_EL2.E2H +* RES1 and a non-functional HCR_EL2.NV1. +*/ + .feature ="id_aa64mmfr4.e2h0=0xe" , + .ranges = { +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD_MAX ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE_MAX ), + {} + }, +}; +static const struct midr_override_data *const midr_ovr_data[]__initconst = { + &e2h0_ni, + &e2h0_nv1_ni, };static void __init apply_midr_overrides (void )
Signature · 1 line
2.39.2
Re: [PATCH v2 11/13] arm64: Add MIDR-based overrides for ID_AA64MMFR4_EL1.E2H0
Quoted 8 lines · Marc Zyngier
None the Apple M1/M2 CPUs effectively implement E2H=0, and M2 doesn't correctly implement NV1=1 (the EL2 S1 PTW seems to barf on the nVHE format).
Override ID_AA64MMFR4_EL1.E2H0 for these CPUs to reflect what they actually support.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 52 lines
--- arch/arm64/kernel/idreg-override.c | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)arch/arm64/kernel/idreg-override.c +36
-0@@ -326,7 +326,43 @@ struct midr_override_data {const struct midr_range ranges[]; }; +static const struct midr_override_data e2h0_ni__initconst = { +/* +* These CPUs predate FEAT_E2H0, but have HCR_EL2.E2H RES1 +* anyway. +*/ + .feature ="id_aa64mmfr4.e2h0=0xf" , + .ranges = { +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_ICESTORM_MAX ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M1_FIRESTORM_MAX ), + {} + }, +}; + +static const struct midr_override_data e2h0_nv1_ni__initconst = { +/* +* These CPUs predate FEAT_E2H0, but have both HCR_EL2.E2H +* RES1 and a non-functional HCR_EL2.NV1. +*/ + .feature ="id_aa64mmfr4.e2h0=0xe" , + .ranges = { +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE_PRO ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_BLIZZARD_MAX ), +MIDR_ALL_VERSIONS (MIDR_APPLE_M2_AVALANCHE_MAX ), + {} + }, +}; +static const struct midr_override_data *const midr_ovr_data[]__initconst = { + &e2h0_ni, + &e2h0_nv1_ni, };static void __init apply_midr_overrides (void )
Marc Zyngier
maintainerPATCH v2 12/13 KVM: arm64: Expose ID_AA64MMFR4_EL1 to guests
In reply to Marc ZyngierWe can now expose ID_AA64MMFR4_EL1 to guests, and let NV guests understand that they cannot really switch HCR_EL2.E2H to 0 on some platforms.
--- arch/arm64/kvm/nested.c | 4 ++++ arch/arm64/kvm/sys_regs.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-)
arch/arm64/kvm/nested.c +4 -0
@@ -137,6 +137,10 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, val |=FIELD_PREP (NV_FTR (MMFR2 ,TTL ),0b0001 );break ; +case SYS_ID_AA64MMFR4_EL1 : + val &=NV_FTR (MMFR4 ,E2H0 ); +break ; +case SYS_ID_AA64DFR0_EL1 :/* Only limited support for PMU, Debug, BPs and WPs */ val &= (NV_FTR(DFR0, PMUVer) |
arch/arm64/kvm/sys_regs.c +1 -1
@@ -2197,7 +2197,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {ID_AA64MMFR2_EL1_NV | ID_AA64MMFR2_EL1_CCIDX)),ID_SANITISED (ID_AA64MMFR3_EL1 ), -ID_UNALLOCATED (7 ,4 ), +ID_SANITISED (ID_AA64MMFR4_EL1 ),ID_UNALLOCATED (7 ,5 ),ID_UNALLOCATED (7 ,6 ), ID_UNALLOCATED(7,7),
Signature · 1 line
2.39.2
Re: [PATCH v2 12/13] KVM: arm64: Expose ID_AA64MMFR4_EL1 to guests
Quoted 5 lines · Marc Zyngier
We can now expose
ID_AA64MMFR4_EL1to guests, and let NV guests understand that they cannot really switch HCR_EL2.E2H to 0 on some platforms.Signed-off-by Marc Zyngier <[email protected]>
Quoted 33 lines
--- arch/arm64/kvm/nested.c | 4 ++++ arch/arm64/kvm/sys_regs.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-)arch/arm64/kvm/nested.c +4
-0@@ -137,6 +137,10 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, val |=FIELD_PREP (NV_FTR (MMFR2 ,TTL ),0b0001 );break ; +case SYS_ID_AA64MMFR4_EL1 : + val &=NV_FTR (MMFR4 ,E2H0 ); +break ; +case SYS_ID_AA64DFR0_EL1 :/* Only limited support for PMU, Debug, BPs and WPs */ val &= (NV_FTR(DFR0, PMUVer) |arch/arm64/kvm/sys_regs.c +1
-1@@ -2197,7 +2197,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {ID_AA64MMFR2_EL1_NV | ID_AA64MMFR2_EL1_CCIDX)),ID_SANITISED (ID_AA64MMFR3_EL1 ), -ID_UNALLOCATED (7 ,4 ), +ID_SANITISED (ID_AA64MMFR4_EL1 ),ID_UNALLOCATED (7 ,5 ),ID_UNALLOCATED (7 ,6 ), ID_UNALLOCATED(7,7),
Marc Zyngier
maintainerPATCH v2 13/13 KVM: arm64: Force guest's HCR_EL2.E2H RES1 when NV1 is not implemented
In reply to Marc ZyngierIf NV1 isn't supported on a system, make sure we always evaluate the guest's HCR_EL2.E2H as RES1, irrespective of what the guest may have written there.
--- arch/arm64/include/asm/kvm_emulate.h | 3 ++- arch/arm64/kvm/sys_regs.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)
arch/arm64/include/asm/kvm_emulate.h +2 -1
@@ -213,7 +213,8 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)static inline bool __vcpu_el2_e2h_is_set (const struct kvm_cpu_context *ctxt) { -return ctxt_sys_reg (ctxt,HCR_EL2 ) &HCR_E2H ; +return (cpus_have_final_cap (ARM64_HCR_NV1_RES0 ) || + (ctxt_sys_reg (ctxt,HCR_EL2 ) &HCR_E2H )); }static inline bool vcpu_el2_e2h_is_set (const struct kvm_vcpu *vcpu)
arch/arm64/kvm/sys_regs.c +11 -1
@@ -2022,6 +2022,16 @@ static bool access_spsr(struct kvm_vcpu *vcpu,return true; } +static u64 reset_hcr (struct kvm_vcpu *vcpu,const struct sys_reg_desc *r) +{ +u64 val = r->val; + +if (cpus_have_final_cap (ARM64_HCR_NV1_RES0 )) + val |=HCR_E2H ; + +return __vcpu_sys_reg (vcpu, r->reg) = val; +} +/* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -2513,7 +2523,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {EL2_REG (VMPIDR_EL2 , access_rw, reset_unknown,0 ),EL2_REG (SCTLR_EL2 , access_rw, reset_val,SCTLR_EL2_RES1 ),EL2_REG (ACTLR_EL2 , access_rw, reset_val,0 ), -EL2_REG (HCR_EL2 , access_rw, reset_val,0 ), +EL2_REG (HCR_EL2 , access_rw, reset_hcr,0 ),EL2_REG (MDCR_EL2 , access_rw, reset_val,0 ),EL2_REG (CPTR_EL2 , access_rw, reset_val,CPTR_NVHE_EL2_RES1 ), EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
Signature · 1 line
2.39.2
Re: [PATCH v2 13/13] KVM: arm64: Force guest's HCR_EL2.E2H RES1 when NV1 is not implemented
Quoted 5 lines · Marc Zyngier
If NV1 isn't supported on a system, make sure we always evaluate the guest's HCR_EL2.E2H as RES1, irrespective of what the guest may have written there.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 49 lines
--- arch/arm64/include/asm/kvm_emulate.h | 3 ++- arch/arm64/kvm/sys_regs.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-)arch/arm64/include/asm/kvm_emulate.h +2
-1@@ -213,7 +213,8 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)static inline bool __vcpu_el2_e2h_is_set (const struct kvm_cpu_context *ctxt) { -return ctxt_sys_reg (ctxt,HCR_EL2 ) &HCR_E2H ; +return (cpus_have_final_cap (ARM64_HCR_NV1_RES0 ) || + (ctxt_sys_reg (ctxt,HCR_EL2 ) &HCR_E2H )); }static inline bool vcpu_el2_e2h_is_set (const struct kvm_vcpu *vcpu)arch/arm64/kvm/sys_regs.c +11
-1@@ -2022,6 +2022,16 @@ static bool access_spsr(struct kvm_vcpu *vcpu,return true; } +static u64 reset_hcr (struct kvm_vcpu *vcpu,const struct sys_reg_desc *r) +{ +u64 val = r->val; + +if (cpus_have_final_cap (ARM64_HCR_NV1_RES0 )) + val |=HCR_E2H ; + +return __vcpu_sys_reg (vcpu, r->reg) = val; +} +/* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 @@ -2513,7 +2523,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {EL2_REG (VMPIDR_EL2 , access_rw, reset_unknown,0 ),EL2_REG (SCTLR_EL2 , access_rw, reset_val,SCTLR_EL2_RES1 ),EL2_REG (ACTLR_EL2 , access_rw, reset_val,0 ), -EL2_REG (HCR_EL2 , access_rw, reset_val,0 ), +EL2_REG (HCR_EL2 , access_rw, reset_hcr,0 ),EL2_REG (MDCR_EL2 , access_rw, reset_val,0 ),EL2_REG (CPTR_EL2 , access_rw, reset_val,CPTR_NVHE_EL2_RES1 ), EL2_REG(HSTR_EL2, access_rw, reset_val, 0),