linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Adds wrapped key support for inline storage encryption
@ 2021-11-03 23:18 Gaurav Kashyap
  2021-11-03 23:18 ` [PATCH 1/4] ufs: move ICE functionality to a common library Gaurav Kashyap
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Gaurav Kashyap @ 2021-11-03 23:18 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath, asutoshd,
	Gaurav Kashyap

This currently has 4 patches with another coming in shortly for MMC.

1. Moves ICE functionality to a common library, so that different storage controllers can use it.
2. Adds a SCM call for derive raw secret needed for wrapped keys.
3. Adds a hardware key manager library needed for wrapped keys.
4. Adds wrapped key support in ufs for storage encryption

Gaurav Kashyap (4):
  ufs: move ICE functionality to a common library
  qcom_scm: scm call for deriving a software secret
  soc: qcom: add HWKM library for storage encryption
  soc: qcom: add wrapped key support for ICE

 drivers/firmware/qcom_scm.c       |  61 +++++++
 drivers/firmware/qcom_scm.h       |   1 +
 drivers/scsi/ufs/ufs-qcom-ice.c   | 200 ++++++-----------------
 drivers/scsi/ufs/ufs-qcom.c       |   1 +
 drivers/scsi/ufs/ufs-qcom.h       |   5 +
 drivers/scsi/ufs/ufshcd-crypto.c  |  47 ++++--
 drivers/scsi/ufs/ufshcd.h         |   5 +
 drivers/soc/qcom/Kconfig          |  14 ++
 drivers/soc/qcom/Makefile         |   2 +
 drivers/soc/qcom/qti-ice-common.c | 215 +++++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-hwkm.c   |  77 +++++++++
 drivers/soc/qcom/qti-ice-regs.h   | 257 ++++++++++++++++++++++++++++++
 include/linux/qcom_scm.h          |   5 +
 include/linux/qti-ice-common.h    |  37 +++++
 14 files changed, 766 insertions(+), 161 deletions(-)
 create mode 100644 drivers/soc/qcom/qti-ice-common.c
 create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c
 create mode 100644 drivers/soc/qcom/qti-ice-regs.h
 create mode 100644 include/linux/qti-ice-common.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/4] ufs: move ICE functionality to a common library
  2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
@ 2021-11-03 23:18 ` Gaurav Kashyap
  2021-11-04 23:05   ` Eric Biggers
  2021-11-03 23:18 ` [PATCH 2/4] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Gaurav Kashyap @ 2021-11-03 23:18 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath, asutoshd,
	Gaurav Kashyap

The Inline Crypto Engine functionality is not limited to
ufs and it can be used by other storage controllers like emmc
which have the HW capabilities. It would be better to move this
functionality to a common location.

Moreover, when wrapped key functionality is added, it would
reduce the effort required to add it for all storage
controllers.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufs-qcom-ice.c   | 172 ++++--------------------------
 drivers/soc/qcom/Kconfig          |   7 ++
 drivers/soc/qcom/Makefile         |   1 +
 drivers/soc/qcom/qti-ice-common.c | 135 +++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-regs.h   | 145 +++++++++++++++++++++++++
 include/linux/qti-ice-common.h    |  26 +++++
 6 files changed, 334 insertions(+), 152 deletions(-)
 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/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index bbb0ad7590ec..6608a9015eab 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -8,96 +8,18 @@
 
 #include <linux/platform_device.h>
 #include <linux/qcom_scm.h>
+#include <linux/qti-ice-common.h>
 
 #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;
 	struct device *dev = hba->dev;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
+	struct ice_mmio_data mmio;
 	int err;
 
 	if (!(ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES) &
@@ -121,8 +43,9 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 		dev_err(dev, "Failed to map ICE registers; err=%d\n", err);
 		return err;
 	}
+	mmio.ice_mmio = host->ice_mmio;
 
-	if (!qcom_ice_supported(host))
+	if (!qti_ice_init(&mmio))
 		goto disable;
 
 	return 0;
@@ -133,71 +56,31 @@ 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)
+static void get_ice_mmio_data(struct ice_mmio_data *data,
+			      const 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);
+	data->ice_mmio = host->ice_mmio;
 }
 
 int ufs_qcom_ice_enable(struct ufs_qcom_host *host)
 {
+	struct ice_mmio_data mmio;
+
 	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;
+	get_ice_mmio_data(&mmio, host);
+	return qti_ice_enable(&mmio);
 }
 
 int ufs_qcom_ice_resume(struct ufs_qcom_host *host)
 {
-	int err;
+	struct ice_mmio_data mmio;
 
 	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;
+	get_ice_mmio_data(&mmio, host);
+	return qti_ice_resume(&mmio);
 }
 
 /*
@@ -208,16 +91,13 @@ 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 ice_mmio_data mmio;
+	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);
 
+	get_ice_mmio_data(&mmio, host);
 	/* Only AES-256-XTS has been tested so far. */
 	cap = hba->crypto_cap_array[cfg->crypto_cap_idx];
 	if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS ||
