devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pankaj Gupta <pankaj.gupta@nxp.com>
To: shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, clin@suse.com, conor+dt@kernel.org,
	pierre.gondois@arm.com, ping.bai@nxp.com, xiaoning.wang@nxp.com,
	wei.fang@nxp.com, peng.fan@nxp.com, haibo.chen@nxp.com,
	festevam@gmail.com, linux-imx@nxp.com, davem@davemloft.net,
	robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, gaurav.jain@nxp.com,
	alexander.stein@ew.tq-group.com, sahil.malhotra@nxp.com,
	aisheng.dong@nxp.com, V.Sethi@nxp.com
Cc: Pankaj Gupta <pankaj.gupta@nxp.com>
Subject: [PATCH v5 09/11] firmware: imx: enclave-fw: add handling for save/restore IMEM region
Date: Wed, 23 Aug 2023 13:03:28 +0530	[thread overview]
Message-ID: <20230823073330.1712721-10-pankaj.gupta@nxp.com> (raw)
In-Reply-To: <20230823073330.1712721-1-pankaj.gupta@nxp.com>

Some IMEM region is lost during kernel power down. Due to this,
firmware's functionaity cannot work correctly.

Saving encrypted IMEM region in kernel memory during power down,
and restore IMEM region on resume.

Signed-off-by: Gaurav Jain <gaurav.jain@nxp.com>
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
---
 drivers/firmware/imx/ele_base_msg.c       |  42 ++++++++
 drivers/firmware/imx/ele_common.c         | 114 ++++++++++++++++++++++
 drivers/firmware/imx/ele_common.h         |   8 ++
 drivers/firmware/imx/se_fw.c              |  45 ++++++++-
 drivers/firmware/imx/se_fw.h              |   8 ++
 include/linux/firmware/imx/ele_base_msg.h |  15 ++-
 6 files changed, 228 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index c42e29e14662..b19ab8abeeb8 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -148,3 +148,45 @@ int ele_start_rng(struct device *dev)
 
 	return -EINVAL;
 }
+
+int ele_service_swap(struct device *dev,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag)
+{
+	struct ele_mu_priv *priv = dev_get_drvdata(dev);
+	int ret;
+	unsigned int tag, command, size, ver, status;
+
+	ret = plat_fill_cmd_msg_hdr(priv,
+				    (struct mu_hdr *)&priv->tx_msg.header,
+				    ELE_SERVICE_SWAP_REQ, 24);
+	if (ret)
+		return ret;
+
+	priv->tx_msg.data[0] = flag;
+	priv->tx_msg.data[1] = addr_size;
+	priv->tx_msg.data[2] = ELE_NONE_VAL;
+	priv->tx_msg.data[3] = lower_32_bits(addr);
+	priv->tx_msg.data[4] = plat_add_msg_crc((uint32_t *)&priv->tx_msg, 24);
+	ret = imx_ele_msg_send_rcv(priv);
+	if (ret < 0)
+		return ret;
+
+	tag = MSG_TAG(priv->rx_msg.header);
+	command = MSG_COMMAND(priv->rx_msg.header);
+	size = MSG_SIZE(priv->rx_msg.header);
+	ver = MSG_VER(priv->rx_msg.header);
+	status = RES_STATUS(priv->rx_msg.data[0]);
+	if (tag == priv->rsp_tag &&
+	    command == ELE_SERVICE_SWAP_REQ &&
+	    size == ELE_SERVICE_SWAP_REQ_MSG_SZ &&
+	    ver == ELE_BASE_API_VERSION &&
+	    status == priv->success_tag) {
+		if (flag == ELE_IMEM_EXPORT)
+			return priv->rx_msg.data[1];
+		else
+			return 0;
+	}
+
+	return -EINVAL;
+}
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index f01e5e3255f9..f6feb8f986a7 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -9,6 +9,18 @@
 
 #include "ele_common.h"
 
