diff mbox series

[2/2] KVM: arm64: PMU: Don't save PMCR_EL0.{C,P} for the vCPU

Message ID 20230302055033.3081456-3-reijiw@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: PMU: Preserve vPMC registers properly on migration | expand

Commit Message

Reiji Watanabe March 2, 2023, 5:50 a.m. UTC
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.

Signed-off-by: Reiji Watanabe <reijiw@google.com>
---
 arch/arm64/kvm/pmu-emul.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Comments

Marc Zyngier March 12, 2023, 3:01 p.m. UTC | #1
On Thu, 02 Mar 2023 05:50:33 +0000,
Reiji Watanabe <reijiw@google.com> wrote:
> 
> 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.
> 
> Signed-off-by: Reiji Watanabe <reijiw@google.com>
> ---
>  arch/arm64/kvm/pmu-emul.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
> index 24908400e190..a5a0a9811ddb 100644
> --- a/arch/arm64/kvm/pmu-emul.c
> +++ b/arch/arm64/kvm/pmu-emul.c
> @@ -538,7 +538,9 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  	if (!kvm_pmu_is_3p5(vcpu))
>  		val &= ~ARMV8_PMU_PMCR_LP;
>  
> -	__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);

nit: assignment on a single line, please.

With that,

Reviewed-by: Marc Zyngier <maz@kernel.org>

Thanks,

	M.
Reiji Watanabe March 13, 2023, 3:34 a.m. UTC | #2
Hi Marc,

On Sun, Mar 12, 2023 at 8:01 AM Marc Zyngier <maz@kernel.org> wrote:
>
> On Thu, 02 Mar 2023 05:50:33 +0000,
> Reiji Watanabe <reijiw@google.com> wrote:
> >
> > 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.
> >
> > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > ---
> >  arch/arm64/kvm/pmu-emul.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
> > index 24908400e190..a5a0a9811ddb 100644
> > --- a/arch/arm64/kvm/pmu-emul.c
> > +++ b/arch/arm64/kvm/pmu-emul.c
> > @@ -538,7 +538,9 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
> >       if (!kvm_pmu_is_3p5(vcpu))
> >               val &= ~ARMV8_PMU_PMCR_LP;
> >
> > -     __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);
>
> nit: assignment on a single line, please.

Yes, I fixed it in v2!

>
> With that,
>
> Reviewed-by: Marc Zyngier <maz@kernel.org>

Thank you!
Reiji
diff mbox series

Patch

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 24908400e190..a5a0a9811ddb 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -538,7 +538,9 @@  void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 	if (!kvm_pmu_is_3p5(vcpu))
 		val &= ~ARMV8_PMU_PMCR_LP;
 
-	__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,