@@ -228,18 +108,6 @@ 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(&mmio, cfg->crypto_key, AES_256_XTS_KEY_SIZE,
+				       slot, cfg->data_unit_size, cfg->crypto_cap_idx);
 }
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 79b568f82a1c..39f223ed8cdd 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 SCSI_UFS_CRYPTO && SCSI_UFS_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..b344a4cab5d4
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common ICE library for storage encryption.
+ *
+ * Copyright (c) 2021, Linux Foundation. All rights reserved.
+ */
+
+#include <linux/qti-ice-common.h>
+#include <linux/module.h>
+#include <linux/qcom_scm.h>
+#include <linux/delay.h>
+#include "qti-ice-regs.h"
+
+#define QTI_ICE_MAX_BIST_CHECK_COUNT    100
+
+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;
+}
+
+int qti_ice_init(const struct ice_mmio_data *mmio)
+{
+	return qti_ice_supported(mmio);
+}
+EXPORT_SYMBOL(qti_ice_init);
+
+static void qti_ice_low_power_and_optimization_enable(
+                            const struct ice_mmio_data *mmio)
+{
+	u32 regval = qti_ice_readl(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, 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;
+}
+
+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(qti_ice_enable);
+
+int qti_ice_resume(const struct ice_mmio_data *mmio)
+{
+	return qti_ice_wait_bist_status(mmio);
+}
+EXPORT_SYMBOL(qti_ice_resume);
+
+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[AES_256_XTS_KEY_SIZE];
+		u32 words[AES_256_XTS_KEY_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, AES_256_XTS_KEY_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(qti_ice_keyslot_program);
+
+int qti_ice_keyslot_evict(unsigned int slot)
+{
+	return qcom_scm_ice_invalidate_key(slot);
+}
+EXPORT_SYMBOL(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..47c625c9d536
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-regs.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _QTI_INLINE_CRYPTO_ENGINE_REGS_H_
+#define _QTI_INLINE_CRYPTO_ENGINE_REGS_H_
+
+#include <linux/io.h>
+
+/* 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..433422b34a7d
--- /dev/null
+++ b/include/linux/qti-ice-common.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _QTI_ICE_COMMON_H
+#define _QTI_ICE_COMMON_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#define AES_256_XTS_KEY_SIZE    64
+
+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 */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/4] qcom_scm: scm call for deriving a software secret
  2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
  2021-11-03 23:18 ` [PATCH 1/4] ufs: move ICE functionality to a common library Gaurav Kashyap
@ 2021-11-03 23:18 ` Gaurav Kashyap
  2021-11-04 23:31   ` Eric Biggers
  2021-11-03 23:18 ` [PATCH 3/4] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Gaurav Kashyap @ 2021-11-03 23:18 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath, asutoshd,
	Gaurav Kashyap

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 only unwrapped
by Qualcomm Trustzone. Hence, it also makes sense that the software
secret is also derived there and returned to the linux kernel for
wrapped keys. Fscrypt invokes this functionality using the crypto
profile APIs provided by the block layer.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/firmware/qcom_scm.c | 61 +++++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.h |  1 +
 include/linux/qcom_scm.h    |  5 +++
 3 files changed, 67 insertions(+)

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 2ee97bab7440..cf62e8056c17 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1062,6 +1062,67 @@ 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
+ * @secret_size: size of the secret derived
+ *
+ * Derive a SW secret to be used for inline encryption using Qualcomm ICE.
+ *
+ * Generally, for non-wrapped keys, fscrypt can derive a sw secret from the
+ * key in the clear in the linux keyring.
+ *
+ * However, for wrapped keys, the key needs to be unwrapped, 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.
+ *
+ * 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_RAW_SECRET,
+		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
+					 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;
+
+	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)
+		return -ENOMEM;
+
+	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);
+	memcpy(sw_secret, secretbuf, secret_size);
+
+	memzero_explicit(keybuf, wrapped_key_size);
+	dma_free_coherent(__scm->dev, wrapped_key_size, keybuf, key_phys);
+	memzero_explicit(secretbuf, secret_size);
+	dma_free_coherent(__scm->dev, secret_size, secretbuf, secret_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..de5d4f8fd20d 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_RAW_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..e1f645d714f9 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -103,6 +103,8 @@ 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 +171,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,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/4] soc: qcom: add HWKM library for storage encryption
  2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
  2021-11-03 23:18 ` [PATCH 1/4] ufs: move ICE functionality to a common library Gaurav Kashyap
  2021-11-03 23:18 ` [PATCH 2/4] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
@ 2021-11-03 23:18 ` Gaurav Kashyap
  2021-11-04 23:46   ` Eric Biggers
  2021-11-03 23:18 ` [PATCH 4/4] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
  2021-11-04 22:49 ` [PATCH 0/4] Adds wrapped key support for inline storage encryption Eric Biggers
  4 siblings, 1 reply; 13+ messages in thread
From: Gaurav Kashyap @ 2021-11-03 23:18 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath, asutoshd,
	Gaurav Kashyap

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
capabilites to be acessed from the linux kernel in the future.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/soc/qcom/Kconfig        |   7 ++
 drivers/soc/qcom/Makefile       |   1 +
 drivers/soc/qcom/qti-ice-hwkm.c |  77 ++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-regs.h | 112 ++++++++++++++++++++++++++++++++
 include/linux/qti-ice-common.h  |   6 ++
 5 files changed, 203 insertions(+)
 create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 39f223ed8cdd..d441d5b81c53 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -216,4 +216,11 @@ config QTI_ICE_COMMON
 	help
 	  Enable the common ICE library that can be used
 	  by UFS and EMMC drivers for ICE functionality.
+
+config QTI_HW_WRAPPED_KEYS
+	tristate "QTI HW Wrapped Keys"
+	depends on QTI_ICE_COMMON
+	help
+	  Enable wrapped key functionality for storage
+	  encryption.
 endmenu
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 57840b19b7ee..56d1f4b8d436 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -27,3 +27,4 @@ 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_HW_WRAPPED_KEYS) += 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..d65873745999
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-hwkm.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HWKM ICE library for storage encryption.
+ *
+ * Copyright (c) 2021, Linux Foundation. All rights reserved.
+ */
+
+#include <linux/qti-ice-common.h>
+#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 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;
+
+	/* 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;
+}
+
+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(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 47c625c9d536..4c8d9fd62e42 100644
--- a/drivers/soc/qcom/qti-ice-regs.h
+++ b/drivers/soc/qcom/qti-ice-regs.h
@@ -137,9 +137,121 @@
 			 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_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 433422b34a7d..b0a50a1c6876 100644
--- a/include/linux/qti-ice-common.h
+++ b/include/linux/qti-ice-common.h
@@ -23,4 +23,10 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
                 unsigned int slot, u8 data_unit_mask, int capid);
 int qti_ice_keyslot_evict(unsigned int slot);
 
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version);
+#else
+static inline int qti_ice_hwkm_init(const struct ice_mmio_data *mmio,
+					int version) { return -ENODEV; }
+#endif /* CONFIG_QTI_HW_WRAPPED_KEYS */
 #endif /* _QTI_ICE_COMMON_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/4] soc: qcom: add wrapped key support for ICE
  2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
                   ` (2 preceding siblings ...)
  2021-11-03 23:18 ` [PATCH 3/4] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
