嵌入式开发论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 79|回复: 0

27. OP-TEE驱动篇----libteec接口在驱动中的实现

[复制链接]

59

主题

62

帖子

249

积分

版主

Rank: 7Rank: 7Rank: 7

积分
249
发表于 2018-11-26 09:44:36 | 显示全部楼层 |阅读模式
libteec提供给上层使用的接口总共有十个,这十个接口的功能和定义介绍请参阅《21. OP-TEE中TA与CA执行流程-------libteec介绍》,这十个接口通过系统调用最终会调用到驱动中,在接口libteec中调用Open函数的时候,在驱动中就对调用到file_operations结构体变量tee_fops中的Open成员。同理在libteec接口中调用ioctl函数,则在驱动中最终会调用tee_fops中的ioctl函数。本文将介绍驱动中file_operation结构体变量tee_fops中各成员函数的具体实现.
1. libteec和tee_supplicant执行Open操作  在libteec中调用open函数来打开/dev/tee0设备的时候,最终会调用到tee_fops中的open成员指定的函数指针tee_open,该函数的内容如下:
  1. static int tee_open(struct inode *inode, struct file *filp)
  2. {
  3.         struct tee_context *ctx;

  4. /* 调用container_of函数,获取设备的tee_device变量的内容 。该变量对于/dev/tee0
  5. 和/dev/teepriv0设备时不一样的,这点可以在驱动过载的过程中查阅*/
  6.         ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev));
  7.         if (IS_ERR(ctx))
  8.                 return PTR_ERR(ctx);

  9.         filp->private_data = ctx;
  10.         return 0;
  11. }

  12. static struct tee_context *teedev_open(struct tee_device *teedev)
  13. {
  14.         int rc;
  15.         struct tee_context *ctx;

  16. /* 标记该设备的使用者加一 */
  17.         if (!tee_device_get(teedev))
  18.                 return ERR_PTR(-EINVAL);

  19. /* 分配tee_context结构体体空间 */
  20.         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
  21.         if (!ctx) {
  22.                 rc = -ENOMEM;
  23.                 goto err;
  24.         }

  25. /* 将tee_context结构体中的teedev变量赋值 */
  26.         ctx->teedev = teedev;
  27.         INIT_LIST_HEAD(&ctx->list_shm);
  28. /*调用设备的des中的open执行设备级别的open操作*/
  29.         rc = teedev->desc->ops->open(ctx);        
  30.         if (rc)
  31.                 goto err;

  32.         return ctx;
  33. err:
  34.         kfree(ctx);
  35.         tee_device_put(teedev);
  36.         return ERR_PTR(rc);
  37. }
复制代码
对于设备级别(/dev/tee0和/dev/teepriv0),最终会调用到optee_open函数,该函数内容如下:
  1. static int optee_open(struct tee_context *ctx)
  2. {
  3.         struct optee_context_data *ctxdata;
  4.         struct tee_device *teedev = ctx->teedev;
  5.         struct optee *optee = tee_get_drvdata(teedev);

  6. /* 分配optee_context_data 结构体变量空间 */
  7.         ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
  8.         if (!ctxdata)
  9.                 return -ENOMEM;

  10. /* 通过teedev的值是否为 optee->supp_teedev,以此来判定当前的Open操作是打
  11. 开/dev/tee0设备还是/dev/teepriv0设备,如果相等,则表示当前是打开/dev/teepriv0设备 */
  12.         if (teedev == optee->supp_teedev) {
  13.                 bool busy = true; //标记/dev/teepriv0正在使用

  14.                 mutex_lock(&optee->supp.mutex);
  15.                 if (!optee->supp.ctx) {
  16.                         busy = false;
  17.                         optee->supp.ctx = ctx;
  18.                 }
  19.                 mutex_unlock(&optee->supp.mutex);
  20.                 if (busy) {
  21.                         kfree(ctxdata);
  22.                         return -EBUSY;
  23.                 }
  24.         }

  25. /* 初始化互斥体和队列 */
  26.         mutex_init(&ctxdata->mutex);
  27.         INIT_LIST_HEAD(&ctxdata->sess_list);

  28. /* 赋值 */
  29.         ctx->data = ctxdata;
  30.         return 0;
  31. }
