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

Commit 2c2e1ce3 authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

soc: qcom: pil-mss: Add scm calls to protect/unprotect subsystem memory



Add support to make scm_calls to TZ/HYP to protect/unprotect
subsystem related memory during boot/shutdown.

Change-Id: I51a438bc60ab7375c36c25783615a51926314708
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent f0cc8eb8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ Optional properties:
- qcom,is-not-loadable: Boolean- Present if the image does not need to
			be loaded.
- qcom,pil-self-auth: Boolean- True if authentication is required.
- qcom,mem-protect-id: Virtual ID used by PIL to call into TZ/HYP to protect/unprotect
			subsystem related memory.
- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ Optional properties:
			need to be loaded.
- qcom,pil-no-auth: Boolean. Present if the subsystem is not authenticated and brought
		    out of reset by using the PIL ops.
- qcom,mem-protect-id: Virtual ID used by PIL to call into TZ/HYP to protect/unprotect
			subsystem related memory.
- qcom,gpio-err-fatal: GPIO used by the subsystem to indicate error fatal to the apps.
- qcom,gpio-err-ready: GPIO used by the subsystem to indicate error ready to the apps.
- qcom,gpio-proxy-unvote: GPIO used by the subsystem to trigger proxy unvoting in
+119 −6
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/dma-mapping.h>
#include <soc/qcom/ramdump.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/secure_buffer.h>

#include <asm/uaccess.h>
#include <asm/setup.h>
@@ -169,6 +170,73 @@ int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
}
EXPORT_SYMBOL(pil_do_ramdump);

int pil_assign_mem_to_subsys(struct pil_desc *desc, phys_addr_t addr,
							size_t size)
{
	int ret;
	int srcVM[1] = {VMID_HLOS};
	int destVM[1] = {desc->subsys_vmid};
	int destVMperm[1] = {PERM_READ | PERM_WRITE};

	ret = hyp_assign_phys(addr, size, srcVM, 1, destVM, destVMperm, 1);
	if (ret)
		pil_err(desc, "%s: failed for %pa address of size %zx - subsys VMid %d\n",
				__func__, &addr, size, desc->subsys_vmid);
	return ret;
}
EXPORT_SYMBOL(pil_assign_mem_to_subsys);

int pil_assign_mem_to_linux(struct pil_desc *desc, phys_addr_t addr,
							size_t size)
{
	int ret;
	int srcVM[1] = {desc->subsys_vmid};
	int destVM[1] = {VMID_HLOS};
	int destVMperm[1] = {PERM_READ | PERM_WRITE};

	ret = hyp_assign_phys(addr, size, srcVM, 1, destVM, destVMperm, 1);
	if (ret)
		panic("%s: failed for %pa address of size %zx - subsys VMid %d. Fatal error.\n",
				__func__, &addr, size, desc->subsys_vmid);

	return ret;
}
EXPORT_SYMBOL(pil_assign_mem_to_linux);

int pil_assign_mem_to_subsys_and_linux(struct pil_desc *desc,
						phys_addr_t addr, size_t size)
{
	int ret;
	int srcVM[1] = {VMID_HLOS};
	int destVM[2] = {VMID_HLOS, desc->subsys_vmid};
	int destVMperm[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE};

	ret = hyp_assign_phys(addr, size, srcVM, 1, destVM, destVMperm, 2);
	if (ret)
		pil_err(desc, "%s: failed for %pa address of size %zx - subsys VMid %d\n",
				__func__, &addr, size, desc->subsys_vmid);

	return ret;
}
EXPORT_SYMBOL(pil_assign_mem_to_subsys_and_linux);

int pil_reclaim_mem(struct pil_desc *desc, phys_addr_t addr, size_t size,
						int VMid)
{
	int ret;
	int srcVM[2] = {VMID_HLOS, desc->subsys_vmid};
	int destVM[1] = {VMid};
	int destVMperm[1] = {PERM_READ | PERM_WRITE};

	ret = hyp_assign_phys(addr, size, srcVM, 2, destVM, destVMperm, 1);
	if (ret)
		panic("%s: failed for %pa address of size %zx - subsys VMid %d. Fatal error.\n",
				__func__, &addr, size, desc->subsys_vmid);

	return ret;
}
EXPORT_SYMBOL(pil_reclaim_mem);

/**
 * pil_get_entry_addr() - Retrieve the entry address of a peripheral image
 * @desc: descriptor from pil_desc_init()
@@ -478,6 +546,16 @@ static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt)
	if (ret)
		return ret;

	if (desc->subsys_vmid > 0) {
		ret = pil_assign_mem_to_subsys_and_linux(desc,
				priv->region_start,
				(priv->region_end - priv->region_start));
		if (ret) {
			pil_err(desc, "Failed to assign memory, ret - %d\n",
								ret);
			return ret;
		}
	}
	pil_info(desc, "loading from %pa to %pa\n", &priv->region_start,
							&priv->region_end);

@@ -605,13 +683,21 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)

static int pil_parse_devicetree(struct pil_desc *desc)
{
	struct device_node *ofnode = desc->dev->of_node;
	int clk_ready = 0;

	if (desc->ops->proxy_unvote &&
		of_find_property(desc->dev->of_node,
	if (!ofnode)
		return -EINVAL;

	if (of_property_read_u32(ofnode, "qcom,mem-protect-id",
					&desc->subsys_vmid))
		pr_debug("Unable to read the addr-protect-id for %s\n",
					desc->name);

	if (desc->ops->proxy_unvote && of_find_property(ofnode,
					"qcom,gpio-proxy-unvote",
					NULL)) {
		clk_ready = of_get_named_gpio(desc->dev->of_node,
		clk_ready = of_get_named_gpio(ofnode,
				"qcom,gpio-proxy-unvote", 0);

		if (clk_ready < 0) {
@@ -651,6 +737,7 @@ int pil_boot(struct pil_desc *desc)
	struct pil_seg *seg;
	const struct firmware *fw;
	struct pil_priv *priv = desc->priv;
	bool mem_protect = false;

	if (desc->shutdown_fail)
		pil_err(desc, "Subsystem shutdown failed previously!\n");
@@ -727,12 +814,29 @@ int pil_boot(struct pil_desc *desc)
			goto err_deinit_image;
	}

	if (desc->subsys_vmid > 0) {
		ret =  pil_reclaim_mem(desc, priv->region_start,
				(priv->region_end - priv->region_start),
				desc->subsys_vmid);
		if (ret) {
			pil_err(desc, "Failed to assign %s memory, ret - %d\n",
							desc->name, ret);
			goto err_deinit_image;
		}
	}

	ret = desc->ops->auth_and_reset(desc);
	if (ret) {
		pil_err(desc, "Failed to bring out of reset\n");
		goto err_deinit_image;
		goto err_auth_and_reset;
	}
	pil_info(desc, "Brought out of reset\n");
err_auth_and_reset:
	if (ret && desc->subsys_vmid > 0) {
		pil_assign_mem_to_linux(desc, priv->region_start,
				(priv->region_end - priv->region_start));
		mem_protect = true;
	}
err_deinit_image:
	if (ret && desc->ops->deinit_image)
		desc->ops->deinit_image(desc);
@@ -746,6 +850,12 @@ out:
	up_read(&pil_pm_rwsem);
	if (ret) {
		if (priv->region) {
			if (desc->subsys_vmid > 0 && !mem_protect) {
				pil_reclaim_mem(desc, priv->region_start,
					(priv->region_end -
						priv->region_start),
					VMID_HLOS);
			}
			dma_free_attrs(desc->dev, priv->region_size,
					priv->region, priv->region_start,
					&desc->attrs);
@@ -792,6 +902,9 @@ void pil_free_memory(struct pil_desc *desc)
	struct pil_priv *priv = desc->priv;

	if (priv->region) {
		if (desc->subsys_vmid > 0)
			pil_assign_mem_to_linux(desc, priv->region_start,
				(priv->region_end - priv->region_start));
		dma_free_attrs(desc->dev, priv->region_size,
				priv->region, priv->region_start, &desc->attrs);
		priv->region = NULL;
+30 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct pil_priv;
 * @unmap_fw_mem: Custom function used to undo mapping by map_fw_mem.
 * This defaults to iounmap if not specified.
 * @shutdown_fail: Set if PIL op for shutting down subsystem fails.
 * @subsys_vmid: memprot id for the subsystem.
 */
struct pil_desc {
	const char *name;
@@ -53,6 +54,7 @@ struct pil_desc {
	void (*unmap_fw_mem)(void *virt, size_t size, void *data);
	void *map_data;
	bool shutdown_fail;
	u32 subsys_vmid;
};

/**
@@ -100,6 +102,14 @@ extern void pil_free_memory(struct pil_desc *desc);
extern void pil_desc_release(struct pil_desc *desc);
extern phys_addr_t pil_get_entry_addr(struct pil_desc *desc);
extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev);
extern int pil_assign_mem_to_subsys(struct pil_desc *desc, phys_addr_t addr,
						size_t size);
extern int pil_assign_mem_to_linux(struct pil_desc *desc, phys_addr_t addr,
						size_t size);
extern int pil_assign_mem_to_subsys_and_linux(struct pil_desc *desc,
						phys_addr_t addr, size_t size);
extern int pil_reclaim_mem(struct pil_desc *desc, phys_addr_t addr, size_t size,
						int VMid);
#else
static inline int pil_desc_init(struct pil_desc *desc) { return 0; }
static inline int pil_boot(struct pil_desc *desc) { return 0; }
@@ -114,6 +124,26 @@ static inline int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
{
	return 0;
}
static inline int pil_assign_mem_to_subsys(struct pil_desc *desc,
						phys_addr_t addr, size_t size)
{
	return 0;
}
static inline int pil_assign_mem_to_linux(struct pil_desc *desc,
						phys_addr_t addr, size_t size)
{
	return 0;
}
static inline int pil_assign_mem_to_subsys_and_linux(struct pil_desc *desc,
						phys_addr_t addr, size_t size)
{
	return 0;
}
static inline int pil_reclaim_mem(struct pil_desc *desc, phys_addr_t addr,
					size_t size, int VMid)
{
	return 0;
}
#endif

#endif
+67 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/regulator/consumer.h>
#include <linux/dma-mapping.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>

#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -322,12 +323,19 @@ int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path)
	/* In case of any failure where reclaim MBA memory
	 * could not happen, free the memory here */
	if (drv->q6->mba_virt) {
		if (pil->subsys_vmid > 0)
			pil_assign_mem_to_linux(pil, drv->q6->mba_phys,
						drv->q6->mba_size);
		dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_size,
				drv->q6->mba_virt, drv->q6->mba_phys,
				&drv->attrs_dma);
		drv->q6->mba_virt = NULL;
	}

	if (drv->q6->dp_virt) {
		if (pil->subsys_vmid > 0)
			pil_assign_mem_to_linux(pil, drv->q6->dp_phys,
						drv->q6->dp_size);
		dma_free_attrs(&drv->mba_mem_dev, drv->q6->dp_size,
				drv->q6->dp_virt, drv->q6->dp_phys,
				&drv->attrs_dma);
@@ -480,6 +488,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
	dma_addr_t mba_phys, mba_phys_end;
	int ret, count;
	const u8 *data;
	bool mba_mem_unprotect = false;

	fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
	/* Load and authenticate mba image */
@@ -520,6 +529,16 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
	memcpy(mba_virt, data, count);
	wmb();

	if (pil->subsys_vmid > 0) {
		ret = pil_assign_mem_to_subsys(pil, drv->mba_phys,
							drv->mba_size);
		if (ret) {
			pr_err("scm_call to unprotect MBA mem failed\n");
			goto err_mba_data;
		}
		mba_mem_unprotect = true;
	}

	/* Load modem debug policy */
	ret = request_firmware(&dp_fw, dp_name, pil->dev);
	if (ret) {
@@ -549,6 +568,15 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
		memcpy(mba_virt, dp_fw->data, dp_fw->size);
		/* Ensure memcpy is done before powering up modem */
		wmb();

		if (pil->subsys_vmid > 0) {
			ret = pil_assign_mem_to_subsys(pil, drv->dp_phys,
							drv->dp_size);
			if (ret) {
				pr_err("scm_call to unprotect DP mem failed\n");
				goto err_dp_scm;
			}
		}
	}

	ret = pil_mss_reset(pil);
@@ -564,17 +592,23 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
	return 0;

err_mss_reset:
	if (drv->dp_virt)
	if (drv->dp_virt && pil->subsys_vmid > 0)
		pil_assign_mem_to_linux(pil, drv->dp_phys, drv->dp_size);
err_dp_scm:
	if (drv->dp_virt) {
		dma_free_attrs(&md->mba_mem_dev, dp_fw->size, drv->dp_virt,
				drv->dp_phys, &md->attrs_dma);
		drv->dp_virt = NULL;
	}
err_invalid_fw:
	if (dp_fw)
		release_firmware(dp_fw);
err_mba_data:
	if (mba_mem_unprotect && pil->subsys_vmid > 0)
		pil_assign_mem_to_linux(pil, drv->mba_phys, drv->mba_size);
	dma_free_attrs(&md->mba_mem_dev, drv->mba_size, drv->mba_virt,
				drv->mba_phys, &md->attrs_dma);
	drv->mba_virt = NULL;
	drv->dp_virt = NULL;
err_dma_alloc:
	release_firmware(fw);
	return ret;
@@ -605,6 +639,17 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
	/* wmb() ensures copy completes prior to starting authentication. */
	wmb();

	if (pil->subsys_vmid > 0) {
		ret = pil_assign_mem_to_subsys(pil, mdata_phys,
							ALIGN(size, SZ_4K));
		if (ret) {
			pr_err("scm_call to unprotect modem metadata mem failed\n");
			dma_free_attrs(&drv->mba_mem_dev, size, mdata_virt,
							mdata_phys, &attrs);
			goto fail;
		}
	}

	/* Initialize length counter to 0 */
	writel_relaxed(0, drv->rmb_base + RMB_PMI_CODE_LENGTH);

@@ -622,6 +667,9 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
		ret = -EINVAL;
	}

	if (pil->subsys_vmid > 0)
		pil_assign_mem_to_linux(pil, mdata_phys, ALIGN(size, SZ_4K));

	dma_free_attrs(&drv->mba_mem_dev, size, mdata_virt, mdata_phys, &attrs);

	if (!ret)
