Skip to content

Commit 28d62e6

Browse files
etienne-lmsthom24
authored andcommitted
tee: optee: Ocall2 implementation
Add kernel client API function tee_client_invoke_ocall2() to invoke a session command with support for an Ocall command from the TEE service back to caller client. On return of that function, caller can call that function again providing the Ocall argument to return to TEE from the Ocall. The interface allows Ocall command to pass 2 32bit arguments: an Ocall command ID and a value parameter. On return, the Ocall passes 2 32bit arguments to output value parameters upon success and an error result. This implementation is based on the OP-TEE OCALL implementation proposed by Hernan Gatta in linaro-swg#72 and OP-TEE/optee_os#3673. Change-Id: Idce8218a6f1c5d45e0a09f33eb2370c1790a571a Co-developed-by: Hernan Gatta <[email protected]> Signed-off-by: Hernan Gatta <[email protected]> Signed-off-by: Etienne Carriere <[email protected]> Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/linux-stm32/+/357079 Domain-Review: Yann GAUTIER <[email protected]> Reviewed-by: Yann GAUTIER <[email protected]> ACI: CITOOLS <[email protected]>
1 parent 5f169dc commit 28d62e6

File tree

8 files changed

+309
-17
lines changed

8 files changed

+309
-17
lines changed

drivers/tee/optee/call.c

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ int optee_open_session(struct tee_context *ctx,
328328
goto out;
329329
}
330330

331-
if (optee->ops->do_call_with_arg(ctx, shm, offs)) {
331+
if (optee->ops->do_call_with_arg(ctx, shm, offs, NULL)) {
332332
msg_arg->ret = TEEC_ERROR_COMMUNICATION;
333333
msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
334334
}
@@ -374,7 +374,7 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session)
374374

375375
msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
376376
msg_arg->session = session;
377-
optee->ops->do_call_with_arg(ctx, shm, offs);
377+
optee->ops->do_call_with_arg(ctx, shm, offs, NULL);
378378

379379
optee_free_msg_arg(ctx, entry, offs);
380380

@@ -389,35 +389,76 @@ int optee_close_session(struct tee_context *ctx, u32 session)
389389
/* Check that the session is valid and remove it from the list */
390390
mutex_lock(&ctxdata->mutex);
391391
sess = find_session(ctxdata, session);
392-
if (sess)
392+
if (sess && !sess->ocall_ctx.thread_p1)
393393
list_del(&sess->list_node);
394394
mutex_unlock(&ctxdata->mutex);
395395
if (!sess)
396396
return -EINVAL;
397+
if (WARN_ONCE(sess->ocall_ctx.thread_p1, "Can't close, on going Ocall\n"))
398+
return -EINVAL;
399+
397400
kfree(sess);
398401

399402
return optee_close_session_helper(ctx, session);
400403
}
401404

