Commit 57f72170 authored by Sibi Sankar's avatar Sibi Sankar Committed by Bjorn Andersson

remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers

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
parent a899d542
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,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>
...@@ -215,6 +216,9 @@ struct q6v5 { ...@@ -215,6 +216,9 @@ struct q6v5 {
size_t mba_size; size_t mba_size;
size_t dp_size; size_t dp_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;
size_t mpss_size; size_t mpss_size;
...@@ -973,15 +977,35 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, ...@@ -973,15 +977,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);
ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); if (qproc->mdata_phys) {
if (!ptr) { if (size > qproc->mdata_size) {
kfree(metadata); ret = -EINVAL;
dev_err(qproc->dev, "failed to allocate mdt buffer\n"); dev_err(qproc->dev, "metadata size outside memory range\n");
return -ENOMEM; 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);
if (!ptr) {
ret = -ENOMEM;
dev_err(qproc->dev, "failed to allocate mdt buffer\n");
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, false, true, ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, true,
...@@ -1010,7 +1034,9 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, ...@@ -1010,7 +1034,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:
dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); if (!qproc->mdata_phys)
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;
...@@ -1847,6 +1873,7 @@ static int q6v5_init_reset(struct q6v5 *qproc) ...@@ -1847,6 +1873,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;
...@@ -1893,6 +1920,26 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) ...@@ -1893,6 +1920,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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment