]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: Initialize PMSCR_EL1 when in VHE
authorAlexandru Elisei <alexandru.elisei@arm.com>
Tue, 2 Sep 2025 13:08:32 +0000 (14:08 +0100)
committerOliver Upton <oliver.upton@linux.dev>
Wed, 10 Sep 2025 09:56:19 +0000 (02:56 -0700)
According to the pseudocode for StatisticalProfilingEnabled() from Arm
DDI0487L.b, PMSCR_EL1 controls profiling at EL1 and EL0:

- PMSCR_EL1.E1SPE controls profiling at EL1.
- PMSCR_EL1.E0SPE controls profiling at EL0 if HCR_EL2.TGE=0.

These two fields reset to UNKNOWN values.

When KVM runs in VHE mode and profiling is enabled in the host, before
entering a guest, KVM does not touch any of the SPE registers, leaving the
buffer enabled, and it clears HCR_EL2.TGE. As a result, depending on the
reset value for the E1SPE and E0SPE fields, KVM might unintentionally
profile a guest. Make the behaviour consistent and predictable by clearing
PMSCR_EL1 when KVM initialises the host debug configuration.

Note that this is not a problem for nVHE, because KVM clears
PMSCR_EL1.{E1SPE,E0SPE} before entering the guest.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
Link: https://lore.kernel.org/r/20250902130833.338216-2-alexandru.elisei@arm.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/arm.c
arch/arm64/kvm/debug.c

index 2b07f0a27a7d85463851a4e42b01eb01c4c7e82e..0ee4f6fa3a172d3d89100c3bad8e2b9b67f324d3 100644 (file)
@@ -1369,6 +1369,7 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
 }
 
 void kvm_init_host_debug_data(void);
+void kvm_debug_init_vhe(void);
 void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu);
 void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu);
 void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
index 5bf101c869c9ab179ebf0672b42b37fe2eec1bc5..bd6b6a620a09ca5273b90f2b4b87c4cb1b5cdfd9 100644 (file)
@@ -2113,8 +2113,10 @@ static void cpu_hyp_init_features(void)
 {
        cpu_set_hyp_vector();
 
-       if (is_kernel_in_hyp_mode())
+       if (is_kernel_in_hyp_mode()) {
                kvm_timer_init_vhe();
+               kvm_debug_init_vhe();
+       }
 
        if (vgic_present)
                kvm_vgic_init_cpu_hardware();
index 381382c19fe4741980c79b08bbdab6a1bcd825ad..fee6e882490ab245759c18c99586ccc5079caafa 100644 (file)
@@ -96,6 +96,13 @@ void kvm_init_host_debug_data(void)
        }
 }
 
+void kvm_debug_init_vhe(void)
+{
+       /* Clear PMSCR_EL1.E{0,1}SPE which reset to UNKNOWN values. */
+       if (SYS_FIELD_GET(ID_AA64DFR0_EL1, PMSVer, read_sysreg(id_aa64dfr0_el1)))
+               write_sysreg_el1(0, SYS_PMSCR);
+}
+
 /*
  * Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
  * has taken over MDSCR_EL1.