@@ -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
402405int 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 ;
0 commit comments