optee學習筆記_2_demo源碼分析

OP-TEE demo源碼分析

上一節的分析,我們在這裏詳細的分析DEMO中CA和TA的源碼,整個分析過程以捋清楚整個流程爲主,在整個過程中,涉及的點很多,後面章節會再一一詳解,如optee os的啓動、driver的註冊、以及守護進程tee_supplicant。


源碼git地址:https://github.com/4LogCoder/optee.git

 

在ca中,我主要封裝了三個函數,分別是:

TEEC_Result ca_demo_sha_open(void);
TEEC_Result ca_demo_sha(void* in, unsigned int size, void *out, SHA_MODE mode);
void ca_demo_sha_close(void);

在main函數中,我們首先調用ca_demo_sha_open()函數,建立和打開一個session,建立CA和TA的聯繫,然後通過ca_demo_sha()函數發起一次SHA計算。

首先我們先從ca_demo_open開始

TEEC_Result ca_demo_sha_open(void)
{
	TEEC_Result ret;
	TEEC_UUID id = TA_DEMO_UUID;
	//printf("ca_demo_sha_open\n",ret);
	ret = TEEC_InitializeContext(NULL, &context);
	if(ret != TEEC_SUCCESS){
		printf("ca_demo_sha_open:TEEC_InitializeContext failed %x\n",ret);
		goto exit_1;
	}
	ret = TEEC_OpenSession(&context, &session, &id, TEEC_LOGIN_PUBLIC, NULL, NULL, NULL);
	if(ret != TEEC_SUCCESS){
		printf("ca_demo_sha_open:TEEC_OpenSession failed %x\n",ret);
		goto finalizeContext;
	}
	sharedMem.size = 1024 + 1024;
	sharedMem.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
	ret = TEEC_AllocateSharedMemory(&context, &sharedMem);
	if(ret != TEEC_SUCCESS){
		printf("ca_demo_sha_open:TEEC_AllocateSharedMemory failed %x\n",ret);
		goto closeSession;
	}
	valid_session = 1;
	return ret;
closeSession:
	TEEC_CloseSession(&session);
finalizeContext:
	TEEC_FinalizeContext(&context);
exit_1:
	return ret;
}

在該函數中,我們依次調用了

TEEC_InitializeContext(NULL, &context);

TEEC_OpenSession(&context, &session, &id, TEEC_LOGIN_PUBLIC, NULL, NULL, NULL);

TEEC_AllocateSharedMemory(&context, &sharedMem);

這三個函數均由libteec庫實現,下面我們一一分析這三個函數都幹了些什麼

TEEC_InitializeContext

首先是調用TEEC_InitializeContext函數

函數原型:TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx)

功能:初始化一個TEEC_Context變量

詳解:在這函數中,首先拼接出devname字符串,然後調用teec_open_dev()函數,這個函數則主要是通過調用open()函數,打開對應的device,並通過ioctl獲取版本等相關信息,進行相應的判斷後,將打開的device的句柄fd放入TEEC_Context變量之中。

TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx)
{
	char devname[PATH_MAX] = { 0 };
	int fd = 0;
	size_t n = 0;
	if (!ctx)
		return TEEC_ERROR_BAD_PARAMETERS;
	for (n = 0; n < TEEC_MAX_DEV_SEQ; n++) {
		uint32_t gen_caps = 0;
		snprintf(devname, sizeof(devname), "/dev/tee%zu", n);
		fd = teec_open_dev(devname, name, &gen_caps);
		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;
}

static int teec_open_dev(const char *devname, const char *capabilities,
			 uint32_t *gen_caps)
{
	int fd = 0;
	struct tee_ioctl_version_data vers; 
	memset(&vers, 0, sizeof(vers));
	fd = open(devname, O_RDWR);
	if (fd < 0)
		return -1;
	if (ioctl(fd, TEE_IOC_VERSION, &vers)) {
		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;
}

TEEC_InitializeContext函數小結:這一函數主要是通過打開對應的設備文件,獲取對應設備文件的fd,並進行版本檢查,將fd填充至context變量。在整個過程中,並沒有和某個特定的TA聯繫。此外這一函數必須是CA調用libteec庫的第一個API,因爲只用通過這一函數,纔打開了對應的設備文件,和optee_linuxdriver建立了聯繫。

 

TEEC_OpenSession

調用TEEC_InitializeContext函數之後,再調用TEEC_OpenSession()函數

函數原型:

TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
			const TEEC_UUID *destination,
			uint32_t connection_method, const void *connection_data,
			TEEC_Operation *operation, uint32_t *ret_origin)

函數功能:在當前context中爲CA和TA建立一個session,具體和那個TA建立session由TEEC_UUID變量決定

詳解:在這一函數中,首先定義了一塊sharememory用於存放ioctl的相關參數,並進行相應的預處理,最終通過調用ioctl發送TEE_IOC_OPEN_SESSION command,陷入正常世界的內核空間,到達tee driver中

TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
			const TEEC_UUID *destination,
			uint32_t connection_method, const void *connection_data,
			TEEC_Operation *operation, uint32_t *ret_origin)
{
	struct tee_ioctl_open_session_arg *arg = NULL;
	struct tee_ioctl_param *params = NULL;
	TEEC_Result res = TEEC_ERROR_GENERIC;
	uint32_t eorig = 0;
	int rc = 0;
	const size_t arg_size = sizeof(struct tee_ioctl_open_session_arg) +
				TEEC_CONFIG_PAYLOAD_REF_COUNT *
					sizeof(struct tee_ioctl_param);
	union {
		struct tee_ioctl_open_session_arg arg;
		uint8_t data[arg_size];
	} buf;
	struct tee_ioctl_buf_data buf_data;
	TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
	memset(&buf, 0, sizeof(buf));
	memset(&shm, 0, sizeof(shm));
	memset(&buf_data, 0, sizeof(buf_data));
	(void)&connection_data;
	if (!ctx || !session) {
		eorig = TEEC_ORIGIN_API;
		res = TEEC_ERROR_BAD_PARAMETERS;
		goto out;
	}
	buf_data.buf_ptr = (uintptr_t)&buf;
	buf_data.buf_len = sizeof(buf);
	arg = &buf.arg;
	arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
	params = (struct tee_ioctl_param *)(arg + 1);
	uuid_to_octets(arg->uuid, destination);
	arg->clnt_login = connection_method;
	res = teec_pre_process_operation(ctx, operation, params, shm);
	if (res != TEEC_SUCCESS) {
		eorig = TEEC_ORIGIN_API;
		goto out_free_temp_refs;
	}
	rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data);
	if (rc) {
		EMSG("TEE_IOC_OPEN_SESSION failed");
		eorig = TEEC_ORIGIN_COMMS;
		res = ioctl_errno_to_res(errno);
		goto out_free_temp_refs;
	}
	res = arg->ret;
	eorig = arg->ret_origin;
	if (res == TEEC_SUCCESS) {
		session->ctx = ctx;
		session->session_id = arg->session;
	}
	teec_post_process_operation(operation, params, shm);
out_free_temp_refs:
	teec_free_temp_refs(operation, shm);
out:
	if (ret_origin)
		*ret_origin = eorig;
	return res;
}

下面我們看一下ioctl的TEE_IOC_OPEN_SESSION command具體幹了些啥

源碼位置: tee/core.c

首先通過tee_ioctl調用tee_ioctl_open_session()函數,在該函數中,首先將用戶空間的參數拷貝到正常世界的內核空間