复制代码
2. libteec和tee_supplicant执行release操作
当在libteec和tee_supplicant打开了对应的设备之后,如果需要release设备,则可以调用该设备的release来实现,在userspace层面调用完成之后,最终会调用到OP-TEE驱动的release成员变量tee_release,该函数内容如下:
  1. static int tee_release(struct inode *inode, struct file *filp)
  2. {
  3.         teedev_close_context(filp->private_data);
  4.         return 0;
  5. }
  6. static void teedev_close_context(struct tee_context *ctx)
  7. {
  8.         struct tee_shm *shm;

  9. /* 调用/dev/tee0或者是/dev/teepriv0设备的release操作函数 */
  10.         ctx->teedev->desc->ops->release(ctx);
  11.         mutex_lock(&ctx->teedev->mutex);
  12. /* 清空设备分配的共享内存,并将其指针指向NULL */
  13.         list_for_each_entry(shm, &ctx->list_shm, link)
  14.                 shm->ctx = NULL;
  15.         mutex_unlock(&ctx->teedev->mutex);
  16.         tee_device_put(ctx->teedev); //设备使用者数量减一,如果已经没有使用者则将desc指向NULL
  17.         kfree(ctx);
  18. }
复制代码
ctx->teedev->desc->ops->release(ctx);将会执行optee_release函数,其内容如下:
  1. static void optee_release(struct tee_context *ctx)
  2. {
  3.         struct optee_context_data *ctxdata = ctx->data;
  4.         struct tee_device *teedev = ctx->teedev;
  5.         struct optee *optee = tee_get_drvdata(teedev);
  6.         struct tee_shm *shm;
  7.         struct optee_msg_arg *arg = NULL;
  8.         phys_addr_t parg;
  9.         struct optee_session *sess;
  10.         struct optee_session *sess_tmp;

  11.         if (!ctxdata)
  12.                 return;

  13. /* 分配驱动与secure world之间的共享内存 */
  14.         shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED);
  15.         if (!IS_ERR(shm)) {
  16.                 arg = tee_shm_get_va(shm, 0); //获取共享内存的虚拟地址
  17.                 /*
  18.                  * If va2pa fails for some reason, we can't call
  19.                  * optee_close_session(), only free the memory. Secure OS
  20.                  * will leak sessions and finally refuse more sessions, but
  21.                  * we will at least let normal world reclaim its memory.
  22.                  */
  23.                 if (!IS_ERR(arg))
  24.                         tee_shm_va2pa(shm, arg, &parg); //解析共享内存的虚拟地址得到物理地址,存放在parg中
  25.         }

  26. /*遍历存放使用该设备的所有session通知secure worldOP-TEE执行关闭session操作*/
  27.         list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
  28.                                  list_node) {
  29.                 list_del(&sess->list_node);
  30.                 if (!IS_ERR_OR_NULL(arg)) {
  31.                         memset(arg, 0, sizeof(*arg));
  32.                         arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
  33.                         arg->session = sess->session_id;
  34.                         optee_do_call_with_arg(ctx, parg);
  35.                 }
  36.                 kfree(sess);
  37.         }
  38.         kfree(ctxdata);

  39. /* 释放共享内存 */
  40.         if (!IS_ERR(shm))
  41.                 tee_shm_free(shm);

  42.         ctx->data = NULL;

  43. /* 如果是对/dev/teepriv0设备进行release操作,则指向optee_supp_release操作,释放该设
  44. 备在使用的时候建立的各种队列 */
  45.         if (teedev == optee->supp_teedev)
  46.                 optee_supp_release(&optee->supp);
  47. }
