From patchwork Mon Dec 6 22:57:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660415 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A219C433F5 for ; Mon, 6 Dec 2021 22:58:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376646AbhLFXCP (ORCPT ); Mon, 6 Dec 2021 18:02:15 -0500 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:25256 "EHLO alexa-out-sd-01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1359564AbhLFXCP (ORCPT ); Mon, 6 Dec 2021 18:02:15 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831526; x=1670367526; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=OK/BCH/proGH0PCKGvXS8Kk1FOt/6gx4f6czFZ3Bdxk=; b=DmApUZZDlNKmlqa1LaRYROEFdpFuPb7IiSPAarOaQL8YA7qpeKJASVX7 Jo0K3lQp/5RDTwnGGcHdy+RmHIlkHw/JeudWAnknm5IyuQL7M/hv1ACUS RKLcggSsdz4RutjSQb/K41ELegjOiGTjuQXRyteH6/YLw6vYRiMGuhGAR o=; Received: from unknown (HELO ironmsg01-sd.qualcomm.com) ([10.53.140.141]) by alexa-out-sd-01.qualcomm.com with ESMTP; 06 Dec 2021 14:58:45 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg01-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:58:45 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:45 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:44 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 01/10] soc: qcom: new common library for ICE functionality Date: Mon, 6 Dec 2021 14:57:16 -0800 Message-ID: <20211206225725.77512-2-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Add a new library which congregates all the ICE functionality so that all storage controllers containing ICE can utilize it. Currently, ufs and sdhci-msm have their own support for ICE, this common library allows code to be shared. Signed-off-by: Gaurav Kashyap --- drivers/soc/qcom/Kconfig | 7 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qti-ice-common.c | 199 ++++++++++++++++++++++++++++++ drivers/soc/qcom/qti-ice-regs.h | 145 ++++++++++++++++++++++ include/linux/qti-ice-common.h | 24 ++++ 5 files changed, 376 insertions(+) create mode 100644 drivers/soc/qcom/qti-ice-common.c create mode 100644 drivers/soc/qcom/qti-ice-regs.h create mode 100644 include/linux/qti-ice-common.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 79b568f82a1c..a900f5ab6263 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -209,4 +209,11 @@ config QCOM_APR application processor and QDSP6. APR is used by audio driver to configure QDSP6 ASM, ADM and AFE modules. + +config QTI_ICE_COMMON + tristate "QTI common ICE functionality" + depends on ARCH_QCOM + help + Enable the common ICE library that can be used + by UFS and EMMC drivers for ICE functionality. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index ad675a6593d0..57840b19b7ee 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o +obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c new file mode 100644 index 000000000000..0c5b529201c5 --- /dev/null +++ b/drivers/soc/qcom/qti-ice-common.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common ICE library for storage encryption. + * + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved. + */ + +#include +#include +#include +#include +#include "qti-ice-regs.h" + +#define QTI_ICE_MAX_BIST_CHECK_COUNT 100 +#define QTI_AES_256_XTS_KEY_RAW_SIZE 64 + +static bool qti_ice_supported(const struct ice_mmio_data *mmio) +{ + u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION); + int major = regval >> 24; + int minor = (regval >> 16) & 0xFF; + int step = regval & 0xFFFF; + + /* For now this driver only supports ICE version 3 and higher. */ + if (major < 3) { + pr_warn("Unsupported ICE version: v%d.%d.%d\n", + major, minor, step); + return false; + } + + pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", + major, minor, step); + + /* If fuses are blown, ICE might not work in the standard way. */ + regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_FUSE_SETTING); + if (regval & (QTI_ICE_FUSE_SETTING_MASK | + QTI_ICE_FORCE_HW_KEY0_SETTING_MASK | + QTI_ICE_FORCE_HW_KEY1_SETTING_MASK)) { + pr_warn("Fuses are blown; ICE is unusable!\n"); + return false; + } + return true; +} + +/** + * qti_ice_init() - Initialize ICE functionality + * @ice_mmio_data: contains ICE register mapping for i/o + * + * Initialize ICE by checking the version for ICE support and + * also checking the fuses blown. + * + * Return: 0 on success; -EINVAL on failure. + */ +int qti_ice_init(const struct ice_mmio_data *mmio) +{ + if (!qti_ice_supported(mmio)) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(qti_ice_init); + +static void qti_ice_low_power_and_optimization_enable( + const struct ice_mmio_data *mmio) +{ + u32 regval = qti_ice_readl(mmio->ice_mmio, + QTI_ICE_REGS_ADVANCED_CONTROL); + + /* Enable low power mode sequence + * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0, + * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING + */ + regval |= 0x7000; + /* Optimization enable sequence*/ + regval |= 0xD807100; + qti_ice_writel(mmio->ice_mmio, regval, QTI_ICE_REGS_ADVANCED_CONTROL); + /* Memory barrier - to ensure write completion before next transaction */ + wmb(); +} + +static int qti_ice_wait_bist_status(const struct ice_mmio_data *mmio) +{ + int count; + u32 regval; + + for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) { + regval = qti_ice_readl(mmio->ice_mmio, + QTI_ICE_REGS_BIST_STATUS); + if (!(regval & QTI_ICE_BIST_STATUS_MASK)) + break; + udelay(50); + } + + if (regval) { + pr_err("%s: wait bist status failed, reg %d\n", + __func__, regval); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * qti_ice_enable() - Enable ICE functionality + * @ice_mmio_data: contains ICE register mapping for i/o + * + * Performs two operations two enable ICE functionality. + * 1. Enable low power mode and optimization. + * 2. Wait for and check if BIST has completed. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_enable(const struct ice_mmio_data *mmio) +{ + qti_ice_low_power_and_optimization_enable(mmio); + return qti_ice_wait_bist_status(mmio); +} +EXPORT_SYMBOL_GPL(qti_ice_enable); + +/** + * qti_ice_resume() - Resume ICE functionality + * @ice_mmio_data: contains ICE register mapping for i/o + * + * This is called from storage controller after suspend. + * It must be ensured that BIST is complete before resuming. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_resume(const struct ice_mmio_data *mmio) +{ + return qti_ice_wait_bist_status(mmio); +} +EXPORT_SYMBOL_GPL(qti_ice_resume); + +/** + * qti_ice_keyslot_program() - Program a key to an ICE slot + * @ice_mmio_data: contains ICE register mapping for i/o + * @crypto_key: key to be program, this can be wrapped or raw + * @crypto_key_size: size of the key to be programmed + * @slot: the keyslot at which the key should be programmed. + * @data_unit_mask: mask for the dun which is part of the + * crypto configuration. + * @capid: capability index indicating the algorithm for the + * crypto configuration + * + * Program the passed in key to a slot in ICE. + * The key that is passed in can either be a raw key or wrapped. + * In both cases, due to access control of ICE for Qualcomm chipsets, + * a scm call is used to program the key into ICE from trustzone. + * Trustzone can differentiate between raw and wrapped keys. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, + const u8 *crypto_key, unsigned int crypto_key_size, + unsigned int slot, u8 data_unit_mask, int capid) +{ + int err = 0; + int i = 0; + union { + u8 bytes[QTI_AES_256_XTS_KEY_RAW_SIZE]; + u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)]; + } key; + + memcpy(key.bytes, crypto_key, crypto_key_size); + /* + * The SCM call byte-swaps the 32-bit words of the key. So we have to + * do the same, in order for the final key be correct. + */ + for (i = 0; i < ARRAY_SIZE(key.words); i++) + __cpu_to_be32s(&key.words[i]); + + err = qcom_scm_ice_set_key(slot, key.bytes, + QTI_AES_256_XTS_KEY_RAW_SIZE, + capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + + memzero_explicit(&key, sizeof(key)); + return err; +} +EXPORT_SYMBOL_GPL(qti_ice_keyslot_program); + +/** + * qti_ice_keyslot_evict() - Evict a key from a keyslot + * @slot: keyslot from which key needs to be evicted. + * + * Make a scm call into trustzone to evict an ICE key + * from its keyslot. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_keyslot_evict(unsigned int slot) +{ + return qcom_scm_ice_invalidate_key(slot); +} +EXPORT_SYMBOL_GPL(qti_ice_keyslot_evict); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h new file mode 100644 index 000000000000..582b73fd60fc --- /dev/null +++ b/drivers/soc/qcom/qti-ice-regs.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ +#define _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ + +#include + +/* QTI ICE Registers from SWI */ +#define QTI_ICE_REGS_CONTROL 0x0000 +#define QTI_ICE_REGS_RESET 0x0004 +#define QTI_ICE_REGS_VERSION 0x0008 +#define QTI_ICE_REGS_FUSE_SETTING 0x0010 +#define QTI_ICE_REGS_PARAMETERS_1 0x0014 +#define QTI_ICE_REGS_PARAMETERS_2 0x0018 +#define QTI_ICE_REGS_PARAMETERS_3 0x001C +#define QTI_ICE_REGS_PARAMETERS_4 0x0020 +#define QTI_ICE_REGS_PARAMETERS_5 0x0024 + +/* Register bits for ICE version */ +#define QTI_ICE_CORE_STEP_REV_MASK 0xFFFF +#define QTI_ICE_CORE_STEP_REV 0 /* bit 15-0 */ +#define QTI_ICE_CORE_MAJOR_REV_MASK 0xFF000000 +#define QTI_ICE_CORE_MAJOR_REV 24 /* bit 31-24 */ +#define QTI_ICE_CORE_MINOR_REV_MASK 0xFF0000 +#define QTI_ICE_CORE_MINOR_REV 16 /* bit 23-16 */ + +#define QTI_ICE_BIST_STATUS_MASK (0xF0000000) /* bits 28-31 */ + +#define QTI_ICE_FUSE_SETTING_MASK 0x1 +#define QTI_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 +#define QTI_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 + +/* QTI ICE v3.X only */ +#define QTI_ICE_INVALID_CCFG_ERR_STTS 0x0030 +#define QTI_ICE_GENERAL_ERR_STTS 0x0040 +#define QTI_ICE_GENERAL_ERR_MASK 0x0044 +#define QTI_ICE_REGS_NON_SEC_IRQ_CLR 0x0048 +#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050 +#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054 +#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME1 0x0058 +#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME2 0x005C +#define QTI_ICE_REGS_STREAM1_BIST_ERROR_VEC 0x0060 +#define QTI_ICE_REGS_STREAM2_BIST_ERROR_VEC 0x0064 +#define QTI_ICE_REGS_STREAM1_BIST_FINISH_VEC 0x0068 +#define QTI_ICE_REGS_STREAM2_BIST_FINISH_VEC 0x006C +#define QTI_ICE_REGS_BIST_STATUS 0x0070 +#define QTI_ICE_REGS_BYPASS_STATUS 0x0074 +#define QTI_ICE_REGS_ADVANCED_CONTROL 0x1000 +#define QTI_ICE_REGS_ENDIAN_SWAP 0x1004 +#define QTI_ICE_REGS_TEST_BUS_CONTROL 0x1010 +#define QTI_ICE_REGS_TEST_BUS_REG 0x1014 +#define QTI_ICE_REGS_STREAM1_COUNTERS1 0x1100 +#define QTI_ICE_REGS_STREAM1_COUNTERS2 0x1104 +#define QTI_ICE_REGS_STREAM1_COUNTERS3 0x1108 +#define QTI_ICE_REGS_STREAM1_COUNTERS4 0x110C +#define QTI_ICE_REGS_STREAM1_COUNTERS5_MSB 0x1110 +#define QTI_ICE_REGS_STREAM1_COUNTERS5_LSB 0x1114 +#define QTI_ICE_REGS_STREAM1_COUNTERS6_MSB 0x1118 +#define QTI_ICE_REGS_STREAM1_COUNTERS6_LSB 0x111C +#define QTI_ICE_REGS_STREAM1_COUNTERS7_MSB 0x1120 +#define QTI_ICE_REGS_STREAM1_COUNTERS7_LSB 0x1124 +#define QTI_ICE_REGS_STREAM1_COUNTERS8_MSB 0x1128 +#define QTI_ICE_REGS_STREAM1_COUNTERS8_LSB 0x112C +#define QTI_ICE_REGS_STREAM1_COUNTERS9_MSB 0x1130 +#define QTI_ICE_REGS_STREAM1_COUNTERS9_LSB 0x1134 +#define QTI_ICE_REGS_STREAM2_COUNTERS1 0x1200 +#define QTI_ICE_REGS_STREAM2_COUNTERS2 0x1204 +#define QTI_ICE_REGS_STREAM2_COUNTERS3 0x1208 +#define QTI_ICE_REGS_STREAM2_COUNTERS4 0x120C +#define QTI_ICE_REGS_STREAM2_COUNTERS5_MSB 0x1210 +#define QTI_ICE_REGS_STREAM2_COUNTERS5_LSB 0x1214 +#define QTI_ICE_REGS_STREAM2_COUNTERS6_MSB 0x1218 +#define QTI_ICE_REGS_STREAM2_COUNTERS6_LSB 0x121C +#define QTI_ICE_REGS_STREAM2_COUNTERS7_MSB 0x1220 +#define QTI_ICE_REGS_STREAM2_COUNTERS7_LSB 0x1224 +#define QTI_ICE_REGS_STREAM2_COUNTERS8_MSB 0x1228 +#define QTI_ICE_REGS_STREAM2_COUNTERS8_LSB 0x122C +#define QTI_ICE_REGS_STREAM2_COUNTERS9_MSB 0x1230 +#define QTI_ICE_REGS_STREAM2_COUNTERS9_LSB 0x1234 + +#define QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE (1L << 0) +#define QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE (1L << 1) +#define QTI_ICE_STREAM1_NOT_EXPECTED_LBO (1L << 2) +#define QTI_ICE_STREAM2_NOT_EXPECTED_LBO (1L << 3) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DUN (1L << 4) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DUN (1L << 5) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DUS (1L << 6) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DUS (1L << 7) +#define QTI_ICE_STREAM1_NOT_EXPECTED_DBO (1L << 8) +#define QTI_ICE_STREAM2_NOT_EXPECTED_DBO (1L << 9) +#define QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL (1L << 10) +#define QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL (1L << 11) +#define QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX (1L << 12) +#define QTI_ICE_STREAM2_NOT_EXPECTED_CONF_IDX (1L << 13) +#define QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS (1L << 14) +#define QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS (1L << 15) + +#define QTI_ICE_NON_SEC_IRQ_MASK \ + (QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE | \ + QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE | \ + QTI_ICE_STREAM1_NOT_EXPECTED_LBO | \ + QTI_ICE_STREAM2_NOT_EXPECTED_LBO | \ + QTI_ICE_STREAM1_NOT_EXPECTED_DUN | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DUN | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DUS | \ + QTI_ICE_STREAM1_NOT_EXPECTED_DBO | \ + QTI_ICE_STREAM2_NOT_EXPECTED_DBO | \ + QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL | \ + QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL | \ + QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\ + QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\ + QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS) + +/* QTI ICE registers from secure side */ +#define QTI_ICE_TEST_BUS_REG_SECURE_INTR (1L << 28) +#define QTI_ICE_TEST_BUS_REG_NON_SECURE_INTR (1L << 2) + +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 0x4040 +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_17 0x4044 +#define QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET 0x80 + +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_STTS 0x6200 +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_MASK 0x6204 +#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_CLR 0x6208 + +#define QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED (1L << 0) +#define QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED (1L << 1) +#define QTI_ICE_QTIC_DBG_OPEN_EVENT (1L << 30) +#define QTI_ICE_KEYS_RAM_RESET_COMPLETED (1L << 31) + +#define QTI_ICE_SEC_IRQ_MASK \ + (QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED |\ + QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED |\ + QTI_ICE_QTIC_DBG_OPEN_EVENT | \ + QTI_ICE_KEYS_RAM_RESET_COMPLETED) + +#define qti_ice_writel(mmio, val, reg) \ + writel_relaxed((val), mmio + (reg)) +#define qti_ice_readl(mmio, reg) \ + readl_relaxed(mmio + (reg)) + +#endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h new file mode 100644 index 000000000000..5a7c6fa99dc1 --- /dev/null +++ b/include/linux/qti-ice-common.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef _QTI_ICE_COMMON_H +#define _QTI_ICE_COMMON_H + +#include +#include + +struct ice_mmio_data { + void __iomem *ice_mmio; +}; + +int qti_ice_init(const struct ice_mmio_data *mmio); +int qti_ice_enable(const struct ice_mmio_data *mmio); +int qti_ice_resume(const struct ice_mmio_data *mmio); +int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, + const u8 *key, unsigned int key_size, + unsigned int slot, u8 data_unit_mask, int capid); +int qti_ice_keyslot_evict(unsigned int slot); + +#endif /* _QTI_ICE_COMMON_H */ From patchwork Mon Dec 6 22:57:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660417 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 18689C43217 for ; Mon, 6 Dec 2021 22:58:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376712AbhLFXC1 (ORCPT ); Mon, 6 Dec 2021 18:02:27 -0500 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:37432 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376698AbhLFXC0 (ORCPT ); Mon, 6 Dec 2021 18:02:26 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831537; x=1670367537; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=WGylPRUG0UYIpdxPi0FmgRwNxnArJ+vsqepiE4sU9QM=; b=aNeTaqqhsF4lInvqRQRcYuhe7m3IydKU2amQpwDBynwtep3GxH5V+e2B iVD4kgzgCno8jPhXIiP6G7R8AbgwsNUACDbGpXHflk4Tv3maYybXsRDDi JdDye8PftkHj/4XE42G7ZVkV22fPvfLA/ptBztB4Rni6VtEUy6RSRldRg o=; Received: from unknown (HELO ironmsg04-sd.qualcomm.com) ([10.53.140.144]) by alexa-out-sd-02.qualcomm.com with ESMTP; 06 Dec 2021 14:58:57 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg04-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:58:57 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:56 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:56 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library Date: Mon, 6 Dec 2021 14:57:17 -0800 Message-ID: <20211206225725.77512-3-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Remove the ICE support in UFS and use the shared library for crypto functionality. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/Kconfig | 1 + drivers/scsi/ufs/ufs-qcom-ice.c | 169 +++----------------------------- drivers/scsi/ufs/ufs-qcom.h | 3 +- 3 files changed, 15 insertions(+), 158 deletions(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 432df76e6318..622a4c3fbf70 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -101,6 +101,7 @@ config SCSI_UFS_QCOM tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM select QCOM_SCM if SCSI_UFS_CRYPTO + select QTI_ICE_COMMON if SCSI_UFS_CRYPTO select RESET_CONTROLLER help This selects the QCOM specific additions to UFSHCD platform driver. diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index bbb0ad7590ec..3826643bf537 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -8,90 +8,11 @@ #include #include +#include #include "ufshcd-crypto.h" #include "ufs-qcom.h" -#define AES_256_XTS_KEY_SIZE 64 - -/* QCOM ICE registers */ - -#define QCOM_ICE_REG_CONTROL 0x0000 -#define QCOM_ICE_REG_RESET 0x0004 -#define QCOM_ICE_REG_VERSION 0x0008 -#define QCOM_ICE_REG_FUSE_SETTING 0x0010 -#define QCOM_ICE_REG_PARAMETERS_1 0x0014 -#define QCOM_ICE_REG_PARAMETERS_2 0x0018 -#define QCOM_ICE_REG_PARAMETERS_3 0x001C -#define QCOM_ICE_REG_PARAMETERS_4 0x0020 -#define QCOM_ICE_REG_PARAMETERS_5 0x0024 - -/* QCOM ICE v3.X only */ -#define QCOM_ICE_GENERAL_ERR_STTS 0x0040 -#define QCOM_ICE_INVALID_CCFG_ERR_STTS 0x0030 -#define QCOM_ICE_GENERAL_ERR_MASK 0x0044 - -/* QCOM ICE v2.X only */ -#define QCOM_ICE_REG_NON_SEC_IRQ_STTS 0x0040 -#define QCOM_ICE_REG_NON_SEC_IRQ_MASK 0x0044 - -#define QCOM_ICE_REG_NON_SEC_IRQ_CLR 0x0048 -#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME1 0x0050 -#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME2 0x0054 -#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME1 0x0058 -#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME2 0x005C -#define QCOM_ICE_REG_STREAM1_BIST_ERROR_VEC 0x0060 -#define QCOM_ICE_REG_STREAM2_BIST_ERROR_VEC 0x0064 -#define QCOM_ICE_REG_STREAM1_BIST_FINISH_VEC 0x0068 -#define QCOM_ICE_REG_STREAM2_BIST_FINISH_VEC 0x006C -#define QCOM_ICE_REG_BIST_STATUS 0x0070 -#define QCOM_ICE_REG_BYPASS_STATUS 0x0074 -#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000 -#define QCOM_ICE_REG_ENDIAN_SWAP 0x1004 -#define QCOM_ICE_REG_TEST_BUS_CONTROL 0x1010 -#define QCOM_ICE_REG_TEST_BUS_REG 0x1014 - -/* BIST ("built-in self-test"?) status flags */ -#define QCOM_ICE_BIST_STATUS_MASK 0xF0000000 - -#define QCOM_ICE_FUSE_SETTING_MASK 0x1 -#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 -#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 - -#define qcom_ice_writel(host, val, reg) \ - writel((val), (host)->ice_mmio + (reg)) -#define qcom_ice_readl(host, reg) \ - readl((host)->ice_mmio + (reg)) - -static bool qcom_ice_supported(struct ufs_qcom_host *host) -{ - struct device *dev = host->hba->dev; - u32 regval = qcom_ice_readl(host, QCOM_ICE_REG_VERSION); - int major = regval >> 24; - int minor = (regval >> 16) & 0xFF; - int step = regval & 0xFFFF; - - /* For now this driver only supports ICE version 3. */ - if (major != 3) { - dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n", - major, minor, step); - return false; - } - - dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", - major, minor, step); - - /* If fuses are blown, ICE might not work in the standard way. */ - regval = qcom_ice_readl(host, QCOM_ICE_REG_FUSE_SETTING); - if (regval & (QCOM_ICE_FUSE_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK | - QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) { - dev_warn(dev, "Fuses are blown; ICE is unusable!\n"); - return false; - } - return true; -} - int ufs_qcom_ice_init(struct ufs_qcom_host *host) { struct ufs_hba *hba = host->hba; @@ -115,14 +36,14 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) goto disable; } - host->ice_mmio = devm_ioremap_resource(dev, res); - if (IS_ERR(host->ice_mmio)) { - err = PTR_ERR(host->ice_mmio); + host->ice_data.ice_mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(host->ice_data.ice_mmio)) { + err = PTR_ERR(host->ice_data.ice_mmio); dev_err(dev, "Failed to map ICE registers; err=%d\n", err); return err; } - if (!qcom_ice_supported(host)) + if (qti_ice_init(&host->ice_data)) goto disable; return 0; @@ -133,71 +54,21 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) return 0; } -static void qcom_ice_low_power_mode_enable(struct ufs_qcom_host *host) -{ - u32 regval; - - regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL); - /* - * Enable low power mode sequence - * [0]-0, [1]-0, [2]-0, [3]-E, [4]-0, [5]-0, [6]-0, [7]-0 - */ - regval |= 0x7000; - qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); -} - -static void qcom_ice_optimization_enable(struct ufs_qcom_host *host) -{ - u32 regval; - - /* ICE Optimizations Enable Sequence */ - regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL); - regval |= 0xD807100; - /* ICE HPG requires delay before writing */ - udelay(5); - qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL); - udelay(5); -} int ufs_qcom_ice_enable(struct ufs_qcom_host *host) { if (!(host->hba->caps & UFSHCD_CAP_CRYPTO)) return 0; - qcom_ice_low_power_mode_enable(host); - qcom_ice_optimization_enable(host); - return ufs_qcom_ice_resume(host); -} -/* Poll until all BIST bits are reset */ -static int qcom_ice_wait_bist_status(struct ufs_qcom_host *host) -{ - int count; - u32 reg; - - for (count = 0; count < 100; count++) { - reg = qcom_ice_readl(host, QCOM_ICE_REG_BIST_STATUS); - if (!(reg & QCOM_ICE_BIST_STATUS_MASK)) - break; - udelay(50); - } - if (reg) - return -ETIMEDOUT; - return 0; + return qti_ice_enable(&host->ice_data); } int ufs_qcom_ice_resume(struct ufs_qcom_host *host) { - int err; - if (!(host->hba->caps & UFSHCD_CAP_CRYPTO)) return 0; - err = qcom_ice_wait_bist_status(host); - if (err) { - dev_err(host->hba->dev, "BIST status error (%d)\n", err); - return err; - } - return 0; + return qti_ice_resume(&host->ice_data); } /* @@ -208,15 +79,10 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, const union ufs_crypto_cfg_entry *cfg, int slot) { union ufs_crypto_cap_entry cap; - union { - u8 bytes[AES_256_XTS_KEY_SIZE]; - u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; - } key; - int i; - int err; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE)) - return qcom_scm_ice_invalidate_key(slot); + return qti_ice_keyslot_evict(slot); /* Only AES-256-XTS has been tested so far. */ cap = hba->crypto_cap_array[cfg->crypto_cap_idx]; @@ -228,18 +94,7 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, return -EINVAL; } - memcpy(key.bytes, cfg->crypto_key, AES_256_XTS_KEY_SIZE); - - /* - * The SCM call byte-swaps the 32-bit words of the key. So we have to - * do the same, in order for the final key be correct. - */ - for (i = 0; i < ARRAY_SIZE(key.words); i++) - __cpu_to_be32s(&key.words[i]); - - err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, - QCOM_SCM_ICE_CIPHER_AES_256_XTS, - cfg->data_unit_size); - memzero_explicit(&key, sizeof(key)); - return err; + return qti_ice_keyslot_program(&host->ice_data, cfg->crypto_key, + UFS_CRYPTO_KEY_SIZE_256, slot, + cfg->data_unit_size, cfg->crypto_cap_idx); } diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 8208e3a3ef59..8efacc0d7888 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -7,6 +7,7 @@ #include #include +#include #define MAX_UFS_QCOM_HOSTS 1 #define MAX_U32 (~(u32)0) @@ -206,7 +207,7 @@ struct ufs_qcom_host { bool is_dev_ref_clk_enabled; struct ufs_hw_version hw_ver; #ifdef CONFIG_SCSI_UFS_CRYPTO - void __iomem *ice_mmio; + struct ice_mmio_data ice_data; #endif u32 dev_ref_clk_en_mask; From patchwork Mon Dec 6 22:57:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660419 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE20CC41535 for ; Mon, 6 Dec 2021 22:59:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376810AbhLFXC3 (ORCPT ); Mon, 6 Dec 2021 18:02:29 -0500 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:25266 "EHLO alexa-out-sd-01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376698AbhLFXC3 (ORCPT ); Mon, 6 Dec 2021 18:02:29 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831540; x=1670367540; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=ZtHeV/8nzFawIG2bxZRyAsVXm2z5YxzeubDnFvOQvm4=; b=YFxG1w9u3JRwd5X7fSBadRxnhWpcliA/nG58Dnle3GfdPdWvRxuNjz8n DS8+yoNvy/oH6k9BCXdWILO76tHZURWm/CIqZY6p/4Offd/0+Rc6ykPDT POJ+Ic+jmzmmgYos1EpzCqIQHvcXqdZP0CzSt7889h04Sle3xjzMVQuFG 4=; Received: from unknown (HELO ironmsg02-sd.qualcomm.com) ([10.53.140.142]) by alexa-out-sd-01.qualcomm.com with ESMTP; 06 Dec 2021 14:59:00 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg02-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:58:59 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:59 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:58:58 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 03/10] qcom_scm: scm call for deriving a software secret Date: Mon, 6 Dec 2021 14:57:18 -0800 Message-ID: <20211206225725.77512-4-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Storage encryption requires fscrypt deriving a sw secret from the keys inserted into the linux keyring. For non-wrapped keys, this can be directly done as keys are in the clear. However, when keys are hardware wrapped, it can be unwrapped by HWKM which is accessible only from Qualcomm Trustzone. Hence, it also makes sense that the software secret is also derived there and returned to the linux kernel for wrapped keys. This can be invoked by using the crypto profile APIs provided by the block layer. Signed-off-by: Gaurav Kashyap --- drivers/firmware/qcom_scm.c | 73 +++++++++++++++++++++++++++++++++++++ drivers/firmware/qcom_scm.h | 1 + include/linux/qcom_scm.h | 6 +++ 3 files changed, 80 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 2ee97bab7440..4a7703846788 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1062,6 +1062,79 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, } EXPORT_SYMBOL(qcom_scm_ice_set_key); +/** + * qcom_scm_derive_sw_secret() - Derive SW secret from wrapped encryption key + * @wrapped_key: the wrapped key used for inline encryption + * @wrapped_key_size: size of the wrapped key + * @sw_secret: the secret to be derived which is at most the secret size + * @secret_size: maximum size of the secret that is derived + * + * Derive a SW secret to be used for inline encryption using Qualcomm ICE. + * + * For wrapped keys, the key needs to be unwrapped, in order to derive a + * SW secret, which can be done only by the secure EE. So, it makes sense + * for the secure EE to derive the sw secret and return to the kernel when + * wrapped keys are used. + * + * For more information on sw secret, please refer to "Hardware-wrapped keys" + * section of Documentation/block/inline-encryption.rst. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size, + u8 *sw_secret, u32 secret_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_DERIVE_SW_SECRET, + .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, + QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL), + .args[1] = wrapped_key_size, + .args[3] = secret_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + void *keybuf, *secretbuf; + dma_addr_t key_phys, secret_phys; + int ret; + + /* + * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly + * get a physical address, while guaranteeing that we can zeroize the + * key material later using memzero_explicit(). + * + */ + keybuf = dma_alloc_coherent(__scm->dev, wrapped_key_size, &key_phys, + GFP_KERNEL); + if (!keybuf) + return -ENOMEM; + secretbuf = dma_alloc_coherent(__scm->dev, secret_size, &secret_phys, + GFP_KERNEL); + if (!secretbuf) { + ret = -ENOMEM; + goto bail_keybuf; + } + + memcpy(keybuf, wrapped_key, wrapped_key_size); + desc.args[0] = key_phys; + desc.args[2] = secret_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + if (!ret) + memcpy(sw_secret, secretbuf, secret_size); + + memzero_explicit(secretbuf, secret_size); + dma_free_coherent(__scm->dev, secret_size, secretbuf, secret_phys); + +bail_keybuf: + memzero_explicit(keybuf, wrapped_key_size); + dma_free_coherent(__scm->dev, wrapped_key_size, keybuf, key_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_derive_sw_secret); + /** * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. * diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index d92156ceb3ac..08bb2a4c80db 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -110,6 +110,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */ #define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03 #define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04 +#define QCOM_SCM_ES_DERIVE_SW_SECRET 0x07 #define QCOM_SCM_SVC_HDCP 0x11 #define QCOM_SCM_HDCP_INVOKE 0x01 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index c0475d1c9885..ccd764bdc357 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -103,6 +103,9 @@ extern int qcom_scm_ice_invalidate_key(u32 index); extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, enum qcom_scm_ice_cipher cipher, u32 data_unit_size); +extern int qcom_scm_derive_sw_secret(const u8 *wrapped_key, + u32 wrapped_key_size, u8 *sw_secret, + u32 secret_size); extern bool qcom_scm_hdcp_available(void); extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, @@ -169,6 +172,9 @@ static inline int qcom_scm_ice_invalidate_key(u32 index) { return -ENODEV; } static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, enum qcom_scm_ice_cipher cipher, u32 data_unit_size) { return -ENODEV; } +static inline int qcom_scm_derive_sw_secret(const u8 *wrapped_key, + u32 wrapped_key_size, u8 *sw_secret, + u32 secret_size) { return -ENODEV; } static inline bool qcom_scm_hdcp_available(void) { return false; } static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, From patchwork Mon Dec 6 22:57:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660421 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A164BC2BA80 for ; Mon, 6 Dec 2021 22:59:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376907AbhLFXCb (ORCPT ); Mon, 6 Dec 2021 18:02:31 -0500 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:37432 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376698AbhLFXCa (ORCPT ); Mon, 6 Dec 2021 18:02:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831541; x=1670367541; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=ALRFuY7so6mPcA8kT5aKmUe7cZ+s4fYanplfvm5bsRs=; b=u/CmK6ZkkbWxxzKaLpHnv0TsbvgNyXumUhbuOwPnE97Y8aef/yPzO1Pk kgA9Mi3DU63zWwevsdlYRMWBzoGF0iSrmHVe5DdrDTxhp8nh/NDWExeko rIDoSK7NxyO4Mj18b9VLqs/YLvPd+4jCjoRkx5m/qAT7OLO+V4SZ5yf/F g=; Received: from unknown (HELO ironmsg01-sd.qualcomm.com) ([10.53.140.141]) by alexa-out-sd-02.qualcomm.com with ESMTP; 06 Dec 2021 14:59:01 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg01-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:01 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:01 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:00 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 04/10] soc: qcom: add HWKM library for storage encryption Date: Mon, 6 Dec 2021 14:57:19 -0800 Message-ID: <20211206225725.77512-5-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Wrapped keys should utilize hardware to protect the keys used for storage encryption. Qualcomm's Inline Crypto Engine supports a hardware block called Hardware Key Manager (HWKM) for key management. Although most of the interactions to this hardware block happens via a secure execution environment, some initializations for the slave present in ICE can be done from the kernel. This can also be a placeholder for when the hardware provides more capabilities to be accessed from the linux kernel in the future. Signed-off-by: Gaurav Kashyap --- drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/qti-ice-hwkm.c | 111 +++++++++++++++++++++++++++++ drivers/soc/qcom/qti-ice-regs.h | 119 ++++++++++++++++++++++++++++++++ include/linux/qti-ice-common.h | 1 + 4 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 57840b19b7ee..e73fefb4f533 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -26,4 +26,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o -obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o +obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o qti-ice-hwkm.o diff --git a/drivers/soc/qcom/qti-ice-hwkm.c b/drivers/soc/qcom/qti-ice-hwkm.c new file mode 100644 index 000000000000..3be6b350cd88 --- /dev/null +++ b/drivers/soc/qcom/qti-ice-hwkm.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * HWKM ICE library for storage encryption. + * + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved. + */ + +#include +#include "qti-ice-regs.h" + +static int qti_ice_hwkm_bist_status(const struct ice_mmio_data *mmio, int version) +{ + if (!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BIST_DONE_V1 : BIST_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? CRYPTO_LIB_BIST_DONE_V1 : + CRYPTO_LIB_BIST_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BOOT_CMD_LIST1_DONE_V1 : + BOOT_CMD_LIST1_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? BOOT_CMD_LIST0_DONE_V1 : + BOOT_CMD_LIST0_DONE_V2) || + !qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + (version == 1) ? KT_CLEAR_DONE_V1 : + KT_CLEAR_DONE_V2)) + return -EINVAL; + return 0; +} + +static void qti_ice_hwkm_configure_ice_registers( + const struct ice_mmio_data *mmio) +{ + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0); + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1); + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2); + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3); + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4); +} + +static int qti_ice_hwkm_init_sequence(const struct ice_mmio_data *mmio, + int version) +{ + u32 val = 0; + + /* + * Put ICE in standard mode, ICE defaults to legacy mode. + * Legacy mode - ICE HWKM slave not supported. + * Standard mode - ICE HWKM slave supported. + * + * Depending on the version of HWKM, it is controlled by different + * registers in ICE. + */ + if (version >= 2) { + val = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_CONTROL); + val = val & 0xFFFFFFFE; + qti_ice_writel(mmio->ice_mmio, val, QTI_ICE_REGS_CONTROL); + } else { + qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0x7, + QTI_HWKM_ICE_RG_TZ_KM_CTL); + } + + /* Check BIST status */ + if (qti_ice_hwkm_bist_status(mmio, version)) + return -EINVAL; + + /* + * Give register bank of the HWKM slave access to read and modify + * the keyslots in ICE HWKM slave. Without this, trustzone will not + * be able to program keys into ICE. + */ + qti_ice_hwkm_configure_ice_registers(mmio); + + /* Disable CRC check */ + qti_ice_hwkm_clearb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_CTL, + CRC_CHECK_EN); + + /* Set RSP_FIFO_FULL bit */ + qti_ice_hwkm_setb(mmio->ice_hwkm_mmio, + QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, RSP_FIFO_FULL); + + return 0; +} + +/** + * qti_ice_hwkm_init() - Initialize ICE HWKM hardware + * @ice_mmio_data: contains ICE register mapping for i/o + * @version: version of hwkm hardware + * + * Perform HWKM initialization in the ICE slave by going + * through the slave initialization routine.The registers + * can vary slightly based on the version. + * + * Return: 0 on success; err on failure. + */ + +int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version) +{ + if (!mmio->ice_hwkm_mmio) + return -EINVAL; + + return qti_ice_hwkm_init_sequence(mmio, version); +} +EXPORT_SYMBOL_GPL(qti_ice_hwkm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h index 582b73fd60fc..256c6feb9072 100644 --- a/drivers/soc/qcom/qti-ice-regs.h +++ b/drivers/soc/qcom/qti-ice-regs.h @@ -137,9 +137,128 @@ QTI_ICE_QTIC_DBG_OPEN_EVENT | \ QTI_ICE_KEYS_RAM_RESET_COMPLETED) +/* Read/write macros for ICE address space */ #define qti_ice_writel(mmio, val, reg) \ writel_relaxed((val), mmio + (reg)) #define qti_ice_readl(mmio, reg) \ readl_relaxed(mmio + (reg)) +/* Registers for ICE HWKM Slave */ + +#define HWKM_VERSION_STEP_REV_MASK 0xFFFF +#define HWKM_VERSION_STEP_REV 0 /* bit 15-0 */ +#define HWKM_VERSION_MAJOR_REV_MASK 0xFF000000 +#define HWKM_VERSION_MAJOR_REV 24 /* bit 31-24 */ +#define HWKM_VERSION_MINOR_REV_MASK 0xFF0000 +#define HWKM_VERSION_MINOR_REV 16 /* bit 23-16 */ + +/* QTI HWKM ICE slave config and status registers */ + +#define QTI_HWKM_ICE_RG_IPCAT_VERSION 0x0000 +#define QTI_HWKM_ICE_RG_KEY_POLICY_VERSION 0x0004 +#define QTI_HWKM_ICE_RG_SHARED_STATUS 0x0008 +#define QTI_HWKM_ICE_RG_KEYTABLE_SIZE 0x000C + +#define QTI_HWKM_ICE_RG_TZ_KM_CTL 0x1000 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS 0x1004 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS_IRQ_MASK 0x1008 +#define QTI_HWKM_ICE_RG_TZ_KM_BOOT_STAGE_OTP 0x100C +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_CTL 0x1010 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_WRITE 0x1014 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_READ 0x1018 +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL 0x101C +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS 0x1020 +#define QTI_HWKM_ICE_RG_TZ_KM_COMMON_IRQ_ROUTING 0x1024 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_CTL */ +#define CRC_CHECK_EN 0 +#define KEYTABLE_HW_WR_ACCESS_EN 1 +#define KEYTABLE_HW_RD_ACCESS_EN 2 +#define BOOT_INIT0_DISABLE 3 +#define BOOT_INIT1_DISABLE 4 +#define ICE_LEGACY_MODE_EN_OTP 5 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v2 and above*/ +#define KT_CLEAR_DONE_V2 0 +#define BOOT_CMD_LIST0_DONE_V2 1 +#define BOOT_CMD_LIST1_DONE_V2 2 +#define LAST_ACTIVITY_BANK_V2 3 +#define CRYPTO_LIB_BIST_ERROR_V2 6 +#define CRYPTO_LIB_BIST_DONE_V2 7 +#define BIST_ERROR_V2 8 +#define BIST_DONE_V2 9 +#define LAST_ACTIVITY_BANK_MASK_V2 0x38 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v1*/ +#define KT_CLEAR_DONE_V1 0 +#define BOOT_CMD_LIST0_DONE_V1 1 +#define BOOT_CMD_LIST1_DONE_V1 2 +#define KEYTABLE_KEY_POLICY_V1 3 +#define KEYTABLE_INTEGRITY_ERROR_V1 4 +#define KEYTABLE_KEY_SLOT_ERROR_V1 5 +#define KEYTABLE_KEY_SLOT_NOT_EVEN_ERROR_V1 6 +#define KEYTABLE_KEY_SLOT_OUT_OF_RANGE_V1 7 +#define KEYTABLE_KEY_SIZE_ERROR_V1 8 +#define KEYTABLE_OPERATION_ERROR_V1 9 +#define LAST_ACTIVITY_BANK_V1 10 +#define CRYPTO_LIB_BIST_ERROR_V1 13 +#define CRYPTO_LIB_BIST_DONE_V1 14 +#define BIST_ERROR_V1 15 +#define BIST_DONE_V1 16 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_TPKEY_RECEIVE_CTL */ +#define TPKEY_EN 8 + +/* QTI HWKM ICE slave register bank 0 */ +#define QTI_HWKM_ICE_RG_BANK0_BANKN_CTL 0x2000 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS 0x2004 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS 0x2008 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_MASK 0x200C +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR 0x2010 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR_IRQ_MASK 0x2014 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESYNR 0x2018 + +/* QTI HWKM access control registers for Bank 0 */ +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0 0x5000 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1 0x5004 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2 0x5008 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3 0x500C +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4 0x5010 + +/* QTI_HWKM_ICE_RG_BANKN_IRQ_STATUS */ +#define ARB_GRAN_WINNER 0 +#define CMD_DONE_BIT 1 +#define RSP_FIFO_NOT_EMPTY 2 +#define RSP_FIFO_FULL 3 +#define RSP_FIFO_UNDERFLOW 4 +#define CMD_FIFO_UNDERFLOW 5 + +/* Read/write macros for ICE HWKM address space */ + +#define qti_ice_hwkm_readl(hwkm_mmio, reg) \ + (readl_relaxed(hwkm_mmio + (reg))) +#define qti_ice_hwkm_writel(hwkm_mmio, val, reg) \ + (writel_relaxed((val), hwkm_mmio + (reg))) +#define qti_ice_hwkm_setb(hwkm_mmio, reg, nr) { \ + u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg); \ + val |= (0x1 << nr); \ + qti_ice_hwkm_writel(hwkm_mmio, val, reg); \ +} +#define qti_ice_hwkm_clearb(hwkm_mmio, reg, nr) { \ + u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg); \ + val &= ~(0x1 << nr); \ + qti_ice_hwkm_writel(hwkm_mmio, val, reg); \ +} + +static inline bool qti_ice_hwkm_testb(void __iomem *ice_hwkm_mmio, + u32 reg, u8 nr) +{ + u32 val = qti_ice_hwkm_readl(ice_hwkm_mmio, reg); + + val = (val >> nr) & 0x1; + if (val == 0) + return false; + return true; +} + #endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h index 5a7c6fa99dc1..51dfe3c12092 100644 --- a/include/linux/qti-ice-common.h +++ b/include/linux/qti-ice-common.h @@ -20,5 +20,6 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, const u8 *key, unsigned int key_size, unsigned int slot, u8 data_unit_mask, int capid); int qti_ice_keyslot_evict(unsigned int slot); +int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version); #endif /* _QTI_ICE_COMMON_H */ From patchwork Mon Dec 6 22:57:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660423 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 98FD1C4332F for ; Mon, 6 Dec 2021 22:59:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376958AbhLFXCe (ORCPT ); Mon, 6 Dec 2021 18:02:34 -0500 Received: from alexa-out.qualcomm.com ([129.46.98.28]:36329 "EHLO alexa-out.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376873AbhLFXCc (ORCPT ); Mon, 6 Dec 2021 18:02:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831544; x=1670367544; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=9qedNGE1JEVmN4kcgOxpqxc9N60VuBMS8Us4NYfi29c=; b=C4zFofd3AowluFztbb18k3W36LPYpFma5cnGx6TgCP7FpTBsTyS9yVlV GvCJVSbX4+bgEIPZjbwyDYSL6NsY5vGhRKFm75G0BfEB8dKt5Iezl7NXA Qj7O1kHbAWaQu52v4zY+QqIopjCrhiAXWiAahhmZRTIW9yhm3K+/CxYP1 Q=; Received: from ironmsg-lv-alpha.qualcomm.com ([10.47.202.13]) by alexa-out.qualcomm.com with ESMTP; 06 Dec 2021 14:59:03 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg-lv-alpha.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:03 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:02 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:02 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 05/10] scsi: ufs: prepare to support wrapped keys Date: Mon, 6 Dec 2021 14:57:20 -0800 Message-ID: <20211206225725.77512-6-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Adds support in ufshcd-core for wrapped keys. 1. Change program key vop to support wrapped key sizes by using blk_crypto_key directly instead of using ufs_crypto_cfg which is not suitable for wrapped keys. 2. Add derive_sw_secret vop and derive_sw_secret crypto_profile op. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufshcd-crypto.c | 52 +++++++++++++++++++++++++------- drivers/scsi/ufs/ufshcd.h | 9 +++++- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index 0ed82741f981..9d68621a0eb4 100644 --- a/drivers/scsi/ufs/ufshcd-crypto.c +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -18,16 +18,23 @@ static const struct ufs_crypto_alg_entry { }; static int ufshcd_program_key(struct ufs_hba *hba, + const struct blk_crypto_key *key, const union ufs_crypto_cfg_entry *cfg, int slot) { int i; u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg); int err = 0; + bool evict = false; ufshcd_hold(hba, false); if (hba->vops && hba->vops->program_key) { - err = hba->vops->program_key(hba, cfg, slot); + if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE)) + evict = true; + err = hba->vops->program_key(hba, key, slot, + cfg->data_unit_size, + cfg->crypto_cap_idx, + evict); goto out; } @@ -80,16 +87,18 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile, cfg.crypto_cap_idx = cap_idx; cfg.config_enable = UFS_CRYPTO_CONFIGURATION_ENABLE; - if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) { - /* In XTS mode, the blk_crypto_key's size is already doubled */ - memcpy(cfg.crypto_key, key->raw, key->size/2); - memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, - key->raw + key->size/2, key->size/2); - } else { - memcpy(cfg.crypto_key, key->raw, key->size); + if (key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) { + if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) { + /* In XTS mode, the blk_crypto_key's size is already doubled */ + memcpy(cfg.crypto_key, key->raw, key->size/2); + memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2, + key->raw + key->size/2, key->size/2); + } else { + memcpy(cfg.crypto_key, key->raw, key->size); + } } - err = ufshcd_program_key(hba, &cfg, slot); + err = ufshcd_program_key(hba, key, &cfg, slot); memzero_explicit(&cfg, sizeof(cfg)); return err; @@ -103,7 +112,7 @@ static int ufshcd_clear_keyslot(struct ufs_hba *hba, int slot) */ union ufs_crypto_cfg_entry cfg = {}; - return ufshcd_program_key(hba, &cfg, slot); + return ufshcd_program_key(hba, NULL, &cfg, slot); } static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile, @@ -126,9 +135,25 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba) return true; } +static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + struct ufs_hba *hba = + container_of(profile, struct ufs_hba, crypto_profile); + + if (hba->vops && hba->vops->derive_secret) + return hba->vops->derive_secret(hba, wrapped_key, + wrapped_key_size, sw_secret); + + return -EOPNOTSUPP; +} + static const struct blk_crypto_ll_ops ufshcd_crypto_ops = { .keyslot_program = ufshcd_crypto_keyslot_program, .keyslot_evict = ufshcd_crypto_keyslot_evict, + .derive_sw_secret = ufshcd_crypto_derive_sw_secret, }; static enum blk_crypto_mode_num @@ -190,7 +215,12 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba) hba->crypto_profile.ll_ops = ufshcd_crypto_ops; /* UFS only supports 8 bytes for any DUN */ hba->crypto_profile.max_dun_bytes_supported = 8; - hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD; + if (hba->hw_wrapped_keys_supported) + hba->crypto_profile.key_types_supported = + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED; + else + hba->crypto_profile.key_types_supported = + BLK_CRYPTO_KEY_TYPE_STANDARD; hba->crypto_profile.dev = hba->dev; /* diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index df5439b12208..095c2d660aa7 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -320,6 +320,7 @@ struct ufs_pwr_mode_info { * @device_reset: called to issue a reset pulse on the UFS device * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events + * @derive_secret: derive sw secret from wrapped inline encryption key */ struct ufs_hba_variant_ops { const char *name; @@ -353,9 +354,14 @@ struct ufs_hba_variant_ops { struct devfreq_dev_profile *profile, void *data); int (*program_key)(struct ufs_hba *hba, - const union ufs_crypto_cfg_entry *cfg, int slot); + const struct blk_crypto_key *crypto_key, + int slot, u8 data_unit_size, int capid, + bool evict); void (*event_notify)(struct ufs_hba *hba, enum ufs_event_type evt, void *data); + int (*derive_secret)(struct ufs_hba *hba, const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); }; /* clock gating state */ @@ -906,6 +912,7 @@ struct ufs_hba { union ufs_crypto_cap_entry *crypto_cap_array; u32 crypto_cfg_register; struct blk_crypto_profile crypto_profile; + bool hw_wrapped_keys_supported; #endif #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; From patchwork Mon Dec 6 22:57:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660425 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A499C4332F for ; Mon, 6 Dec 2021 22:59:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376991AbhLFXCp (ORCPT ); Mon, 6 Dec 2021 18:02:45 -0500 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:34326 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377028AbhLFXCg (ORCPT ); Mon, 6 Dec 2021 18:02:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831547; x=1670367547; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=3DbJocESiVT640e7qeul3nWqq5xIH+alIHva07yq8SU=; b=dzU9EX4+OuctoSqrvwEeRnlK0ARu/6R/VuuikmCNy500gZp6qFa9+vtW LmVOAGj86lQ8zs1PtziYXd+G7JguQBd9RZLayUx6C2eXqnjk5HlyComi5 0Cw0y3FF65Ie16tWxdBQRMMwwL+30EX8dTCQLijFYtCDmQZjXn380JiLL Y=; Received: from unknown (HELO ironmsg02-sd.qualcomm.com) ([10.53.140.142]) by alexa-out-sd-02.qualcomm.com with ESMTP; 06 Dec 2021 14:59:07 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg02-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:07 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:07 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:06 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 06/10] soc: qcom: add wrapped key support for ICE Date: Mon, 6 Dec 2021 14:57:21 -0800 Message-ID: <20211206225725.77512-7-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Add support for wrapped keys in ufs and common ICE library. Qualcomm's ICE solution uses a hardware block called Hardware Key Manager (HWKM) to handle wrapped keys. This patch adds the following changes to support this. 1. Link to HWKM library for initialization. 2. Most of the key management is done from Trustzone via scm calls. Added calls to this from the ICE library. 3. Added support for this framework in ufs qcom. 4. Added support for deriving SW secret as it cannot be done in linux kernel for wrapped keys. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufs-qcom-ice.c | 48 +++++++-- drivers/scsi/ufs/ufs-qcom.c | 1 + drivers/scsi/ufs/ufs-qcom.h | 7 +- drivers/soc/qcom/qti-ice-common.c | 158 +++++++++++++++++++++++++++--- include/linux/qti-ice-common.h | 11 ++- 5 files changed, 198 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 3826643bf537..c8305aab6714 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -43,6 +43,24 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) return err; } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm"); + if (!res) { + dev_warn(dev, "ICE HWKM registers not found\n"); + host->ice_data.hw_wrapped_keys_supported = false; + goto init; + } + + host->ice_data.ice_hwkm_mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(host->ice_data.ice_hwkm_mmio)) { + err = PTR_ERR(host->ice_data.ice_hwkm_mmio); + dev_err(dev, "Failed to map HWKM registers; err=%d\n", err); + return err; + } + host->ice_data.hw_wrapped_keys_supported = true; + +init: + hba->hw_wrapped_keys_supported = + host->ice_data.hw_wrapped_keys_supported; if (qti_ice_init(&host->ice_data)) goto disable; @@ -54,7 +72,6 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host) return 0; } - int ufs_qcom_ice_enable(struct ufs_qcom_host *host) { if (!(host->hba->caps & UFSHCD_CAP_CRYPTO)) @@ -76,16 +93,17 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *host) * vendor-specific SCM calls for this; it doesn't support the standard way. */ int ufs_qcom_ice_program_key(struct ufs_hba *hba, - const union ufs_crypto_cfg_entry *cfg, int slot) + const struct blk_crypto_key *key, int slot, + u8 data_unit_size, int capid, bool evict) { union ufs_crypto_cap_entry cap; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE)) - return qti_ice_keyslot_evict(slot); + if (evict) + return qti_ice_keyslot_evict(&host->ice_data, slot); /* Only AES-256-XTS has been tested so far. */ - cap = hba->crypto_cap_array[cfg->crypto_cap_idx]; + cap = hba->crypto_cap_array[capid]; if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS || cap.key_size != UFS_CRYPTO_KEY_SIZE_256) { dev_err_ratelimited(hba->dev, @@ -94,7 +112,21 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, return -EINVAL; } - return qti_ice_keyslot_program(&host->ice_data, cfg->crypto_key, - UFS_CRYPTO_KEY_SIZE_256, slot, - cfg->data_unit_size, cfg->crypto_cap_idx); + return qti_ice_keyslot_program(&host->ice_data, key, slot, + data_unit_size, capid); +} + +/* + * Derive a SW secret from the wrapped key to be used in fscrypt. The key + * is unwrapped in QTI and a SW key is then derived. + */ +int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + return qti_ice_derive_sw_secret(&host->ice_data, + wrapped_key, wrapped_key_size, + sw_secret); } diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 9d9770f1db4f..9f85332fbe64 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1495,6 +1495,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .device_reset = ufs_qcom_device_reset, .config_scaling_param = ufs_qcom_config_scaling_param, .program_key = ufs_qcom_ice_program_key, + .derive_secret = ufs_qcom_ice_derive_sw_secret, }; /** diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 8efacc0d7888..e7da3d1dc3c7 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -253,7 +253,12 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host); int ufs_qcom_ice_enable(struct ufs_qcom_host *host); int ufs_qcom_ice_resume(struct ufs_qcom_host *host); int ufs_qcom_ice_program_key(struct ufs_hba *hba, - const union ufs_crypto_cfg_entry *cfg, int slot); + const struct blk_crypto_key *key, + int slot, u8 data_unit_size, int capid, + bool evict); +int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); #else static inline int ufs_qcom_ice_init(struct ufs_qcom_host *host) { diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c index 0c5b529201c5..76703afa4834 100644 --- a/drivers/soc/qcom/qti-ice-common.c +++ b/drivers/soc/qcom/qti-ice-common.c @@ -14,6 +14,23 @@ #define QTI_ICE_MAX_BIST_CHECK_COUNT 100 #define QTI_AES_256_XTS_KEY_RAW_SIZE 64 +/* + * ICE resets during power collapse and HWKM has to be + * reconfigured which can be kept track with this flag. + */ +static bool qti_hwkm_init_done; +static int hwkm_version; + +union crypto_cfg { + __le32 regval; + struct { + u8 dusize; + u8 capidx; + u8 reserved; + u8 cfge; + }; +}; + static bool qti_ice_supported(const struct ice_mmio_data *mmio) { u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION); @@ -28,6 +45,11 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio) return false; } + if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1))) + hwkm_version = 2; + else + hwkm_version = 1; + pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", major, minor, step); @@ -131,6 +153,58 @@ int qti_ice_resume(const struct ice_mmio_data *mmio) } EXPORT_SYMBOL_GPL(qti_ice_resume); +static int qti_ice_program_wrapped_key(const struct ice_mmio_data *mmio, + const struct blk_crypto_key *crypto_key, + unsigned int slot, u8 data_unit_mask, + int capid) +{ + int err = 0; + union crypto_cfg cfg; + + /* + * HWKM slave in ICE should be initialized before the first + * time we perform ICE HWKM related operations. This is because + * ICE by default comes up in legacy mode where HWKM operations + * won't work. + */ + if (!qti_hwkm_init_done) { + err = qti_ice_hwkm_init(mmio, hwkm_version); + if (err) { + pr_err("%s: Error initializing hwkm, err = %d", + __func__, err); + return -EINVAL; + } + qti_hwkm_init_done = true; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.dusize = data_unit_mask; + cfg.capidx = capid; + cfg.cfge = 0x80; + + /* Make sure CFGE is cleared */ + qti_ice_writel(mmio->ice_mmio, 0x0, (QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 + + QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot)); + /* Memory barrier - to ensure write completion before next transaction */ + wmb(); + + /* Call trustzone to program the wrapped key using hwkm */ + err = qcom_scm_ice_set_key(slot, crypto_key->raw, crypto_key->size, + capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + + /* Make sure CFGE is enabled after programming the key */ + qti_ice_writel(mmio->ice_mmio, cfg.regval, + (QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 + + QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot)); + /* Memory barrier - to ensure write completion before next transaction */ + wmb(); + + return err; +} + /** * qti_ice_keyslot_program() - Program a key to an ICE slot * @ice_mmio_data: contains ICE register mapping for i/o @@ -151,7 +225,7 @@ EXPORT_SYMBOL_GPL(qti_ice_resume); * Return: 0 on success; err on failure. */ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, - const u8 *crypto_key, unsigned int crypto_key_size, + const struct blk_crypto_key *crypto_key, unsigned int slot, u8 data_unit_mask, int capid) { int err = 0; @@ -161,22 +235,28 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)]; } key; - memcpy(key.bytes, crypto_key, crypto_key_size); - /* - * The SCM call byte-swaps the 32-bit words of the key. So we have to - * do the same, in order for the final key be correct. - */ - for (i = 0; i < ARRAY_SIZE(key.words); i++) - __cpu_to_be32s(&key.words[i]); + if (crypto_key->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) { + if (!mmio->hw_wrapped_keys_supported) + return -EINVAL; + err = qti_ice_program_wrapped_key(mmio, crypto_key, slot, + data_unit_mask, capid); + } else { + memcpy(key.bytes, crypto_key->raw, crypto_key->size); + /* + * The SCM call byte-swaps the 32-bit words of the key. So we have to + * do the same, in order for the final key be correct. + */ + for (i = 0; i < ARRAY_SIZE(key.words); i++) + __cpu_to_be32s(&key.words[i]); - err = qcom_scm_ice_set_key(slot, key.bytes, - QTI_AES_256_XTS_KEY_RAW_SIZE, - capid, data_unit_mask); - if (err) - pr_err("%s:SCM call Error: 0x%x slot %d\n", - __func__, err, slot); + err = qcom_scm_ice_set_key(slot, key.bytes, + QTI_AES_256_XTS_KEY_RAW_SIZE, capid, data_unit_mask); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + memzero_explicit(&key, sizeof(key)); + } - memzero_explicit(&key, sizeof(key)); return err; } EXPORT_SYMBOL_GPL(qti_ice_keyslot_program); @@ -190,10 +270,56 @@ EXPORT_SYMBOL_GPL(qti_ice_keyslot_program); * * Return: 0 on success; err on failure. */ -int qti_ice_keyslot_evict(unsigned int slot) +int qti_ice_keyslot_evict(const struct ice_mmio_data *mmio, unsigned int slot) { + /* + * Ignore calls to evict key when wrapped keys are supported and + * hwkm init is not yet done. This is to avoid the clearing all slots + * call that comes from ufs during ufs reset. HWKM slave in ICE takes + * care of zeroing out the keytable on reset. + */ + if (mmio->hw_wrapped_keys_supported && !qti_hwkm_init_done) + return 0; return qcom_scm_ice_invalidate_key(slot); } EXPORT_SYMBOL_GPL(qti_ice_keyslot_evict); +/** + * qti_ice_derive_sw_secret() - Derive SW secret from wrapped key + * @wrapped_key: wrapped key from which secret should be derived + * @wrapped_key_size: size of the wrapped key + * @sw_secret: secret to be returned, which is atmost BLK_CRYPTO_SW_SECRET_SIZE + * + * Make a scm call into trustzone to derive a sw secret from the + * given wrapped key. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) +{ + int err = 0; + + /* + * HWKM slave in ICE should be initialized before the first + * time we perform ICE HWKM related operations. This is because + * ICE by default comes up in legacy mode where HWKM operations + * won't work. + */ + if (!qti_hwkm_init_done) { + err = qti_ice_hwkm_init(mmio, qti_hwkm_version); + if (err) { + pr_err("%s: Error initializing hwkm, err = %d", + __func__, err); + return -EINVAL; + } + qti_hwkm_init_done = true; + } + return qcom_scm_derive_sw_secret(wrapped_key, wrapped_key_size, + sw_secret, BLK_CRYPTO_SW_SECRET_SIZE); +} +EXPORT_SYMBOL_GPL(qti_ice_derive_sw_secret); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h index 51dfe3c12092..e329afeba113 100644 --- a/include/linux/qti-ice-common.h +++ b/include/linux/qti-ice-common.h @@ -8,18 +8,25 @@ #include #include +#include struct ice_mmio_data { void __iomem *ice_mmio; + void __iomem *ice_hwkm_mmio; + bool hw_wrapped_keys_supported; }; int qti_ice_init(const struct ice_mmio_data *mmio); int qti_ice_enable(const struct ice_mmio_data *mmio); int qti_ice_resume(const struct ice_mmio_data *mmio); int qti_ice_keyslot_program(const struct ice_mmio_data *mmio, - const u8 *key, unsigned int key_size, + const struct blk_crypto_key *crypto_key, unsigned int slot, u8 data_unit_mask, int capid); -int qti_ice_keyslot_evict(unsigned int slot); +int qti_ice_keyslot_evict(const struct ice_mmio_data *mmio, unsigned int slot); int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version); +int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); #endif /* _QTI_ICE_COMMON_H */ From patchwork Mon Dec 6 22:57:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660427 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5D3D5C433FE for ; Mon, 6 Dec 2021 22:59:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1353679AbhLFXCs (ORCPT ); Mon, 6 Dec 2021 18:02:48 -0500 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:25283 "EHLO alexa-out-sd-01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377040AbhLFXCj (ORCPT ); Mon, 6 Dec 2021 18:02:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831550; x=1670367550; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=9pDqBy7b4J82ylZCzc4TAkcjhQdpn6D73KXKK36EV68=; b=EHdJQK49Bgp/TgU+5c2ZXnDJgWT6rV+TAZgk5A5cBacrv3deJZa5+yHk jtujRv2EmlFhWAKnqLYgs03Fx61Rb7k7zy6veuosoUxdwMXrNjJaWGT0b sHXOplE0atNudDKW2TzhvxyLSVlGeNo6+UotJ6VueHVJXYpx4V0fIQQYs M=; Received: from unknown (HELO ironmsg05-sd.qualcomm.com) ([10.53.140.145]) by alexa-out-sd-01.qualcomm.com with ESMTP; 06 Dec 2021 14:59:09 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg05-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:09 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:09 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:08 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys Date: Mon, 6 Dec 2021 14:57:22 -0800 Message-ID: <20211206225725.77512-8-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Storage encryption has two IOCTLs for creating, importing and preparing keys for encryption. For wrapped keys, these IOCTLs need to interface with the secure environment, which require these SCM calls. generate_key: This is used to generate and return a longterm wrapped key. Trustzone achieves this by generating a key and then wrapping it using hwkm, returning a wrapped keyblob. import_key: The functionality is similar to generate, but here, a raw key is imported into hwkm and a longterm wrapped keyblob is returned. prepare_key: The longterm wrapped key from import or generate is made further secure by rewrapping it with a per-boot ephemeral wrapped key before installing it to the linux kernel for programming to ICE. Signed-off-by: Gaurav Kashyap --- drivers/firmware/qcom_scm.c | 213 ++++++++++++++++++++++++++++++++++++ drivers/firmware/qcom_scm.h | 3 + include/linux/qcom_scm.h | 24 +++- 3 files changed, 239 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 4a7703846788..cca5c1ac5666 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1135,6 +1135,219 @@ int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size, } EXPORT_SYMBOL(qcom_scm_derive_sw_secret); +/** + * qcom_scm_generate_ice_key() - Generate a wrapped key for encryption. + * @longterm_wrapped_key: the wrapped key returned after key generation + * @longterm_wrapped_key_size: size of the wrapped key to be returned. + * + * Qualcomm wrapped keys need to be generated in a trusted environment. + * A generate key IOCTL call is used to achieve this. These are longterm + * in nature as they need to be generated and wrapped only once per + * requirement. + * + * This SCM calls adds support for the generate key IOCTL to interface + * with the secure environment to generate and return a wrapped key.. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_GENERATE_ICE_KEY, + .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, + QCOM_SCM_VAL), + .args[1] = longterm_wrapped_key_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + void *longterm_wrapped_keybuf; + dma_addr_t longterm_wrapped_key_phys; + int ret; + + /* + * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly + * get a physical address, while guaranteeing that we can zeroize the + * key material later using memzero_explicit(). + * + */ + longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev, + longterm_wrapped_key_size, + &longterm_wrapped_key_phys, GFP_KERNEL); + if (!longterm_wrapped_keybuf) + return -ENOMEM; + + desc.args[0] = longterm_wrapped_key_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + memcpy(longterm_wrapped_key, longterm_wrapped_keybuf, + longterm_wrapped_key_size); + + memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size); + dma_free_coherent(__scm->dev, longterm_wrapped_key_size, + longterm_wrapped_keybuf, longterm_wrapped_key_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_generate_ice_key); + +/** + * qcom_scm_prepare_ice_key() - Get per boot ephemeral wrapped key + * @longterm_wrapped_key: the wrapped key + * @longterm_wrapped_key_size: size of the wrapped key + * @ephemeral_wrapped_key: ephemeral wrapped key to be returned + * @ephemeral_wrapped_key_size: size of the ephemeral wrapped key + * + * Qualcomm wrapped keys (longterm keys) are rewrapped with a per-boot + * ephemeral key for added protection. These are ephemeral in nature as + * they are valid only for that boot. A create key IOCTL is used to + * achieve this. These are the keys that are installed into the kernel + * to be then unwrapped and programmed into ICE. + * + * This SCM call adds support for the create key IOCTL to interface + * with the secure environment to rewrap the wrapped key with an + * ephemeral wrapping key. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size, + u8 *ephemeral_wrapped_key, + u32 ephemeral_wrapped_key_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_PREPARE_ICE_KEY, + .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, + QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL), + .args[1] = longterm_wrapped_key_size, + .args[3] = ephemeral_wrapped_key_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + void *longterm_wrapped_keybuf, *ephemeral_wrapped_keybuf; + dma_addr_t longterm_wrapped_key_phys, ephemeral_wrapped_key_phys; + int ret; + + /* + * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly + * get a physical address, while guaranteeing that we can zeroize the + * key material later using memzero_explicit(). + * + */ + longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev, + longterm_wrapped_key_size, + &longterm_wrapped_key_phys, GFP_KERNEL); + if (!longterm_wrapped_keybuf) + return -ENOMEM; + ephemeral_wrapped_keybuf = dma_alloc_coherent(__scm->dev, + ephemeral_wrapped_key_size, + &ephemeral_wrapped_key_phys, GFP_KERNEL); + if (!ephemeral_wrapped_keybuf) { + ret = -ENOMEM; + goto bail_keybuf; + } + + memcpy(longterm_wrapped_keybuf, longterm_wrapped_key, + longterm_wrapped_key_size); + desc.args[0] = longterm_wrapped_key_phys; + desc.args[2] = ephemeral_wrapped_key_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + if (!ret) + memcpy(ephemeral_wrapped_key, ephemeral_wrapped_keybuf, + ephemeral_wrapped_key_size); + + memzero_explicit(ephemeral_wrapped_keybuf, ephemeral_wrapped_key_size); + dma_free_coherent(__scm->dev, ephemeral_wrapped_key_size, + ephemeral_wrapped_keybuf, + ephemeral_wrapped_key_phys); + +bail_keybuf: + memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size); + dma_free_coherent(__scm->dev, longterm_wrapped_key_size, + longterm_wrapped_keybuf, longterm_wrapped_key_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_prepare_ice_key); + +/** + * qcom_scm_import_ice_key() - Import a wrapped key for encryption + * @imported_key: the raw key that is imported + * @imported_key_size: size of the key to be imported + * @longterm_wrapped_key: the wrapped key to be returned + * @longterm_wrapped_key_size: size of the wrapped key + * + * Conceptually, this is very similar to generate, the difference being, + * here we want to import a raw key and return a longterm wrapped key + * from it. THe same create key IOCTL is used to achieve this. + * + * This SCM call adds support for the create key IOCTL to interface with + * the secure environment to import a raw key and generate a longterm + * wrapped key. + * + * Return: 0 on success; -errno on failure. + */ +int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size, + u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_ES, + .cmd = QCOM_SCM_ES_IMPORT_ICE_KEY, + .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, + QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL), + .args[1] = imported_key_size, + .args[3] = longterm_wrapped_key_size, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + void *imported_keybuf, *longterm_wrapped_keybuf; + dma_addr_t imported_key_phys, longterm_wrapped_key_phys; + int ret; + /* + * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly + * get a physical address, while guaranteeing that we can zeroize the + * key material later using memzero_explicit(). + * + */ + imported_keybuf = dma_alloc_coherent(__scm->dev, imported_key_size, + &imported_key_phys, GFP_KERNEL); + if (!imported_keybuf) + return -ENOMEM; + longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev, + longterm_wrapped_key_size, + &longterm_wrapped_key_phys, GFP_KERNEL); + if (!longterm_wrapped_keybuf) { + ret = -ENOMEM; + goto bail_keybuf; + } + + memcpy(imported_keybuf, imported_key, imported_key_size); + desc.args[0] = imported_key_phys; + desc.args[2] = longterm_wrapped_key_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + if (!ret) + memcpy(longterm_wrapped_key, longterm_wrapped_keybuf, + longterm_wrapped_key_size); + + memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size); + dma_free_coherent(__scm->dev, longterm_wrapped_key_size, + longterm_wrapped_keybuf, longterm_wrapped_key_phys); +bail_keybuf: + memzero_explicit(imported_keybuf, imported_key_size); + dma_free_coherent(__scm->dev, imported_key_size, imported_keybuf, + imported_key_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_import_ice_key); + /** * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. * diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 08bb2a4c80db..efd0ede1fb37 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -111,6 +111,9 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03 #define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04 #define QCOM_SCM_ES_DERIVE_SW_SECRET 0x07 +#define QCOM_SCM_ES_GENERATE_ICE_KEY 0x08 +#define QCOM_SCM_ES_PREPARE_ICE_KEY 0x09 +#define QCOM_SCM_ES_IMPORT_ICE_KEY 0xA #define QCOM_SCM_SVC_HDCP 0x11 #define QCOM_SCM_HDCP_INVOKE 0x01 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index ccd764bdc357..865e4b4392a1 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -106,6 +106,16 @@ extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, extern int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size, u8 *sw_secret, u32 secret_size); +extern int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size); +extern int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size, + u8 *ephemeral_wrapped_key, + u32 ephemeral_wrapped_key_size); +extern int qcom_scm_import_ice_key(const u8 *imported_key, + u32 imported_key_size, + u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size); extern bool qcom_scm_hdcp_available(void); extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, @@ -175,7 +185,19 @@ static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, static inline int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size, u8 *sw_secret, u32 secret_size) { return -ENODEV; } - +static inline int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size) + { return -ENODEV; } +static inline int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size, + u8 *ephemeral_wrapped_key, + u32 ephemeral_wrapped_key_size) + { return -ENODEV; } +static inline int qcom_scm_import_ice_key(const u8 *imported_key, + u32 imported_key_size, + u8 *longterm_wrapped_key, + u32 longterm_wrapped_key_size) + { return -ENODEV; } static inline bool qcom_scm_hdcp_available(void) { return false; } static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) { return -ENODEV; } From patchwork Mon Dec 6 22:57:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660429 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 88A85C43217 for ; Mon, 6 Dec 2021 22:59:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358962AbhLFXCt (ORCPT ); Mon, 6 Dec 2021 18:02:49 -0500 Received: from alexa-out.qualcomm.com ([129.46.98.28]:16498 "EHLO alexa-out.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377123AbhLFXCl (ORCPT ); Mon, 6 Dec 2021 18:02:41 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831552; x=1670367552; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=ECagi/BaTQQeNMjMZWtRvSI3lnAfi1QCeUU8K69Xtrc=; b=QVoeE1ap3nytNDbvoJ7JPdryF15qrlIBxmU/X64RlD1FTNKkusLCtPOj iDv49cQAzXwA52JjjmpYCTtZ4HZy4JYMpkkqE6qKswXV9Yk6fHQUMjkhT Dmsxj4t+EZXGvdkQ5EQlGMoYxu1P0z3JcltsuUXLNnR/erLPFwk5v9NaL s=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 06 Dec 2021 14:59:11 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg08-lv.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:11 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:10 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:10 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys Date: Mon, 6 Dec 2021 14:57:23 -0800 Message-ID: <20211206225725.77512-9-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org This patch contains two changes in UFS for wrapped keys. 1. Implements the blk_crypto_profile ops for generate, import and prepare key apis. 2. Adds UFS vops for generate, import and prepare keys so that vendors can hooks to them. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufshcd-crypto.c | 50 ++++++++++++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 11 +++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index 9d68621a0eb4..2bea9b924f77 100644 --- a/drivers/scsi/ufs/ufshcd-crypto.c +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -136,9 +136,9 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba) } static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile, - const u8 *wrapped_key, - unsigned int wrapped_key_size, - u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) { struct ufs_hba *hba = container_of(profile, struct ufs_hba, crypto_profile); @@ -146,6 +146,47 @@ static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile, if (hba->vops && hba->vops->derive_secret) return hba->vops->derive_secret(hba, wrapped_key, wrapped_key_size, sw_secret); + return 0; +} + +static int ufshcd_crypto_generate_key(struct blk_crypto_profile *profile, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + struct ufs_hba *hba = + container_of(profile, struct ufs_hba, crypto_profile); + + if (hba->vops && hba->vops->generate_key) + return hba->vops->generate_key(longterm_wrapped_key); + + return -EOPNOTSUPP; +} + +static int ufshcd_crypto_prepare_key(struct blk_crypto_profile *profile, + const u8 *longterm_wrapped_key, + size_t longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + struct ufs_hba *hba = + container_of(profile, struct ufs_hba, crypto_profile); + + if (hba->vops && hba->vops->prepare_key) + return hba->vops->prepare_key(longterm_wrapped_key, + longterm_wrapped_key_size, ephemerally_wrapped_key); + + return -EOPNOTSUPP; +} + +static int ufshcd_crypto_import_key(struct blk_crypto_profile *profile, + const u8 *imported_key, + size_t imported_key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + struct ufs_hba *hba = + container_of(profile, struct ufs_hba, crypto_profile); + + if (hba->vops && hba->vops->import_key) + return hba->vops->import_key(imported_key, + imported_key_size, longterm_wrapped_key); return -EOPNOTSUPP; } @@ -154,6 +195,9 @@ static const struct blk_crypto_ll_ops ufshcd_crypto_ops = { .keyslot_program = ufshcd_crypto_keyslot_program, .keyslot_evict = ufshcd_crypto_keyslot_evict, .derive_sw_secret = ufshcd_crypto_derive_sw_secret, + .generate_key = ufshcd_crypto_generate_key, + .prepare_key = ufshcd_crypto_prepare_key, + .import_key = ufshcd_crypto_import_key, }; static enum blk_crypto_mode_num diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 095c2d660aa7..88cd21dec0d9 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -321,6 +321,10 @@ struct ufs_pwr_mode_info { * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events * @derive_secret: derive sw secret from wrapped inline encryption key + * @generate_key: generate a longterm wrapped key for inline encryption + * @prepare_key: prepare the longterm wrapped key for inline encryption + * by rewrapping with a ephemeral wrapping key. + * @import_key: import a raw key and return a longterm wrapped key. */ struct ufs_hba_variant_ops { const char *name; @@ -362,6 +366,13 @@ struct ufs_hba_variant_ops { int (*derive_secret)(struct ufs_hba *hba, const u8 *wrapped_key, unsigned int wrapped_key_size, u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); + int (*generate_key)(u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); + int (*prepare_key)(const u8 *longterm_wrapped_key, + unsigned int longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); + int (*import_key)(const u8 *imported_key, + unsigned int imported_key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); }; /* clock gating state */ From patchwork Mon Dec 6 22:57:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660433 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 24F8EC4167B for ; Mon, 6 Dec 2021 22:59:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1376287AbhLFXCw (ORCPT ); Mon, 6 Dec 2021 18:02:52 -0500 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:15870 "EHLO alexa-out-sd-02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377162AbhLFXCo (ORCPT ); Mon, 6 Dec 2021 18:02:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831555; x=1670367555; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=NmElV7T+xzPa6AFGYUpxLexgr3R7EJAkax7bo6Hf2K0=; b=HSMzcP5U8wku5t0X37e2TEqc7X5MsGdXZQE/93HYImdzDH6SChTucqTx xi7ohUrsDDQO54NUNyxJllUgwtaRzSxUalCW5Sfy//Q7KZhX36cE2JUqW c/rOx7vhmE9biAKTl8ZPgvTKNpTIKG5Z83SGH+pPXPepDvPkwUVMlH8AM Q=; Received: from unknown (HELO ironmsg03-sd.qualcomm.com) ([10.53.140.143]) by alexa-out-sd-02.qualcomm.com with ESMTP; 06 Dec 2021 14:59:12 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg03-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:12 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:12 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:11 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 09/10] soc: qcom: support for generate, import and prepare key Date: Mon, 6 Dec 2021 14:57:24 -0800 Message-ID: <20211206225725.77512-10-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Implements the vops for generate, prepare and import key apis and hooks it up the scm calls defined for them. Key management has to be done from Qualcomm Trustzone as only it can interface with HWKM. Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufs-qcom-ice.c | 22 ++++++++ drivers/scsi/ufs/ufs-qcom.c | 3 ++ drivers/scsi/ufs/ufs-qcom.h | 12 +++++ drivers/soc/qcom/qti-ice-common.c | 89 ++++++++++++++++++++++++++++--- include/linux/qti-ice-common.h | 8 +++ 5 files changed, 128 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index c8305aab6714..7f0485553d75 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -130,3 +130,25 @@ int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key, wrapped_key, wrapped_key_size, sw_secret); } + +int ufs_qcom_ice_generate_key( + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qti_ice_generate_key(longterm_wrapped_key); +} + +int ufs_qcom_ice_prepare_key(const u8 *longterm_wrapped_key, + unsigned int longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qti_ice_prepare_key(longterm_wrapped_key, longterm_wrapped_key_size, + ephemerally_wrapped_key); +} + +int ufs_qcom_ice_import_key(const u8 *imported_key, + unsigned int imported_key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qti_ice_import_key(imported_key, imported_key_size, + longterm_wrapped_key); +} diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 9f85332fbe64..cbd472844065 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1496,6 +1496,9 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .config_scaling_param = ufs_qcom_config_scaling_param, .program_key = ufs_qcom_ice_program_key, .derive_secret = ufs_qcom_ice_derive_sw_secret, + .generate_key = ufs_qcom_ice_generate_key, + .prepare_key = ufs_qcom_ice_prepare_key, + .import_key = ufs_qcom_ice_import_key, }; /** diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index e7da3d1dc3c7..1f8ed9adb28f 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -259,6 +259,14 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba, int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key, unsigned int wrapped_key_size, u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); +int ufs_qcom_ice_generate_key( + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); +int ufs_qcom_ice_prepare_key(const u8 *longterm_wrapped_key, + unsigned int longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); +int ufs_qcom_ice_import_key(const u8 *imported_key, + unsigned int imported_key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); #else static inline int ufs_qcom_ice_init(struct ufs_qcom_host *host) { @@ -273,6 +281,10 @@ static inline int ufs_qcom_ice_resume(struct ufs_qcom_host *host) return 0; } #define ufs_qcom_ice_program_key NULL +#define ufs_qcom_ice_derive_sw_secret NULL +#define ufs_qcom_ice_generate_key NULL +#define ufs_qcom_ice_prepare_key NULL +#define ufs_qcom_ice_import_key NULL #endif /* !CONFIG_SCSI_UFS_CRYPTO */ #endif /* UFS_QCOM_H_ */ diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c index 76703afa4834..cc035f1a1d42 100644 --- a/drivers/soc/qcom/qti-ice-common.c +++ b/drivers/soc/qcom/qti-ice-common.c @@ -13,13 +13,21 @@ #define QTI_ICE_MAX_BIST_CHECK_COUNT 100 #define QTI_AES_256_XTS_KEY_RAW_SIZE 64 +#define QTI_HWKM_WRAPPED_KEY_SIZE_V1 68 +#define QTI_HWKM_WRAPPED_KEY_SIZE_V2 100 /* * ICE resets during power collapse and HWKM has to be * reconfigured which can be kept track with this flag. */ static bool qti_hwkm_init_done; -static int hwkm_version; +static int qti_hwkm_version; + +/* + * Size of the wrapped key returned by HWKM, which varies with + * hwkm version + */ +static unsigned int qti_hwkm_wrapped_key_size; union crypto_cfg { __le32 regval; @@ -45,10 +53,13 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio) return false; } - if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1))) - hwkm_version = 2; - else - hwkm_version = 1; + if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1))) { + qti_hwkm_wrapped_key_size = QTI_HWKM_WRAPPED_KEY_SIZE_V2; + qti_hwkm_version = 2; + } else { + qti_hwkm_wrapped_key_size = QTI_HWKM_WRAPPED_KEY_SIZE_V1; + qti_hwkm_version = 1; + } pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", major, minor, step); @@ -168,7 +179,7 @@ static int qti_ice_program_wrapped_key(const struct ice_mmio_data *mmio, * won't work. */ if (!qti_hwkm_init_done) { - err = qti_ice_hwkm_init(mmio, hwkm_version); + err = qti_ice_hwkm_init(mmio, qti_hwkm_version); if (err) { pr_err("%s: Error initializing hwkm, err = %d", __func__, err); @@ -322,4 +333,70 @@ int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio, } EXPORT_SYMBOL_GPL(qti_ice_derive_sw_secret); +/** + * qti_ice_generate_key() - Generate a wrapped key for inline encryption + * @longterm_wrapped_key: wrapped key that is generated, which is at most + * BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE in size. + * + * Make a scm call into trustzone to generate a wrapped key for storage + * encryption using hwkm. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_generate_key( + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qcom_scm_generate_ice_key(longterm_wrapped_key, + qti_hwkm_wrapped_key_size); +} +EXPORT_SYMBOL_GPL(qti_ice_generate_key); + +/** + * qti_ice_prepare_key() - Prepare a longterm wrapped key for inline encryption + * @longterm_wrapped_key: wrapped key that is generated, + * @longterm_wrapped_key_size: size of the longterm wrapped_key + * @ephemerally_wrapped_key: wrapped key returned which has been wrapped with + * a per-boot ephemeral key, size of which is at most + * BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE + * + * Make a scm call into trustzone to prepare a wrapped key for storage + * encryption by rewrapping the longterm wrapped key with a per boot ephemeral + * key using hwkm. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_prepare_key(const u8 *longterm_wrapped_key, + unsigned int longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qcom_scm_prepare_ice_key(longterm_wrapped_key, + longterm_wrapped_key_size, + ephemerally_wrapped_key, + qti_hwkm_wrapped_key_size); +} +EXPORT_SYMBOL_GPL(qti_ice_prepare_key); + +/** + * qti_ice_import_key() - Importa raw key for inline encryption + * @imported_key: raw key that has to be imported + * @imported_key_size: size of the imported key + * @longterm_wrapped_key: longterm wrapped key returned which has been wrapped + * after imporint the raw key using hwkm. + * + * Make a scm call into trustzone to import a raw key for storage encryption + * and generating a longterm wrapped key using hwkm. + * + * Return: 0 on success; err on failure. + */ +int qti_ice_import_key(const u8 *imported_key, + unsigned int imported_key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]) +{ + return qcom_scm_import_ice_key(imported_key, + imported_key_size, + longterm_wrapped_key, + qti_hwkm_wrapped_key_size); +} +EXPORT_SYMBOL_GPL(qti_ice_import_key); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h index e329afeba113..cae5275ee1d9 100644 --- a/include/linux/qti-ice-common.h +++ b/include/linux/qti-ice-common.h @@ -28,5 +28,13 @@ int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio, const u8 *wrapped_key, unsigned int wrapped_key_size, u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); +int qti_ice_generate_key( + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); +int qti_ice_prepare_key(const u8 *longterm_wrapped_key, + unsigned int longterm_wrapped_key_size, + u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); +int qti_ice_import_key(const u8 *imported_key, + unsigned int imported__key_size, + u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]); #endif /* _QTI_ICE_COMMON_H */ From patchwork Mon Dec 6 22:57:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gaurav Kashyap (QUIC)" X-Patchwork-Id: 12660431 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B03C1C43219 for ; Mon, 6 Dec 2021 22:59:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1359694AbhLFXCu (ORCPT ); Mon, 6 Dec 2021 18:02:50 -0500 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:25287 "EHLO alexa-out-sd-01.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376929AbhLFXCo (ORCPT ); Mon, 6 Dec 2021 18:02:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1638831555; x=1670367555; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=Ue4j4uhm1swKWHsP5swU+lpTqR0o0aLaH/vHm0ED9Xc=; b=ad6rULnG6q02l8dIRnJ7OwVqPpCyFrwDlqOQvwGawN6eW1em7u2j1Enf 1RT8POt1x87ra9/twRa96J1mFqHzsXqsAF7/CyTvrTw6Ui7/ZKpW1n9xJ U1gpItjSvEdYbclYsqutrKsxEvOCu/bv7atHNO50w18W09sLzn7yfFiF9 o=; Received: from unknown (HELO ironmsg05-sd.qualcomm.com) ([10.53.140.145]) by alexa-out-sd-01.qualcomm.com with ESMTP; 06 Dec 2021 14:59:14 -0800 X-QCInternal: smtphost Received: from nasanex01c.na.qualcomm.com ([10.47.97.222]) by ironmsg05-sd.qualcomm.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Dec 2021 14:59:14 -0800 Received: from nalasex01a.na.qualcomm.com (10.47.209.196) by nasanex01c.na.qualcomm.com (10.47.97.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:13 -0800 Received: from gabriel.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.922.19; Mon, 6 Dec 2021 14:59:13 -0800 From: Gaurav Kashyap To: , CC: , , , , , , Gaurav Kashyap Subject: [PATCH 10/10] arm64: dts: qcom: sm8350: add ice and hwkm mappings Date: Mon, 6 Dec 2021 14:57:25 -0800 Message-ID: <20211206225725.77512-11-quic_gaurkash@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211206225725.77512-1-quic_gaurkash@quicinc.com> References: <20211206225725.77512-1-quic_gaurkash@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To nalasex01a.na.qualcomm.com (10.47.209.196) Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org Add register mappings for ICE (Inline Crypto Engine) and HWKM (Hardware Key Manager) slave, which are both part of the UFS controller for sm8350. These are required for inline storage encryption using hardware wrapped key. Signed-off-by: Gaurav Kashyap --- arch/arm64/boot/dts/qcom/sm8350.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index e91cd8a5e535..8e15524731b3 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -1019,7 +1019,10 @@ ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sm8350-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; - reg = <0 0x01d84000 0 0x3000>; + reg = <0 0x01d84000 0 0x3000>, + <0 0x01d88000 0 0x8000>, + <0 0x01d90000 0 0x9000>; + reg-names = "ufs_mem", "ice", "ice_hwkm"; interrupts = ; phys = <&ufs_mem_phy_lanes>; phy-names = "ufsphy";