Commit 36629d52 authored by Jens Wiklander's avatar Jens Wiklander
Browse files

Merge branch...

Merge branch '20250911-qcom-tee-using-tee-ss-without-mem-obj-v12-2-17f07a942b8d@oss.qualcomm.com' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux



      firmware: qcom: tzmem: export shm_bridge create/delete
      firmware: qcom: scm: add support for object invocation

Signed-off-by: default avatarJens Wiklander <jens.wiklander@linaro.org>
parents dbc2868b 4b700098
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -2093,6 +2093,122 @@ static int qcom_scm_qseecom_init(struct qcom_scm *scm)

#endif /* CONFIG_QCOM_QSEECOM */

/**
 * qcom_scm_qtee_invoke_smc() - Invoke a QTEE object.
 * @inbuf: start address of memory area used for inbound buffer.
 * @inbuf_size: size of the memory area used for inbound buffer.
 * @outbuf: start address of memory area used for outbound buffer.
 * @outbuf_size: size of the memory area used for outbound buffer.
 * @result: result of QTEE object invocation.
 * @response_type: response type returned by QTEE.
 *
 * @response_type determines how the contents of @inbuf and @outbuf
 * should be processed.
 *
 * Return: On success, return 0 or <0 on failure.
 */
int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size,
			     phys_addr_t outbuf, size_t outbuf_size,
			     u64 *result, u64 *response_type)
{
	struct qcom_scm_desc desc = {
		.svc = QCOM_SCM_SVC_SMCINVOKE,
		.cmd = QCOM_SCM_SMCINVOKE_INVOKE,
		.owner = ARM_SMCCC_OWNER_TRUSTED_OS,
		.args[0] = inbuf,
		.args[1] = inbuf_size,
		.args[2] = outbuf,
		.args[3] = outbuf_size,
		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL,
					 QCOM_SCM_RW, QCOM_SCM_VAL),
	};
	struct qcom_scm_res res;
	int ret;

	ret = qcom_scm_call(__scm->dev, &desc, &res);
	if (ret)
		return ret;

	if (response_type)
		*response_type = res.result[0];

	if (result)
		*result = res.result[1];

	return 0;
}
EXPORT_SYMBOL(qcom_scm_qtee_invoke_smc);

/**
 * qcom_scm_qtee_callback_response() - Submit response for callback request.
 * @buf: start address of memory area used for outbound buffer.
 * @buf_size: size of the memory area used for outbound buffer.
 * @result: Result of QTEE object invocation.
 * @response_type: Response type returned by QTEE.
 *
 * @response_type determines how the contents of @buf should be processed.
 *
 * Return: On success, return 0 or <0 on failure.
 */
int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size,
				    u64 *result, u64 *response_type)
{
	struct qcom_scm_desc desc = {
		.svc = QCOM_SCM_SVC_SMCINVOKE,
		.cmd = QCOM_SCM_SMCINVOKE_CB_RSP,
		.owner = ARM_SMCCC_OWNER_TRUSTED_OS,
		.args[0] = buf,
		.args[1] = buf_size,
		.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL),
	};
	struct qcom_scm_res res;
	int ret;

	ret = qcom_scm_call(__scm->dev, &desc, &res);
	if (ret)
		return ret;

	if (response_type)
		*response_type = res.result[0];

	if (result)
		*result = res.result[1];

	return 0;
}
EXPORT_SYMBOL(qcom_scm_qtee_callback_response);

static void qcom_scm_qtee_free(void *data)
{
	struct platform_device *qtee_dev = data;

	platform_device_unregister(qtee_dev);
}

static void qcom_scm_qtee_init(struct qcom_scm *scm)
{
	struct platform_device *qtee_dev;
	u64 result, response_type;
	int ret;

	/*
	 * Probe for smcinvoke support. This will fail due to invalid buffers,
	 * but first, it checks whether the call is supported in QTEE syscall
	 * handler. If it is not supported, -EIO is returned.
	 */
	ret = qcom_scm_qtee_invoke_smc(0, 0, 0, 0, &result, &response_type);
	if (ret == -EIO)
		return;

	/* Setup QTEE interface device. */
	qtee_dev = platform_device_register_data(scm->dev, "qcomtee",
						 PLATFORM_DEVID_NONE, NULL, 0);
	if (IS_ERR(qtee_dev))
		return;

	devm_add_action_or_reset(scm->dev, qcom_scm_qtee_free, qtee_dev);
}

/**
 * qcom_scm_is_available() - Checks if SCM is available
 */
@@ -2325,6 +2441,9 @@ static int qcom_scm_probe(struct platform_device *pdev)
	ret = qcom_scm_qseecom_init(scm);
	WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);

	/* Initialize the QTEE object interface. */
	qcom_scm_qtee_init(scm);

	return 0;
}