复制代码
3. libteec和tee_supplicant中执行ioctl操作
在libteec中获取OP-TEE版本信息,创建和关闭session,调用TA,分配和注册共享内存和fd以及释放共享内存,接收来自OP-TEE的请求以及回复数据给OP-TEE都是通过ioctl来完成的。在libteec和tee_supplicant中通过带上对应的参数调用ioctl函数来实现对应的操作需求,最终会调用到OP-TEE驱动中file_operation结构体变量tee_fops变量中的tee_ioctl函数,该函数的内容如下:
  1. static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  2. {
  3.         struct tee_context *ctx = filp->private_data;        //获取设备的私有数据
  4.         void __user *uarg = (void __user *)arg;         //定义指向userspace层面输入参数的指针变量

  5.         switch (cmd) {
  6. /* 和获取OP-TEE OS的版本 */
  7.         case TEE_IOC_VERSION:
  8.                 return tee_ioctl_version(ctx, uarg);

  9. /* 分配,注册,释放共享内存操作 */
  10.         case TEE_IOC_SHM_ALLOC:
  11.                 return tee_ioctl_shm_alloc(ctx, uarg);

  12. /* 注册共享文件句柄 */
  13.         case TEE_IOC_SHM_REGISTER_FD:
  14.                 return tee_ioctl_shm_register_fd(ctx, uarg);

  15. /* 打开CA与TA通信的session */
  16.         case TEE_IOC_OPEN_SESSION:
  17.                 return tee_ioctl_open_session(ctx, uarg);

  18. /* 调用TA,让根据参数中的command ID让TA执行特定的command */
  19.         case TEE_IOC_INVOKE:
  20.                 return tee_ioctl_invoke(ctx, uarg);

  21. /* 通知TA取消掉对某一个来自normal world请求的响应 */
  22.         case TEE_IOC_CANCEL:
  23.                 return tee_ioctl_cancel(ctx, uarg);

  24. /* 关闭CA与TA之间通信的session */
  25.         case TEE_IOC_CLOSE_SESSION:
  26.                 return tee_ioctl_close_session(ctx, uarg);

  27. /* 接收来自secure world的请求 */
  28.         case TEE_IOC_SUPPL_RECV:
  29.                 return tee_ioctl_supp_recv(ctx, uarg);

  30. /* 根据来自secure world的请求执行处理后回复数据给secure world */
  31.         case TEE_IOC_SUPPL_SEND:
  32.                 return tee_ioctl_supp_send(ctx, uarg);
  33.         default:
  34.                 return -EINVAL;
  35.         }
  36. }
复制代码
3.1 获取OP-TEE版本信息
当libteec和tee_supplicant调用ioctl来获取OP-TEE OS的版本信息时,驱动会执行tee_ioctl_version函数,该函数内容如下:
  1. static int tee_ioctl_version(struct tee_context *ctx,
  2.                              struct tee_ioctl_version_data __user *uvers)
  3. {
  4.         struct tee_ioctl_version_data vers;

  5. /* 调用设备的get_version操作 */
  6.         ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);

  7. /* 判定该操作是来至于tee_supplicant还是libteec */
  8.         if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED)
  9.                 vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED;

  10. /* 将获取到的版本信息数据拷贝到userspace层面提供的buffer中 */
  11.         if (copy_to_user(uvers, &vers, sizeof(vers)))
  12.                 return -EFAULT;

  13.         return 0;
  14. }
复制代码
而设备的get_version的内容如下:
  1. static void optee_get_version(struct tee_device *teedev,
  2.                               struct tee_ioctl_version_data *vers)
  3. {
  4.         struct tee_ioctl_version_data v = {
  5.                 .impl_id = TEE_IMPL_ID_OPTEE,
  6.                 .impl_caps = TEE_OPTEE_CAP_TZ,
  7.                 .gen_caps = TEE_GEN_CAP_GP,
  8.         };
  9.         *vers = v;
  10. }