static int tee_ioctl_open_session(struct tee_context *ctx,
				  struct tee_ioctl_buf_data __user *ubuf)
{
	int rc;
	size_t n;
	struct tee_ioctl_buf_data buf;
	struct tee_ioctl_open_session_arg __user *uarg;
	struct tee_ioctl_open_session_arg arg;
	struct tee_ioctl_param __user *uparams = NULL;
	struct tee_param *params = NULL;
	bool have_session = false;
	if (!ctx->teedev->desc->ops->open_session)
		return -EINVAL;
	if (copy_from_user(&buf, ubuf, sizeof(buf)))
		return -EFAULT;
	if (buf.buf_len > TEE_MAX_ARG_SIZE ||
	    buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
		return -EINVAL;

	uarg = u64_to_user_ptr(buf.buf_ptr);
	if (copy_from_user(&arg, uarg, sizeof(arg)))
		return -EFAULT;
	if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
		return -EINVAL;
	if (arg.num_params) {
		params = kcalloc(arg.num_params, sizeof(struct tee_param),
				 GFP_KERNEL);
		if (!params)
			return -ENOMEM;
		uparams = uarg->params;
		rc = params_from_user(ctx, params, arg.num_params, uparams);
		if (rc)
			goto out;
	}
	rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
	if (rc)
		goto out;
	have_session = true;
	if (put_user(arg.session, &uarg->session) ||
	    put_user(arg.ret, &uarg->ret) ||
	    put_user(arg.ret_origin, &uarg->ret_origin)) {
		rc = -EFAULT;
		goto out;
	}
	rc = params_to_user(uparams, arg.num_params, params);
out:
	/*
	 * If we've succeeded to open the session but failed to communicate
	 * it back to user space, close the session again to avoid leakage.
	 */
	if (rc && have_session && ctx->teedev->desc->ops->close_session)
		ctx->teedev->desc->ops->close_session(ctx, arg.session);
	if (params) {
		/* Decrease ref count for all valid shared memory pointers */
		for (n = 0; n < arg.num_params; n++)
			if (tee_param_is_memref(params + n) &&
			    params[n].u.memref.shm)
				tee_shm_put(params[n].u.memref.shm);
		kfree(params);
	}
	return rc;
}

然後調用fops:的open_session變量,即optee_open_session函數,在optee_open_session函數中,通過get_msg_arg分配一塊sharememory,並將參數填充至sharememory中,最後調用optee_do_call_with_arg函數,在這一函數中,通過optee->invoke_fn觸發smc調用。

int optee_open_session(struct tee_context *ctx,
		       struct tee_ioctl_open_session_arg *arg,
		       struct tee_param *param)
{
	struct optee_context_data *ctxdata = ctx->data;
	int rc;
	struct tee_shm *shm;
	struct optee_msg_arg *msg_arg;
	phys_addr_t msg_parg;
	struct optee_session *sess = NULL;

	/* +2 for the meta parameters added below */
	shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg, &msg_parg);
	if (IS_ERR(shm))
		return PTR_ERR(shm);

	msg_arg->cmd = OPTEE_MSG_CMD_OPEN_SESSION;
	msg_arg->cancel_id = arg->cancel_id;

	/*
	 * Initialize and add the meta parameters needed when opening a
	 * session.
	 */
	msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
				  OPTEE_MSG_ATTR_META;
	msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
				  OPTEE_MSG_ATTR_META;
	memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
	memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
	msg_arg->params[1].u.value.c = arg->clnt_login;
	rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
	if (rc)
		goto out;
	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
	if (!sess) {
		rc = -ENOMEM;
		goto out;
	}

	if (optee_do_call_with_arg(ctx, msg_parg)) {
		msg_arg->ret = TEEC_ERROR_COMMUNICATION;
		msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
	}

