OPTEE學習筆記 - CA呼叫TA流程
阿新 • • 發佈:2019-01-01
今天開始學習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;
}