Skip to content

Commit 31ff96c

Browse files
James Morseoupton
authored andcommitted
KVM: arm64: Fix missing traps of guest accesses to the MPAM registers
commit 011e5f5 ("arm64/cpufeature: Add remaining feature bits in ID_AA64PFR0 register") exposed the MPAM field of AA64PFR0_EL1 to guests, but didn't add trap handling. If you are unlucky, this results in an MPAM aware guest being delivered an undef during boot. The host prints: | kvm [97]: Unsupported guest sys_reg access at: ffff800080024c64 [00000005] | { Op0( 3), Op1( 0), CRn(10), CRm( 5), Op2( 0), func_read }, Which results in: | Internal error: Oops - Undefined instruction: 0000000002000000 [#1] PREEMPT SMP | Modules linked in: | CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.6.0-rc7-00559-gd89c186d50b2 #14616 | Hardware name: linux,dummy-virt (DT) | pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) | pc : test_has_mpam+0x18/0x30 | lr : test_has_mpam+0x10/0x30 | sp : ffff80008000bd90 ... | Call trace: | test_has_mpam+0x18/0x30 | update_cpu_capabilities+0x7c/0x11c | setup_cpu_features+0x14/0xd8 | smp_cpus_done+0x24/0xb8 | smp_init+0x7c/0x8c | kernel_init_freeable+0xf8/0x280 | kernel_init+0x24/0x1e0 | ret_from_fork+0x10/0x20 | Code: 910003fd 97ffffde 72001c0 5400008 (d538a500) | ---[ end trace 0000000000000000 ]--- | Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b | ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- Add the support to enable the traps, and handle the three guest accessible registers by injecting an UNDEF. This stops KVM from spamming the host log, but doesn't yet hide the feature from the id registers. With MPAM v1.0 we can trap the MPAMIDR_EL1 register only if ARM64_HAS_MPAM_HCR, with v1.1 an additional MPAM2_EL2.TIDR bit traps MPAMIDR_EL1 on platforms that don't have MPAMHCR_EL2. Enable one of these if either is supported. If neither is supported, the guest can discover that the CPU has MPAM support, and how many PARTID etc the host has ... but it can't influence anything, so its harmless. Fixes: 011e5f5 ("arm64/cpufeature: Add remaining feature bits in ID_AA64PFR0 register") CC: Anshuman Khandual <anshuman.khandual@arm.com> Link: https://lore.kernel.org/linux-arm-kernel/20200925160102.118858-1-james.morse@arm.com/ Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Joey Gouly <joey.gouly@arm.com> Reviewed-by: Gavin Shan <gshan@redhat.com> Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20241030160317.2528209-5-joey.gouly@arm.com Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 09e6b30 commit 31ff96c

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

arch/arm64/include/asm/cpufeature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ static inline bool system_supports_poe(void)
845845
alternative_has_cap_unlikely(ARM64_HAS_S1POE);
846846
}
847847

848-
static inline bool system_supports_mpam(void)
848+
static __always_inline bool system_supports_mpam(void)
849849
{
850850
return alternative_has_cap_unlikely(ARM64_MPAM);
851851
}

arch/arm64/include/asm/kvm_arm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
104104

105105
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM)
106+
#define MPAMHCR_HOST_FLAGS 0
106107

107108
/* TCR_EL2 Registers bits */
108109
#define TCR_EL2_DS (1UL << 32)

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,35 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
204204
__deactivate_fgt(hctxt, vcpu, kvm, HAFGRTR_EL2);
205205
}
206206

207+
static inline void __activate_traps_mpam(struct kvm_vcpu *vcpu)
208+
{
209+
u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
210+
211+
if (!system_supports_mpam())
212+
return;
213+
214+
/* trap guest access to MPAMIDR_EL1 */
215+
if (system_supports_mpam_hcr()) {
216+
write_sysreg_s(MPAMHCR_EL2_TRAP_MPAMIDR_EL1, SYS_MPAMHCR_EL2);
217+
} else {
218+
/* From v1.1 TIDR can trap MPAMIDR, set it unconditionally */
219+
r |= MPAM2_EL2_TIDR;
220+
}
221+
222+
write_sysreg_s(r, SYS_MPAM2_EL2);
223+
}
224+
225+
static inline void __deactivate_traps_mpam(void)
226+
{
227+
if (!system_supports_mpam())
228+
return;
229+
230+
write_sysreg_s(0, SYS_MPAM2_EL2);
231+
232+
if (system_supports_mpam_hcr())
233+
write_sysreg_s(MPAMHCR_HOST_FLAGS, SYS_MPAMHCR_EL2);
234+
}
235+
207236
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
208237
{
209238
/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
@@ -244,6 +273,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
244273
}
245274

246275
__activate_traps_hfgxtr(vcpu);
276+
__activate_traps_mpam(vcpu);
247277
}
248278

249279
static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
@@ -263,6 +293,7 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
263293
write_sysreg_s(HCRX_HOST_FLAGS, SYS_HCRX_EL2);
264294

265295
__deactivate_traps_hfgxtr(vcpu);
296+
__deactivate_traps_mpam();
266297
}
267298

268299
static inline void ___activate_traps(struct kvm_vcpu *vcpu, u64 hcr)

arch/arm64/kvm/sys_regs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,8 +2553,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
25532553
{ SYS_DESC(SYS_LOREA_EL1), trap_loregion },
25542554
{ SYS_DESC(SYS_LORN_EL1), trap_loregion },
25552555
{ SYS_DESC(SYS_LORC_EL1), trap_loregion },
2556+
{ SYS_DESC(SYS_MPAMIDR_EL1), undef_access },
25562557
{ SYS_DESC(SYS_LORID_EL1), trap_loregion },
25572558

2559+
{ SYS_DESC(SYS_MPAM1_EL1), undef_access },
2560+
{ SYS_DESC(SYS_MPAM0_EL1), undef_access },
25582561
{ SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
25592562
{ SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },
25602563

@@ -2854,6 +2857,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
28542857

28552858
EL2_REG(MAIR_EL2, access_rw, reset_val, 0),
28562859
EL2_REG(AMAIR_EL2, access_rw, reset_val, 0),
2860+
{ SYS_DESC(SYS_MPAMHCR_EL2), undef_access },
2861+
{ SYS_DESC(SYS_MPAMVPMV_EL2), undef_access },
2862+
{ SYS_DESC(SYS_MPAM2_EL2), undef_access },
2863+
{ SYS_DESC(SYS_MPAMVPM0_EL2), undef_access },
2864+
{ SYS_DESC(SYS_MPAMVPM1_EL2), undef_access },
2865+
{ SYS_DESC(SYS_MPAMVPM2_EL2), undef_access },
2866+
{ SYS_DESC(SYS_MPAMVPM3_EL2), undef_access },
2867+
{ SYS_DESC(SYS_MPAMVPM4_EL2), undef_access },
2868+
{ SYS_DESC(SYS_MPAMVPM5_EL2), undef_access },
2869+
{ SYS_DESC(SYS_MPAMVPM6_EL2), undef_access },
2870+
{ SYS_DESC(SYS_MPAMVPM7_EL2), undef_access },
28572871

28582872
EL2_REG(VBAR_EL2, access_rw, reset_val, 0),
28592873
EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),

0 commit comments

Comments
 (0)