+7 −0
Original line number Diff line number Diff line
@@ -156,6 +156,13 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
#define QCOM_SCM_SVC_GPU			0x28
#define QCOM_SCM_SVC_GPU_INIT_REGS		0x01

/* ARM_SMCCC_OWNER_TRUSTED_OS calls */

#define QCOM_SCM_SVC_SMCINVOKE			0x06
#define QCOM_SCM_SMCINVOKE_INVOKE_LEGACY	0x00
#define QCOM_SCM_SMCINVOKE_CB_RSP		0x01
#define QCOM_SCM_SMCINVOKE_INVOKE		0x02

/* common error codes */
#define QCOM_SCM_V2_EBUSY	-12
#define QCOM_SCM_ENOMEM		-5
+52 −11
Original line number Diff line number Diff line
@@ -109,7 +109,19 @@ static int qcom_tzmem_init(void)
	return 0;
}

static int qcom_tzmem_init_area(struct qcom_tzmem_area *area)
/**
 * qcom_tzmem_shm_bridge_create() - Create a SHM bridge.
 * @paddr: Physical address of the memory to share.
 * @size: Size of the memory to share.
 * @handle: Handle to the SHM bridge.
 *
 * On platforms that support SHM bridge, this function creates a SHM bridge
 * for the given memory region with QTEE. The handle returned by this function
 * must be passed to qcom_tzmem_shm_bridge_delete() to free the SHM bridge.
 *
 * Return: On success, returns 0; on failure, returns < 0.
 */
int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *handle)
{
	u64 pfn_and_ns_perm, ipfn_and_s_perm, size_and_flags;
	int ret;
@@ -117,17 +129,49 @@ static int qcom_tzmem_init_area(struct qcom_tzmem_area *area)
	if (!qcom_tzmem_using_shm_bridge)
		return 0;

	pfn_and_ns_perm = (u64)area->paddr | QCOM_SCM_PERM_RW;
	ipfn_and_s_perm = (u64)area->paddr | QCOM_SCM_PERM_RW;
	size_and_flags = area->size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT);
	pfn_and_ns_perm = paddr | QCOM_SCM_PERM_RW;
	ipfn_and_s_perm = paddr | QCOM_SCM_PERM_RW;
	size_and_flags = size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT);

	ret = qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm,
					 size_and_flags, QCOM_SCM_VMID_HLOS,
					 handle);
	if (ret) {
		dev_err(qcom_tzmem_dev,
			"SHM Bridge failed: ret %d paddr 0x%pa, size %zu\n",
			ret, &paddr, size);

		return ret;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_create);

/**
 * qcom_tzmem_shm_bridge_delete() - Delete a SHM bridge.
 * @handle: Handle to the SHM bridge.
 *
 * On platforms that support SHM bridge, this function deletes the SHM bridge
 * for the given memory region. The handle must be the same as the one
 * returned by qcom_tzmem_shm_bridge_create().
 */
void qcom_tzmem_shm_bridge_delete(u64 handle)
{
	if (qcom_tzmem_using_shm_bridge)
		qcom_scm_shm_bridge_delete(handle);
}
EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_delete);

static int qcom_tzmem_init_area(struct qcom_tzmem_area *area)
{
	int ret;

	u64 *handle __free(kfree) = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (!handle)
		return -ENOMEM;

	ret = qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm,
					 size_and_flags, QCOM_SCM_VMID_HLOS,
					 handle);
	ret = qcom_tzmem_shm_bridge_create(area->paddr, area->size, handle);
	if (ret)
		return ret;

@@ -140,10 +184,7 @@ static void qcom_tzmem_cleanup_area(struct qcom_tzmem_area *area)
{
	u64 *handle = area->priv;

	if (!qcom_tzmem_using_shm_bridge)
		return;

	qcom_scm_shm_bridge_delete(*handle);
	qcom_tzmem_shm_bridge_delete(*handle);
	kfree(handle);
}

+6 −0
Original line number Diff line number Diff line
@@ -175,4 +175,10 @@ static inline int qcom_scm_qseecom_app_send(u32 app_id,

#endif /* CONFIG_QCOM_QSEECOM */

int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size,
			     phys_addr_t outbuf, size_t outbuf_size,
			     u64 *result, u64 *response_type);
int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size,
				    u64 *result, u64 *response_type);

#endif
+15 −0
Original line number Diff line number Diff line
@@ -53,4 +53,19 @@ DEFINE_FREE(qcom_tzmem, void *, if (_T) qcom_tzmem_free(_T))

phys_addr_t qcom_tzmem_to_phys(void *ptr);

#if IS_ENABLED(CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE)
int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *handle);
void qcom_tzmem_shm_bridge_delete(u64 handle);
#else
static inline int qcom_tzmem_shm_bridge_create(phys_addr_t paddr,
					       size_t size, u64 *handle)
{
	return 0;
}

static inline void qcom_tzmem_shm_bridge_delete(u64 handle)
{
}
#endif

#endif /* __QCOM_TZMEM */