@ 2021-11-03 23:18 ` Gaurav Kashyap
  2021-11-05  0:08   ` Eric Biggers
  2021-11-04 22:49 ` [PATCH 0/4] Adds wrapped key support for inline storage encryption Eric Biggers
  4 siblings, 1 reply; 13+ messages in thread
From: Gaurav Kashyap @ 2021-11-03 23:18 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath, asutoshd,
	Gaurav Kashyap

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.
4. Added support for deriving SW secret as it cannot be done in
   linux kernel for wrapped keys.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufs-qcom-ice.c   |  34 +++++++++-
 drivers/scsi/ufs/ufs-qcom.c       |   1 +
 drivers/scsi/ufs/ufs-qcom.h       |   5 ++
 drivers/scsi/ufs/ufshcd-crypto.c  |  47 ++++++++++---
 drivers/scsi/ufs/ufshcd.h         |   5 ++
 drivers/soc/qcom/qti-ice-common.c | 108 ++++++++++++++++++++++++++----
 include/linux/qti-ice-common.h    |   7 +-
 7 files changed, 180 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 6608a9015eab..79d642190997 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -45,6 +45,21 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 	}
 	mmio.ice_mmio = host->ice_mmio;
 
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm");
+	if (!res) {
+		dev_warn(dev, "ICE HWKM registers not found\n");
+		goto disable;
+	}
+
+	host->ice_hwkm_mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->ice_hwkm_mmio)) {
+		err = PTR_ERR(host->ice_hwkm_mmio);
+		dev_err(dev, "Failed to map ICE registers; err=%d\n", err);
+		return err;
+	}
+	mmio.ice_hwkm_mmio = host->ice_hwkm_mmio;
+#endif
 	if (!qti_ice_init(&mmio))
 		goto disable;
 
@@ -60,6 +75,9 @@ static void get_ice_mmio_data(struct ice_mmio_data *data,
 			      const struct ufs_qcom_host *host)
 {
 	data->ice_mmio = host->ice_mmio;
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+	data->ice_hwkm_mmio = host->ice_hwkm_mmio;
+#endif
 }
 
 int ufs_qcom_ice_enable(struct ufs_qcom_host *host)
@@ -88,6 +106,7 @@ 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 struct blk_crypto_key *key,
 			     const union ufs_crypto_cfg_entry *cfg, int slot)
 {
 	union ufs_crypto_cap_entry cap;
@@ -108,6 +127,17 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba,
 		return -EINVAL;
 	}
 
-	return qti_ice_keyslot_program(&mmio, cfg->crypto_key, AES_256_XTS_KEY_SIZE,
-				       slot, cfg->data_unit_size, cfg->crypto_cap_idx);
+	return qti_ice_keyslot_program(&mmio, key, slot,
+				       cfg->data_unit_size, cfg->crypto_cap_idx);
+}
+
+/*
+ * 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(const u8 *wrapped_key,
+				  unsigned int wrapped_key_size,
+				  u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+	return qti_ice_derive_sw_secret(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 8208e3a3ef59..420fdc1dfeaa 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -207,6 +207,7 @@ struct ufs_qcom_host {
 	struct ufs_hw_version hw_ver;
 #ifdef CONFIG_SCSI_UFS_CRYPTO
 	void __iomem *ice_mmio;
+	void __iomem *ice_hwkm_mmio;
 #endif
 
 	u32 dev_ref_clk_en_mask;
@@ -252,7 +253,11 @@ 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 struct blk_crypto_key *key,
 			     const union ufs_crypto_cfg_entry *cfg, int slot);
+int ufs_qcom_ice_derive_sw_secret(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/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index 0ed82741f981..965a8cc6c183 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -18,6 +18,7 @@ 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;
@@ -27,7 +28,7 @@ static int ufshcd_program_key(struct ufs_hba *hba,
 	ufshcd_hold(hba, false);
 
 	if (hba->vops && hba->vops->program_key) {
-		err = hba->vops->program_key(hba, cfg, slot);
+		err = hba->vops->program_key(hba, key, cfg, slot);
 		goto out;
 	}
 
@@ -80,16 +81,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 +106,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 +129,29 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba)
 	return true;
 }
 
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+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(wrapped_key,
+							wrapped_key_size, sw_secret);
+
+	return 0;
+}
+#endif
+
 static const struct blk_crypto_ll_ops ufshcd_crypto_ops = {
 	.keyslot_program	= ufshcd_crypto_keyslot_program,
 	.keyslot_evict		= ufshcd_crypto_keyslot_evict,
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+	.derive_sw_secret	= ufshcd_crypto_derive_sw_secret,
+#endif
 };
 
 static enum blk_crypto_mode_num
@@ -190,7 +213,11 @@ 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;
+#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
+	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
+#else
 	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD;
+#endif
 	hba->crypto_profile.dev = hba->dev;
 
 	/*
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index df5439b12208..ff712358225d 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,13 @@ struct ufs_hba_variant_ops {
 					struct devfreq_dev_profile *profile,
 					void *data);
 	int	(*program_key)(struct ufs_hba *hba,
+			       const struct blk_crypto_key *crypto_key,
 			       const union ufs_crypto_cfg_entry *cfg, int slot);
 	void	(*event_notify)(struct ufs_hba *hba,
 				enum ufs_event_type evt, void *data);
+	int (*derive_secret)(const u8 *wrapped_key,
+					 unsigned int wrapped_key_size,
+					 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 };
 
 /* clock gating state  */
diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
index b344a4cab5d4..ffec27087543 100644
--- a/drivers/soc/qcom/qti-ice-common.c
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -13,6 +13,23 @@
 
 #define QTI_ICE_MAX_BIST_CHECK_COUNT    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;
+
+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);
@@ -27,6 +44,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);
 
@@ -97,8 +119,51 @@ int qti_ice_resume(const struct ice_mmio_data *mmio)
 }
 EXPORT_SYMBOL(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;
+
+	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));
+	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));
+	wmb();
+
+	return err;
+}
+
 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;
@@ -108,20 +173,26 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
 		u32 words[AES_256_XTS_KEY_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, AES_256_XTS_KEY_SIZE,
-				   capid, data_unit_mask);
-	if (err)
-		pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err, slot);
+	if (crypto_key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
+		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, 
+				AES_256_XTS_KEY_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(qti_ice_keyslot_program);
@@ -132,4 +203,13 @@ int qti_ice_keyslot_evict(unsigned int slot)
 }
 EXPORT_SYMBOL(qti_ice_keyslot_evict);
 
+int qti_ice_derive_sw_secret(const u8 *wrapped_key,
+			     unsigned int wrapped_key_size,
+			     u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+    return qcom_scm_derive_sw_secret(wrapped_key, wrapped_key_size,
+				     sw_secret, BLK_CRYPTO_SW_SECRET_SIZE);
+}
+EXPORT_SYMBOL(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 b0a50a1c6876..73365764a595 100644
--- a/include/linux/qti-ice-common.h
+++ b/include/linux/qti-ice-common.h
@@ -8,23 +8,28 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
+#include <linux/blk-crypto.h>
 
 #define AES_256_XTS_KEY_SIZE    64
 
 struct ice_mmio_data {
 	void __iomem *ice_mmio;
+	void __iomem *ice_hwkm_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,
+                const struct blk_crypto_key *crypto_key,
                 unsigned int slot, u8 data_unit_mask, int capid);
 int qti_ice_keyslot_evict(unsigned int slot);
 
 #if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
 int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version);
+int qti_ice_derive_sw_secret(const u8 *wrapped_key,
+					 unsigned int wrapped_key_size,
+					 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 #else
 static inline int qti_ice_hwkm_init(const struct ice_mmio_data *mmio,
 					int version) { return -ENODEV; }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/4] Adds wrapped key support for inline storage encryption
  2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
                   ` (3 preceding siblings ...)
  2021-11-03 23:18 ` [PATCH 4/4] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
@ 2021-11-04 22:49 ` Eric Biggers
  2021-12-08  0:09   ` Gaurav Kashyap
  4 siblings, 1 reply; 13+ messages in thread
From: Eric Biggers @ 2021-11-04 22:49 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

Hi Gaurav,

On Wed, Nov 03, 2021 at 04:18:36PM -0700, Gaurav Kashyap wrote:
> This currently has 4 patches with another coming in shortly for MMC.
> 
> 1. Moves ICE functionality to a common library, so that different storage controllers can use it.
> 2. Adds a SCM call for derive raw secret needed for wrapped keys.
> 3. Adds a hardware key manager library needed for wrapped keys.
> 4. Adds wrapped key support in ufs for storage encryption
> 
> Gaurav Kashyap (4):
>   ufs: move ICE functionality to a common library
>   qcom_scm: scm call for deriving a software secret
>   soc: qcom: add HWKM library for storage encryption
>   soc: qcom: add wrapped key support for ICE
> 
>  drivers/firmware/qcom_scm.c       |  61 +++++++
>  drivers/firmware/qcom_scm.h       |   1 +
>  drivers/scsi/ufs/ufs-qcom-ice.c   | 200 ++++++-----------------
>  drivers/scsi/ufs/ufs-qcom.c       |   1 +
>  drivers/scsi/ufs/ufs-qcom.h       |   5 +
>  drivers/scsi/ufs/ufshcd-crypto.c  |  47 ++++--
>  drivers/scsi/ufs/ufshcd.h         |   5 +
>  drivers/soc/qcom/Kconfig          |  14 ++
>  drivers/soc/qcom/Makefile         |   2 +
>  drivers/soc/qcom/qti-ice-common.c | 215 +++++++++++++++++++++++++
>  drivers/soc/qcom/qti-ice-hwkm.c   |  77 +++++++++
>  drivers/soc/qcom/qti-ice-regs.h   | 257 ++++++++++++++++++++++++++++++
>  include/linux/qcom_scm.h          |   5 +
>  include/linux/qti-ice-common.h    |  37 +++++
>  14 files changed, 766 insertions(+), 161 deletions(-)
>  create mode 100644 drivers/soc/qcom/qti-ice-common.c
>  create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c
>  create mode 100644 drivers/soc/qcom/qti-ice-regs.h
>  create mode 100644 include/linux/qti-ice-common.h

Thanks for the patches!  These are on top of my patchset
"[RFC PATCH v2 0/5] Support for hardware-wrapped inline encryption keys"
(https://lore.kernel.org/linux-block/20210916174928.65529-1-ebiggers@kernel.org),
right?  You should mention that in your cover letter, so that it's possible for
people to apply your patches for reviewing or testing, and also to provide
context about what this feature is and why it is important.

As part of that, it would be helpful to specifically mention the documentation
for hardware-wrapped keys in Documentation/block/inline-encryption.rst that I
included in my patchset.  It provides a lot of background information that your
patches are hard to understand without (at least your patches 2-4; your first
patch isn't dependent on the hardware-wrapped keys feature).

Can you include information about how your patches were tested?  That's really
important to include.

Please run './scripts/checkpatch.pl' on your patches, as recommended in
Documentation/process/submitting-patches.rst.  It can catch a lot of issues.

Please use the imperative tense, like "add wrapped key support" rather than
"adds wrapped key support".

I'll leave some more comments on the individual patches.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/4] ufs: move ICE functionality to a common library
  2021-11-03 23:18 ` [PATCH 1/4] ufs: move ICE functionality to a common library Gaurav Kashyap
