Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc85fb57 authored by Sibi Sankar's avatar Sibi Sankar Committed by Greg Kroah-Hartman
Browse files

remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers



[ Upstream commit 57f72170a2b2a362c35bb9407fc844eac5afdec1 ]

Any access to the dynamically allocated metadata region by the application
processor after assigning it to the remote Q6 will result in a XPU
violation. Fix this by replacing the dynamically allocated memory region
with a no-map carveout and unmap the modem metadata memory region before
passing control to the remote Q6.

Reported-and-tested-by: default avatarAmit Pundir <amit.pundir@linaro.org>
Fixes: 6c5a9dc2 ("remoteproc: qcom: Make secure world call for mem ownership switch")
Signed-off-by: default avatarSibi Sankar <quic_sibis@quicinc.com>
Reviewed-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230117085840.32356-7-quic_sibis@quicinc.com


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 3acbec35
Loading
Loading
Loading
Loading
+53 −6
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_runtime.h>
@@ -175,6 +176,9 @@ struct q6v5 {
	void *mba_region;
	void *mba_region;
	size_t mba_size;
	size_t mba_size;


	phys_addr_t mdata_phys;
	size_t mdata_size;

	phys_addr_t mpss_phys;
	phys_addr_t mpss_phys;
	phys_addr_t mpss_reloc;
	phys_addr_t mpss_reloc;
	void *mpss_region;
	void *mpss_region;
@@ -679,15 +683,35 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
	if (IS_ERR(metadata))
	if (IS_ERR(metadata))
		return PTR_ERR(metadata);
		return PTR_ERR(metadata);


	if (qproc->mdata_phys) {
		if (size > qproc->mdata_size) {
			ret = -EINVAL;
			dev_err(qproc->dev, "metadata size outside memory range\n");
			goto free_metadata;
		}

		phys = qproc->mdata_phys;
		ptr = memremap(qproc->mdata_phys, size, MEMREMAP_WC);
		if (!ptr) {
			ret = -EBUSY;
			dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
				&qproc->mdata_phys, size);
			goto free_metadata;
		}
	} else {
		ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
		ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
		if (!ptr) {
		if (!ptr) {
		kfree(metadata);
			ret = -ENOMEM;
			dev_err(qproc->dev, "failed to allocate mdt buffer\n");
			dev_err(qproc->dev, "failed to allocate mdt buffer\n");
		return -ENOMEM;
			goto free_metadata;
		}
	}
	}


	memcpy(ptr, metadata, size);
	memcpy(ptr, metadata, size);


	if (qproc->mdata_phys)
		memunmap(ptr);

	/* Hypervisor mapping to access metadata by modem */
	/* Hypervisor mapping to access metadata by modem */
	mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
	mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
	ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
	ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
@@ -714,7 +738,9 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
			 "mdt buffer not reclaimed system may become unstable\n");
			 "mdt buffer not reclaimed system may become unstable\n");


free_dma_attrs:
free_dma_attrs:
	if (!qproc->mdata_phys)
		dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
		dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
free_metadata:
	kfree(metadata);
	kfree(metadata);


	return ret < 0 ? ret : 0;
	return ret < 0 ? ret : 0;
@@ -1383,6 +1409,7 @@ static int q6v5_init_reset(struct q6v5 *qproc)
static int q6v5_alloc_memory_region(struct q6v5 *qproc)
static int q6v5_alloc_memory_region(struct q6v5 *qproc)
{
{
	struct device_node *child;
	struct device_node *child;
	struct reserved_mem *rmem;
	struct device_node *node;
	struct device_node *node;
	struct resource r;
	struct resource r;
	int ret;
	int ret;
@@ -1417,6 +1444,26 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
	qproc->mpss_phys = qproc->mpss_reloc = r.start;
	qproc->mpss_phys = qproc->mpss_reloc = r.start;
	qproc->mpss_size = resource_size(&r);
	qproc->mpss_size = resource_size(&r);


	if (!child) {
		node = of_parse_phandle(qproc->dev->of_node, "memory-region", 2);
	} else {
		child = of_get_child_by_name(qproc->dev->of_node, "metadata");
		node = of_parse_phandle(child, "memory-region", 0);
		of_node_put(child);
	}

	if (!node)
		return 0;

	rmem = of_reserved_mem_lookup(node);
	if (!rmem) {
		dev_err(qproc->dev, "unable to resolve metadata region\n");
		return -EINVAL;
	}

	qproc->mdata_phys = rmem->base;
	qproc->mdata_size = rmem->size;

	return 0;
	return 0;
}
}