复制代码
3.2 分配和注册共享内存操作
当libteec和tee_supplicant需要分配和注册于secure world之间的共享内存时,可以通过调用驱动的ioctl方法来实现,然后驱动调用tee_ioctl_shm_alloc来实现具体的分配,注册共享内存的操作。该函数的内容如下:
  1. static int tee_ioctl_shm_alloc(struct tee_context *ctx,
  2.                                struct tee_ioctl_shm_alloc_data __user *udata)
  3. {
  4.         long ret;
  5.         struct tee_ioctl_shm_alloc_data data;
  6.         struct tee_shm *shm;

  7. /* 将userspace传递的参数数据拷贝到kernel的buffer中 */
  8.         if (copy_from_user(&data, udata, sizeof(data)))
  9.                 return -EFAULT;

  10.         /* Currently no input flags are supported */
  11.         if (data.flags)
  12.                 return -EINVAL;

  13. /* 将共享内存的ID值设置成-1,以便分配好共享内存之后重新赋值 */
  14.         data.id = -1;

  15. /* 调用tee_shm_all函数,从驱动与secure world之间的共享内存池中分配对应大小的内存,
  16. 并设定对应的ID值 */
  17.         shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
  18.         if (IS_ERR(shm))
  19.                 return PTR_ERR(shm);

  20. /* 设定需要返回给userspace的数据 */
  21.         data.id = shm->id;
  22.         data.flags = shm->flags;
  23.         data.size = shm->size;

  24. /* 将需要返回的数据从kernespace拷贝到userspace层面 */
  25.         if (copy_to_user(udata, &data, sizeof(data)))
  26.                 ret = -EFAULT;
  27.         else
  28.                 ret = tee_shm_get_fd(shm);

  29.         /*
  30.          * When user space closes the file descriptor the shared memory
  31.          * should be freed or if tee_shm_get_fd() failed then it will
  32.          * be freed immediately.
  33.          */
  34.         tee_shm_put(shm); //如果分配的是DMA的buffer则要减少count值
  35.         return ret;
  36. }
复制代码
而在tee_shm_all中驱动做了什么操作呢?该函数的内容如下:
  1. struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
  2. {
  3.         struct tee_device *teedev = ctx->teedev;
  4.         struct tee_shm_pool_mgr *poolm = NULL;
  5.         struct tee_shm *shm;
  6.         void *ret;
  7.         int rc;

  8. /* 判定参数是否合法 */
  9.         if (!(flags & TEE_SHM_MAPPED)) {
  10.                 dev_err(teedev->dev.parent,
  11.                         "only mapped allocations supported\n");
  12.                 return ERR_PTR(-EINVAL);
  13.         }

  14. /* 判定flags,表明该操作只能从驱动的私有共享呢村或者DMA buffer中进行分配 */
  15.         if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
  16.                 dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
  17.                 return ERR_PTR(-EINVAL);
  18.         }

  19. /* 获取设备结构体 */
  20.         if (!tee_device_get(teedev))
  21.                 return ERR_PTR(-EINVAL);

  22. /* 判定设备的poll成员是否存在,该成员在驱动挂载的时候会被初始化成驱动与secure world
  23. 之间的共享内存池结构体 */
  24.         if (!teedev->pool) {
  25.                 /* teedev has been detached from driver */
  26.                 ret = ERR_PTR(-EINVAL);
  27.                 goto err_dev_put;
  28.         }

  29. /* 分配存放shm的kernel空间的内存 */
  30.         shm = kzalloc(sizeof(*shm), GFP_KERNEL);
  31.         if (!shm) {
  32.                 ret = ERR_PTR(-ENOMEM);
  33.                 goto err_dev_put;
  34.         }

  35. /* 设定该块共享内存的flag以及对应的使用者 */
  36.         shm->flags = flags;
  37.         shm->teedev = teedev;
  38.         shm->ctx = ctx;

  39. /* 通过传入的flags来判定是从驱动的私有共享内存池还是工dma buffer中来进行分配 */
  40.         if (flags & TEE_SHM_DMA_BUF)
  41.                 poolm = &teedev->pool->dma_buf_mgr;
  42.         else
  43.                 poolm = &teedev->pool->private_mgr;

  44. /* 调用pool中对应的alloc操作分配size大小的共享内存 */
  45.         rc = poolm->ops->alloc(poolm, shm, size);
  46.         if (rc) {
  47.                 ret = ERR_PTR(rc);
  48.                 goto err_kfree;
  49.         }

  50. /* 获取分配好的共享内存的id */
  51.         mutex_lock(&teedev->mutex);
  52.         shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
  53.         mutex_unlock(&teedev->mutex);
  54.         if (shm->id < 0) {
  55.                 ret = ERR_PTR(shm->id);
  56.                 goto err_pool_free;
  57.         }

  58. /* 如果指定的是DMA buffer,则指定相关的operation */
  59.         if (flags & TEE_SHM_DMA_BUF) {
  60.                 DEFINE_DMA_BUF_EXPORT_INFO(exp_info);

  61.                 exp_info.ops = &tee_shm_dma_buf_ops;
  62.                 exp_info.size = shm->size;
  63.                 exp_info.flags = O_RDWR;
  64.                 exp_info.priv = shm;

  65.                 shm->dmabuf = dma_buf_export(&exp_info);
  66.                 if (IS_ERR(shm->dmabuf)) {
  67.                         ret = ERR_CAST(shm->dmabuf);
  68.                         goto err_rem;
  69.                 }
  70.         }

  71. /* 将分配的内存链接到共享内存队列的末尾 */
  72.         mutex_lock(&teedev->mutex);
  73.         list_add_tail(&shm->link, &ctx->list_shm);
  74.         mutex_unlock(&teedev->mutex);

  75.         return shm;
  76. err_rem:
  77.         mutex_lock(&teedev->mutex);
  78.         idr_remove(&teedev->idr, shm->id);
  79.         mutex_unlock(&teedev->mutex);
  80. err_pool_free:
  81.         poolm->ops->free(poolm, shm);
  82. err_kfree:
  83.         kfree(shm);
  84. err_dev_put:
  85.         tee_device_put(teedev);
  86.         return ret;
  87. }
