OPTEE std call process

Table of Contents

OPTEE 主要通过std call的方式来给non-secure world来提供服务,在本文中主要研究一下这个服务如何实现,给以后的框架设计提供参考。
为了方便起见,这里使用optee example中的hello_world来作为例子

Example Code

#include <err.h>
#include <stdio.h>
#include <string.h>

/* OP-TEE TEE client API (built by optee_client) */
#include <tee_client_api.h>

/* For the UUID (found in the TA's h-file(s)) */
#include <hello_world_ta.h>

int main(void)
{
    TEEC_Result res;
    TEEC_Context ctx;
    TEEC_Session sess;
    TEEC_Operation op;
    TEEC_UUID uuid = TA_HELLO_WORLD_UUID;
    uint32_t err_origin;

    /* Initialize a context connecting us to the TEE */
    res = TEEC_InitializeContext(NULL, &ctx);
    if (res != TEEC_SUCCESS)
        errx(1, "TEEC_InitializeContext failed with code 0x%x", res);

    /*
     * Open a session to the "hello world" TA, the TA will print "hello
     * world!" in the log when the session is created.
     */
    res = TEEC_OpenSession(&ctx, &sess, &uuid,
                   TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
    if (res != TEEC_SUCCESS)
        errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
            res, err_origin);

    /*
     * Execute a function in the TA by invoking it, in this case
     * we're incrementing a number.
     *
     * The value of command ID part and how the parameters are
     * interpreted is part of the interface provided by the TA.
     */

    /* Clear the TEEC_Operation struct */
    memset(&op, 0, sizeof(op));

    /*
     * Prepare the argument. Pass a value in the first parameter,
     * the remaining three parameters are unused.
     */
    op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE,
                     TEEC_NONE, TEEC_NONE);
    op.params[0].value.a = 42;

    /*
     * TA_HELLO_WORLD_CMD_INC_VALUE is the actual function in the TA to be
     * called.
     */
    printf("Invoking TA to increment %d\n", op.params[0].value.a);
    res = TEEC_InvokeCommand(&sess, TA_HELLO_WORLD_CMD_INC_VALUE, &op,
                 &err_origin);
    if (res != TEEC_SUCCESS)
        errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
            res, err_origin);
    printf("TA incremented value to %d\n", op.params[0].value.a);

    /*
     * We're done with the TA, close the session and
     * destroy the context.
     *
     * The TA will print "Goodbye!" in the log when the
     * session is closed.
     */

    TEEC_CloseSession(&sess);

    TEEC_FinalizeContext(&ctx);

    return 0;
}

由上面的代码可知,non secureworld共需要5步来完成整个服务调用

  1. 初始化context
  2. 打开session
  3. 调用session中的服务,命令
  4. 关闭session
  5. 释放context

std call process

下图展示了一次helloworld的调用中,系统内部的大致流程,由此图可知,每次系统进行trusted world服务调用时,系统都需要进入smc来进行运行环境的切换(aarch64进行secure/non secure的切换必须通过EL3来完成)

optee-std-call-flow.png
通过上面示意图可以看到,系统调用trusted world的服务时,系统会经过比较长的链路,从 NSEL0 -> NSEL2/NSEL1 -> EL3 -> SEL1 -> SEL0 一共需要切换多次的cpu执行环境

optee data struct

optee服务调用时涉及很多个数据结构的传递,下面的图展示了一下open_session操作时各个数据结构之间的大致关系,分析代码时可以作为参考


Contact me via :)
虚怀乃若谷,水深则流缓。