Skip to content

Commit 92d05e2

Browse files
committed
Merge branch kvm-arm64/ampere1-hafdbs-mitigation into kvmarm/next
* kvm-arm64/ampere1-hafdbs-mitigation: : AmpereOne erratum AC03_CPU_38 mitigation : : AmpereOne does not advertise support for FEAT_HAFDBS due to an : underlying erratum in the feature. The associated control bits do not : have RES0 behavior as required by the architecture. : : Introduce mitigations to prevent KVM from enabling the feature at : stage-2 as well as preventing KVM guests from enabling HAFDBS at : stage-1. KVM: arm64: Prevent guests from enabling HA/HD on Ampere1 KVM: arm64: Refactor HFGxTR configuration into separate helpers arm64: errata: Mitigate Ampere1 erratum AC03_CPU_38 at stage-2 Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
2 parents e1e315c + 082fdfd commit 92d05e2

6 files changed

Lines changed: 122 additions & 21 deletions

File tree

Documentation/arm64/silicon-errata.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ stable kernels.
5252
| Allwinner | A64/R18 | UNKNOWN1 | SUN50I_ERRATUM_UNKNOWN1 |
5353
+----------------+-----------------+-----------------+-----------------------------+
5454
+----------------+-----------------+-----------------+-----------------------------+
55+
| Ampere | AmpereOne | AC03_CPU_38 | AMPERE_ERRATUM_AC03_CPU_38 |
56+
+----------------+-----------------+-----------------+-----------------------------+
57+
+----------------+-----------------+-----------------+-----------------------------+
5558
| ARM | Cortex-A510 | #2457168 | ARM64_ERRATUM_2457168 |
5659
+----------------+-----------------+-----------------+-----------------------------+
5760
| ARM | Cortex-A510 | #2064142 | ARM64_ERRATUM_2064142 |

arch/arm64/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,25 @@ menu "Kernel Features"
407407

408408
menu "ARM errata workarounds via the alternatives framework"
409409

410+
config AMPERE_ERRATUM_AC03_CPU_38
411+
bool "AmpereOne: AC03_CPU_38: Certain bits in the Virtualization Translation Control Register and Translation Control Registers do not follow RES0 semantics"
412+
default y
413+
help
414+
This option adds an alternative code sequence to work around Ampere
415+
erratum AC03_CPU_38 on AmpereOne.
416+
417+
The affected design reports FEAT_HAFDBS as not implemented in
418+
ID_AA64MMFR1_EL1.HAFDBS, but (V)TCR_ELx.{HA,HD} are not RES0
419+
as required by the architecture. The unadvertised HAFDBS
420+
implementation suffers from an additional erratum where hardware
421+
A/D updates can occur after a PTE has been marked invalid.
422+
423+
The workaround forces KVM to explicitly set VTCR_EL2.HA to 0,
424+
which avoids enabling unadvertised hardware Access Flag management
425+
at stage-2.
426+
427+
If unsure, say Y.
428+
410429
config ARM64_WORKAROUND_CLEAN_CACHE
411430
bool
412431

arch/arm64/kernel/cpu_errata.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
729729
MIDR_FIXED(MIDR_CPU_VAR_REV(1,1), BIT(25)),
730730
.cpu_enable = cpu_clear_bf16_from_user_emulation,
731731
},
732+
#endif
733+
#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_38
734+
{
735+
.desc = "AmpereOne erratum AC03_CPU_38",
736+
.capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_38,
737+
ERRATA_MIDR_ALL_VERSIONS(MIDR_AMPERE1),
738+
},
732739
#endif
733740
{
734741
}

arch/arm64/kvm/hyp/include/hyp/switch.h

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,56 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
7070
}
7171
}
7272

73+
static inline bool __hfgxtr_traps_required(void)
74+
{
75+
if (cpus_have_final_cap(ARM64_SME))
76+
return true;
77+
78+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
79+
return true;
80+
81+
return false;
82+
}
83+
84+
static inline void __activate_traps_hfgxtr(void)
85+
{
86+
u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp;
87+
88+
if (cpus_have_final_cap(ARM64_SME)) {
89+
tmp = HFGxTR_EL2_nSMPRI_EL1_MASK | HFGxTR_EL2_nTPIDR2_EL0_MASK;
90+
91+
r_clr |= tmp;
92+
w_clr |= tmp;
93+
}
94+
95+
/*
96+
* Trap guest writes to TCR_EL1 to prevent it from enabling HA or HD.
97+
*/
98+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
99+
w_set |= HFGxTR_EL2_TCR_EL1_MASK;
100+
101+
sysreg_clear_set_s(SYS_HFGRTR_EL2, r_clr, r_set);
102+
sysreg_clear_set_s(SYS_HFGWTR_EL2, w_clr, w_set);
103+
}
104+
105+
static inline void __deactivate_traps_hfgxtr(void)
106+
{
107+
u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp;
108+
109+
if (cpus_have_final_cap(ARM64_SME)) {
110+
tmp = HFGxTR_EL2_nSMPRI_EL1_MASK | HFGxTR_EL2_nTPIDR2_EL0_MASK;
111+
112+
r_set |= tmp;
113+
w_set |= tmp;
114+
}
115+
116+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
117+
w_clr |= HFGxTR_EL2_TCR_EL1_MASK;
118+
119+
sysreg_clear_set_s(SYS_HFGRTR_EL2, r_clr, r_set);
120+
sysreg_clear_set_s(SYS_HFGWTR_EL2, w_clr, w_set);
121+
}
122+
73123
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
74124
{
75125
/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
@@ -89,16 +139,8 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
89139
vcpu->arch.mdcr_el2_host = read_sysreg(mdcr_el2);
90140
write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
91141

92-
if (cpus_have_final_cap(ARM64_SME)) {
93-
sysreg_clear_set_s(SYS_HFGRTR_EL2,
94-
HFGxTR_EL2_nSMPRI_EL1_MASK |
95-
HFGxTR_EL2_nTPIDR2_EL0_MASK,
96-
0);
97-
sysreg_clear_set_s(SYS_HFGWTR_EL2,
98-
HFGxTR_EL2_nSMPRI_EL1_MASK |
99-
HFGxTR_EL2_nTPIDR2_EL0_MASK,
100-
0);
101-
}
142+
if (__hfgxtr_traps_required())
143+
__activate_traps_hfgxtr();
102144
}
103145

