Jiri Slaby ef7db2
From: Sibi Sankar <quic_sibis@quicinc.com>
Jiri Slaby ef7db2
Date: Tue, 17 Jan 2023 14:28:35 +0530
Jiri Slaby ef7db2
Subject: [PATCH] remoteproc: qcom_q6v5_mss: Use a carveout to authenticate
Jiri Slaby ef7db2
 modem headers
Jiri Slaby ef7db2
References: bsc#1012628
Jiri Slaby ef7db2
Patch-mainline: 6.2.3
Jiri Slaby ef7db2
Git-commit: 57f72170a2b2a362c35bb9407fc844eac5afdec1
Jiri Slaby ef7db2
Jiri Slaby ef7db2
[ Upstream commit 57f72170a2b2a362c35bb9407fc844eac5afdec1 ]
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Any access to the dynamically allocated metadata region by the application
Jiri Slaby ef7db2
processor after assigning it to the remote Q6 will result in a XPU
Jiri Slaby ef7db2
violation. Fix this by replacing the dynamically allocated memory region
Jiri Slaby ef7db2
with a no-map carveout and unmap the modem metadata memory region before
Jiri Slaby ef7db2
passing control to the remote Q6.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Reported-and-tested-by: Amit Pundir <amit.pundir@linaro.org>
Jiri Slaby ef7db2
Fixes: 6c5a9dc2481b ("remoteproc: qcom: Make secure world call for mem ownership switch")
Jiri Slaby ef7db2
Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com>
Jiri Slaby ef7db2
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Jiri Slaby ef7db2
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Jiri Slaby ef7db2
Link: https://lore.kernel.org/r/20230117085840.32356-7-quic_sibis@quicinc.com
Jiri Slaby ef7db2
Signed-off-by: Sasha Levin <sashal@kernel.org>
Jiri Slaby ef7db2
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby ef7db2
---
Jiri Slaby ef7db2
 drivers/remoteproc/qcom_q6v5_mss.c | 59 +++++++++++++++++++++++++++---
Jiri Slaby ef7db2
 1 file changed, 53 insertions(+), 6 deletions(-)
Jiri Slaby ef7db2
Jiri Slaby ef7db2
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
Jiri Slaby ef7db2
index a8b141db..7dbab5fc 100644
Jiri Slaby ef7db2
--- a/drivers/remoteproc/qcom_q6v5_mss.c
Jiri Slaby ef7db2
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
Jiri Slaby ef7db2
@@ -17,6 +17,7 @@
Jiri Slaby ef7db2
 #include <linux/module.h>
Jiri Slaby ef7db2
 #include <linux/of_address.h>
Jiri Slaby ef7db2
 #include <linux/of_device.h>
Jiri Slaby ef7db2
+#include <linux/of_reserved_mem.h>
Jiri Slaby ef7db2
 #include <linux/platform_device.h>
Jiri Slaby ef7db2
 #include <linux/pm_domain.h>
Jiri Slaby ef7db2
 #include <linux/pm_runtime.h>
