summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorReiji Watanabe <reijiw@google.com>2023-03-12 20:32:34 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-04-13 16:55:17 +0200
commit74347b99d4ebbbab43ac21b7a4420ab03369c568 (patch)
treeaa4be44b219fbfa0362f2c4780728f0c0da399e9 /arch
parent3d8c8a9ad53e96dccc941ee5159a7e19f2f33169 (diff)
downloadlinux-74347b99d4ebbbab43ac21b7a4420ab03369c568.tar.gz
KVM: arm64: PMU: Don't save PMCR_EL0.{C,P} for the vCPU
[ Upstream commit f6da81f650fa47b61b847488f3938d43f90d093d ]

Presently, when a guest writes 1 to PMCR_EL0.{C,P}, which is WO/RAZ,
KVM saves the register value, including these bits.
When userspace reads the register using KVM_GET_ONE_REG, KVM returns
the saved register value as it is (the saved value might have these
bits set).  This could result in userspace setting these bits on the
destination during migration.  Consequently, KVM may end up resetting
the vPMU counter registers (PMCCNTR_EL0 and/or PMEVCNTR<n>_EL0) to
zero on the first KVM_RUN after migration.

Fix this by not saving those bits when a guest writes 1 to those bits.

Fixes: ab9468340d2b ("arm64: KVM: Add access handler for PMCR register")
Cc: stable@vger.kernel.org
Reviewed-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Reiji Watanabe <reijiw@google.com>
Link: https://lore.kernel.org/r/20230313033234.1475987-1-reijiw@google.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm64/kvm/pmu-emul.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 50b6ba593a10..67770375c5ee 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -511,7 +511,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 	if (!kvm_vcpu_has_pmu(vcpu))
 		return;
 
-	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
+	/* The reset bits don't indicate any state, and shouldn't be saved. */
+	__vcpu_sys_reg(vcpu, PMCR_EL0) = val & ~(ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_P);
 
 	if (val & ARMV8_PMU_PMCR_E) {
 		kvm_pmu_enable_counter_mask(vcpu,