复制代码
从整个过程来看,如果在libteec执行共享内存的分配或者是注册操作时,驱动都会从驱动与secure world的共享内存池中分配一块内存,然后将该分配好的内存的id值返回给libteec,然后在libteec中,如果是调用TEEC_AllocateSharedMemory函数,则会将该共享内存的id值进行mmap,然后将map后的值赋值给shm中的buffer成员。如果调用的是TEEC_RegisterSharedMemory,则会将共享内存id执行mmap之后的值赋值给shm中的shadow_buffer成员。
由此可见,当libteec中是执行注册共享内存操作时,并不是讲userspace的内存直接共享给secure world,而是将userspace的内存与驱动中分配的一块共享内存做shadow操作,是两者实现一个类似映射的关系。
3.3 libteec中打开session的操作
当用户调用libteec中的TEEC_OpenSession接口时会执行驱动中ioctl函数的TEE_IOC_OPEN_SESSION分支去执行tee_ioctl_open_session函数,该函数只会在打开了/dev/tee0设备之后才能被使用,其的内容如下:
  1. static int tee_ioctl_open_session(struct tee_context *ctx,
  2.                                   struct tee_ioctl_buf_data __user *ubuf)
  3. {
  4.         int rc;
  5.         size_t n;
  6.         struct tee_ioctl_buf_data buf;
  7.         struct tee_ioctl_open_session_arg __user *uarg;
  8.         struct tee_ioctl_open_session_arg arg;
  9.         struct tee_ioctl_param __user *uparams = NULL;
  10.         struct tee_param *params = NULL;
  11.         bool have_session = false;

  12. /* 判定设备是否存在open_session函数 */
  13.         if (!ctx->teedev->desc->ops->open_session)
  14.                 return -EINVAL;

  15. /* 将userspace传入的参数拷贝到kernelspace */
  16.         if (copy_from_user(&buf, ubuf, sizeof(buf)))
  17.                 return -EFAULT;

  18. /* 判定传入的参数的大小是否合法 */
  19.         if (buf.buf_len > TEE_MAX_ARG_SIZE ||
  20.             buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
  21.                 return -EINVAL;

  22. /* 为兼容性64位系统做出转换,并将数据拷贝到arg变量中 */
  23.         uarg = u64_to_user_ptr(buf.buf_ptr);
  24.         if (copy_from_user(&arg, uarg, sizeof(arg)))
  25.                 return -EFAULT;

  26.         if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
  27.                 return -EINVAL;

  28. /* 判定userspace层面传递的参数的个数并在kernelspace中分配对应的空间,将该空间的起
  29. 始地址保存在params,然后userspace中的参数数据存放到params中 */
  30.         if (arg.num_params) {
  31.                 params = kcalloc(arg.num_params, sizeof(struct tee_param),
  32.                                  GFP_KERNEL);
  33.                 if (!params)
  34.                         return -ENOMEM;
  35.                 uparams = uarg->params;

  36. /* 将来自userspace的参数数据保存到刚刚分配的params指向的内存中 */
  37.                 rc = params_from_user(ctx, params, arg.num_params, uparams);
  38.                 if (rc)
  39.                         goto out;
  40.         }

  41. /* 调用设备的open_session方法,并将参数传递給该函数  */
  42.         rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
  43.         if (rc)
  44.                 goto out;
  45.         have_session = true;

  46.         if (put_user(arg.session, &uarg->session) ||
  47.             put_user(arg.ret, &uarg->ret) ||
  48.             put_user(arg.ret_origin, &uarg->ret_origin)) {
  49.                 rc = -EFAULT;
  50.                 goto out;
  51.         }
  52. /* 将从secure world中返回的数据保存到userspace对应的buffer中 */
  53.         rc = params_to_user(uparams, arg.num_params, params);
  54. out:
  55.         /*
  56.          * If we've succeeded to open the session but failed to communicate
  57.          * it back to user space, close the session again to avoid leakage.
  58.          */
  59. /* 如果调用不成功则执行close session操作 */
  60.         if (rc && have_session && ctx->teedev->desc->ops->close_session)

  61.         if (params) {
  62.                 /* Decrease ref count for all valid shared memory pointers */
  63.                 for (n = 0; n < arg.num_params; n++)
  64.                         if (tee_param_is_memref(params + n) &&
  65.                             params[n].u.memref.shm)
  66.                                 tee_shm_put(params[n].u.memref.shm);
  67.                 kfree(params);
  68.         }

  69.         return rc;
  70. }
复制代码
调用设备的open_session操作来完成向OP-TEE发送打开与特定TA的session操作,open_session函数的执行流程如下图所示:
​​整个调用中会调用optee_do_call_with_arg函数来完成驱动与secure world之间的交互,该函数的内容如下:
  1. u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
  2. {
  3.         struct optee *optee = tee_get_drvdata(ctx->teedev);
  4.         struct optee_call_waiter w;
  5.         struct optee_rpc_param param = { };
  6.         u32 ret;

  7. /* 设定触发smc操作的第一个参数a0的值为OPTEE_SMC_CALL_WITH_ARG
  8.     通过OPTEE_SMC_CALL_WITH_ARG值可以知道,该函数将会执行std的smc操作 */
  9.         param.a0 = OPTEE_SMC_CALL_WITH_ARG;
  10.         reg_pair_from_64(¶m.a1, ¶m.a2, parg);
  11.         /* Initialize waiter */
  12. /* 初始化调用的等待队列 */
  13.         optee_cq_wait_init(&optee->call_queue, &w);

  14. /*进入到loop循环,触发smc操作并等待secure world的返回*/
  15.         while (true) {
  16.                 struct arm_smccc_res res;

  17. /* 触发smc操作 */
  18.                 optee->invoke_fn(param.a0, param.a1, param.a2, param.a3,
  19.                                  param.a4, param.a5, param.a6, param.a7,
  20.                                  &res);

  21. /* 判定secure world是否超时,如果超时,完成一次啊调用,进入下一次循环
  22.     知道secure world端完成open session请求 */
  23.                 if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
  24.                         /*
  25.                          * Out of threads in secure world, wait for a thread
  26.                          * become available.
  27.                          */
  28.                         optee_cq_wait_for_completion(&optee->call_queue, &w);
  29.                 } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
  30. /* 处理rpc操作 */
  31.                         param.a0 = res.a0;
  32.                         param.a1 = res.a1;
  33.                         param.a2 = res.a2;
  34.                         param.a3 = res.a3;
  35.                         optee_handle_rpc(ctx, ¶m);
  36.                 } else {
  37. /* 创建session完成之后跳出loop,并返回a0的值 */
  38.                         ret = res.a0;
  39.                         break;
  40.                 }
  41.         }

  42.         /*
  43.          * We're done with our thread in secure world, if there's any
  44.          * thread waiters wake up one.
  45.          */
  46. /* 执行等待队列最后完成操作 */
  47.         optee_cq_wait_final(&optee->call_queue, &w);

  48.         return ret;
  49. }