@ 2021-11-04 23:05   ` Eric Biggers
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Biggers @ 2021-11-04 23:05 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

On Wed, Nov 03, 2021 at 04:18:37PM -0700, Gaurav Kashyap wrote:
> The Inline Crypto Engine functionality is not limited to
> ufs and it can be used by other storage controllers like emmc
> which have the HW capabilities. It would be better to move this
> functionality to a common location.

I think you should be a bit more concrete here: both sdhci-msm and ufs-qcom
already have ICE support, and this common library allows code to be shared.

> Moreover, when wrapped key functionality is added, it would
> reduce the effort required to add it for all storage
> controllers.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/scsi/ufs/ufs-qcom-ice.c   | 172 ++++--------------------------
>  drivers/soc/qcom/Kconfig          |   7 ++
>  drivers/soc/qcom/Makefile         |   1 +
>  drivers/soc/qcom/qti-ice-common.c | 135 +++++++++++++++++++++++
>  drivers/soc/qcom/qti-ice-regs.h   | 145 +++++++++++++++++++++++++
>  include/linux/qti-ice-common.h    |  26 +++++
>  6 files changed, 334 insertions(+), 152 deletions(-)
>  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

This should be split up into two patches: one that adds the library, and one
that converts ufs-qcom to use it.  There should also be a third patch that
converts sdhci-msm to use it.

> +static void get_ice_mmio_data(struct ice_mmio_data *data,
> +			      const struct ufs_qcom_host *host)
> +{
> +	data->ice_mmio = host->ice_mmio;
> +}

I think the struct ice_mmio_data should just be a field of struct ufs_qcom_host.
Then you wouldn't have to keep initializing a new one.

> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 79b568f82a1c..39f223ed8cdd 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 SCSI_UFS_CRYPTO && SCSI_UFS_QCOM
> +	help
> +	  Enable the common ICE library that can be used
> +	  by UFS and EMMC drivers for ICE functionality.

"Libraries" should not be user-selectable.  Instead, they should be selected by
the kconfig options that need them.  That also means that the "depends on"
clause should not be here.

So it should look more like:

config QTI_ICE_COMMON
	tristate
	help
	  Enable the common ICE library that can be used
	  by UFS and EMMC drivers for ICE functionality.

If the library itself has dependencies (perhaps ARCH_QCOM?), then add those.

> +
> +int qti_ice_init(const struct ice_mmio_data *mmio)
> +{
> +	return qti_ice_supported(mmio);
> +}
> +EXPORT_SYMBOL(qti_ice_init);

Please use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL.

The exported functions could also use kerneldoc comments.

> diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h
> new file mode 100644
> index 000000000000..433422b34a7d
> --- /dev/null
> +++ b/include/linux/qti-ice-common.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2021, The Linux Foundation. All rights reserved.
> + */
> +
> +#ifndef _QTI_ICE_COMMON_H
> +#define _QTI_ICE_COMMON_H
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +
> +#define AES_256_XTS_KEY_SIZE    64

Is the definition of AES_256_XTS_KEY_SIZE needed in this header?  It's not
properly "namespaced", so it's sort of the odd thing out in this header.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/4] qcom_scm: scm call for deriving a software secret
  2021-11-03 23:18 ` [PATCH 2/4] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
@ 2021-11-04 23:31   ` Eric Biggers
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Biggers @ 2021-11-04 23:31 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

On Wed, Nov 03, 2021 at 04:18:38PM -0700, Gaurav Kashyap wrote:
> 
> However, when keys are hardware wrapped, it can be only unwrapped
> by Qualcomm Trustzone.

Qualcomm Trustzone is software.  There is a mode where it passes the key to the
actual HWKM hardware as intended, right?

> +/**
> + * 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
> + * @secret_size: size of the secret derived

Please make the semantics of the @secret_size parameter clear.  Will the output
be at least @secret_size, exactly @secret_size, or at most @secret_size?

> + *
> + * Derive a SW secret to be used for inline encryption using Qualcomm ICE.
> + *
> + * Generally, for non-wrapped keys, fscrypt can derive a sw secret from the
> + * key in the clear in the linux keyring.
> + *
> + * However, for wrapped keys, the key needs to be unwrapped, 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.

It's sort of a layering violation to mention fscrypt here, as this is low-level
driver code.  fscrypt is just an example user.  I recommend documenting this in
more general terms, and maybe referring to the "Hardware-wrapped keys" section
of Documentation/block/inline-encryption.rst (which my patchset adds) as that is
intended to explain derive_sw_secret already.

> +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_RAW_SECRET,
> +		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,

wrapped_key is const.  Should it use QCOM_SCM_RO instead of QCOM_SCM_RW?

> +	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)
> +		return -ENOMEM;

In the '!secretbuf' case, this leaks 'keybuf'.

Also, my understanding is that the use of dma_alloc_coherent() here is a bit
unusual.  It would be helpful to leave a comment like:

	/*
	 * 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().
	 */

> +	ret = qcom_scm_call(__scm->dev, &desc, NULL);
> +	memcpy(sw_secret, secretbuf, secret_size);

This is copying out the data even if the SCM call failed.

> diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
> index d92156ceb3ac..de5d4f8fd20d 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_RAW_SECRET 0x07

Can this be renamed to DERIVE_SW_SECRET?

If not, then you probably should call the function qcom_scm_derive_raw_secret()
instead of qcom_scm_derive_sw_secret(), since the functions in qcom_scm.c are
intended to be thin wrappers around the SCM calls.  The naming difference can be
dealt with at a higher level.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 3/4] soc: qcom: add HWKM library for storage encryption
  2021-11-03 23:18 ` [PATCH 3/4] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
