summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2023-12-22 10:42:19 +0000
committerArnd Bergmann <arnd@arndb.de>2023-12-22 10:42:19 +0000
commit9d0e3c5a3d89bbd77c671a84301c38e0a71bfa14 (patch)
tree73109355b77f7737c971b1972dc25bbfed678645
parent60cc77704eb23558c46a4428792515e48273dde0 (diff)
parent4b391c9c37646f25118355f414b9e6d9fefe782f (diff)
Merge tag 'system-thread-for-v6.8' of https://git.linaro.org/people/jens.wiklander/linux-tee into soc/drivers
OP-TEE add reserved system thread Add support for a reserved system thread in the SMC-ABI of the OP-TEE driver. SCMI with OP-TEE transport uses this to guarantee that it will always have a thread available in the secure world. * tag 'system-thread-for-v6.8' of https://git.linaro.org/people/jens.wiklander/linux-tee: firmware: arm_scmi: optee: use optee system invocation tee: optee: support tracking system threads tee: system session tee: optee: system thread call property Link: https://lore.kernel.org/r/20231211102600.GA571787@rayden Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--drivers/firmware/arm_scmi/optee.c4
-rw-r--r--drivers/tee/optee/call.c130
-rw-r--r--drivers/tee/optee/core.c5
-rw-r--r--drivers/tee/optee/ffa_abi.c14
-rw-r--r--drivers/tee/optee/optee_private.h29
-rw-r--r--drivers/tee/optee/smc_abi.c32
-rw-r--r--drivers/tee/tee_core.c8
-rw-r--r--include/linux/tee_drv.h16
8 files changed, 211 insertions, 27 deletions
diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c
index e123de6e8c67..25bfb465484d 100644
--- a/drivers/firmware/arm_scmi/optee.c
+++ b/drivers/firmware/arm_scmi/optee.c
@@ -440,6 +440,10 @@ static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *de
if (ret)
goto err_free_shm;
+ ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session);
+ if (ret)
+ dev_warn(dev, "Could not switch to system session, do best effort\n");
+
ret = get_channel(channel);
if (ret)
goto err_close_sess;
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index df5fb5410b72..b04c49c69619 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -39,9 +39,29 @@ struct optee_shm_arg_entry {
DECLARE_BITMAP(map, MAX_ARG_COUNT_PER_ENTRY);
};
+void optee_cq_init(struct optee_call_queue *cq, int thread_count)
+{
+ mutex_init(&cq->mutex);
+ INIT_LIST_HEAD(&cq->waiters);
+
+ /*
+ * If cq->total_thread_count is 0 then we're not trying to keep
+ * track of how many free threads we have, instead we're relying on
+ * the secure world to tell us when we're out of thread and have to
+ * wait for another thread to become available.
+ */
+ cq->total_thread_count = thread_count;
+ cq->free_thread_count = thread_count;
+}
+
void optee_cq_wait_init(struct optee_call_queue *cq,
- struct optee_call_waiter *w)
+ struct optee_call_waiter *w, bool sys_thread)
{
+ unsigned int free_thread_threshold;
+ bool need_wait = false;
+
+ memset(w, 0, sizeof(*w));
+
/*
* We're preparing to make a call to secure world. In case we can't
* allocate a thread in secure world we'll end up waiting in
@@ -60,8 +80,38 @@ void optee_cq_wait_init(struct optee_call_queue *cq,
*/
init_completion(&w->c);
list_add_tail(&w->list_node, &cq->waiters);
+ w->sys_thread = sys_thread;
+
+ if (cq->total_thread_count) {
+ if (sys_thread || !cq->sys_thread_req_count)
+ free_thread_threshold = 0;
+ else
+ free_thread_threshold = 1;
+
+ if (cq->free_thread_count > free_thread_threshold)
+ cq->free_thread_count--;
+ else
+ need_wait = true;
+ }
mutex_unlock(&cq->mutex);
+
+ while (need_wait) {
+ optee_cq_wait_for_completion(cq, w);
+ mutex_lock(&cq->mutex);
+
+ if (sys_thread || !cq->sys_thread_req_count)
+ free_thread_threshold = 0;
+ else
+ free_thread_threshold = 1;
+
+ if (cq->free_thread_count > free_thread_threshold) {
+ cq->free_thread_count--;
+ need_wait = false;
+ }
+
+ mutex_unlock(&cq->mutex);
+ }
}
void optee_cq_wait_for_completion(struct optee_call_queue *cq,
@@ -83,6 +133,14 @@ static void optee_cq_complete_one(struct optee_call_queue *cq)
{
struct optee_call_waiter *w;
+ /* Wake a waiting system session if any, prior to a normal session */
+ list_for_each_entry(w, &cq->waiters, list_node) {
+ if (w->sys_thread && !completion_done(&w->c)) {
+ complete(&w->c);
+ return;
+ }
+ }
+
list_for_each_entry(w, &cq->waiters, list_node) {
if (!completion_done(&w->c)) {
complete(&w->c);
@@ -104,6 +162,8 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
/* Get out of the list */
list_del(&w->list_node);
+ cq->free_thread_count++;
+
/* Wake up one eventual waiting task */
optee_cq_complete_one(cq);
@@ -119,6 +179,28 @@ void optee_cq_wait_final(struct optee_call_queue *cq,
mutex_unlock(&cq->mutex);
}
+/* Count registered system sessions to reserved a system thread or not */
+static bool optee_cq_incr_sys_thread_count(struct optee_call_queue *cq)
+{
+ if (cq->total_thread_count <= 1)
+ return false;
+
+ mutex_lock(&cq->mutex);
+ cq->sys_thread_req_count++;
+ mutex_unlock(&cq->mutex);
+
+ return true;
+}
+
+static void optee_cq_decr_sys_thread_count(struct optee_call_queue *cq)
+{
+ mutex_lock(&cq->mutex);
+ cq->sys_thread_req_count--;
+ /* If there's someone waiting, let it resume */
+ optee_cq_complete_one(cq);
+ mutex_unlock(&cq->mutex);
+}
+
/* Requires the filpstate mutex to be held */
static struct optee_session *find_session(struct optee_context_data *ctxdata,
u32 session_id)
@@ -328,7 +410,8 @@ int optee_open_session(struct tee_context *ctx,
goto out;
}
- if (optee->ops->do_call_with_arg(ctx, shm, offs)) {
+ if (optee->ops->do_call_with_arg(ctx, shm, offs,
+ sess->use_sys_thread)) {
msg_arg->ret = TEEC_ERROR_COMMUNICATION;
msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
}
@@ -360,7 +443,29 @@ out:
return rc;
}
-int optee_close_session_helper(struct tee_context *ctx, u32 session)
+int optee_system_session(struct tee_context *ctx, u32 session)
+{
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_context_data *ctxdata = ctx->data;
+ struct optee_session *sess;
+ int rc = -EINVAL;
+
+ mutex_lock(&ctxdata->mutex);
+
+ sess = find_session(ctxdata, session);
+ if (sess && (sess->use_sys_thread ||
+ optee_cq_incr_sys_thread_count(&optee->call_queue))) {
+ sess->use_sys_thread = true;
+ rc = 0;
+ }
+
+ mutex_unlock(&ctxdata->mutex);
+
+ return rc;
+}
+
+int optee_close_session_helper(struct tee_context *ctx, u32 session,
+ bool system_thread)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
struct optee_shm_arg_entry *entry;
@@ -374,10 +479,13 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session)
msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
msg_arg->session = session;
- optee->ops->do_call_with_arg(ctx, shm, offs);
+ optee->ops->do_call_with_arg(ctx, shm, offs, system_thread);
optee_free_msg_arg(ctx, entry, offs);
+ if (system_thread)
+ optee_cq_decr_sys_thread_count(&optee->call_queue);
+
return 0;
}
@@ -385,6 +493,7 @@ int optee_close_session(struct tee_context *ctx, u32 session)
{
struct optee_context_data *ctxdata = ctx->data;
struct optee_session *sess;
+ bool system_thread;
/* Check that the session is valid and remove it from the list */
mutex_lock(&ctxdata->mutex);
@@ -394,9 +503,10 @@ int optee_close_session(struct tee_context *ctx, u32 session)
mutex_unlock(&ctxdata->mutex);
if (!sess)
return -EINVAL;
+ system_thread = sess->use_sys_thread;
kfree(sess);
- return optee_close_session_helper(ctx, session);
+ return optee_close_session_helper(ctx, session, system_thread);
}
int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
@@ -408,12 +518,15 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
struct optee_msg_arg *msg_arg;
struct optee_session *sess;
struct tee_shm *shm;
+ bool system_thread;
u_int offs;
int rc;
/* Check that the session is valid */
mutex_lock(&ctxdata->mutex);
sess = find_session(ctxdata, arg->session);
+ if (sess)
+ system_thread = sess->use_sys_thread;
mutex_unlock(&ctxdata->mutex);
if (!sess)
return -EINVAL;
@@ -432,7 +545,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
if (rc)
goto out;
- if (optee->ops->do_call_with_arg(ctx, shm, offs)) {
+ if (optee->ops->do_call_with_arg(ctx, shm, offs, system_thread)) {
msg_arg->ret = TEEC_ERROR_COMMUNICATION;
msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
}
@@ -457,12 +570,15 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
struct optee_shm_arg_entry *entry;
struct optee_msg_arg *msg_arg;
struct optee_session *sess;
+ bool system_thread;
struct tee_shm *shm;
u_int offs;
/* Check that the session is valid */
mutex_lock(&ctxdata->mutex);
sess = find_session(ctxdata, session);
+ if (sess)
+ system_thread = sess->use_sys_thread;
mutex_unlock(&ctxdata->mutex);
if (!sess)
return -EINVAL;
@@ -474,7 +590,7 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
msg_arg->cmd = OPTEE_MSG_CMD_CANCEL;
msg_arg->session = session;
msg_arg->cancel_id = cancel_id;
- optee->ops->do_call_with_arg(ctx, shm, offs);
+ optee->ops->do_call_with_arg(ctx, shm, offs, system_thread);
optee_free_msg_arg(ctx, entry, offs);
return 0;
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 2a258bd3b6b5..d01ca47f7bde 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -129,7 +129,8 @@ int optee_open(struct tee_context *ctx, bool cap_memref_null)
static void optee_release_helper(struct tee_context *ctx,
int (*close_session)(struct tee_context *ctx,
- u32 session))
+ u32 session,
+ bool system_thread))
{
struct optee_context_data *ctxdata = ctx->data;
struct optee_session *sess;
@@ -141,7 +142,7 @@ static void optee_release_helper(struct tee_context *ctx,
list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
list_node) {
list_del(&sess->list_node);
- close_session(ctx, sess->session_id);
+ close_session(ctx, sess->session_id, sess->use_sys_thread);
kfree(sess);
}
kfree(ctxdata);
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index 0828240f27e6..d73396ed5b93 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -528,7 +528,8 @@ static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee,
static int optee_ffa_yielding_call(struct tee_context *ctx,
struct ffa_send_direct_data *data,
- struct optee_msg_arg *rpc_arg)
+ struct optee_msg_arg *rpc_arg,
+ bool system_thread)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
@@ -541,7 +542,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
int rc;
/* Initialize waiter */
- optee_cq_wait_init(&optee->call_queue, &w);
+ optee_cq_wait_init(&optee->call_queue, &w, system_thread);
while (true) {
rc = msg_ops->sync_send_receive(ffa_dev, data);
if (rc)
@@ -604,6 +605,7 @@ done:
* @ctx: calling context
* @shm: shared memory holding the message to pass to secure world
* @offs: offset of the message in @shm
+ * @system_thread: true if caller requests TEE system thread support
*
* Does a FF-A call to OP-TEE in secure world and handles eventual resulting
* Remote Procedure Calls (RPC) from OP-TEE.
@@ -612,7 +614,8 @@ done:
*/
static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
- struct tee_shm *shm, u_int offs)
+ struct tee_shm *shm, u_int offs,
+ bool system_thread)
{
struct ffa_send_direct_data data = {
.data0 = OPTEE_FFA_YIELDING_CALL_WITH_ARG,
@@ -642,7 +645,7 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
if (IS_ERR(rpc_arg))
return PTR_ERR(rpc_arg);
- return optee_ffa_yielding_call(ctx, &data, rpc_arg);
+ return optee_ffa_yielding_call(ctx, &data, rpc_arg, system_thread);
}
/*
@@ -850,8 +853,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
if (rc)
goto err_unreg_supp_teedev;
mutex_init(&optee->ffa.mutex);
- mutex_init(&optee->call_queue.mutex);
- INIT_LIST_HEAD(&optee->call_queue.waiters);
+ optee_cq_init(&optee->call_queue, 0);
optee_supp_init(&optee->supp);
optee_shm_arg_cache_init(optee, arg_cache_flags);
ffa_dev_set_drvdata(ffa_dev, optee);
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 6bb5cae09688..7832ccefe6d0 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -40,15 +40,33 @@ typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long,
struct arm_smccc_res *);
+/*
+ * struct optee_call_waiter - TEE entry may need to wait for a free TEE thread
+ * @list_node Reference in waiters list
+ * @c Waiting completion reference
+ * @sys_thread True if waiter belongs to a system thread
+ */
struct optee_call_waiter {
struct list_head list_node;
struct completion c;
+ bool sys_thread;
};
+/*
+ * struct optee_call_queue - OP-TEE call queue management
+ * @mutex Serializes access to this struct
+ * @waiters List of threads waiting to enter OP-TEE
+ * @total_thread_count Overall number of thread context in OP-TEE or 0
+ * @free_thread_count Number of threads context free in OP-TEE
+ * @sys_thread_req_count Number of registered system thread sessions
+ */
struct optee_call_queue {
/* Serializes access to this struct */
struct mutex mutex;
struct list_head waiters;
+ int total_thread_count;
+ int free_thread_count;
+ int sys_thread_req_count;
};
struct optee_notif {
@@ -154,7 +172,8 @@ struct optee;
*/
struct optee_ops {
int (*do_call_with_arg)(struct tee_context *ctx,
- struct tee_shm *shm_arg, u_int offs);
+ struct tee_shm *shm_arg, u_int offs,
+ bool system_thread);
int (*to_msg_param)(struct optee *optee,
struct optee_msg_param *msg_params,
size_t num_params, const struct tee_param *params);
@@ -204,6 +223,7 @@ struct optee {
struct optee_session {
struct list_head list_node;
u32 session_id;
+ bool use_sys_thread;
};
struct optee_context_data {
@@ -250,7 +270,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
int optee_open_session(struct tee_context *ctx,
struct tee_ioctl_open_session_arg *arg,
struct tee_param *param);
-int optee_close_session_helper(struct tee_context *ctx, u32 session);
+int optee_system_session(struct tee_context *ctx, u32 session);
+int optee_close_session_helper(struct tee_context *ctx, u32 session,
+ bool system_thread);
int optee_close_session(struct tee_context *ctx, u32 session);
int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
struct tee_param *param);
@@ -298,8 +320,9 @@ static inline void optee_to_msg_param_value(struct optee_msg_param *mp,
mp->u.value.c = p->u.value.c;
}
+void optee_cq_init(struct optee_call_queue *cq, int thread_count);
void optee_cq_wait_init(struct optee_call_queue *cq,
- struct optee_call_waiter *w);
+ struct optee_call_waiter *w, bool sys_thread);
void optee_cq_wait_for_completion(struct optee_call_queue *cq,
struct optee_call_waiter *w);
void optee_cq_wait_final(struct optee_call_queue *cq,
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index d5b28fd35d66..3b60acc15cf0 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -283,7 +283,7 @@ static void optee_enable_shm_cache(struct optee *optee)
struct optee_call_waiter w;
/* We need to retry until secure world isn't busy. */
- optee_cq_wait_init(&optee->call_queue, &w);
+ optee_cq_wait_init(&optee->call_queue, &w, false);
while (true) {
struct arm_smccc_res res;
@@ -308,7 +308,7 @@ static void __optee_disable_shm_cache(struct optee *optee, bool is_mapped)
struct optee_call_waiter w;
/* We need to retry until secure world isn't busy. */
- optee_cq_wait_init(&optee->call_queue, &w);
+ optee_cq_wait_init(&optee->call_queue, &w, false);
while (true) {
union {
struct arm_smccc_res smccc;
@@ -507,7 +507,7 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
(tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
- if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
+ if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) ||
msg_arg->ret != TEEC_SUCCESS)
rc = -EINVAL;
@@ -550,7 +550,7 @@ static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
- if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
+ if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) ||
msg_arg->ret != TEEC_SUCCESS)
rc = -EINVAL;
out:
@@ -878,6 +878,7 @@ static void optee_handle_rpc(struct tee_context *ctx,
* @ctx: calling context
* @shm: shared memory holding the message to pass to secure world
* @offs: offset of the message in @shm
+ * @system_thread: true if caller requests TEE system thread support
*
* Does and SMC to OP-TEE in secure world and handles eventual resulting
* Remote Procedure Calls (RPC) from OP-TEE.
@@ -885,7 +886,8 @@ static void optee_handle_rpc(struct tee_context *ctx,
* Returns return code from secure world, 0 is OK
*/
static int optee_smc_do_call_with_arg(struct tee_context *ctx,
- struct tee_shm *shm, u_int offs)
+ struct tee_shm *shm, u_int offs,
+ bool system_thread)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
struct optee_call_waiter w;
@@ -926,7 +928,7 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
reg_pair_from_64(&param.a1, &param.a2, parg);
}
/* Initialize waiter */
- optee_cq_wait_init(&optee->call_queue, &w);
+ optee_cq_wait_init(&optee->call_queue, &w, system_thread);
while (true) {
struct arm_smccc_res res;
@@ -977,7 +979,7 @@ static int simple_call_with_arg(struct tee_context *ctx, u32 cmd)
return PTR_ERR(msg_arg);
msg_arg->cmd = cmd;
- optee_smc_do_call_with_arg(ctx, shm, offs);
+ optee_smc_do_call_with_arg(ctx, shm, offs, false);
optee_free_msg_arg(ctx, entry, offs);
return 0;
@@ -1210,6 +1212,7 @@ static const struct tee_driver_ops optee_clnt_ops = {
.release = optee_release,
.open_session = optee_open_session,
.close_session = optee_close_session,
+ .system_session = optee_system_session,
.invoke_func = optee_invoke_func,
.cancel_req = optee_cancel_req,
.shm_register = optee_shm_register,
@@ -1357,6 +1360,16 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
return true;
}
+static unsigned int optee_msg_get_thread_count(optee_invoke_fn *invoke_fn)
+{
+ struct arm_smccc_res res;
+
+ invoke_fn(OPTEE_SMC_GET_THREAD_COUNT, 0, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ return 0;
+ return res.a1;
+}
+
static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
{
@@ -1609,6 +1622,7 @@ static int optee_probe(struct platform_device *pdev)
struct optee *optee = NULL;
void *memremaped_shm = NULL;
unsigned int rpc_param_count;
+ unsigned int thread_count;
struct tee_device *teedev;
struct tee_context *ctx;
u32 max_notif_value;
@@ -1636,6 +1650,7 @@ static int optee_probe(struct platform_device *pdev)
return -EINVAL;
}
+ thread_count = optee_msg_get_thread_count(invoke_fn);
if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps,
&max_notif_value,
&rpc_param_count)) {
@@ -1725,8 +1740,7 @@ static int optee_probe(struct platform_device *pdev)
if (rc)
goto err_unreg_supp_teedev;
- mutex_init(&optee->call_queue.mutex);
- INIT_LIST_HEAD(&optee->call_queue.waiters);
+ optee_cq_init(&optee->call_queue, thread_count);
optee_supp_init(&optee->supp);
optee->smc.memremaped_shm = memremaped_shm;
optee->pool = pool;
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 5ddfd5d9ac7f..792d6fae4354 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1173,6 +1173,14 @@ int tee_client_close_session(struct tee_context *ctx, u32 session)
}
EXPORT_SYMBOL_GPL(tee_client_close_session);
+int tee_client_system_session(struct tee_context *ctx, u32 session)
+{
+ if (!ctx->teedev->desc->ops->system_session)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->system_session(ctx, session);
+}
+EXPORT_SYMBOL_GPL(tee_client_system_session);
+
int tee_client_invoke_func(struct tee_context *ctx,
struct tee_ioctl_invoke_arg *arg,
struct tee_param *param)
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 17eb1c5205d3..911ddf92dcee 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -84,6 +84,7 @@ struct tee_param {
* @release: release this open file
* @open_session: open a new session
* @close_session: close a session
+ * @system_session: declare session as a system session
* @invoke_func: invoke a trusted function
* @cancel_req: request cancel of an ongoing invoke or open
* @supp_recv: called for supplicant to get a command
@@ -100,6 +101,7 @@ struct tee_driver_ops {
struct tee_ioctl_open_session_arg *arg,
struct tee_param *param);
int (*close_session)(struct tee_context *ctx, u32 session);
+ int (*system_session)(struct tee_context *ctx, u32 session);
int (*invoke_func)(struct tee_context *ctx,
struct tee_ioctl_invoke_arg *arg,
struct tee_param *param);
@@ -430,6 +432,20 @@ int tee_client_open_session(struct tee_context *ctx,
int tee_client_close_session(struct tee_context *ctx, u32 session);
/**
+ * tee_client_system_session() - Declare session as a system session
+ * @ctx: TEE Context
+ * @session: Session id
+ *
+ * This function requests TEE to provision an entry context ready to use for
+ * that session only. The provisioned entry context is used for command
+ * invocation and session closure, not for command cancelling requests.
+ * TEE releases the provisioned context upon session closure.
+ *
+ * Return < 0 on error else 0 if an entry context has been provisioned.
+ */
+int tee_client_system_session(struct tee_context *ctx, u32 session);
+
+/**
* tee_client_invoke_func() - Invoke a function in a Trusted Application
* @ctx: TEE Context
* @arg: Invoke arguments, see description of