From patchwork Sun Oct 20 10:11:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 11200869 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEFF614ED for ; Sun, 20 Oct 2019 10:11:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9C1BF222C3 for ; Sun, 20 Oct 2019 10:11:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571566299; bh=V53P7Vn0aPiKYwrOMap7wcByveXMeM32VmJKA4bI76s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=TEsBLYMsyZJmHytVvWlx5a4Rr8qGIaz7kLKqfp/UdiI3nGqaNcbMsDCHDJbjIkk15 aJizWVHtvQNR/boNPzW4ref/B/YHEJ799eFMnj36vAUOBPx5Ckn6j/j2fT9so2bTKO nU0xkLprK3SZ1U2lQkeaSWShMCAI0E7h3idV2ocA= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726179AbfJTKLj (ORCPT ); Sun, 20 Oct 2019 06:11:39 -0400 Received: from mail.kernel.org ([198.145.29.99]:55342 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725893AbfJTKLi (ORCPT ); Sun, 20 Oct 2019 06:11:38 -0400 Received: from big-swifty.lan (78.163-31-62.static.virginmediabusiness.co.uk [62.31.163.78]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 6929D222BD; Sun, 20 Oct 2019 10:11:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571566297; bh=V53P7Vn0aPiKYwrOMap7wcByveXMeM32VmJKA4bI76s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=peYUqeE2CB2w33fmbugervLQNX+GX31Uh5sbOoiIy1LVvBeTnM0OewPJuZ2QHh4fk +p8U85CFm+SrKBF+MQhBhnaWCIHAxHNbgKhplRjH8mHeC3qn+Ke5Lvgat8eFVrafJZ LGMMdfb/RiiK/jb3OMUP3kjM9ATxDcgxa6oOk1bA= From: Marc Zyngier To: Paolo Bonzini , =?utf-8?b?UmFkaW0gS3LEjW3DocWZ?= Cc: Julien Thierry , Suzuki K Poulose , James Morse , Andrew Murray , linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Subject: [PATCH 1/4] KVM: arm64: pmu: Fix cycle counter truncation Date: Sun, 20 Oct 2019 11:11:26 +0100 Message-Id: <20191020101129.2612-2-maz@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191020101129.2612-1-maz@kernel.org> References: <20191020101129.2612-1-maz@kernel.org> MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org When a counter is disabled, its value is sampled before the event is being disabled, and the value written back in the shadow register. In that process, the value gets truncated to 32bit, which is adequate for any counter but the cycle counter (defined as a 64bit counter). This obviously results in a corrupted counter, and things like "perf record -e cycles" not working at all when run in a guest... A similar, but less critical bug exists in kvm_pmu_get_counter_value. Make the truncation conditional on the counter not being the cycle counter, which results in a minor code reorganisation. Fixes: 80f393a23be6 ("KVM: arm/arm64: Support chained PMU counters") Reviewed-by: Andrew Murray Reported-by: Julien Thierry Signed-off-by: Marc Zyngier --- virt/kvm/arm/pmu.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c index 362a01886bab..c30c3a74fc7f 100644 --- a/virt/kvm/arm/pmu.c +++ b/virt/kvm/arm/pmu.c @@ -146,8 +146,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx) if (kvm_pmu_pmc_is_chained(pmc) && kvm_pmu_idx_is_high_counter(select_idx)) counter = upper_32_bits(counter); - - else if (!kvm_pmu_idx_is_64bit(vcpu, select_idx)) + else if (select_idx != ARMV8_PMU_CYCLE_IDX) counter = lower_32_bits(counter); return counter; @@ -193,7 +192,7 @@ static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc) */ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc) { - u64 counter, reg; + u64 counter, reg, val; pmc = kvm_pmu_get_canonical_pmc(pmc); if (!pmc->perf_event) @@ -201,16 +200,19 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc) counter = kvm_pmu_get_pair_counter_value(vcpu, pmc); - if (kvm_pmu_pmc_is_chained(pmc)) { - reg = PMEVCNTR0_EL0 + pmc->idx; - __vcpu_sys_reg(vcpu, reg) = lower_32_bits(counter); - __vcpu_sys_reg(vcpu, reg + 1) = upper_32_bits(counter); + if (pmc->idx == ARMV8_PMU_CYCLE_IDX) { + reg = PMCCNTR_EL0; + val = counter; } else { - reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX) - ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx; - __vcpu_sys_reg(vcpu, reg) = lower_32_bits(counter); + reg = PMEVCNTR0_EL0 + pmc->idx; + val = lower_32_bits(counter); } + __vcpu_sys_reg(vcpu, reg) = val; + + if (kvm_pmu_pmc_is_chained(pmc)) + __vcpu_sys_reg(vcpu, reg + 1) = upper_32_bits(counter); + kvm_pmu_release_perf_event(pmc); }