mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
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. -----BEGIN PGP SIGNATURE----- iQJOBAABCgA4FiEEFV+gSSXZJY9ZyuB5LinzTIcAHJcFAmV23KsaHGplbnMud2lr bGFuZGVyQGxpbmFyby5vcmcACgkQLinzTIcAHJeEbBAAi5QNyLc9G6jhnix/QdeU s3kYLH4Vm0BeE3a+6iY3sxsfMQe+sGaAet5tBYGujJv4f1AzKjoCSysaCnekcJNQ JNph6nwCdg8DrohVvTiIq571uYv0pV43WQ+CWTnVl4H0qOtdiqrlUuxJ/ER/kKOo HdluX0HU22b6N9QllImjNQM5jEGzTJZNRxe2ruClxvEbcbbWAvYy4QW3XSeRt/dU mBeJslPydY5IexbTGhElbpRxAG1zSGPZYPEFKaVFQ+Cs3DBc3JpVwjOWrHoix8P+ vln/WlKUoyesGssdqOT9nKxFG6lCKh+66TPi12F//7PN1fG2TsDcy3DTNLL0N/kk +msi/01QBSCBZs3zXIQT1TZ5ICPN1VMaKaHZ89zi/cL0cKpbe/j4IryDsl95HF3W QBkpTpYBbx1ehlL0y6Fdpv3Syx7z/1Uk/+oOqlF0dTPOv0aOBjGRyjZK/p3cZFAJ qyB6CI17UGzc8s8mPdxc2KjQMw+IZD+qPWPkNGutm3mto/mtc91cwjOKuj/k/x1j FkcKm+nm1nyrLGkkyvMa/HyWbFY/MG7oB0q+BquVKnjp2LXisWH/mKbhzr/h2Qjw y8yH6SYipDbJAY/WhwM5+wkJqTp5q7CyFv7P0ZTCTH0Ku5vxzvk2pLO/aTaeoyab APHDXEoBE8nj57wnNy7t6qI= =0+RD -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmWFaAsACgkQYKtH/8kJ UieeRg/+KDdh712emkEv8LCfTkS5mddPdx8MjLs/pUWmSV/OxA1qHDz1P7dEDU6t YEFFhN9vcQDcy5asJkgBkerjOqU4riJAWC/iEm3p/EAB6WTEBk5L/5txYAeTJBly 4kDoCABkMaGbSTpqLC5QWHrOStWFrTqx742wUivJtdceCLJQ1bHBloB5e96mXm9M P0a4QSaAD+kWDZVsgaJWVNh54FcFERkvqSHtE/CES3UrHQZ6iKU2aOyNjw278DVO dX81Shm7N2OXy9s6CaDzry274/4Cc3lcw6Ey+TO5/h/QlzldBOu6t5seaG/AX2vV aboGvlZ81x6tw3CHhji3wz5nMPl99mOPOB0JMRZReZAFbFxXDAhl1KI8tzCruAnJ OhiIQIiz90JAyUcE+5OMLdYbu2RITHNl4JWwUzUKl+BLOWv7yF+tN3+hLVSiZPAZ FjSYWBbZaPktChA0v93Jxfqfenqr4p+MXuOqV7DT9cEU5KDAQ4qB+4dcXcm5yDJR Lqw6O9BazpfrwyXSpl1yMtZUHOmQjLHCj+08tjig/AZNWONFkPckaVRPLA6u2Sxi tujM738gE+kMr1DD0G98TUrJh70qo8gQOUz16VNfFlzwgTf26LbFb2QIFnuqgzQz 8vu2z8P75xx5dU9255ZF4yqmodmGhjZ29BqzlAu+L0CBmFqhFKI= =IrSQ -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
9d0e3c5a3d
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -39,9 +39,29 @@ struct optee_shm_arg_entry {
|
|||
DECLARE_BITMAP(map, MAX_ARG_COUNT_PER_ENTRY);
|
||||
};
|
||||
|
||||
void optee_cq_wait_init(struct optee_call_queue *cq,
|
||||
struct optee_call_waiter *w)
|
||||
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, 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 @@ int optee_open_session(struct tee_context *ctx,
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 @@ static int optee_ffa_yielding_call(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 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 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
|
|||
*/
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(¶m.a1, ¶m.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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -429,6 +431,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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user