402405
int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
403406
struct tee_param *param)
407+
{
408+
return optee_invoke_func_helper(ctx, arg, param, NULL);
409+
}
410+
411+
int optee_invoke_func_helper(struct tee_context *ctx,
412+
struct tee_ioctl_invoke_arg *arg,
413+
struct tee_param *param,
414+
struct tee_ocall2_arg *ocall_arg)
404415
{
405416
struct optee *optee = tee_get_drvdata(ctx->teedev);
406417
struct optee_context_data *ctxdata = ctx->data;
418+
struct optee_call_extra call_extra;
407419
struct optee_shm_arg_entry *entry;
408420
struct optee_msg_arg *msg_arg;
409421
struct optee_session *sess;
410422
struct tee_shm *shm;
423+
u32 session_id;
411424
u_int offs;
412425
int rc;
413426

427+
if (tee_ocall_in_progress(ocall_arg))
428+
session_id = ocall_arg->session;
429+
else
430+
session_id = arg->session;
431+
414432
/* Check that the session is valid */
415433
mutex_lock(&ctxdata->mutex);
416-
sess = find_session(ctxdata, arg->session);
434+
sess = find_session(ctxdata, session_id);
417435
mutex_unlock(&ctxdata->mutex);
418436
if (!sess)
419437
return -EINVAL;
420438

439+
if (tee_ocall_in_progress(ocall_arg) && !sess->ocall_ctx.thread_p1) {
440+
pr_err("Unexpected return from Ocall for the session\n");
441+
return -EINVAL;
442+
}
443+
if (!tee_ocall_is_used(ocall_arg) && sess->ocall_ctx.thread_p1) {
444+
pr_err("Session is busy with an on-going Ocall\n");
445+
return -EINVAL;
446+
}
447+
448+
/* Setup TEE call extra data */
449+
memset(&call_extra, 0, sizeof(call_extra));
450+
451+
if (tee_ocall_is_used(ocall_arg)) {
452+
call_extra.ocall_arg = ocall_arg;
453+
call_extra.ocall_call_waiter = &sess->ocall_ctx.call_waiter;
454+
}
455+
456+
if (tee_ocall_in_progress(ocall_arg)) {
457+
call_extra.tee_thread_id = sess->ocall_ctx.thread_p1 - 1;
458+
/* Skip shared memory buffer part, not needed with ocall2 */
459+
goto do_call;
460+
}
461+
421462
msg_arg = optee_get_msg_arg(ctx, arg->num_params,
422463
&entry, &shm, &offs);
423464
if (IS_ERR(msg_arg))
@@ -432,7 +473,54 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
432473
if (rc)
433474
goto out;
434475

435-
if (optee->ops->do_call_with_arg(ctx, shm, offs)) {
476+
if (tee_ocall_is_used(ocall_arg)) {
477+
/* Save initial call context in ocall context */
478+
memcpy(&sess->ocall_ctx.call_arg, arg, sizeof(*arg));
479+
sess->ocall_ctx.msg_arg = msg_arg;
480+
sess->ocall_ctx.msg_entry = entry;
481+
sess->ocall_ctx.msg_offs = offs;
482+
}
483+
484+
do_call:
485+
rc = optee->ops->do_call_with_arg(ctx, shm, offs, &call_extra);
486+
if (rc == -EAGAIN) {
487+
/* We are executing an Ocall request from TEE */
488+
if (tee_ocall_in_progress(ocall_arg)) {
489+
mutex_lock(&ctxdata->mutex);
490+
ocall_arg->session = session_id;
491+
sess->ocall_ctx.thread_p1 = call_extra.tee_thread_id + 1;
492+
mutex_unlock(&ctxdata->mutex);
493+
494+
return 0;
495+
}
496+
WARN_ONCE(1, "optee: unexpected ocall\n");
497+
}
498+
499+
/* Session may be leaving an Ocall */
500+
mutex_lock(&ctxdata->mutex);
501+
sess->ocall_ctx.thread_p1 = 0;
502+
503+
if (tee_ocall_is_used(ocall_arg)) {
504+
/* We are returning from initial call, get initial call msg */
505+
msg_arg = sess->ocall_ctx.msg_arg;
506+
entry = sess->ocall_ctx.msg_entry;
507+
offs = sess->ocall_ctx.msg_offs;
508+
if (arg) {
509+
unsigned int num_params = arg->num_params;
510+
511+
memcpy(arg, &sess->ocall_ctx.call_arg, sizeof(*arg));
512+
if (num_params < sess->ocall_ctx.call_arg.num_params) {
513+
arg->num_params = 0;
514+
rc = -EINVAL;
515+
}
516+
}
517+
518+
/* Wipe Ocall context deprecated information */
519+
memset(&sess->ocall_ctx, 0, sizeof(sess->ocall_ctx));
520+
}
521+
mutex_unlock(&ctxdata->mutex);
522+
523+
if (rc) {
436524
msg_arg->ret = TEEC_ERROR_COMMUNICATION;
437525
msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
438526
}
@@ -466,6 +554,8 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
466554
mutex_unlock(&ctxdata->mutex);
467555
if (!sess)
468556
return -EINVAL;
557+
if (WARN_ONCE(sess->ocall_ctx.thread_p1, "Can't cancel, on going Ocall\n"))
558+
return -EINVAL;
469559

470560
msg_arg = optee_get_msg_arg(ctx, 0, &entry, &shm, &offs);
471561
if (IS_ERR(msg_arg))
@@ -474,7 +564,7 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
474564
msg_arg->cmd = OPTEE_MSG_CMD_CANCEL;
475565
msg_arg->session = session;
476566
msg_arg->cancel_id = cancel_id;
477-
optee->ops->do_call_with_arg(ctx, shm, offs);
567+
optee->ops->do_call_with_arg(ctx, shm, offs, NULL);
478568

479569
optee_free_msg_arg(ctx, entry, offs);
480570
return 0;

drivers/tee/optee/core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ static void optee_release_helper(struct tee_context *ctx,
141141
list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
142142
list_node) {
143143
list_del(&sess->list_node);
144-
close_session(ctx, sess->session_id);
144+
if (!WARN_ONCE(sess->ocall_ctx.thread_p1, "Can't close, on going Ocall\n"))
145+
close_session(ctx, sess->session_id);
145146
kfree(sess);
146147
}
147148
kfree(ctxdata);

drivers/tee/optee/ffa_abi.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,8 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
612612
*/
613613

614614
static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
615-
struct tee_shm *shm, u_int offs)
615+
struct tee_shm *shm, u_int offs,
616+
struct optee_call_extra *call_extra)
616617
{
617618
struct ffa_send_direct_data data = {
618619
.data0 = OPTEE_FFA_YIELDING_CALL_WITH_ARG,

drivers/tee/optee/optee_private.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ struct optee_ffa {
142142

143143
struct optee;
144144

145+
/**
146+
* struct optee_call_extra - Extra data used by calling TEE
147+
* @ocall_arg: OCall arguments related to the call or NULL
148+
* @tee_thread_id: TEE thread ID to use to return from an OCall, or 0
149+
* @ocall_call_waiter: Reference to the waiter that tracks TEE entry
150+
*/
151+
struct optee_call_extra {
152+
struct tee_ocall2_arg *ocall_arg;
153+
u32 tee_thread_id;
154+
struct optee_call_waiter *ocall_call_waiter;
155+
};
156+
145157
/**
146158
* struct optee_ops - OP-TEE driver internal operations
147159
* @do_call_with_arg: enters OP-TEE in secure world
@@ -154,7 +166,8 @@ struct optee;
154166
*/
155167
struct optee_ops {
156168
int (*do_call_with_arg)(struct tee_context *ctx,
157-
struct tee_shm *shm_arg, u_int offs);
169+
struct tee_shm *shm_arg, u_int offs,
170+
struct optee_call_extra *extra);
158171
int (*to_msg_param)(struct optee *optee,
159172
struct optee_msg_param *msg_params,
160173
size_t num_params, const struct tee_param *params);
@@ -201,9 +214,34 @@ struct optee {
201214
struct work_struct scan_bus_work;
202215
};
203216

217+
/**
218+
* struct tee_session_ocall - Ocall context of a session
219+
* @thread_p1: TEE thread ID plus 1 (0 means no suspended TEE thread)
220+
* @call_waiter: Waiter for the call entry completed at Ocall return entry
221+
* @call_arg: Invocation argument from initial call that issued the Ocall
222+
* @msg_arg: Reference to optee msg used at initial call
223+
* @msg_entry: Reference to optee msg allocation entry
224+
* @msg_offs: Reference to optee msg allocation offset
225+
*/
226+
struct tee_session_ocall {
227+
u32 thread_p1;
228+
struct optee_call_waiter call_waiter;
229+
struct tee_ioctl_invoke_arg call_arg;
230+
struct optee_msg_arg *msg_arg;
231+
struct optee_shm_arg_entry *msg_entry;
232+
u_int msg_offs;
233+
};
234+
235+
/**
236+
* struct tee_session - Session between a client and a TEE service (TA)
237+
* @list_node: User list for the session
238+
* @session_id: Session identifier provided by the TEE
239+
* @ocall_ctx: OCall context
240+
*/
204241
struct optee_session {
205242
struct list_head list_node;
206243
u32 session_id;
244+
struct tee_session_ocall ocall_ctx;
207245
};
208246

209247
struct optee_context_data {
@@ -256,6 +294,11 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
256294
struct tee_param *param);
257295
int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
258296

297+
int optee_invoke_func_helper(struct tee_context *ctx,
298+
struct tee_ioctl_invoke_arg *arg,
299+
struct tee_param *param,
300+
struct tee_ocall2_arg *ocall_arg);
301+
259302
#define PTA_CMD_GET_DEVICES 0x0
260303
#define PTA_CMD_GET_DEVICES_SUPP 0x1
261304
int optee_enumerate_devices(u32 func);

drivers/tee/optee/optee_smc.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,29 @@ struct optee_smc_disable_shm_cache_result {
579579
#define OPTEE_SMC_RETURN_RPC_CMD \
580580
OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD)
581581

582+
/*
583+
* Do an OCall RPC request to caller client. The Ocall request ABI is very
584+
* minimal: 2 input arguments and 2 output arguments. 1st output argument
585+
* value 0 is reserved to error management requesting OCall termination.
586+
* When 1st output argument is 0, 2nd output argument is either 0 or can
587+
* carry a TEEC_Result like error code.
588+
*
589+
* "Call" register usage:
590+
* a0 OPTEE_SMC_RETURN_RPC_OCALL2
591+
* a1 OCall input argument 1 (32 bit)
592+
* a2 OCall input argument 2 (32 bit)
593+
* a3-7 Resume information, must be preserved
594+
*
595+
* "Return" register usage:
596+
* a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
597+
* a1 OCall output argument 1 (32 bit), value 0 upon error
598+
* a2 OCall output argument 2 (32 bit), TEEC_Result error if @a1 is 0
599+
* a3-7 Preserved
600+
*/
601+
#define OPTEE_SMC_RPC_FUNC_OCALL2 2048
602+
#define OPTEE_SMC_RETURN_RPC_OCALL2 \
603+
OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_OCALL2)
604+
582605
/* Returned in a0 */
583606
#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
584607

0 commit comments

Comments
 (0)