@ 2021-11-04 23:46   ` Eric Biggers
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Biggers @ 2021-11-04 23:46 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

On Wed, Nov 03, 2021 at 04:18:39PM -0700, Gaurav Kashyap wrote:
> 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
> capabilites to be acessed from the linux kernel in the future.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/soc/qcom/Kconfig        |   7 ++
>  drivers/soc/qcom/Makefile       |   1 +
>  drivers/soc/qcom/qti-ice-hwkm.c |  77 ++++++++++++++++++++++
>  drivers/soc/qcom/qti-ice-regs.h | 112 ++++++++++++++++++++++++++++++++
>  include/linux/qti-ice-common.h  |   6 ++
>  5 files changed, 203 insertions(+)
>  create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c
> 
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 39f223ed8cdd..d441d5b81c53 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -216,4 +216,11 @@ config QTI_ICE_COMMON
>  	help
>  	  Enable the common ICE library that can be used
>  	  by UFS and EMMC drivers for ICE functionality.
> +
> +config QTI_HW_WRAPPED_KEYS
> +	tristate "QTI HW Wrapped Keys"
> +	depends on QTI_ICE_COMMON
> +	help
> +	  Enable wrapped key functionality for storage
> +	  encryption.

It might be reasonable to just include the hardware-wrapped key support whenever
QTI_ICE_COMMON is enabled.  Note that I'm not planning separate kconfig options
at the block or fscrypt levels.

If we do have this kconfig option, then please make sure that the help text
properly explains it.  That should include linking to the documentation where
the reader can find out more about what this feature is, and hence why they
might want to enable it, or not enable it.

Also this code probably should be part of the qti-ice-common module (which maybe
should be called "qti-ice-lib"?) rather than its own module.  That would mean
making QTI_HW_WRAPPED_KEYS a bool option that controls whether qti-ice-hwkm.c is
built into qti-ice-common, rather than a tristate that controls whether it's
built into its own module.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] soc: qcom: add wrapped key support for ICE
  2021-11-03 23:18 ` [PATCH 4/4] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
@ 2021-11-05  0:08   ` Eric Biggers
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Biggers @ 2021-11-05  0:08 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

On Wed, Nov 03, 2021 at 04:18:40PM -0700, Gaurav Kashyap wrote:
> 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.
> 4. Added support for deriving SW secret as it cannot be done in
>    linux kernel for wrapped keys.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/scsi/ufs/ufs-qcom-ice.c   |  34 +++++++++-
>  drivers/scsi/ufs/ufs-qcom.c       |   1 +
>  drivers/scsi/ufs/ufs-qcom.h       |   5 ++
>  drivers/scsi/ufs/ufshcd-crypto.c  |  47 ++++++++++---
>  drivers/scsi/ufs/ufshcd.h         |   5 ++
>  drivers/soc/qcom/qti-ice-common.c | 108 ++++++++++++++++++++++++++----
>  include/linux/qti-ice-common.h    |   7 +-
>  7 files changed, 180 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
> index 6608a9015eab..79d642190997 100644
> --- a/drivers/scsi/ufs/ufs-qcom-ice.c
> +++ b/drivers/scsi/ufs/ufs-qcom-ice.c
> @@ -45,6 +45,21 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
>  	}
>  	mmio.ice_mmio = host->ice_mmio;
>  
> +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm");
> +	if (!res) {
> +		dev_warn(dev, "ICE HWKM registers not found\n");
> +		goto disable;
> +	}
> +
> +	host->ice_hwkm_mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(host->ice_hwkm_mmio)) {
> +		err = PTR_ERR(host->ice_hwkm_mmio);
> +		dev_err(dev, "Failed to map ICE registers; err=%d\n", err);
> +		return err;
> +	}
> +	mmio.ice_hwkm_mmio = host->ice_hwkm_mmio;
> +#endif

The driver shouldn't completely disable ICE support just because HW wrapped keys
aren't supported by the hardware or by the device tree file.  Instead, it should
declare support for standard keys only.  I.e. CONFIG_QTI_HW_WRAPPED_KEYS
shouldn't force the use of HW wrapped keys, it should just add support for them.

> diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
> index 0ed82741f981..965a8cc6c183 100644
> --- a/drivers/scsi/ufs/ufshcd-crypto.c
> +++ b/drivers/scsi/ufs/ufshcd-crypto.c

ufshcd-crypto.c is part of ufshcd-core, not ufs_qcom.  It should be changed in a
separate patch.

> @@ -18,6 +18,7 @@ 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;
> @@ -27,7 +28,7 @@ static int ufshcd_program_key(struct ufs_hba *hba,
>  	ufshcd_hold(hba, false);
>  
>  	if (hba->vops && hba->vops->program_key) {
> -		err = hba->vops->program_key(hba, cfg, slot);
> +		err = hba->vops->program_key(hba, key, cfg, slot);
>  		goto out;
>  	}

vops->program_key shouldn't take in both a key and a cfg.  It should be just one
or the other.  'cfg' doesn't appear to work for HW wrapped keys, and it seems
the existing user doesn't really need a 'cfg' in the first place, so it would
have to be just 'key'.

> +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)

As noted above, ufshcd-crypto isn't specific to ufs_qcom.  It therefore must not
contain references to CONFIG_QTI_HW_WRAPPED_KEYS, as that kconfig option is
specific to Qualcomm platforms.

> +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(wrapped_key,
> +							wrapped_key_size, sw_secret);
> +
> +	return 0;
> +}

The fallback case should return -EOPNOTSUPP, which indicates that the operation
is not supported, rather than 0 which indicates that it succeeded.

> @@ -190,7 +213,11 @@ 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;
> +#if IS_ENABLED(CONFIG_QTI_HW_WRAPPED_KEYS)
> +	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
> +#else
>  	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD;
> +#endif
>  	hba->crypto_profile.dev = hba->dev;

My comments from above apply to this too.  Checking a Qualcomm-specific kconfig
option isn't appropriate here.  Also the supported key types shouldn't be static
from the kconfig; they should be determined by the actual hardware capabilities.

Note that in the Android kernels, for the division of work between ufshcd-core
and host drivers, we ended up going with a solution where the UFS host drivers
can just override the whole blk_crypto_profile (previously called
blk_keyslot_manager).  You may have to do the same, although it would be
preferable to find a way to share more code.

Also, at runtime, does any of the Qualcomm hardware support multiple key types,
and if so can they be used at the same time?

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 0/4] Adds wrapped key support for inline storage encryption
  2021-11-04 22:49 ` [PATCH 0/4] Adds wrapped key support for inline storage encryption Eric Biggers
