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步来完成整个服务调用
- 初始化context
- 打开session
- 调用session中的服务,命令
- 关闭session
- 释放context
std call process
下图展示了一次helloworld的调用中,系统内部的大致流程,由此图可知,每次系统进行trusted world服务调用时,系统都需要进入smc来进行运行环境的切换(aarch64进行secure/non secure的切换必须通过EL3来完成)
通过上面示意图可以看到,系统调用trusted world的服务时,系统会经过比较长的链路,从 NSEL0 -> NSEL2/NSEL1 -> EL3 -> SEL1 -> SEL0 一共需要切换多次的cpu执行环境
optee data struct
optee服务调用时涉及很多个数据结构的传递,下面的图展示了一下open_session操作时各个数据结构之间的大致关系,分析代码时可以作为参考