复制代码
3.4 libteec中执行invoke的操作
当完成了session打开之后,用户就可以调用TEEC_InvokeCommand接口来调用对应的TA中执行特定的操作了,TEEC_InvokeCommand函数最终会调用驱动的tee_ioctl_invoke函数来完成具体的操作。该函数内如如下:
  1. static int tee_ioctl_invoke(struct tee_context *ctx,
  2.                             struct tee_ioctl_buf_data __user *ubuf)
  3. {
  4.         int rc;
  5.         size_t n;
  6.         struct tee_ioctl_buf_data buf;
  7.         struct tee_ioctl_invoke_arg __user *uarg;
  8.         struct tee_ioctl_invoke_arg arg;
  9.         struct tee_ioctl_param __user *uparams = NULL;
  10.         struct tee_param *params = NULL;

  11. /* 参数检查 */
  12.         if (!ctx->teedev->desc->ops->invoke_func)
  13.                 return -EINVAL;

  14. /* 数据拷贝到kernel space */
  15.         if (copy_from_user(&buf, ubuf, sizeof(buf)))
  16.                 return -EFAULT;

  17.         if (buf.buf_len > TEE_MAX_ARG_SIZE ||
  18.             buf.buf_len < sizeof(struct tee_ioctl_invoke_arg))
  19.                 return -EINVAL;

  20.         uarg = u64_to_user_ptr(buf.buf_ptr);
  21.         if (copy_from_user(&arg, uarg, sizeof(arg)))
  22.                 return -EFAULT;

  23.         if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
  24.                 return -EINVAL;

  25. /* 组合需要传递到secure world中的参数buffer */
  26.         if (arg.num_params) {
  27.                 params = kcalloc(arg.num_params, sizeof(struct tee_param),
  28.                                  GFP_KERNEL);
  29.                 if (!params)
  30.                         return -ENOMEM;
  31.                 uparams = uarg->params;
  32.                 rc = params_from_user(ctx, params, arg.num_params, uparams);
  33.                 if (rc)
  34.                         goto out;
  35.         }

  36. /* 使用对应的session出发smc操作 */
  37.         rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params);
  38.         if (rc)
  39.                 goto out;

  40. /* 检查和解析返回的数据,并将数据拷贝到userspace用户体用的Buffser中 */
  41.         if (put_user(arg.ret, &uarg->ret) ||
  42.             put_user(arg.ret_origin, &uarg->ret_origin)) {
  43.                 rc = -EFAULT;
  44.                 goto out;
  45.         }
  46.         rc = params_to_user(uparams, arg.num_params, params);
  47. out:
  48.         if (params) {
  49.                 /* Decrease ref count for all valid shared memory pointers */
  50.                 for (n = 0; n < arg.num_params; n++)
  51.                         if (tee_param_is_memref(params + n) &&
  52.                             params[n].u.memref.shm)
  53.                                 tee_shm_put(params[n].u.memref.shm);
  54.                 kfree(params);
  55.         }
  56.         return rc;
  57. }
复制代码



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|TEE and Virtualization

GMT+8, 2019-3-19 00:10 , Processed in 0.071876 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表