@ 2021-12-08  0:09   ` Gaurav Kashyap
  2021-12-08  0:23     ` Eric Biggers
  0 siblings, 1 reply; 13+ messages in thread
From: Gaurav Kashyap @ 2021-12-08  0:09 UTC (permalink / raw)
  To: Eric Biggers, Gaurav Kashyap (QUIC)
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

Hey Eric, here are the answers to some of the questions across all the patches

Also, at runtime, does any of the Qualcomm hardware support multiple key types, and if so can they be used at the same time?

- 	Currently, with hardware key manager data path, there is no support for standard keys. So, when HWKM is being used, only wrapped keys are supported.
	If standard keys need to be supported, it can be, but modifications are required within trustzone.

> However, when keys are hardware wrapped, it can be only unwrapped by 
> Qualcomm Trustzone.
Qualcomm Trustzone is software.  There is a mode where it passes the key to the actual HWKM hardware as intended, right?

-	That's right, trustzone does not perform any unwrap, it is done by the hardware. It was a wrong explanation from my end.

Please make the semantics of the @secret_size parameter clear.  Will the output be at least @secret_size, exactly @secret_size, or at most @secret_size?
- 	Updated this in the latest patches.

Warm Regards,
Gaurav Kashyap

-----Original Message-----
From: Eric Biggers <ebiggers@kernel.org> 
Sent: Thursday, November 4, 2021 3:49 PM
To: Gaurav Kashyap (QUIC) <quic_gaurkash@quicinc.com>
Cc: linux-scsi@vger.kernel.org; linux-arm-msm@vger.kernel.org; linux-mmc@vger.kernel.org; linux-block@vger.kernel.org; linux-fscrypt@vger.kernel.org; thara.gopinath@linaro.org; asutoshd@codeaurora.org
Subject: Re: [PATCH 0/4] Adds wrapped key support for inline storage encryption

WARNING: This email originated from outside of Qualcomm. Please be wary of any links or attachments, and do not enable macros.

Hi Gaurav,

On Wed, Nov 03, 2021 at 04:18:36PM -0700, Gaurav Kashyap wrote:
> This currently has 4 patches with another coming in shortly for MMC.
>
> 1. Moves ICE functionality to a common library, so that different storage controllers can use it.
> 2. Adds a SCM call for derive raw secret needed for wrapped keys.
> 3. Adds a hardware key manager library needed for wrapped keys.
> 4. Adds wrapped key support in ufs for storage encryption
>
> Gaurav Kashyap (4):
>   ufs: move ICE functionality to a common library
>   qcom_scm: scm call for deriving a software secret
>   soc: qcom: add HWKM library for storage encryption
>   soc: qcom: add wrapped key support for ICE
>
>  drivers/firmware/qcom_scm.c       |  61 +++++++
>  drivers/firmware/qcom_scm.h       |   1 +
>  drivers/scsi/ufs/ufs-qcom-ice.c   | 200 ++++++-----------------
>  drivers/scsi/ufs/ufs-qcom.c       |   1 +
>  drivers/scsi/ufs/ufs-qcom.h       |   5 +
>  drivers/scsi/ufs/ufshcd-crypto.c  |  47 ++++--
>  drivers/scsi/ufs/ufshcd.h         |   5 +
>  drivers/soc/qcom/Kconfig          |  14 ++
>  drivers/soc/qcom/Makefile         |   2 +
>  drivers/soc/qcom/qti-ice-common.c | 215 +++++++++++++++++++++++++
>  drivers/soc/qcom/qti-ice-hwkm.c   |  77 +++++++++
>  drivers/soc/qcom/qti-ice-regs.h   | 257 ++++++++++++++++++++++++++++++
>  include/linux/qcom_scm.h          |   5 +
>  include/linux/qti-ice-common.h    |  37 +++++
>  14 files changed, 766 insertions(+), 161 deletions(-)  create mode 
> 100644 drivers/soc/qcom/qti-ice-common.c  create mode 100644 
> drivers/soc/qcom/qti-ice-hwkm.c  create mode 100644 
> drivers/soc/qcom/qti-ice-regs.h  create mode 100644 
> include/linux/qti-ice-common.h