	if (msg_arg->ret == TEEC_SUCCESS) {
		/* A new session has been created, add it to the list. */
		sess->session_id = msg_arg->session;
		mutex_lock(&ctxdata->mutex);
		list_add(&sess->list_node, &ctxdata->sess_list);
		mutex_unlock(&ctxdata->mutex);
	} else {
		kfree(sess);
	}
	if (optee_from_msg_param(param, arg->num_params, msg_arg->params + 2)) {
		arg->ret = TEEC_ERROR_COMMUNICATION;
		arg->ret_origin = TEEC_ORIGIN_COMMS;
		/* Close session again to avoid leakage */
		optee_close_session(ctx, msg_arg->session);
	} else {
		arg->session = msg_arg->session;
		arg->ret = msg_arg->ret;
		arg->ret_origin = msg_arg->ret_origin;
	}
out:
	tee_shm_free(shm);
	return rc;
}

在optee_do_call_with_arg函數中,通過invoke_fn函數觸發smc調用

u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
{
	struct optee *optee = tee_get_drvdata(ctx->teedev);
	struct optee_call_waiter w;
	struct optee_rpc_param param = { };
	struct optee_call_ctx call_ctx = { };
	u32 ret;

	param.a0 = OPTEE_SMC_CALL_WITH_ARG;
	reg_pair_from_64(&param.a1, &param.a2, parg);
	/* Initialize waiter */
	optee_cq_wait_init(&optee->call_queue, &w);
	while (true) {
		struct arm_smccc_res res;

		optee->invoke_fn(param.a0, param.a1, param.a2, param.a3,
				 param.a4, param.a5, param.a6, param.a7,
				 &res);

		if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
			/*
			 * Out of threads in secure world, wait for a thread
			 * become available.
			 */
			optee_cq_wait_for_completion(&optee->call_queue, &w);
		} else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
			param.a0 = res.a0;
			param.a1 = res.a1;
			param.a2 = res.a2;
			param.a3 = res.a3;
			optee_handle_rpc(ctx, &param, &call_ctx);
		} else {
			ret = res.a0;
			break;
		}
	}

	optee_rpc_finalize_call(&call_ctx);
	/*
	 * We're done with our thread in secure world, if there's any
	 * thread waiters wake up one.
	 */
	optee_cq_wait_final(&optee->call_queue, &w);

	return ret;
}

在這裏具體是怎麼觸發smc調用的,先大致介紹下,後面章節會詳細講解。這個函數指針是通過get_invoke_func函數遍歷設備樹,獲取相應的smc調用方式

/* Simple wrapper functions to be able to use a function pointer */
static void optee_smccc_smc(unsigned long a0, unsigned long a1,
			    unsigned long a2, unsigned long a3,
			    unsigned long a4, unsigned long a5,
			    unsigned long a6, unsigned long a7,
			    struct arm_smccc_res *res)
{
	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
}

static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
			    unsigned long a2, unsigned long a3,
			    unsigned long a4, unsigned long a5,
			    unsigned long a6, unsigned long a7,
			    struct arm_smccc_res *res)
{
	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
}
static optee_invoke_fn *get_invoke_func(struct device_node *np)
{
	const char *method;
	pr_info("probing for conduit method from DT.\n");
	if (of_property_read_string(np, "method", &method)) {
		pr_warn("missing \"method\" property\n");
		return ERR_PTR(-ENXIO);
	}

	if (!strcmp("hvc", method))
		return optee_smccc_hvc;
	else if (!strcmp("smc", method))
		return optee_smccc_smc;
	pr_warn("invalid \"method\" property: %s\n", method);
	return ERR_PTR(-EINVAL);
}

觸發smc調用之後,處理器就進入Monitor模式,並將一系列的寄存器值更新,獲取MVBAR寄存器中異常向量表中的sm_vect_table的基地址,並命中smc異常,從而進入sm_smc_entry函數。函數位置:optee_os-master\core\arch\arm\sm\sm_a32.S,然後更新一些寄存器值,最後依次調用smc_from_nsec -> sm_from_nsec

