今天开始学习optee相关的代码,目的是弄清optee的执行逻辑,学习optee。以下是杂记,仅用做学习记录。学习代码均取自github和《手机安全和可信应用开发指南》(帅峰云,黄腾,宋洋)
学习代码示例:
void g_CryptoVerifyCa_Helloworld(void)
{
TEEC_Session l_session; /* Define the session of TA&CA */
TEEC_Operation l_operation; /* Define the operation for communicating between TA&CA */
int l_RetVal = FAIL; /* Define the return value of function */
/**1) Initialize this task */
l_RetVal = l_CryptoVerifyCa_TaskInit();
if(FAIL == l_RetVal)
{
goto cleanup_1;
}
/**2) Open session */
l_RetVal = l_CryptoVerifyCa_OpenSession(&l_session);
if(FAIL == l_RetVal)
{
goto cleanup_2;
}
/* Clear the TEEC_Operation struct */
memset(&l_operation, 0, sizeof(TEEC_Operation));
/*
* Prepare the argument. Pass a value in the first parameter,
* the remaining three parameters are unused.
*/
l_operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE,
TEEC_NONE, TEEC_NONE);
l_operation.params[0].value.a = 42;
/**4) Send command to TA */
l_RetVal = l_CryptoVerifyCa_SendCommand(&l_operation, &l_session, TA_MY_TEST_CMD_INC_VALUE);
if(FAIL == l_RetVal)
{
goto cleanup_3;
}
/**5) The clean up operation */
cleanup_3:
TEEC_CloseSession(&l_session);
cleanup_2:
TEEC_FinalizeContext(&g_TaskContext);
cleanup_1:
printf("over\n");
}
TaskInit流程分析
l_CryptoVerifyCa_TaskInit()函数主要是调用了TEEC_InitializeContext(NULL, &g_TaskContext)来初始化context。传入的name是NULL,根据注释可知,这里只能传NULL
/**
* TEEC_InitializeContext() - Initializes a context holding connection
* information on the specific TEE, designated by the name string.
* @param name A zero-terminated string identifying the TEE to connect to.
* If name is set to NULL, the default TEE is connected to. NULL
* is the only supported value in this version of the API
* implementation.
*
* @param context The context structure which is to be initialized.
*
* @return TEEC_SUCCESS The initialization was successful.
* @return TEEC_Result Something failed.
*/
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx)
{
char devname[PATH_MAX];
int fd;
size_t n;
if (!ctx)
return TEEC_ERROR_BAD_PARAMETERS;
for (n = 0; n < TEEC_MAX_DEV_SEQ; n++) { //TEEC_MAX_DEV_SEQ=10,只使用前10个tee设备
uint32_t gen_caps;
snprintf(devname, sizeof(devname), "/dev/tee%zu", n);
fd = teec_open_dev(devname, name, &gen_caps); //打开节点,并取的caps,cap是什么意思后面需要研究
if (fd >= 0) {
ctx->fd = fd;
ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM;
return TEEC_SUCCESS;
}
}
return TEEC_ERROR_ITEM_NOT_FOUND;
}
/**
* struct tee_ioctl_version_data - TEE version
* @impl_id: [out] TEE implementation id
* @impl_caps: [out] Implementation specific capabilities
* @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above
*
* Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above.
* @impl_caps is implementation specific, for example TEE_OPTEE_CAP_*
* is valid when @impl_id == TEE_IMPL_ID_OPTEE.
*/
//下面的成员变量都是干什么的
struct tee_ioctl_version_data {
__u32 impl_id;
__u32 impl_caps;
__u32 gen_caps;
};
static int teec_open_dev(const char *devname, const char *capabilities,
uint32_t *gen_caps)
{
struct tee_ioctl_version_data vers; //
int fd;
fd = open(devname, O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, TEE_IOC_VERSION, &vers)) { //ioctl打开/dev/tee0,获取TEE VERSION DATA
EMSG("TEE_IOC_VERSION failed");
goto err;
}
/* We can only handle GP TEEs */
if (!(vers.gen_caps & TEE_GEN_CAP_GP))
goto err;
if (capabilities) {
if (strcmp(capabilities, "optee-tz") == 0) {
if (vers.impl_id != TEE_IMPL_ID_OPTEE)
goto err;
if (!(vers.impl_caps & TEE_OPTEE_CAP_TZ))
goto err;
} else {
/* Unrecognized capability requested */
goto err;
}
}
*gen_caps = vers.gen_caps;
return fd;
err:
close(fd);
return -1;
}
ioctl会调用到kernel的tee driver:kernel/drivers/tee/tee_core.c
OPTEE的驱动的加载和初始化可以参考https://blog.csdn.net/shuaifengyun/article/details/72934531
static const struct file_operations tee_fops = {
.owner = THIS_MODULE,
.open = tee_open,
.release = tee_release,
.unlocked_ioctl = tee_ioctl,
.compat_ioctl = tee_ioctl,
};
static int tee_ioctl_version(struct tee_context *ctx,
struct tee_ioctl_version_data __user *uvers)
{
struct tee_ioctl_version_data vers;
ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);
if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED)
vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED;
if (copy_to_user(uvers, &vers, sizeof(vers))) //把数据copy到userspace需要研究
return -EFAULT;
return 0;
}
static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct tee_context *ctx = filp->private_data;
void __user *uarg = (void __user *)arg;
switch (cmd) {
case TEE_IOC_VERSION:
return tee_ioctl_version(ctx, uarg);
case TEE_IOC_SHM_ALLOC:
return tee_ioctl_shm_alloc(ctx, uarg);
case TEE_IOC_SHM_REGISTER:
return tee_ioctl_shm_register(ctx, uarg);
case TEE_IOC_SHM_REGISTER_FD:
return tee_ioctl_shm_register_fd(ctx, uarg);
case TEE_IOC_OPEN_SESSION:
return tee_ioctl_open_session(ctx, uarg);
case TEE_IOC_INVOKE:
return tee_ioctl_invoke(ctx, uarg);
case TEE_IOC_CANCEL:
return tee_ioctl_cancel(ctx, uarg);
case TEE_IOC_CLOSE_SESSION:
return tee_ioctl_close_session(ctx, uarg);
case TEE_IOC_SUPPL_RECV:
return tee_ioctl_supp_recv(ctx, uarg);
case TEE_IOC_SUPPL_SEND:
return tee_ioctl_supp_send(ctx, uarg);
default:
return -EINVAL;
}
}
get_version最后调用的是optee_get_version函数:kernel/drivers/tee/optee/core.c
static void optee_get_version(struct tee_device *teedev,
struct tee_ioctl_version_data *vers)
{
struct tee_ioctl_version_data v = {
.impl_id = TEE_IMPL_ID_OPTEE,
.impl_caps = TEE_OPTEE_CAP_TZ,
.gen_caps = TEE_GEN_CAP_GP,
};
struct optee *optee = tee_get_drvdata(teedev);
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
v.gen_caps |= TEE_GEN_CAP_REG_MEM;
*vers = v;
}