Commit 4b700098 authored by Amirreza Zarrabi's avatar Amirreza Zarrabi Committed by Bjorn Andersson
Browse files

firmware: qcom: scm: add support for object invocation



Qualcomm TEE (QTEE) hosts Trusted Applications (TAs) and services in
the secure world, accessed via objects. A QTEE client can invoke these
objects to request services. Similarly, QTEE can request services from
the nonsecure world using objects exported to the secure world.

Add low-level primitives to facilitate the invocation of objects hosted
in QTEE, as well as those hosted in the nonsecure world.

If support for object invocation is available, the qcom_scm allocates
a dedicated child platform device. The driver for this device communicates
with QTEE using low-level primitives.

Tested-by: default avatarNeil Armstrong <neil.armstrong@linaro.org>
Tested-by: default avatarHarshal Dev <quic_hdev@quicinc.com>
Signed-off-by: default avatarAmirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250911-qcom-tee-using-tee-ss-without-mem-obj-v12-2-17f07a942b8d@oss.qualcomm.com


Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
parent 8aa1e3a6
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
+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