uint32_t sm_from_nsec(struct sm_ctx *ctx)
{
	uint32_t *nsec_r0 = (uint32_t *)(&ctx->nsec.r0);
	/*
	 * Check that struct sm_ctx has the different parts properly
	 * aligned since the stack pointer will be updated to point at
	 * different parts of this struct.
	 */
	COMPILE_TIME_ASSERT(!(offsetof(struct sm_ctx, sec.r0) % 8));
	COMPILE_TIME_ASSERT(!(offsetof(struct sm_ctx, nsec.r0) % 8));
	COMPILE_TIME_ASSERT(!(sizeof(struct sm_ctx) % 8));

#ifdef CFG_SM_PLATFORM_HANDLER
	if (sm_platform_handler(ctx) == SM_HANDLER_SMC_HANDLED)
		return SM_EXIT_TO_NON_SECURE;
#endif
#ifdef CFG_PSCI_ARM32
	if (OPTEE_SMC_OWNER_NUM(*nsec_r0) == OPTEE_SMC_OWNER_STANDARD) {
		smc_std_handler((struct thread_smc_args *)nsec_r0, &ctx->nsec);
		return SM_EXIT_TO_NON_SECURE;
	}
#endif
	sm_save_unbanked_regs(&ctx->nsec.ub_regs);
	sm_restore_unbanked_regs(&ctx->sec.ub_regs);
	memcpy(&ctx->sec.r0, nsec_r0, sizeof(uint32_t) * 8);
	if (OPTEE_SMC_IS_FAST_CALL(ctx->sec.r0))
		ctx->sec.mon_lr = (uint32_t)&thread_vector_table.fast_smc_entry;
	else
		ctx->sec.mon_lr = (uint32_t)&thread_vector_table.std_smc_entry;
	return SM_EXIT_TO_SECURE;
}

在sm_from_nsec函數中,通過判斷,最後進入std_smc_entry,調用entry_open_session()處理,最後通過一系列的調用,直到調用到ta_load()函數。

static TEE_Result ta_load(struct tee_tadb_ta_read *ta)
{
	TEE_Result res;
	const size_t sz = ta->entry.prop.custom_size + ta->entry.prop.bin_size;

	if (ta->ta_mobj)
		return TEE_SUCCESS;

	ta->ta_mobj = thread_rpc_alloc_payload(sz);
	if (!ta->ta_mobj)
		return TEE_ERROR_OUT_OF_MEMORY;

	ta->ta_buf = mobj_get_va(ta->ta_mobj, 0);
	assert(ta->ta_buf);

	struct thread_param params[] = {
		[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, ta->fd, 0),
		[1] = THREAD_PARAM_MEMREF(OUT, ta->ta_mobj, 0, sz),
	};

	res = thread_rpc_cmd(OPTEE_RPC_CMD_FS, ARRAY_SIZE(params), params);
	if (res) {
		thread_rpc_free_payload(ta->ta_mobj);
		ta->ta_mobj = NULL;
	}
	return res;
}

在ta_load函數中,主要通過調用thread_rpc_cmd函數,再在thread_rpc_cmd函數中調用thread_rpc函數,發起RPC請求,其中thread_rpc由彙編實現,通過smc指令,將系統從secure world轉換至Normal World

FUNC thread_smc , :
	smc	#0
	ret
END_FUNC thread_smc

在linux kernel tee driver中,driver將會通知supplicant完成TA文件的加載(後面章節中,再詳細講解這一過程)。

 

至此,我們已經通過調用TEEC_OpenSession完成了相應TA文件的加載。

TEEC_OpenSession小結:在這一函數中,我們通過ioctl調用,陷入內核空間,然後調用smc指令,從NormalWorld轉換至SecureWorld,轉換至secureWorld後,由optee os解析command,準備load相應的TA文件,在這一步驟中,還需要調用smc指令,轉換至NormalWorld,請求tee_supplicat進程在文件系統中找到對應UUID的TA文件,並傳至secureWorld中。至此TEEC_OpenSession函數才全部執行完成。

 

