From patchwork Mon Jul 17 16:12:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Marussi X-Patchwork-Id: 121450 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp1228613vqt; Mon, 17 Jul 2023 09:52:55 -0700 (PDT) X-Google-Smtp-Source: APBJJlHVZgW62rSMlkYypCdrYk4wnfyAhWH49wQyXNdKqO/simsf2oaojLImkG2KRTImaenSWV59 X-Received: by 2002:a17:902:dad2:b0:1b7:e9e9:1004 with SMTP id q18-20020a170902dad200b001b7e9e91004mr13816660plx.30.1689612775445; Mon, 17 Jul 2023 09:52:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689612775; cv=none; d=google.com; s=arc-20160816; b=loeyJwpSZ2PiFPIbGXlM90CyDYdA69fn/h9o76vsN0QVmKm0EEckjd94nCirqWaUCJ urWzzHccrZdXf5oYZ8LRNKxOKSLQeNeOHz/r/PxmTWeyh1dypd+Hs/n29aTx1aSpfyFN 5JRTNBllbrcM0jZzYmSAM52Su20kjIEXpYOylus38AGnAqolUimxsjS0zv/7zY0x66dD yLZxAAdK+Z9Tg/sJ/FpVbtWEBdJF58icxL3Mv0ZuIKzLyiYPt7i0I9FoFddOJS8CkfRB cRkv1E2ACoAA8o7rwD7CgUgnxkrpxvvC52paJv6swqIspTOC+kcXA/S+r+tuCth2bBhi v0AA== 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; bh=p0fwBaFzXP26om3dHp8Zg5u84so6vUloPURSwDAH5vM=; fh=KzBh99KOPzz59kL3CJj2foKa9OfzOtt6jyZbwR+45UY=; b=UEVwbMOFcSN1UwAOwVaLivWJr1uu63K754JDFrGKAiga6mZg9GSjF0V6MDcao/DqtI H/cGG1nK0epssJdY756DbwAI3XcX1JZvFAXWlqXa7vRgyxjA0daYW0pjcE3+Q8Pjox/n 2lFuygxNjk40onvxZ93fX03dudZHKVVjcLkLiGmgxzfnLJPKJ95O1srP6faAt0AUwDZX JMbiAeF1h1a7xAu60NQh06K9bOnmjZkYZPrOpGLNBOXMs6asjMlWUrsEz2X+qLd9sThs aMvl1s4u9Fkqbkn+TkEiRD+lAu8x+LZ4UbTJ9OLLupleBlSetebJ1l6eCmiC/pXQQ8jQ Hi/g== ARC-Authentication-Results: i=1; mx.google.com; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id s21-20020a170902a51500b001b9e29fe870si121356plq.62.2023.07.17.09.52.41; Mon, 17 Jul 2023 09:52:55 -0700 (PDT) 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; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232085AbjGQQNj (ORCPT + 99 others); Mon, 17 Jul 2023 12:13:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59046 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232127AbjGQQNW (ORCPT ); Mon, 17 Jul 2023 12:13:22 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1239511C for ; Mon, 17 Jul 2023 09:13:21 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3A9F8D75; Mon, 17 Jul 2023 09:14:04 -0700 (PDT) Received: from pluto.. (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 044863F738; Mon, 17 Jul 2023 09:13:18 -0700 (PDT) From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: sudeep.holla@arm.com, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, aidapala@qti.qualcomm.com, souvik.chakravarty@arm.com, satyakim@qti.qualcomm.com, atouzni@qti.qualcomm.com, Cristian Marussi Subject: [PATCH 1/2] firmware: arm_scmi: Harden PERF domain info access Date: Mon, 17 Jul 2023 17:12:45 +0100 Message-ID: <20230717161246.1761777-2-cristian.marussi@arm.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230717161246.1761777-1-cristian.marussi@arm.com> References: <20230717161246.1761777-1-cristian.marussi@arm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham 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: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771687406078963781 X-GMAIL-MSGID: 1771687406078963781 Harden internal accesses to domain info in PERF protocol. Signed-off-by: Cristian Marussi --- drivers/firmware/arm_scmi/perf.c | 89 +++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index ecf5c4de851b..43dd242ecc49 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -139,7 +139,7 @@ struct perf_dom_info { struct scmi_perf_info { u32 version; - int num_domains; + u16 num_domains; enum scmi_power_scale power_scale; u64 stats_addr; u32 stats_size; @@ -356,11 +356,26 @@ static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph, return ret; } +static inline struct perf_dom_info * +scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) +{ + struct scmi_perf_info *pi = ph->get_priv(ph); + + if (domain >= pi->num_domains) + return ERR_PTR(-EINVAL); + + return pi->dom_info + domain; +} + static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, u32 domain, u32 max_perf, u32 min_perf) { struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf) return -EINVAL; @@ -408,8 +423,11 @@ static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph, static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph, u32 domain, u32 *max_perf, u32 *min_perf) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) { struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT]; @@ -449,8 +467,11 @@ static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph, static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, u32 domain, u32 level, bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) { struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL]; @@ -490,8 +511,11 @@ static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph, static int scmi_perf_level_get(const struct scmi_protocol_handle *ph, u32 domain, u32 *level, bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) { *level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr); @@ -574,13 +598,14 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, unsigned long freq; struct scmi_opp *opp; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); domain = scmi_dev_domain_id(dev); if (domain < 0) - return domain; + return -EINVAL; - dom = pi->dom_info + domain; + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { freq = opp->perf * dom->mult_factor; @@ -603,14 +628,17 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, struct device *dev) { + int domain; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); - int domain = scmi_dev_domain_id(dev); + domain = scmi_dev_domain_id(dev); if (domain < 0) - return domain; + return -EINVAL; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); - dom = pi->dom_info + domain; /* uS to nS */ return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; } @@ -618,8 +646,11 @@ scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain, unsigned long freq, bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll); } @@ -630,11 +661,14 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain, int ret; u32 level; struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; ret = scmi_perf_level_get(ph, domain, &level, poll); - if (!ret) + if (!ret) { + struct perf_dom_info *dom = pi->dom_info + domain; + + /* Note domain is validated implicitly by scmi_perf_level_get */ *freq = level * dom->mult_factor; + } return ret; } @@ -643,15 +677,14 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, u32 domain, unsigned long *freq, unsigned long *power) { - struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom; unsigned long opp_freq; int idx, ret = -EINVAL; struct scmi_opp *opp; - dom = pi->dom_info + domain; - if (!dom) - return -EIO; + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { opp_freq = opp->perf * dom->mult_factor; @@ -670,10 +703,16 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph, struct device *dev) { + int domain; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); - dom = pi->dom_info + scmi_dev_domain_id(dev); + domain = scmi_dev_domain_id(dev); + if (domain < 0) + return false; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return false; return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr; }