@@ -631,11 +679,18 @@ fail:
	modem_log_rmb_regs(drv->rmb_base);
	if (drv->q6) {
		pil_mss_shutdown(pil);
		if (pil->subsys_vmid > 0)
			pil_assign_mem_to_linux(pil, drv->q6->mba_phys,
						drv->q6->mba_size);
		dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_size,
				drv->q6->mba_virt, drv->q6->mba_phys,
				&drv->attrs_dma);
		drv->q6->mba_virt = NULL;

		if (drv->q6->dp_virt) {
			if (pil->subsys_vmid > 0)
				pil_assign_mem_to_linux(pil, drv->q6->dp_phys,
						drv->q6->dp_size);
			dma_free_attrs(&drv->mba_mem_dev, drv->q6->dp_size,
					drv->q6->dp_virt, drv->q6->dp_phys,
					&drv->attrs_dma);
@@ -704,14 +759,21 @@ static int pil_msa_mba_auth(struct pil_desc *pil)
	if (drv->q6) {
		if (drv->q6->mba_virt) {
			/* Reclaim MBA memory. */
			if (pil->subsys_vmid > 0)
				pil_assign_mem_to_linux(pil, drv->q6->mba_phys,
					drv->q6->mba_size);
			dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_size,
					drv->q6->mba_virt, drv->q6->mba_phys,
					&drv->attrs_dma);

			drv->q6->mba_virt = NULL;
		}

		if (drv->q6->dp_virt) {
			/* Reclaim Modem DP memory. */
			if (pil->subsys_vmid > 0)
				pil_assign_mem_to_linux(pil, drv->q6->dp_phys,
					drv->q6->dp_size);
			dma_free_attrs(&drv->mba_mem_dev, drv->q6->dp_size,
					drv->q6->dp_virt, drv->q6->dp_phys,
					&drv->attrs_dma);