+uint32_t plat_add_msg_crc(uint32_t *msg, uint32_t msg_len)
+{
+	uint32_t i;
+	uint32_t crc = 0;
+	uint32_t nb_words = msg_len / (uint32_t)sizeof(uint32_t);
+
+	for (i = 0; i < nb_words - 1; i++)
+		crc ^= *(msg + i);
+
+	return crc;
+}
+
 int imx_ele_msg_send_rcv(struct ele_mu_priv *priv)
 {
 	unsigned int wait;
@@ -72,3 +84,105 @@ int ele_do_start_rng(struct device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+int save_imem(struct device *dev)
+{
+	int ret;
+	struct ele_mu_priv *priv = dev_get_drvdata(dev);
+
+	/* EXPORT command will save encrypted IMEM to given address,
+	 * so later in resume, IMEM can be restored from the given
+	 * address.
+	 *
+	 * Size must be at least 64 kB.
+	 */
+	ret = ele_service_swap(dev,
+			       priv->imem.phyaddr,
+			       ELE_IMEM_SIZE,
+			       ELE_IMEM_EXPORT);
+	if (ret < 0)
+		dev_err(dev, "Failed to export IMEM\n");
+	else
+		dev_info(dev,
+				"Exported %d bytes of encrypted IMEM\n",
+				ret);
+
+	return ret;
+}
+
+int restore_imem(struct device *dev,
+		 uint8_t *pool_name)
+{
+	int ret;
+	u32 imem_state;
+	u32 *get_info_buf = NULL;
+	phys_addr_t get_info_phyaddr = 0;
+	struct ele_mu_priv *priv = dev_get_drvdata(dev);
+
+	get_info_phyaddr
+		= pool_name ? get_phy_buf_mem_pool(dev,
+						   pool_name,
+						   &get_info_buf,
+						   DEVICE_GET_INFO_SZ)
+			    : 0x0;
+
+	if (!get_info_buf) {
+		dev_err(dev, "Unable to alloc sram from sram pool\n");
+		return -ENOMEM;
+	}
+
+	ret = ele_do_start_rng(dev);
+	if (ret)
+		goto exit;
+
+	/* get info from ELE */
+	ret = ele_get_info(dev, get_info_phyaddr, ELE_GET_INFO_READ_SZ);
+	if (ret) {
+		dev_err(dev, "Failed to get info from ELE.\n");
+		goto exit;
+	}
+
+	/* Get IMEM state, if 0xFE then import IMEM */
+	imem_state = (get_info_buf[ELE_IMEM_STATE_WORD]
+			& ELE_IMEM_STATE_MASK) >> 16;
+	if (imem_state == ELE_IMEM_STATE_BAD) {
+		/* IMPORT command will restore IMEM from the given
+		 * address, here size is the actual size returned by ELE
+		 * during the export operation
+		 */
+		ret = ele_service_swap(dev,
+				       priv->imem.phyaddr,
+				       priv->imem.size,
+				       ELE_IMEM_IMPORT);
+		if (ret) {
+			dev_err(dev, "Failed to import IMEM\n");
+			goto exit;
+		}
+	} else
+		goto exit;
+
+	/* After importing IMEM, check if IMEM state is equal to 0xCA
+	 * to ensure IMEM is fully loaded and
+	 * ELE functionality can be used.
+	 */
+	ret = ele_get_info(dev, get_info_phyaddr, ELE_GET_INFO_READ_SZ);
+	if (ret) {
+		dev_err(dev, "Failed to get info from ELE.\n");
+		goto exit;
+	}
+
+	imem_state = (get_info_buf[ELE_IMEM_STATE_WORD]
+			& ELE_IMEM_STATE_MASK) >> 16;
+	if (imem_state == ELE_IMEM_STATE_OK)
+		dev_info(dev, "Successfully restored IMEM\n");
+	else
+		dev_err(dev, "Failed to restore IMEM\n");
+
+exit:
+	if (pool_name && get_info_buf)
+		free_phybuf_mem_pool(dev, pool_name,
+				get_info_buf, DEVICE_GET_INFO_SZ);
+
+	return ret;
+}
+#endif
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index ed68e5cf9638..55bcbb9fc261 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -9,6 +9,7 @@
 
 #include "se_fw.h"
 
+uint32_t plat_add_msg_crc(uint32_t *msg, uint32_t msg_len);
 int imx_ele_msg_send_rcv(struct ele_mu_priv *priv);
 #ifdef CONFIG_IMX_ELE_TRNG
 int ele_trng_init(struct device *dev);
@@ -20,4 +21,11 @@ static inline int ele_trng_init(struct device *dev)
 #endif
 
 int ele_do_start_rng(struct device *dev);
+
+#ifdef CONFIG_PM_SLEEP
+int save_imem(struct device *dev);
+int restore_imem(struct device *dev,
+		 uint8_t *pool_name);
 #endif
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_fw.c b/drivers/firmware/imx/se_fw.c
index 6083c42dcda3..936fc0352054 100644
--- a/drivers/firmware/imx/se_fw.c
+++ b/drivers/firmware/imx/se_fw.c
@@ -46,6 +46,7 @@ struct imx_info {
 	/* platform specific flag to enable/disable the ELE True RNG */
 	bool start_rng;
 	bool enable_ele_trng;
+	bool imem_mgmt;
 };
 
 static LIST_HEAD(priv_data_list);
@@ -63,6 +64,7 @@ static const struct imx_info imx8ulp_info = {
 	.init_fw = false,
 	.start_rng = true,
 	.enable_ele_trng = false,
+	.imem_mgmt = true,
 };
 
 static const struct imx_info imx93_info = {
@@ -78,6 +80,7 @@ static const struct imx_info imx93_info = {
 	.init_fw = true,
 	.start_rng = true,
 	.enable_ele_trng = true,
+	.imem_mgmt = false,
 };
 
 static const struct of_device_id se_fw_match[] = {
@@ -160,7 +163,7 @@ static void ele_mu_rx_callback(struct mbox_client *c, void *msg)
 
 }
 
-static phys_addr_t get_phy_buf_mem_pool(struct device *dev,
+phys_addr_t get_phy_buf_mem_pool(struct device *dev,
 					char *mem_pool_name,
 					u32 **buf,
 					uint32_t size)
@@ -182,7 +185,7 @@ static phys_addr_t get_phy_buf_mem_pool(struct device *dev,
 	return gen_pool_virt_to_phys(mem_pool, (ulong)*buf);
 }
 
-static void free_phybuf_mem_pool(struct device *dev,
+void free_phybuf_mem_pool(struct device *dev,
 				 char *mem_pool_name,
 				 u32 *buf,
 				 uint32_t size)
@@ -959,6 +962,17 @@ static int se_probe_cleanup(struct platform_device *pdev)
 		priv->flags &= (~RESERVED_DMA_POOL);
 	}
 
+	/* free the buffer in ele-mu remove, previously allocated
+	 * in ele-mu probe to store encrypted IMEM
+	 */
+	if (priv->imem.buf) {
+		dmam_free_coherent(&pdev->dev,
+				   ELE_IMEM_SIZE,
+				   priv->imem.buf,
+				   priv->imem.phyaddr);
+		priv->imem.buf = NULL;
+	}
+
 	if (priv->ctxs) {
 		for (i = 0; i < priv->max_dev_ctx; i++) {
 			if (priv->ctxs[i])
@@ -1160,6 +1174,19 @@ static int se_fw_probe(struct platform_device *pdev)
 			dev_err(dev, "Failed to init ele-trng\n");
 	}
 
+	if (info->imem_mgmt) {
+		/* allocate buffer where ELE store encrypted IMEM */
+		priv->imem.buf = dmam_alloc_coherent(dev, ELE_IMEM_SIZE,
+						     &priv->imem.phyaddr,
+						     GFP_KERNEL);
+		if (!priv->imem.buf) {
+			dev_err(dev,
+				"dmam-alloc-failed: To store encr-IMEM.\n");
+			ret = -ENOMEM;
+			goto exit;
+		}
+	}
+
 	pr_info("i.MX secure-enclave: %s's mu#%d interface to firmware, configured.\n",
 		info->se_name,
 		priv->ele_mu_id);
@@ -1196,17 +1223,31 @@ static int se_fw_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int se_fw_suspend(struct device *dev)
 {
+	struct ele_mu_priv *priv = dev_get_drvdata(dev);
+	const struct of_device_id *of_id = of_match_device(se_fw_match, dev);
+	struct imx_info *info = (of_id != NULL) ? (struct imx_info *)of_id->data
+						: NULL;
+
+	if (info && info->imem_mgmt)
+		priv->imem.size = save_imem(dev);
+
 	return 0;
 }
 
 static int se_fw_resume(struct device *dev)
 {
 	struct ele_mu_priv *priv = dev_get_drvdata(dev);
+	const struct of_device_id *of_id = of_match_device(se_fw_match, dev);
+	struct imx_info *info = (of_id != NULL) ? (struct imx_info *)of_id->data
+						: NULL;
 	int i;
 
 	for (i = 0; i < priv->max_dev_ctx; i++)
 		wake_up_interruptible(&priv->ctxs[i]->wq);
 
+	if (info && info->imem_mgmt)
+		restore_imem(dev, info->pool_name);
+
 	return 0;
 }
 #endif
diff --git a/drivers/firmware/imx/se_fw.h b/drivers/firmware/imx/se_fw.h
index b3502affbc85..acb967f2357c 100644
--- a/drivers/firmware/imx/se_fw.h
+++ b/drivers/firmware/imx/se_fw.h
@@ -165,4 +165,12 @@ struct ele_mu_priv {
 	struct ele_imem_buf imem;
 };
 
+phys_addr_t get_phy_buf_mem_pool(struct device *dev,
+				 char *mem_pool_name,
+				 u32 **buf,
+				 uint32_t size);
+void free_phybuf_mem_pool(struct device *dev,
+			  char *mem_pool_name,
+			  u32 *buf,
+			  uint32_t size);
 #endif
diff --git a/include/linux/firmware/imx/ele_base_msg.h b/include/linux/firmware/imx/ele_base_msg.h
index 8a5c385210fc..6fbea7a8d7c9 100644
--- a/include/linux/firmware/imx/ele_base_msg.h
+++ b/include/linux/firmware/imx/ele_base_msg.h
@@ -37,12 +37,23 @@
 #define ELE_GET_TRNG_STATE_RETRY_COUNT	0x5
 #define CSAL_TRNG_STATE_MASK		0x0000ffff
 
+#define ELE_SERVICE_SWAP_REQ		0xDF
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ	0x03
+#define ELE_IMEM_SIZE			0x10000
+#define ELE_IMEM_STATE_OK		0xCA
+#define ELE_IMEM_STATE_BAD		0xFE
+#define ELE_IMEM_STATE_WORD		0x27
+#define ELE_IMEM_STATE_MASK		0x00ff0000
+#define ELE_IMEM_EXPORT			0x1
+#define ELE_IMEM_IMPORT			0x2
+
 #define ELE_BASE_API_VERSION		0x6
-#define ELE_SUCCESS_IND			0xD6
-#define ELE_FAILURE_IND			0x29
 
 int ele_get_info(struct device *dev, phys_addr_t addr, u32 data_size);
 int ele_start_rng(struct device *dev);
 int ele_get_trng_state(struct device *dev);
+int ele_service_swap(struct device *dev,
+		     phys_addr_t addr,
+		     u32 addr_size, u16 flag);
 
 #endif
-- 
2.34.1


  parent reply	other threads:[~2023-08-23  7:37 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-23  7:33 [PATCH v5 00/11] firmware: imx: NXP Secure-Enclave FW Driver Pankaj Gupta
2023-08-23  7:33 ` [PATCH v5 01/11] dt-bindings: arm: fsl: add imx-se-fw binding doc Pankaj Gupta
2023-08-23  8:28   ` Rob Herring
2023-08-23 10:42     ` [EXT] " Pankaj Gupta
2023-08-23 12:43   ` Rob Herring
2023-08-24 18:45     ` Krzysztof Kozlowski
2023-08-24 19:23       ` Greg Kroah-Hartman
2023-08-28  6:00         ` [EXT] " Varun Sethi
2023-08-28  6:55           ` Krzysztof Kozlowski
2023-08-28  9:14             ` Varun Sethi
     [not found]       ` <DU2PR04MB86302A2639CA64D8DF08BF0495E3A@DU2PR04MB8630.eurprd04.prod.outlook.com>
2023-08-25  7:56         ` Varun Sethi
2023-08-23  7:33 ` [PATCH v5 02/11] arm64: dts: imx8ulp-evk: added nxp secure enclave firmware Pankaj Gupta
2023-08-23  7:33 ` [PATCH v5 03/11] arm64: dts: imx8ulp-evk: reserved mem-ranges to constrain ele_fw dma-range Pankaj Gupta
2023-08-23  7:33 ` [PATCH v5 04/11] arm64: dts: imx93-11x11-evk: added nxp secure enclave fw Pankaj Gupta
2023-08-23  7:33 ` [PATCH v5 05/11] arm64: dts: imx93-11x11-evk: reserved mem-ranges to constrain ele_fw dma-range Pankaj Gupta
2023-08-23  7:33 ` [PATCH v5 06/11] firmware: imx: add driver for NXP EdgeLock Enclave Pankaj Gupta
2023-08-24 18:31   ` Krzysztof Kozlowski
2023-08-25 10:22   ` Stefan Wahren
2023-08-25 15:16     ` Conor Dooley
2023-08-23  7:33 ` [PATCH v5 07/11] firmware: imx: init-fw api exchange on imx93 Pankaj Gupta
2023-08-24 18:35   ` Krzysztof Kozlowski
2023-08-23  7:33 ` [PATCH v5 08/11] firmware: imx: enable trng Pankaj Gupta
2023-08-24 18:23   ` Krzysztof Kozlowski
2023-08-23  7:33 ` Pankaj Gupta [this message]
2023-08-24 18:37   ` [PATCH v5 09/11] firmware: imx: enclave-fw: add handling for save/restore IMEM region Krzysztof Kozlowski
2023-08-23  7:33 ` [PATCH v5 10/11] firmware: imx: enclave api to read-common-fuses Pankaj Gupta
2023-08-24 18:38   ` Krzysztof Kozlowski
2023-08-23  7:33 ` [PATCH v5 11/11] MAINTAINERS: Added maintainer details Pankaj Gupta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230823073330.1712721-10-pankaj.gupta@nxp.com \
    --to=pankaj.gupta@nxp.com \
    --cc=V.Sethi@nxp.com \
    --cc=aisheng.dong@nxp.com \
    --cc=alexander.stein@ew.tq-group.com \
    --cc=clin@suse.com \
    --cc=conor+dt@kernel.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=festevam@gmail.com \
    --cc=gaurav.jain@nxp.com \
    --cc=haibo.chen@nxp.com \
    --cc=kernel@pengutronix.de \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peng.fan@nxp.com \
    --cc=pierre.gondois@arm.com \
    --cc=ping.bai@nxp.com \
    --cc=robh+dt@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=sahil.malhotra@nxp.com \
    --cc=shawnguo@kernel.org \
    --cc=wei.fang@nxp.com \
    --cc=xiaoning.wang@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).