Thanks for the patches!  These are on top of my patchset "[RFC PATCH v2 0/5] Support for hardware-wrapped inline encryption keys"
(https://lore.kernel.org/linux-block/20210916174928.65529-1-ebiggers@kernel.org),
right?  You should mention that in your cover letter, so that it's possible for people to apply your patches for reviewing or testing, and also to provide context about what this feature is and why it is important.

As part of that, it would be helpful to specifically mention the documentation for hardware-wrapped keys in Documentation/block/inline-encryption.rst that I included in my patchset.  It provides a lot of background information that your patches are hard to understand without (at least your patches 2-4; your first patch isn't dependent on the hardware-wrapped keys feature).

Can you include information about how your patches were tested?  That's really important to include.

Please run './scripts/checkpatch.pl' on your patches, as recommended in Documentation/process/submitting-patches.rst.  It can catch a lot of issues.

Please use the imperative tense, like "add wrapped key support" rather than "adds wrapped key support".

I'll leave some more comments on the individual patches.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/4] Adds wrapped key support for inline storage encryption
  2021-12-08  0:09   ` Gaurav Kashyap
@ 2021-12-08  0:23     ` Eric Biggers
  2021-12-08 18:13       ` Gaurav Kashyap
  0 siblings, 1 reply; 13+ messages in thread
From: Eric Biggers @ 2021-12-08  0:23 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: Gaurav Kashyap (QUIC),
	linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd

On Wed, Dec 08, 2021 at 12:09:03AM +0000, Gaurav Kashyap wrote:
> Hey Eric, here are the answers to some of the questions across all the patches
> 
> > Also, at runtime, does any of the Qualcomm hardware support multiple key
> > types, and if so can they be used at the same time?
> 
> Currently, with hardware key manager data path, there is no support for
> standard keys. So, when HWKM is being used, only wrapped keys are supported.
> If standard keys need to be supported, it can be, but modifications are
> required within trustzone.

Do the SoCs support both key types though, just not at the same time?  E.g. when
the ufs_qcom driver loads on SM8350, could it choose to expose either standard
key support or wrapped key support, or is it predetermined by the hardware
and/or firmware?  If the driver has a choice, then there should be a kernel
module parameter (module_param()) that controls it, so that the user can choose
which key type they want when they boot their kernel.

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 0/4] Adds wrapped key support for inline storage encryption
  2021-12-08  0:23     ` Eric Biggers
@ 2021-12-08 18:13       ` Gaurav Kashyap
  0 siblings, 0 replies; 13+ messages in thread
From: Gaurav Kashyap @ 2021-12-08 18:13 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Gaurav Kashyap (QUIC),
	linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, asutoshd



Warm Regards,
Gaurav Kashyap

-----Original Message-----
From: Eric Biggers <ebiggers@kernel.org> 
Sent: Tuesday, December 7, 2021 4:23 PM
To: Gaurav Kashyap <gaurkash@qti.qualcomm.com>
Cc: Gaurav Kashyap (QUIC) <quic_gaurkash@quicinc.com>; linux-scsi@vger.kernel.org; linux-arm-msm@vger.kernel.org; linux-mmc@vger.kernel.org; linux-block@vger.kernel.org; linux-fscrypt@vger.kernel.org; thara.gopinath@linaro.org; asutoshd@codeaurora.org
Subject: Re: [PATCH 0/4] Adds wrapped key support for inline storage encryption

WARNING: This email originated from outside of Qualcomm. Please be wary of any links or attachments, and do not enable macros.

On Wed, Dec 08, 2021 at 12:09:03AM +0000, Gaurav Kashyap wrote:
> Hey Eric, here are the answers to some of the questions across all the 
> patches
>
> > Also, at runtime, does any of the Qualcomm hardware support multiple 
> > key types, and if so can they be used at the same time?
>
> Currently, with hardware key manager data path, there is no support 
> for standard keys. So, when HWKM is being used, only wrapped keys are supported.
> If standard keys need to be supported, it can be, but modifications 
> are required within trustzone.

> Do the SoCs support both key types though, just not at the same time?  E.g. when the ufs_qcom driver loads on SM8350, could it choose to expose either standard key support or wrapped key support, or is it predetermined by the hardware and/or firmware?  If the driver has a choice, > then there should be a kernel module parameter (module_param()) that controls it, so that the user can choose which key type they want when they boot their kernel.
	
As of now, it is predetermined in TZ firmware. As in, if TZ has booted up with HWKM support, only wrapped keys are supported. But it is not impossible for HWKM to support standard keys as well, it is just that currently there is no path in TZ for standard keys when HWKM is being used.
	

- Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-12-08 18:13 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-03 23:18 [PATCH 0/4] Adds wrapped key support for inline storage encryption Gaurav Kashyap
2021-11-03 23:18 ` [PATCH 1/4] ufs: move ICE functionality to a common library Gaurav Kashyap
2021-11-04 23:05   ` Eric Biggers
2021-11-03 23:18 ` [PATCH 2/4] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
2021-11-04 23:31   ` Eric Biggers
2021-11-03 23:18 ` [PATCH 3/4] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
2021-11-04 23:46   ` Eric Biggers
2021-11-03 23:18 ` [PATCH 4/4] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
2021-11-05  0:08   ` Eric Biggers
2021-11-04 22:49 ` [PATCH 0/4] Adds wrapped key support for inline storage encryption Eric Biggers
2021-12-08  0:09   ` Gaurav Kashyap
2021-12-08  0:23     ` Eric Biggers
2021-12-08 18:13       ` Gaurav Kashyap

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).