Skip to content

Commit 082fdfd

Browse files
committed
KVM: arm64: Prevent guests from enabling HA/HD on Ampere1
An erratum in the HAFDBS implementation in AmpereOne was addressed by clearing the feature in the ID register, with the expectation that software would not attempt to use the corresponding controls in TCR_EL1. The architecture, on the other hand, takes a much more pedantic stance on the subject, requiring the TCR bits behave as RES0. Take an extremely conservative stance on the issue and leverage the precise write trap afforded by FGT. Handle guest writes by clearing HA and HD before writing the intended value to the EL1 register alias. Link: https://lore.kernel.org/r/20230609220104.1836988-4-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent ce4a362 commit 082fdfd

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ static inline bool __hfgxtr_traps_required(void)
7575
if (cpus_have_final_cap(ARM64_SME))
7676
return true;
7777

78+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
79+
return true;
80+
7881
return false;
7982
}
8083

@@ -89,6 +92,12 @@ static inline void __activate_traps_hfgxtr(void)
8992
w_clr |= tmp;
9093
}
9194

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+
92101
sysreg_clear_set_s(SYS_HFGRTR_EL2, r_clr, r_set);
93102
sysreg_clear_set_s(SYS_HFGWTR_EL2, w_clr, w_set);
94103
}
@@ -104,6 +113,9 @@ static inline void __deactivate_traps_hfgxtr(void)
104113
w_set |= tmp;
105114
}
106115

116+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38))
117+
w_clr |= HFGxTR_EL2_TCR_EL1_MASK;
118+
107119
sysreg_clear_set_s(SYS_HFGRTR_EL2, r_clr, r_set);
108120
sysreg_clear_set_s(SYS_HFGWTR_EL2, w_clr, w_set);
109121
}
@@ -408,12 +420,39 @@ static bool kvm_hyp_handle_cntpct(struct kvm_vcpu *vcpu)
408420
return true;
409421
}
410422

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+
411446
static bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code)
412447
{
413448
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
414449
handle_tx2_tvm(vcpu))
415450
return true;
416451

452+
if (cpus_have_final_cap(ARM64_WORKAROUND_AMPERE_AC03_CPU_38) &&
453+
handle_ampere1_tcr(vcpu))
454+
return true;
455+
417456
if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
418457
__vgic_v3_perform_cpuif_access(vcpu) == 1)
419458
return true;

0 commit comments

Comments
 (0)