Message ID | 20230127182558.2416400-12-atishp@rivosinc.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp980524wrn; Fri, 27 Jan 2023 10:28:22 -0800 (PST) X-Google-Smtp-Source: AMrXdXveMqLZ0/TXzp25yYNvWAWB5HyTNNsjxiZmnMQl5Pss8ZrtUJicrl9RwAnF+vPOuG8h3T7G X-Received: by 2002:a17:902:d650:b0:193:13fc:8840 with SMTP id y16-20020a170902d65000b0019313fc8840mr38828051plh.21.1674844102561; Fri, 27 Jan 2023 10:28:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674844102; cv=none; d=google.com; s=arc-20160816; b=uGI10XGeYZYCP9sLL6aBtDqs22KAh2d9f6EHj3yECsg7WWv2yPIVa8U1AyTKnJ29EO PoDnT+U24Z3FGLqEdYNJbgJYsjwyaxybWa7bgRx7lw45+D6cQKC56VjCQiQIqQn1esUV 9B3RRNsi+6YuX/5w0kgPR94nh5nqaNBSbxWrwu6C/YdiEmophqaHqkjdstFnkCeGf2eP j1sYFpDxBOBXKu7dipbgB+s0uRj7/m0h0Am1ayps5ttkQclJO3L9wbRKLwXLfPSW1WxG h9hRZ4EpP4OF9VkJUdqvcn2sXyF+hVf9hDY2HVS5fAtc9+IG+eVncX4lipzhvgglMQNt sA6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=2eB56PlxVYYG9BW+idfsAIH60JlcBASeIP8IcBFqjbQ=; b=IOPwRLaOwQSEYdv18okL/yo9JTVGSbkIroqsTQtgFc6Y/Fr725fYfnz5faUzeu+9g9 hSyFu5+8cshC9MCA5blcsv7ljvJXHChGZMrq8+sjcd2P0/a7Bm0ENKdOaIAmT/6QDdtM jB7CRRIs6pQ8Nanapwmuflw7rF7Qdhn1dOERfmcCYjouzr82pUg/SJ2AMFcRy148EyTE XVmoFRtB2vk5050Pze6oCu8GdjtCarkwWPMcNqKzDTAFPww0kwrKRIvs9pWhvOeoXui3 yij6mX2+WzaJwN2fOFcv0wCIuspHtrfxQfzDh0wW51ekTGlLNUJguLVK3xjuQpcgG1ET cdPw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@rivosinc-com.20210112.gappssmtp.com header.s=20210112 header.b=6tHALczf; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h4-20020a633844000000b0049ca23d4915si4708260pgn.104.2023.01.27.10.28.10; Fri, 27 Jan 2023 10:28:22 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@rivosinc-com.20210112.gappssmtp.com header.s=20210112 header.b=6tHALczf; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235010AbjA0S0y (ORCPT <rfc822;lekhanya01809@gmail.com> + 99 others); Fri, 27 Jan 2023 13:26:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235303AbjA0S0g (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 27 Jan 2023 13:26:36 -0500 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 87A2386E81 for <linux-kernel@vger.kernel.org>; Fri, 27 Jan 2023 10:26:24 -0800 (PST) Received: by mail-pj1-x102b.google.com with SMTP id m11so5397969pji.0 for <linux-kernel@vger.kernel.org>; Fri, 27 Jan 2023 10:26:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2eB56PlxVYYG9BW+idfsAIH60JlcBASeIP8IcBFqjbQ=; b=6tHALczfMbO8hse+3nrl1EO2mLFyq7flzJfTD3DpnSn2HXfxrnmud2b1bJLig7zxsC nbMCPzVzxWzfujxyIf3eM9MR3OpgNMIjwoO8ZOmLNNhMHi3n91saw1z16D3JdgLOR/4Z hl4TwdItUXrD6ixIe9gzHpd+70KjkqhLApicV8ke19vKhGbW7RtqcaqBgU4vRhojWRBH tfPbkA/cS2eonmVQKajbTs9Y40yZ5rJgSiq7h9X3lF7eKKpYieg0se7+8xtyI7UQk59Q 9KQWR7a3SMnndznUFFGX8jqJDkQS3sqrVaKWKImVrHp7RCW3k6MjZBqg/+bPCaHemItz NiCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2eB56PlxVYYG9BW+idfsAIH60JlcBASeIP8IcBFqjbQ=; b=gOV8Edma7toL0V4VMn0bDgCLSN6xT2sAojg32bHm7i8ORxpxuczpnFXJvkcVKAh1TF kBwr06q3aD/k21tc2Gx+XDVUsYNne8jcXY6URl+LIeQzmjr/gY/MA96fC8kA3fx3DQhw VsMEuVxrtjBM2M0q7ljcROOwXHDgqEd7k1bgvfrKG409/liH99syCil/SFu9jSotmTwG 4TXab9+ocwJij4o1iyHKzX3ufu2nLT3KLAJxcFcqnxQi11CNq0X+udYBmgXq4i24Ji3u uomRBd5nP4/wbvdqSA0p8s3vEWq5dO1mcgbRzIS86ie3Ssp6PJw3rJzpwYhjudPB81UK 7Zsw== X-Gm-Message-State: AO0yUKWB7osMS+hIhYmgBdC6ClDraxqnW7Hq45p+vWAX+FVMSvfaiD8/ 9YQ4zRt3peUeHVNV4SYB5rb5PHpleBjYVpdb X-Received: by 2002:a17:902:d4c8:b0:196:357f:9398 with SMTP id o8-20020a170902d4c800b00196357f9398mr10667341plg.34.1674843983718; Fri, 27 Jan 2023 10:26:23 -0800 (PST) Received: from atishp.ba.rivosinc.com ([66.220.2.162]) by smtp.gmail.com with ESMTPSA id jc5-20020a17090325c500b00189d4c666c8sm3195219plb.153.2023.01.27.10.26.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Jan 2023 10:26:23 -0800 (PST) From: Atish Patra <atishp@rivosinc.com> To: linux-kernel@vger.kernel.org Cc: Atish Patra <atishp@rivosinc.com>, Andrew Jones <ajones@ventanamicro.com>, Anup Patel <anup@brainfault.org>, Atish Patra <atishp@atishpatra.org>, Guo Ren <guoren@kernel.org>, Heiko Stuebner <heiko@sntech.de>, kvm-riscv@lists.infradead.org, kvm@vger.kernel.org, linux-riscv@lists.infradead.org, Mark Rutland <mark.rutland@arm.com>, Palmer Dabbelt <palmer@dabbelt.com>, Paul Walmsley <paul.walmsley@sifive.com>, Sergey Matyukevich <sergey.matyukevich@syntacore.com>, Will Deacon <will@kernel.org> Subject: [PATCH v3 11/14] RISC-V: KVM: Implement trap & emulate for hpmcounters Date: Fri, 27 Jan 2023 10:25:55 -0800 Message-Id: <20230127182558.2416400-12-atishp@rivosinc.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230127182558.2416400-1-atishp@rivosinc.com> References: <20230127182558.2416400-1-atishp@rivosinc.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756201329583601121?= X-GMAIL-MSGID: =?utf-8?q?1756201329583601121?= |
Series |
KVM perf support
|
|
Commit Message
Atish Patra
Jan. 27, 2023, 6:25 p.m. UTC
As the KVM guests only see the virtual PMU counters, all hpmcounter access should trap and KVM emulates the read access on behalf of guests. Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Atish Patra <atishp@rivosinc.com> --- arch/riscv/include/asm/kvm_vcpu_pmu.h | 16 ++++++++++ arch/riscv/kvm/vcpu_insn.c | 4 ++- arch/riscv/kvm/vcpu_pmu.c | 45 ++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-)
Comments
On Fri, Jan 27, 2023 at 11:56 PM Atish Patra <atishp@rivosinc.com> wrote: > > As the KVM guests only see the virtual PMU counters, all hpmcounter > access should trap and KVM emulates the read access on behalf of guests. > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> > Signed-off-by: Atish Patra <atishp@rivosinc.com> > --- > arch/riscv/include/asm/kvm_vcpu_pmu.h | 16 ++++++++++ > arch/riscv/kvm/vcpu_insn.c | 4 ++- > arch/riscv/kvm/vcpu_pmu.c | 45 ++++++++++++++++++++++++++- > 3 files changed, 63 insertions(+), 2 deletions(-) > > diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h > index 3f43a43..022d45d 100644 > --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h > +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h > @@ -43,6 +43,19 @@ struct kvm_pmu { > #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) > #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) > > +#if defined(CONFIG_32BIT) > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > +{ .base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > +#else > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > +#endif > + > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > + unsigned long *val, unsigned long new_val, > + unsigned long wr_mask); > + > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata); > int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx, > struct kvm_vcpu_sbi_ext_data *edata); > @@ -65,6 +78,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); > #else > struct kvm_pmu { > }; > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > +{ .base = 0, .count = 0, .func = NULL }, > + Redundant newline here. > > static inline int kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) > { > diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c > index 0bb5276..f689337 100644 > --- a/arch/riscv/kvm/vcpu_insn.c > +++ b/arch/riscv/kvm/vcpu_insn.c > @@ -213,7 +213,9 @@ struct csr_func { > unsigned long wr_mask); > }; > > -static const struct csr_func csr_funcs[] = { }; > +static const struct csr_func csr_funcs[] = { > + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS > +}; > > /** > * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > index 7713927..894053a 100644 > --- a/arch/riscv/kvm/vcpu_pmu.c > +++ b/arch/riscv/kvm/vcpu_pmu.c > @@ -17,6 +17,44 @@ > > #define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs) > > +static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > + unsigned long *out_val) > +{ > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > + struct kvm_pmc *pmc; > + u64 enabled, running; > + > + pmc = &kvpmu->pmc[cidx]; > + if (!pmc->perf_event) > + return -EINVAL; > + > + pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); > + *out_val = pmc->counter_val; > + > + return 0; > +} > + > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > + unsigned long *val, unsigned long new_val, > + unsigned long wr_mask) > +{ > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > + int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC; > + > + if (!kvpmu || !kvpmu->init_done) > + return KVM_INSN_EXIT_TO_USER_SPACE; As discussed previously, this should be KVM_INSN_ILLEGAL_TRAP. > + > + if (wr_mask) > + return KVM_INSN_ILLEGAL_TRAP; > + > + cidx = csr_num - CSR_CYCLE; > + > + if (pmu_ctr_read(vcpu, cidx, val) < 0) > + return KVM_INSN_EXIT_TO_USER_SPACE; Same as above. > + > + return ret; > +} > + > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata) > { > struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > @@ -69,7 +107,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba > int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > struct kvm_vcpu_sbi_ext_data *edata) > { > - /* TODO */ > + int ret; > + > + ret = pmu_ctr_read(vcpu, cidx, &edata->out_val); > + if (ret == -EINVAL) > + edata->err_val = SBI_ERR_INVALID_PARAM; > + > return 0; > } > > -- > 2.25.1 > Regards, Anup
On Sun, Jan 29, 2023 at 4:44 AM Anup Patel <anup@brainfault.org> wrote: > > On Fri, Jan 27, 2023 at 11:56 PM Atish Patra <atishp@rivosinc.com> wrote: > > > > As the KVM guests only see the virtual PMU counters, all hpmcounter > > access should trap and KVM emulates the read access on behalf of guests. > > > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> > > Signed-off-by: Atish Patra <atishp@rivosinc.com> > > --- > > arch/riscv/include/asm/kvm_vcpu_pmu.h | 16 ++++++++++ > > arch/riscv/kvm/vcpu_insn.c | 4 ++- > > arch/riscv/kvm/vcpu_pmu.c | 45 ++++++++++++++++++++++++++- > > 3 files changed, 63 insertions(+), 2 deletions(-) > > > > diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > index 3f43a43..022d45d 100644 > > --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h > > +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > @@ -43,6 +43,19 @@ struct kvm_pmu { > > #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) > > #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) > > > > +#if defined(CONFIG_32BIT) > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > +{ .base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > +#else > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > +#endif > > + > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > + unsigned long *val, unsigned long new_val, > > + unsigned long wr_mask); > > + > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata); > > int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx, > > struct kvm_vcpu_sbi_ext_data *edata); > > @@ -65,6 +78,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); > > #else > > struct kvm_pmu { > > }; > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > +{ .base = 0, .count = 0, .func = NULL }, > > + > > Redundant newline here. > Fixed. > > > > static inline int kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) > > { > > diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c > > index 0bb5276..f689337 100644 > > --- a/arch/riscv/kvm/vcpu_insn.c > > +++ b/arch/riscv/kvm/vcpu_insn.c > > @@ -213,7 +213,9 @@ struct csr_func { > > unsigned long wr_mask); > > }; > > > > -static const struct csr_func csr_funcs[] = { }; > > +static const struct csr_func csr_funcs[] = { > > + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS > > +}; > > > > /** > > * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > > index 7713927..894053a 100644 > > --- a/arch/riscv/kvm/vcpu_pmu.c > > +++ b/arch/riscv/kvm/vcpu_pmu.c > > @@ -17,6 +17,44 @@ > > > > #define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs) > > > > +static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > + unsigned long *out_val) > > +{ > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > + struct kvm_pmc *pmc; > > + u64 enabled, running; > > + > > + pmc = &kvpmu->pmc[cidx]; > > + if (!pmc->perf_event) > > + return -EINVAL; > > + > > + pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); > > + *out_val = pmc->counter_val; > > + > > + return 0; > > +} > > + > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > + unsigned long *val, unsigned long new_val, > > + unsigned long wr_mask) > > +{ > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > + int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC; > > + > > + if (!kvpmu || !kvpmu->init_done) > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > As discussed previously, this should be KVM_INSN_ILLEGAL_TRAP. > Done. > > + > > + if (wr_mask) > > + return KVM_INSN_ILLEGAL_TRAP; > > + > > + cidx = csr_num - CSR_CYCLE; > > + > > + if (pmu_ctr_read(vcpu, cidx, val) < 0) > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > Same as above. > Done. > > + > > + return ret; > > +} > > + > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata) > > { > > struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > @@ -69,7 +107,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba > > int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > struct kvm_vcpu_sbi_ext_data *edata) > > { > > - /* TODO */ > > + int ret; > > + > > + ret = pmu_ctr_read(vcpu, cidx, &edata->out_val); > > + if (ret == -EINVAL) > > + edata->err_val = SBI_ERR_INVALID_PARAM; > > + > > return 0; > > } > > > > -- > > 2.25.1 > > > > Regards, > Anup
On Tue, Jan 31, 2023 at 2:46 PM Atish Patra <atishp@atishpatra.org> wrote: > > On Sun, Jan 29, 2023 at 4:44 AM Anup Patel <anup@brainfault.org> wrote: > > > > On Fri, Jan 27, 2023 at 11:56 PM Atish Patra <atishp@rivosinc.com> wrote: > > > > > > As the KVM guests only see the virtual PMU counters, all hpmcounter > > > access should trap and KVM emulates the read access on behalf of guests. > > > > > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> > > > Signed-off-by: Atish Patra <atishp@rivosinc.com> > > > --- > > > arch/riscv/include/asm/kvm_vcpu_pmu.h | 16 ++++++++++ > > > arch/riscv/kvm/vcpu_insn.c | 4 ++- > > > arch/riscv/kvm/vcpu_pmu.c | 45 ++++++++++++++++++++++++++- > > > 3 files changed, 63 insertions(+), 2 deletions(-) > > > > > > diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > index 3f43a43..022d45d 100644 > > > --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > @@ -43,6 +43,19 @@ struct kvm_pmu { > > > #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) > > > #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) > > > > > > +#if defined(CONFIG_32BIT) > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > +{ .base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ > > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > > +#else > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > > +#endif > > > + > > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > > + unsigned long *val, unsigned long new_val, > > > + unsigned long wr_mask); > > > + > > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata); > > > int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx, > > > struct kvm_vcpu_sbi_ext_data *edata); > > > @@ -65,6 +78,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); > > > #else > > > struct kvm_pmu { > > > }; > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > +{ .base = 0, .count = 0, .func = NULL }, > > > + > > > > Redundant newline here. > > > > Fixed. > > > > > > > static inline int kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) > > > { > > > diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c > > > index 0bb5276..f689337 100644 > > > --- a/arch/riscv/kvm/vcpu_insn.c > > > +++ b/arch/riscv/kvm/vcpu_insn.c > > > @@ -213,7 +213,9 @@ struct csr_func { > > > unsigned long wr_mask); > > > }; > > > > > > -static const struct csr_func csr_funcs[] = { }; > > > +static const struct csr_func csr_funcs[] = { > > > + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS > > > +}; > > > > > > /** > > > * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space > > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > > > index 7713927..894053a 100644 > > > --- a/arch/riscv/kvm/vcpu_pmu.c > > > +++ b/arch/riscv/kvm/vcpu_pmu.c > > > @@ -17,6 +17,44 @@ > > > > > > #define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs) > > > > > > +static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > > + unsigned long *out_val) > > > +{ > > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > + struct kvm_pmc *pmc; > > > + u64 enabled, running; > > > + > > > + pmc = &kvpmu->pmc[cidx]; > > > + if (!pmc->perf_event) > > > + return -EINVAL; > > > + > > > + pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); > > > + *out_val = pmc->counter_val; > > > + > > > + return 0; > > > +} > > > + > > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > > + unsigned long *val, unsigned long new_val, > > > + unsigned long wr_mask) > > > +{ > > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > + int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC; > > > + > > > + if (!kvpmu || !kvpmu->init_done) > > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > > > As discussed previously, this should be KVM_INSN_ILLEGAL_TRAP. > > Thinking about it more, this results in a panic in guest S-mode which is probably undesirable. As per your earlier suggestion, we can return 0 for cycle/instret counters if accessed. This is only possible through legacy pmu drivers running in guests or some other OS that access any hpmcounters for random reasons. I think we should return KVM_INSN_ILLEGAL_TRAP for other counters and make the guest kernel panic. This does separate the behavior between fixed and programmable counters when everything is denied access in hcounteren. The new code will look like this: if (!kvpmu || !kvpmu->init_done) { if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) { *val = 0; return ret; } else return KVM_INSN_ILLEGAL_TRAP; } Let me know if you think otherwise. > > Done. > > > + > > > + if (wr_mask) > > > + return KVM_INSN_ILLEGAL_TRAP; > > > + > > > + cidx = csr_num - CSR_CYCLE; > > > + > > > + if (pmu_ctr_read(vcpu, cidx, val) < 0) > > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > > > Same as above. > > We can get rid of this as pmu_ctr_read doesn't return errors anyways. > > Done. > > > > + > > > + return ret; > > > +} > > > + > > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata) > > > { > > > struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > @@ -69,7 +107,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba > > > int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > > struct kvm_vcpu_sbi_ext_data *edata) > > > { > > > - /* TODO */ > > > + int ret; > > > + > > > + ret = pmu_ctr_read(vcpu, cidx, &edata->out_val); > > > + if (ret == -EINVAL) > > > + edata->err_val = SBI_ERR_INVALID_PARAM; > > > + > > > return 0; > > > } > > > > > > -- > > > 2.25.1 > > > > > > > Regards, > > Anup > > > > -- > Regards, > Atish
On Wed, Feb 1, 2023 at 2:29 PM Atish Patra <atishp@atishpatra.org> wrote: > > On Tue, Jan 31, 2023 at 2:46 PM Atish Patra <atishp@atishpatra.org> wrote: > > > > On Sun, Jan 29, 2023 at 4:44 AM Anup Patel <anup@brainfault.org> wrote: > > > > > > On Fri, Jan 27, 2023 at 11:56 PM Atish Patra <atishp@rivosinc.com> wrote: > > > > > > > > As the KVM guests only see the virtual PMU counters, all hpmcounter > > > > access should trap and KVM emulates the read access on behalf of guests. > > > > > > > > Reviewed-by: Andrew Jones <ajones@ventanamicro.com> > > > > Signed-off-by: Atish Patra <atishp@rivosinc.com> > > > > --- > > > > arch/riscv/include/asm/kvm_vcpu_pmu.h | 16 ++++++++++ > > > > arch/riscv/kvm/vcpu_insn.c | 4 ++- > > > > arch/riscv/kvm/vcpu_pmu.c | 45 ++++++++++++++++++++++++++- > > > > 3 files changed, 63 insertions(+), 2 deletions(-) > > > > > > > > diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > > index 3f43a43..022d45d 100644 > > > > --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > > +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h > > > > @@ -43,6 +43,19 @@ struct kvm_pmu { > > > > #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) > > > > #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) > > > > > > > > +#if defined(CONFIG_32BIT) > > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > > +{ .base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ > > > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > > > +#else > > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > > +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, > > > > +#endif > > > > + > > > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > > > + unsigned long *val, unsigned long new_val, > > > > + unsigned long wr_mask); > > > > + > > > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata); > > > > int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx, > > > > struct kvm_vcpu_sbi_ext_data *edata); > > > > @@ -65,6 +78,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); > > > > #else > > > > struct kvm_pmu { > > > > }; > > > > +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ > > > > +{ .base = 0, .count = 0, .func = NULL }, > > > > + > > > > > > Redundant newline here. > > > > > > > Fixed. > > > > > > > > > > static inline int kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) > > > > { > > > > diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c > > > > index 0bb5276..f689337 100644 > > > > --- a/arch/riscv/kvm/vcpu_insn.c > > > > +++ b/arch/riscv/kvm/vcpu_insn.c > > > > @@ -213,7 +213,9 @@ struct csr_func { > > > > unsigned long wr_mask); > > > > }; > > > > > > > > -static const struct csr_func csr_funcs[] = { }; > > > > +static const struct csr_func csr_funcs[] = { > > > > + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS > > > > +}; > > > > > > > > /** > > > > * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space > > > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > > > > index 7713927..894053a 100644 > > > > --- a/arch/riscv/kvm/vcpu_pmu.c > > > > +++ b/arch/riscv/kvm/vcpu_pmu.c > > > > @@ -17,6 +17,44 @@ > > > > > > > > #define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs) > > > > > > > > +static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > > > + unsigned long *out_val) > > > > +{ > > > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > > + struct kvm_pmc *pmc; > > > > + u64 enabled, running; > > > > + > > > > + pmc = &kvpmu->pmc[cidx]; > > > > + if (!pmc->perf_event) > > > > + return -EINVAL; > > > > + > > > > + pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); > > > > + *out_val = pmc->counter_val; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, > > > > + unsigned long *val, unsigned long new_val, > > > > + unsigned long wr_mask) > > > > +{ > > > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > > + int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC; > > > > + > > > > + if (!kvpmu || !kvpmu->init_done) > > > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > > > > > As discussed previously, this should be KVM_INSN_ILLEGAL_TRAP. > > > > > Thinking about it more, this results in a panic in guest S-mode which > is probably undesirable. > As per your earlier suggestion, we can return 0 for cycle/instret > counters if accessed. > This is only possible through legacy pmu drivers running in guests or > some other OS that access any hpmcounters > for random reasons. > > I think we should return KVM_INSN_ILLEGAL_TRAP for other counters and > make the guest kernel panic. > This does separate the behavior between fixed and programmable > counters when everything is denied access in hcounteren. > > The new code will look like this: > > if (!kvpmu || !kvpmu->init_done) { > if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) { > *val = 0; > return ret; > } else > return KVM_INSN_ILLEGAL_TRAP; > } > > Let me know if you think otherwise. Looks good to me. Please also add comment block inside "if (!kvpmu || !kvpmu->init_done)" > > > > > Done. > > > > + > > > > + if (wr_mask) > > > > + return KVM_INSN_ILLEGAL_TRAP; > > > > + > > > > + cidx = csr_num - CSR_CYCLE; > > > > + > > > > + if (pmu_ctr_read(vcpu, cidx, val) < 0) > > > > + return KVM_INSN_EXIT_TO_USER_SPACE; > > > > > > Same as above. > > > > > We can get rid of this as pmu_ctr_read doesn't return errors anyways. > > > > > Done. > > > > > > + > > > > + return ret; > > > > +} > > > > + > > > > int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata) > > > > { > > > > struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > > > @@ -69,7 +107,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba > > > > int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > > > struct kvm_vcpu_sbi_ext_data *edata) > > > > { > > > > - /* TODO */ > > > > + int ret; > > > > + > > > > + ret = pmu_ctr_read(vcpu, cidx, &edata->out_val); > > > > + if (ret == -EINVAL) > > > > + edata->err_val = SBI_ERR_INVALID_PARAM; > > > > + > > > > return 0; > > > > } > > > > > > > > -- > > > > 2.25.1 > > > > > > > > > > Regards, > > > Anup > > > > > > > > -- > > Regards, > > Atish > > > > -- > Regards, > Atish Regards, Anup
diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h index 3f43a43..022d45d 100644 --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h @@ -43,6 +43,19 @@ struct kvm_pmu { #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) +#if defined(CONFIG_32BIT) +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +{ .base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, +#else +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +{ .base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, +#endif + +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask); + int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata); int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx, struct kvm_vcpu_sbi_ext_data *edata); @@ -65,6 +78,9 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); #else struct kvm_pmu { }; +#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +{ .base = 0, .count = 0, .func = NULL }, + static inline int kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) { diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index 0bb5276..f689337 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -213,7 +213,9 @@ struct csr_func { unsigned long wr_mask); }; -static const struct csr_func csr_funcs[] = { }; +static const struct csr_func csr_funcs[] = { + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS +}; /** * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 7713927..894053a 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -17,6 +17,44 @@ #define kvm_pmu_num_counters(pmu) ((pmu)->num_hw_ctrs + (pmu)->num_fw_ctrs) +static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, + unsigned long *out_val) +{ + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); + struct kvm_pmc *pmc; + u64 enabled, running; + + pmc = &kvpmu->pmc[cidx]; + if (!pmc->perf_event) + return -EINVAL; + + pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); + *out_val = pmc->counter_val; + + return 0; +} + +int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask) +{ + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); + int cidx, ret = KVM_INSN_CONTINUE_NEXT_SEPC; + + if (!kvpmu || !kvpmu->init_done) + return KVM_INSN_EXIT_TO_USER_SPACE; + + if (wr_mask) + return KVM_INSN_ILLEGAL_TRAP; + + cidx = csr_num - CSR_CYCLE; + + if (pmu_ctr_read(vcpu, cidx, val) < 0) + return KVM_INSN_EXIT_TO_USER_SPACE; + + return ret; +} + int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_ext_data *edata) { struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); @@ -69,7 +107,12 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba int kvm_riscv_vcpu_pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, struct kvm_vcpu_sbi_ext_data *edata) { - /* TODO */ + int ret; + + ret = pmu_ctr_read(vcpu, cidx, &edata->out_val); + if (ret == -EINVAL) + edata->err_val = SBI_ERR_INVALID_PARAM; + return 0; }