104146
static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
@@ -109,14 +151,8 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
109151
if (kvm_arm_support_pmu_v3())
110152
write_sysreg(0, pmuserenr_el0);
111153

112-
if (cpus_have_final_cap(ARM64_SME)) {
113-
sysreg_clear_set_s(SYS_HFGRTR_EL2, 0,
114-
HFGxTR_EL2_nSMPRI_EL1_MASK |
115-
HFGxTR_EL2_nTPIDR2_EL0_MASK);
116-
sysreg_clear_set_s(SYS_HFGWTR_EL2, 0,
117-
HFGxTR_EL2_nSMPRI_EL1_MASK |
118-
HFGxTR_EL2_nTPIDR2_EL0_MASK);
119-
}
154+
if (__hfgxtr_traps_required())
155+
__deactivate_traps_hfgxtr();
120156
}
121157

122158
static inline void ___activate_traps(struct kvm_vcpu *vcpu)
@@ -384,12 +420,39 @@ static bool kvm_hyp_handle_cntpct(struct kvm_vcpu *vcpu)
384420
return true;
385421
}
386422

423+
static bool handle_ampere1_tcr(struct kvm_vcpu *vcpu)
424+
{
425+
u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
426+
int rt = kvm_vcpu_sys_get_rt(vcpu);
427+
u64 val = vcpu_get_reg(vcpu, rt);
428+
429+
if (sysreg != SYS_TCR_EL1)
430+
return false;
431+
432+
/*
433+
* Affected parts do not advertise support for hardware Access Flag /
434+
* Dirty state management in ID_AA64MMFR1_EL1.HAFDBS, but the underlying
435+
* control bits are still functional. The architecture requires these be
436+
* RES0 on systems that do not implement FEAT_HAFDBS.
437+
*
438+
* Uphold the requirements of the architecture by masking guest writes
439+
* to TCR_EL1.{HA,HD} here.
440+
*/
441+
val &= ~(TCR_HD | TCR_HA);
442+
write_sysreg_el1(val, SYS_TCR);
443+
return true;
444+
}
445+
387446
static bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
388447
{
389448
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
390449
handle_tx2_tvm(vcpu))
391450
return true;
392451

452+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38) &&
453+
handle_ampere1_tcr(vcpu))
454+
return true;
455+
393456
if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
394457
__vgic_v3_perform_cpuif_access(vcpu) == 1)
395458
return true;

arch/arm64/kvm/hyp/pgtable.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -628,10 +628,18 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
628628
#ifdef CONFIG_ARM64_HW_AFDBM
629629
/*
630630
* Enable the Hardware Access Flag management, unconditionally
631-
* on all CPUs. The features is RES0 on CPUs without the support
632-
* and must be ignored by the CPUs.
631+
* on all CPUs. In systems that have asymmetric support for the feature
632+
* this allows KVM to leverage hardware support on the subset of cores
633+
* that implement the feature.
634+
*
635+
* The architecture requires VTCR_EL2.HA to be RES0 (thus ignored by
636+
* hardware) on implementations that do not advertise support for the
637+
* feature. As such, setting HA unconditionally is safe, unless you
638+
* happen to be running on a design that has unadvertised support for
639+
* HAFDBS. Here be dragons.
633640
*/
634-
vtcr |= VTCR_EL2_HA;
641+
if (!cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
642+
vtcr |= VTCR_EL2_HA;
635643
#endif /* CONFIG_ARM64_HW_AFDBM */
636644

637645
/* Set the vmid bits */

arch/arm64/tools/cpucaps

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ WORKAROUND_2077057
7979
WORKAROUND_2457168
8080
WORKAROUND_2645198
8181
WORKAROUND_2658417
82+
WORKAROUND_AMPERE_AC03_CPU_38
8283
WORKAROUND_TRBE_OVERWRITE_FILL_MODE
8384
WORKAROUND_TSB_FLUSH_FAILURE
8485
WORKAROUND_TRBE_WRITE_OUT_OF_RANGE

0 commit comments

Comments
 (0)