Jiri Slaby ef7db2
@@ -210,6 +211,9 @@ struct q6v5 {
Jiri Slaby ef7db2
 	size_t mba_size;
Jiri Slaby ef7db2
 	size_t dp_size;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+	phys_addr_t mdata_phys;
Jiri Slaby ef7db2
+	size_t mdata_size;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 	phys_addr_t mpss_phys;
Jiri Slaby ef7db2
 	phys_addr_t mpss_reloc;
Jiri Slaby ef7db2
 	size_t mpss_size;
Jiri Slaby ef7db2
@@ -945,15 +949,35 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
Jiri Slaby ef7db2
 	if (IS_ERR(metadata))
Jiri Slaby ef7db2
 		return PTR_ERR(metadata);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-	ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
Jiri Slaby ef7db2
-	if (!ptr) {
Jiri Slaby ef7db2
-		kfree(metadata);
Jiri Slaby ef7db2
-		dev_err(qproc->dev, "failed to allocate mdt buffer\n");
Jiri Slaby ef7db2
-		return -ENOMEM;
Jiri Slaby ef7db2
+	if (qproc->mdata_phys) {
Jiri Slaby ef7db2
+		if (size > qproc->mdata_size) {
Jiri Slaby ef7db2
+			ret = -EINVAL;
Jiri Slaby ef7db2
+			dev_err(qproc->dev, "metadata size outside memory range\n");
Jiri Slaby ef7db2
+			goto free_metadata;
Jiri Slaby ef7db2
+		}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+		phys = qproc->mdata_phys;
Jiri Slaby ef7db2
+		ptr = memremap(qproc->mdata_phys, size, MEMREMAP_WC);
Jiri Slaby ef7db2
+		if (!ptr) {
Jiri Slaby ef7db2
+			ret = -EBUSY;
Jiri Slaby ef7db2
+			dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
Jiri Slaby ef7db2
+				&qproc->mdata_phys, size);
Jiri Slaby ef7db2
+			goto free_metadata;
Jiri Slaby ef7db2
+		}
Jiri Slaby ef7db2
+	} else {
Jiri Slaby ef7db2
+		ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
Jiri Slaby ef7db2
+		if (!ptr) {
Jiri Slaby ef7db2
+			ret = -ENOMEM;
Jiri Slaby ef7db2
+			dev_err(qproc->dev, "failed to allocate mdt buffer\n");
Jiri Slaby ef7db2
+			goto free_metadata;
Jiri Slaby ef7db2
+		}
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	memcpy(ptr, metadata, size);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+	if (qproc->mdata_phys)
Jiri Slaby ef7db2
+		memunmap(ptr);
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 	/* Hypervisor mapping to access metadata by modem */
Jiri Slaby ef7db2
 	mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
Jiri Slaby ef7db2
 	ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, true,
Jiri Slaby ef7db2
@@ -982,7 +1006,9 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
Jiri Slaby ef7db2
 			 "mdt buffer not reclaimed system may become unstable\n");
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 free_dma_attrs:
Jiri Slaby ef7db2
-	dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
Jiri Slaby ef7db2
+	if (!qproc->mdata_phys)
Jiri Slaby ef7db2
+		dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
Jiri Slaby ef7db2
+free_metadata:
Jiri Slaby ef7db2
 	kfree(metadata);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	return ret < 0 ? ret : 0;
Jiri Slaby ef7db2
@@ -1810,6 +1836,7 @@ static int q6v5_init_reset(struct q6v5 *qproc)
Jiri Slaby ef7db2
 static int q6v5_alloc_memory_region(struct q6v5 *qproc)
Jiri Slaby ef7db2
 {
Jiri Slaby ef7db2
 	struct device_node *child;
Jiri Slaby ef7db2
+	struct reserved_mem *rmem;
Jiri Slaby ef7db2
 	struct device_node *node;
Jiri Slaby ef7db2
 	struct resource r;
Jiri Slaby ef7db2
 	int ret;
Jiri Slaby ef7db2
@@ -1856,6 +1883,26 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
Jiri Slaby ef7db2
 	qproc->mpss_phys = qproc->mpss_reloc = r.start;
Jiri Slaby ef7db2
 	qproc->mpss_size = resource_size(&r);
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+	if (!child) {
Jiri Slaby ef7db2
+		node = of_parse_phandle(qproc->dev->of_node, "memory-region", 2);
Jiri Slaby ef7db2
+	} else {
Jiri Slaby ef7db2
+		child = of_get_child_by_name(qproc->dev->of_node, "metadata");
Jiri Slaby ef7db2
+		node = of_parse_phandle(child, "memory-region", 0);
Jiri Slaby ef7db2
+		of_node_put(child);
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	if (!node)
Jiri Slaby ef7db2
+		return 0;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	rmem = of_reserved_mem_lookup(node);
Jiri Slaby ef7db2
+	if (!rmem) {
Jiri Slaby ef7db2
+		dev_err(qproc->dev, "unable to resolve metadata region\n");
Jiri Slaby ef7db2
+		return -EINVAL;
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	qproc->mdata_phys = rmem->base;
Jiri Slaby ef7db2
+	qproc->mdata_size = rmem->size;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 	return 0;
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
-- 
Jiri Slaby ef7db2
2.35.3
Jiri Slaby ef7db2