AllocateSharedMemory

此後,我們再調用AllocateSharedMemory函數,分配一塊shareMemory,存放待計算的明文。

通過上述三個函數的準備工作之後,我們再在main函數中,調用ca_demo_sha()函數,發起一次計算請求。

TEEC_Result ca_demo_sha(void* in, unsigned int size, void *out, SHA_MODE mode)
{
	TEEC_Result ret;
	TEEC_Operation op;
	uint32_t err_origin;
	
	//printf("ca_demo_sha\n");
	if(!valid_session)
		return TEEC_ERROR_BAD_STATE;
	if(size > 1024)
		return TEEC_ERROR_BAD_PARAMETERS;

	memcpy(sharedMem.buffer, in, size);
	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_PARTIAL_INPUT,
										TEEC_MEMREF_PARTIAL_OUTPUT, TEEC_NONE);
	op.started = 1;
	op.params[0].value.a = mode;
	op.params[1].memref.parent = &sharedMem;
	op.params[1].memref.offset = 0;
	op.params[1].memref.size = size;

	op.params[2].memref.parent = &sharedMem;
	op.params[2].memref.offset = 1024;
	op.params[2].memref.size = 1024;
	
	ret = TEEC_InvokeCommand(&session, CA_DEMO_CMD_SHA, &op, &err_origin);
	if(ret != TEEC_SUCCESS){
		printf("invoke faild %d\n",ret);
		return ret;
	}
	
	memcpy(out, (void*)((char *)sharedMem.buffer + 1024), op.params[2].memref.size);
	uint32_t len = op.params[2].memref.size;
	printf("ca_demo_sha: len:%d sha:\n", len);
	int i;
	char* p = out;
	for(i= 0; i<len; i++)
		printf("%02x",p[i]);
	printf("\n");
	return ret;
}

在這一過程中,我們首先需要構建填充好相應的參數(具體可參考官方文檔),然後調用TEEC_InvokeCommand函數,正式發起一次計算command。

整個過程和TEEC_InvokeCommand類似,主要是通過ioctl陷入內核,然後調用smc指令,轉換至secureWorld,並由optee os解析指令,最終調用到TA文件中的TA_InvokeCommandEntryPoint函數

TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,uint32_t nCommandID,
                                    uint32_t nParamTypes, TEE_Param pParams[4])

至此,就開始執行用戶設定的一些code.

TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,uint32_t nCommandID,
                                    uint32_t nParamTypes, TEE_Param pParams[4])
{
	DMSG("TA Invoke Command Entry Point for %s commandId: %d\n",TA_NAME,nCommandID);
	switch(nCommandID){
		case TA_DEMO_CMD_SHA:
			return ta_demo_entry_sha(nParamTypes, pParams);
		case TA_DEMO_CMD_RSA:
			return ta_demo_entry_rsa(nParamTypes, pParams);
		default:
			return TEE_ERROR_BAD_PARAMETERS;
	}
}

在此計算完成之後,就會通過類似於RPC請求的方式,將結果返回值NormalWorld.

然後再在main函數中,調用ca_demo_close()函數,釋放相應的session和設備。在這裏就不再詳細介紹了。

 

總結下,整個demo主要就是封裝了ca_demo_sha_open(),ca_demo_sha(),ca_demo_sha_close,首先在ca_demo_sha_oopen函數中,調用了TEEC_InitializeContext、TEEC_OpenSession、TEEC_AllocateSharedMemory三個函數,打開了相應的tee設備文件,並將指定的TA load進了內存之中,並和當前CA進行了關聯;然後通過在ca_demo_sha()中調用TEEC_InvokeCommand函數,最終調用到TA文件中的TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,uint32_t nCommandID, uint32_t  nParamTypes,  TEE_Param  pParams[4])函數,在這一函數中執行相應的SHA操作,並將計算結果放在sharememory中,返回至NormalWorld中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章