KVM: arm64: Initialize PMSCR_EL1 when in VHE
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>
This commit is contained in:
parent
860b21c31d
commit
efad60e460
|
@ -1369,6 +1369,7 @@ static inline bool kvm_system_needs_idmapped_vectors(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_init_host_debug_data(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_load_debug(struct kvm_vcpu *vcpu);
|
||||||
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu);
|
void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu);
|
||||||
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
|
void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu);
|
||||||
|
|
|
@ -2113,8 +2113,10 @@ static void cpu_hyp_init_features(void)
|
||||||
{
|
{
|
||||||
cpu_set_hyp_vector();
|
cpu_set_hyp_vector();
|
||||||
|
|
||||||
if (is_kernel_in_hyp_mode())
|
if (is_kernel_in_hyp_mode()) {
|
||||||
kvm_timer_init_vhe();
|
kvm_timer_init_vhe();
|
||||||
|
kvm_debug_init_vhe();
|
||||||
|
}
|
||||||
|
|
||||||
if (vgic_present)
|
if (vgic_present)
|
||||||
kvm_vgic_init_cpu_hardware();
|
kvm_vgic_init_cpu_hardware();
|
||||||
|
|
|
@ -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
|
* Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host
|
||||||
* has taken over MDSCR_EL1.
|
* has taken over MDSCR_EL1.
|
||||||
|
|
Loading…
Reference in New Issue