@@ -328,7 +328,7 @@ int optee_open_session(struct tee_context *ctx,
328
328
goto out ;
329
329
}
330
330
331
- if (optee -> ops -> do_call_with_arg (ctx , shm , offs )) {
331
+ if (optee -> ops -> do_call_with_arg (ctx , shm , offs , NULL )) {
332
332
msg_arg -> ret = TEEC_ERROR_COMMUNICATION ;
333
333
msg_arg -> ret_origin = TEEC_ORIGIN_COMMS ;
334
334
}
@@ -374,7 +374,7 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session)
374
374
375
375
msg_arg -> cmd = OPTEE_MSG_CMD_CLOSE_SESSION ;
376
376
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 );
378
378
379
379
optee_free_msg_arg (ctx , entry , offs );
380
380
@@ -389,35 +389,76 @@ int optee_close_session(struct tee_context *ctx, u32 session)
389
389
/* Check that the session is valid and remove it from the list */
390
390
mutex_lock (& ctxdata -> mutex );
391
391
sess = find_session (ctxdata , session );
392
- if (sess )
392
+ if (sess && ! sess -> ocall_ctx . thread_p1 )
393
393
list_del (& sess -> list_node );
394
394
mutex_unlock (& ctxdata -> mutex );
395
395
if (!sess )
396
396
return - EINVAL ;
397
+ if (WARN_ONCE (sess -> ocall_ctx .thread_p1 , "Can't close, on going Ocall\n" ))
398
+ return - EINVAL ;
399
+
397
400
kfree (sess );
398
401
399
402
return optee_close_session_helper (ctx , session );
400
403
}
401
404
402
405
int optee_invoke_func (struct tee_context * ctx , struct tee_ioctl_invoke_arg * arg ,
403
406
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 )
404
415
{
405
416
struct optee * optee = tee_get_drvdata (ctx -> teedev );
406
417
struct optee_context_data * ctxdata = ctx -> data ;
418
+ struct optee_call_extra call_extra ;
407
419
struct optee_shm_arg_entry * entry ;
408
420
struct optee_msg_arg * msg_arg ;
409
421
struct optee_session * sess ;
410
422
struct tee_shm * shm ;
423
+ u32 session_id ;
411
424
u_int offs ;
412
425
int rc ;
413
426
427
+ if (tee_ocall_in_progress (ocall_arg ))
428
+ session_id = ocall_arg -> session ;
429
+ else
430
+ session_id = arg -> session ;
431
+
414
432
/* Check that the session is valid */
415
433
mutex_lock (& ctxdata -> mutex );
416
- sess = find_session (ctxdata , arg -> session );
434
+ sess = find_session (ctxdata , session_id );
417
435
mutex_unlock (& ctxdata -> mutex );
418
436
if (!sess )
419
437
return - EINVAL ;
420
438
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
+
421
462
msg_arg = optee_get_msg_arg (ctx , arg -> num_params ,
422
463
& entry , & shm , & offs );
423
464
if (IS_ERR (msg_arg ))
@@ -432,7 +473,54 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
432
473
if (rc )
433
474
goto out ;
434
475
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 ) {
436
524
msg_arg -> ret = TEEC_ERROR_COMMUNICATION ;
437
525
msg_arg -> ret_origin = TEEC_ORIGIN_COMMS ;
438
526
}
@@ -466,6 +554,8 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
466
554
mutex_unlock (& ctxdata -> mutex );
467
555
if (!sess )
468
556
return - EINVAL ;
557
+ if (WARN_ONCE (sess -> ocall_ctx .thread_p1 , "Can't cancel, on going Ocall\n" ))
558
+ return - EINVAL ;
469
559
470
560
msg_arg = optee_get_msg_arg (ctx , 0 , & entry , & shm , & offs );
471
561
if (IS_ERR (msg_arg ))
@@ -474,7 +564,7 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
474
564
msg_arg -> cmd = OPTEE_MSG_CMD_CANCEL ;
475
565
msg_arg -> session = session ;
476
566
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 );
478
568
479
569
optee_free_msg_arg (ctx , entry , offs );
480
570
return 0 ;
0 commit comments