Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: Guard PMSCR_EL1 initialization with SPE presence check

Commit efad60e46057 ("KVM: arm64: Initialize PMSCR_EL1 when in VHE")
does not perform sufficient check before initializing PMSCR_EL1 to 0
when running in VHE mode. On some platforms, this causes the system to
hang during boot, as EL3 has not delegated access to the Profiling
Buffer to the Non-secure world, nor does it reinject an UNDEF on sysreg
trap.

To avoid this issue, restrict the PMSCR_EL1 initialization to CPUs that
support Statistical Profiling Extension (FEAT_SPE) and have the
Profiling Buffer accessible in Non-secure EL1. This is determined via a
new helper `cpu_has_spe()` which checks both PMSVer and PMBIDR_EL1.P.

This ensures the initialization only affects CPUs where SPE is
implemented and usable, preventing boot failures on platforms where SPE
is not properly configured.

Fixes: efad60e46057 ("KVM: arm64: Initialize PMSCR_EL1 when in VHE")
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Mukesh Ojha and committed by
Marc Zyngier
c35dd838 9a7f87eb

+10 -5
+10 -5
arch/arm64/kvm/debug.c
··· 15 15 #include <asm/kvm_arm.h> 16 16 #include <asm/kvm_emulate.h> 17 17 18 + static int cpu_has_spe(u64 dfr0) 19 + { 20 + return cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) && 21 + !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P); 22 + } 23 + 18 24 /** 19 25 * kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value 20 26 * ··· 83 77 *host_data_ptr(debug_brps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr0); 84 78 *host_data_ptr(debug_wrps) = SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr0); 85 79 80 + if (cpu_has_spe(dfr0)) 81 + host_data_set_flag(HAS_SPE); 82 + 86 83 if (has_vhe()) 87 84 return; 88 - 89 - if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) && 90 - !(read_sysreg_s(SYS_PMBIDR_EL1) & PMBIDR_EL1_P)) 91 - host_data_set_flag(HAS_SPE); 92 85 93 86 /* Check if we have BRBE implemented and available at the host */ 94 87 if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_BRBE_SHIFT)) ··· 107 102 void kvm_debug_init_vhe(void) 108 103 { 109 104 /* Clear PMSCR_EL1.E{0,1}SPE which reset to UNKNOWN values. */ 110 - if (SYS_FIELD_GET(ID_AA64DFR0_EL1, PMSVer, read_sysreg(id_aa64dfr0_el1))) 105 + if (host_data_test_flag(HAS_SPE)) 111 106 write_sysreg_el1(0, SYS_PMSCR); 112 107 } 113 108