天天看點

optee中utee syscall的實作(系統調用實作)

快速連結:

.

👉👉👉 個人部落格筆記導讀目錄(全部) 👈👈👈

相關連結:

Linux Kernel中的系統調用分析

文章目錄

        • 1、GP internal API調用utee func
        • 2、utee func組的定義
        • 3、utee func的實作其實是一段調用SVC了的彙編函數
        • 4、異常向量表的el0_svc實作
        • 5、thread_svc_handler--->user_ta_handle_svc
        • 6、user_ta_handle_svc中調用tee_svc_syscall_table數組中map的具體函數
        • 7、tee_svc_syscall_table函數數組的定義

我們就以TEE_CipherInit為例,講述一下系統調用的流程,先看一張框圖如下:

optee中utee syscall的實作(系統調用實作)

總結也寫在前面,其實不必深究具體原理,我們隻要知道:

1、usersapce層的系統調用函數,一定會調用到svc指令

2、當userspace層調用了utee_xxx, 底層對應着syscall_xxx函數。

例如,userspace調用utee_open_ta_session(),那麼底層就會走進syscall_open_ta_session()中

1、GP internal API調用utee func

/* Cryptographic Operations API - Symmetric Cipher Functions */

void TEE_CipherInit(TEE_OperationHandle operation, const void *IV,
		    uint32_t IVLen)
{
	TEE_Result res;

	if (operation == TEE_HANDLE_NULL)
		TEE_Panic(0);

	if (operation->info.operationClass != TEE_OPERATION_CIPHER)
		TEE_Panic(0);

	if (!(operation->info.handleState & TEE_HANDLE_FLAG_KEY_SET) ||
	    !(operation->key1))
		TEE_Panic(0);

	if (operation->operationState != TEE_OPERATION_STATE_INITIAL)
		TEE_ResetOperation(operation);

	operation->operationState = TEE_OPERATION_STATE_ACTIVE;

	res = utee_cipher_init(operation->state, IV, IVLen);
	if (res != TEE_SUCCESS)
		TEE_Panic(res);

	operation->buffer_offs = 0;
	operation->info.handleState |= TEE_HANDLE_FLAG_INITIALIZED;
}
           

2、utee func組的定義

在utee_syscalls_asm.s定義了一系列函數,UTEE_SYSCALL是一個用于定義函數的宏

(lib\libutee\arch\arm\utee_syscalls_asm.s)
        UTEE_SYSCALL utee_return, TEE_SCN_RETURN, 1

        UTEE_SYSCALL utee_log, TEE_SCN_LOG, 2

        UTEE_SYSCALL __utee_panic, TEE_SCN_PANIC, 2

        UTEE_SYSCALL utee_get_property, TEE_SCN_GET_PROPERTY, 7

        UTEE_SYSCALL utee_get_property_name_to_index, \
                TEE_SCN_GET_PROPERTY_NAME_TO_INDEX, 4

        UTEE_SYSCALL utee_open_ta_session, TEE_SCN_OPEN_TA_SESSION, 5

        UTEE_SYSCALL utee_close_ta_session, TEE_SCN_CLOSE_TA_SESSION, 1

        UTEE_SYSCALL utee_invoke_ta_command, TEE_SCN_INVOKE_TA_COMMAND, 5
        
        UTEE_SYSCALL utee_get_cancellation_flag, \
                     TEE_SCN_GET_CANCELLATION_FLAG, 1

        UTEE_SYSCALL utee_check_access_rights, TEE_SCN_CHECK_ACCESS_RIGHTS, 3

        UTEE_SYSCALL utee_unmask_cancellation, TEE_SCN_UNMASK_CANCELLATION, 1

        UTEE_SYSCALL utee_mask_cancellation, TEE_SCN_MASK_CANCELLATION, 1

        UTEE_SYSCALL utee_wait, TEE_SCN_WAIT, 1

        UTEE_SYSCALL utee_get_time, TEE_SCN_GET_TIME, 2

        UTEE_SYSCALL utee_set_ta_time, TEE_SCN_SET_TA_TIME, 1

        UTEE_SYSCALL utee_cryp_state_alloc, TEE_SCN_CRYP_STATE_ALLOC, 5

        UTEE_SYSCALL utee_cryp_state_copy, TEE_SCN_CRYP_STATE_COPY, 2

        UTEE_SYSCALL utee_cryp_state_free, TEE_SCN_CRYP_STATE_FREE, 1

        UTEE_SYSCALL utee_hash_init, TEE_SCN_HASH_INIT, 3

        UTEE_SYSCALL utee_hash_update, TEE_SCN_HASH_UPDATE, 3

        UTEE_SYSCALL utee_hash_final, TEE_SCN_HASH_FINAL, 5

        UTEE_SYSCALL utee_cipher_init, TEE_SCN_CIPHER_INIT, 3

        UTEE_SYSCALL utee_cipher_update, TEE_SCN_CIPHER_UPDATE, 5

        UTEE_SYSCALL utee_cipher_final, TEE_SCN_CIPHER_FINAL, 5

        UTEE_SYSCALL utee_cryp_obj_get_info, TEE_SCN_CRYP_OBJ_GET_INFO, 2

        UTEE_SYSCALL utee_cryp_obj_restrict_usage, \
                     TEE_SCN_CRYP_OBJ_RESTRICT_USAGE, 2

        UTEE_SYSCALL utee_cryp_obj_get_attr, TEE_SCN_CRYP_OBJ_GET_ATTR, 4

        UTEE_SYSCALL utee_cryp_obj_alloc, TEE_SCN_CRYP_OBJ_ALLOC, 3

        UTEE_SYSCALL utee_cryp_obj_close, TEE_SCN_CRYP_OBJ_CLOSE, 1

        UTEE_SYSCALL utee_cryp_obj_reset, TEE_SCN_CRYP_OBJ_RESET,  1

        UTEE_SYSCALL utee_cryp_obj_populate, TEE_SCN_CRYP_OBJ_POPULATE, 3

        UTEE_SYSCALL utee_cryp_obj_copy, TEE_SCN_CRYP_OBJ_COPY, 2

        UTEE_SYSCALL utee_cryp_derive_key, TEE_SCN_CRYP_DERIVE_KEY, 4

        UTEE_SYSCALL utee_cryp_random_number_generate, \
                     TEE_SCN_CRYP_RANDOM_NUMBER_GENERATE, 2

        UTEE_SYSCALL utee_authenc_init, TEE_SCN_AUTHENC_INIT, 6

        UTEE_SYSCALL utee_authenc_update_aad, TEE_SCN_AUTHENC_UPDATE_AAD, 3

        UTEE_SYSCALL utee_authenc_update_payload, \
                     TEE_SCN_AUTHENC_UPDATE_PAYLOAD, 5

        UTEE_SYSCALL utee_authenc_enc_final, TEE_SCN_AUTHENC_ENC_FINAL, 7

        UTEE_SYSCALL utee_authenc_dec_final, TEE_SCN_AUTHENC_DEC_FINAL, 7

        UTEE_SYSCALL utee_asymm_operate, TEE_SCN_ASYMM_OPERATE, 7

        UTEE_SYSCALL utee_asymm_verify, TEE_SCN_ASYMM_VERIFY, 7

        UTEE_SYSCALL utee_storage_obj_open, TEE_SCN_STORAGE_OBJ_OPEN, 5

        UTEE_SYSCALL utee_storage_obj_create, TEE_SCN_STORAGE_OBJ_CREATE, 8

        UTEE_SYSCALL utee_storage_obj_del, TEE_SCN_STORAGE_OBJ_DEL, 1

        UTEE_SYSCALL utee_storage_obj_rename, TEE_SCN_STORAGE_OBJ_RENAME, 3

        UTEE_SYSCALL utee_storage_alloc_enum, TEE_SCN_STORAGE_ENUM_ALLOC, 1

        UTEE_SYSCALL utee_storage_free_enum, TEE_SCN_STORAGE_ENUM_FREE, 1

        UTEE_SYSCALL utee_storage_reset_enum, TEE_SCN_STORAGE_ENUM_RESET, 1

        UTEE_SYSCALL utee_storage_start_enum, TEE_SCN_STORAGE_ENUM_START, 2

        UTEE_SYSCALL utee_storage_next_enum, TEE_SCN_STORAGE_ENUM_NEXT, 4

        UTEE_SYSCALL utee_storage_obj_read, TEE_SCN_STORAGE_OBJ_READ, 4

        UTEE_SYSCALL utee_storage_obj_write, TEE_SCN_STORAGE_OBJ_WRITE, 3

        UTEE_SYSCALL utee_storage_obj_trunc, TEE_SCN_STORAGE_OBJ_TRUNC, 2

        UTEE_SYSCALL utee_storage_obj_seek, TEE_SCN_STORAGE_OBJ_SEEK, 3

        UTEE_SYSCALL utee_cryp_obj_generate_key, \
                     TEE_SCN_CRYP_OBJ_GENERATE_KEY, 4

        UTEE_SYSCALL utee_cache_operation, TEE_SCN_CACHE_OPERATION, 3
           

3、utee func的實作其實是一段調用SVC了的彙編函數

在調用svc指令之前,将TEE_SCN_CIPHER_INIT寫入到了X8寄存器

.macro UTEE_SYSCALL name, scn, num_args
	FUNC \name , :

	.if \num_args > TEE_SVC_MAX_ARGS || \num_args > 8
	.error "Too many arguments for syscall"
	.endif
#if defined(CFG_SYSCALL_WRAPPERS_MCOUNT) && !defined(__LDELF__)
	.if \scn != TEE_SCN_RETURN
	stp	x29, x30, [sp, #-80]!
	mov	x29, sp
	stp	x0, x1, [sp, #16]
	stp	x2, x3, [sp, #32]
	stp	x4, x5, [sp, #48]
	stp	x6, x7, [sp, #64]
	mov	x0, x30
	bl	_mcount
	ldp	x0, x1, [sp, #16]
	ldp	x2, x3, [sp, #32]
	ldp	x4, x5, [sp, #48]
	ldp	x6, x7, [sp, #64]
	ldp	x29, x30, [sp], #80
	.endif
#endif
        mov     x8, #(\scn)
        svc #0
        ret
        END_FUNC \name
        .endm

	FUNC utee_panic, :
	stp	x29, x30, [sp, #-16]!
	mov	x1, sp
	bl	__utee_panic
	/* Not reached */
	END_FUNC utee_panic

           

4、異常向量表的el0_svc實作

觸發svc異常後,将會跳轉到Optee的el0_svc向量表中,在該函數中調用了bl thread_svc_handler

LOCAL_FUNC el0_svc , :
	/* get pointer to current thread context in x0 */
	get_thread_ctx sp, 0, 1, 2
	/* load saved kernel sp */
	ldr	x0, [x0, #THREAD_CTX_KERN_SP]
	/* Keep pointer to initial recod in x1 */
	mov	x1, sp
	/* Switch to SP_EL0 and restore kernel sp */
	msr	spsel, #0
	mov	x2, sp	/* Save SP_EL0 */
	mov	sp, x0

	/* Make room for struct thread_svc_regs */
	sub	sp, sp, #THREAD_SVC_REG_SIZE
	stp	x30,x2, [sp, #THREAD_SVC_REG_X30]

	/* Restore x0-x3 */
	ldp	x2, x3, [x1, #THREAD_CORE_LOCAL_X2]
	ldp	x0, x1, [x1, #THREAD_CORE_LOCAL_X0]

	/* Prepare the argument for the handler */
	store_xregs sp, THREAD_SVC_REG_X0, 0, 14
	mrs	x0, elr_el1
	mrs	x1, spsr_el1
	store_xregs sp, THREAD_SVC_REG_ELR, 0, 1
	mov	x0, sp

	/*
	 * Unmask native interrupts, Serror, and debug exceptions since we have
	 * nothing left in sp_el1. Note that the SVC handler is excepted to
	 * re-enable foreign interrupts by itself.
	 */
#if defined(CFG_ARM_GICV3)
	msr	daifclr, #(DAIFBIT_IRQ | DAIFBIT_ABT | DAIFBIT_DBG)
#else
	msr	daifclr, #(DAIFBIT_FIQ | DAIFBIT_ABT | DAIFBIT_DBG)
#endif

	/* Call the handler */
	bl	thread_svc_handler

	/* Mask all maskable exceptions since we're switching back to sp_el1 */
	msr	daifset, #DAIFBIT_ALL

	/*
	 * Save kernel sp we'll had at the beginning of this function.
	 * This is when this TA has called another TA because
	 * __thread_enter_user_mode() also saves the stack pointer in this
	 * field.
	 */
	msr	spsel, #1
	get_thread_ctx sp, 0, 1, 2
	msr	spsel, #0
	add	x1, sp, #THREAD_SVC_REG_SIZE
	str	x1, [x0, #THREAD_CTX_KERN_SP]

	/* Restore registers to the required state and return*/
	load_xregs sp, THREAD_SVC_REG_ELR, 0, 1
	msr	elr_el1, x0
	msr	spsr_el1, x1
	load_xregs sp, THREAD_SVC_REG_X2, 2, 14
	mov	x30, sp
	ldr	x0, [x30, #THREAD_SVC_REG_SP_EL0]
	mov	sp, x0
	b_if_spsr_is_el0 w1, 1f
	ldp	x0, x1, [x30, THREAD_SVC_REG_X0]
	ldr	x30, [x30, #THREAD_SVC_REG_X30]

	return_from_exception

1:	ldp	x0, x1, [x30, THREAD_SVC_REG_X0]
	ldr	x30, [x30, #THREAD_SVC_REG_X30]

	msr	spsel, #1
	store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 1
	b	eret_to_el0
END_FUNC el0_svc
           

5、thread_svc_handler—>user_ta_handle_svc

thread_svc_handler調用了handle_svc

/*
 * Note: this function is weak just to make it possible to exclude it from
 * the unpaged area.
 */
void __weak thread_svc_handler(struct thread_svc_regs *regs)
{
	struct tee_ta_session *sess = NULL;
	uint32_t state = 0;

	/* Enable native interrupts */
	state = thread_get_exceptions();
	thread_unmask_exceptions(state & ~THREAD_EXCP_NATIVE_INTR);

	thread_user_save_vfp();

	/* TA has just entered kernel mode */
	tee_ta_update_session_utime_suspend();

	/* Restore foreign interrupts which are disabled on exception entry */
	thread_restore_foreign_intr();

	tee_ta_get_current_session(&sess);
	assert(sess && sess->ctx->ops && sess->ctx->ops->handle_svc);
	if (sess->ctx->ops->handle_svc(regs)) {
		/* We're about to switch back to user mode */
		tee_ta_update_session_utime_resume();
	} else {
		/* We're returning from __thread_enter_user_mode() */
		setup_unwind_user_mode(regs);
	}
}

           

而handle_svc指向user_ta_handle_svc

static const struct tee_ta_ops user_ta_ops __rodata_unpaged = {
	.enter_open_session = user_ta_enter_open_session,
	.enter_invoke_cmd = user_ta_enter_invoke_cmd,
	.enter_close_session = user_ta_enter_close_session,
	.dump_state = user_ta_dump_state,
#ifdef CFG_FTRACE_SUPPORT
	.dump_ftrace = user_ta_dump_ftrace,
#endif
	.destroy = user_ta_ctx_destroy,
	.get_instance_id = user_ta_get_instance_id,
	.handle_svc = user_ta_handle_svc,
};

           

6、user_ta_handle_svc中調用tee_svc_syscall_table數組中map的具體函數

user_ta_handle_svc調用tee_svc_syscall_table[scn].fn

bool user_ta_handle_svc(struct thread_svc_regs *regs)
{
	size_t scn;
	size_t max_args;
	syscall_t scf;

	COMPILE_TIME_ASSERT(ARRAY_SIZE(tee_svc_syscall_table) ==
				(TEE_SCN_MAX + 1));

	get_scn_max_args(regs, &scn, &max_args);

	trace_syscall(scn);

	if (max_args > TEE_SVC_MAX_ARGS) {
		DMSG("Too many arguments for SCN %zu (%zu)", scn, max_args);
		set_svc_retval(regs, TEE_ERROR_GENERIC);
		return true; /* return to user mode */
	}

	if (scn > TEE_SCN_MAX)
		scf = (syscall_t)syscall_not_supported;
	else
		scf = tee_svc_syscall_table[scn].fn;

	ftrace_syscall_enter(scn);

	set_svc_retval(regs, tee_svc_do_call(regs, scf));

	ftrace_syscall_leave();

	/*
	 * Return true if we're to return to user mode,
	 * thread_svc_handler() will take care of the rest.
	 */
	return scn != TEE_SCN_RETURN && scn != TEE_SCN_PANIC;
}
           

scn是從x8取出的,正是userspace寫入的TEE_SCN_CIPHER_INIT

#ifdef ARM64
static void get_scn_max_args(struct thread_svc_regs *regs, size_t *scn,
		size_t *max_args)
{
	if (((regs->spsr >> SPSR_MODE_RW_SHIFT) & SPSR_MODE_RW_MASK) ==
	     SPSR_MODE_RW_32) {
		*scn = regs->x7;
		*max_args = regs->x6;
	} else {
		*scn = regs->x8;
		*max_args = 0;
	}
}
#endif /*ARM64*/
           

7、tee_svc_syscall_table函數數組的定義

/*
 * This array is ordered according to the SYSCALL ids TEE_SCN_xxx
 */
static const struct syscall_entry tee_svc_syscall_table[] = {
	SYSCALL_ENTRY(syscall_sys_return),
	SYSCALL_ENTRY(syscall_log),
	SYSCALL_ENTRY(syscall_panic),
	SYSCALL_ENTRY(syscall_get_property),
	SYSCALL_ENTRY(syscall_get_property_name_to_index),
	SYSCALL_ENTRY(syscall_open_ta_session),
	SYSCALL_ENTRY(syscall_close_ta_session),
	SYSCALL_ENTRY(syscall_invoke_ta_command),
	SYSCALL_ENTRY(syscall_check_access_rights),
	SYSCALL_ENTRY(syscall_get_cancellation_flag),
	SYSCALL_ENTRY(syscall_unmask_cancellation),
	SYSCALL_ENTRY(syscall_mask_cancellation),
	SYSCALL_ENTRY(syscall_wait),
	SYSCALL_ENTRY(syscall_get_time),
	SYSCALL_ENTRY(syscall_set_ta_time),
	SYSCALL_ENTRY(syscall_cryp_state_alloc),
	SYSCALL_ENTRY(syscall_cryp_state_copy),
	SYSCALL_ENTRY(syscall_cryp_state_free),
	SYSCALL_ENTRY(syscall_hash_init),
	SYSCALL_ENTRY(syscall_hash_update),
	SYSCALL_ENTRY(syscall_hash_final),
	SYSCALL_ENTRY(syscall_cipher_init),
	SYSCALL_ENTRY(syscall_cipher_update),
	SYSCALL_ENTRY(syscall_cipher_final),
	SYSCALL_ENTRY(syscall_cryp_obj_get_info),
	SYSCALL_ENTRY(syscall_cryp_obj_restrict_usage),
	SYSCALL_ENTRY(syscall_cryp_obj_get_attr),
	SYSCALL_ENTRY(syscall_cryp_obj_alloc),
	SYSCALL_ENTRY(syscall_cryp_obj_close),
	SYSCALL_ENTRY(syscall_cryp_obj_reset),
	SYSCALL_ENTRY(syscall_cryp_obj_populate),
	SYSCALL_ENTRY(syscall_cryp_obj_copy),
	SYSCALL_ENTRY(syscall_cryp_derive_key),
	SYSCALL_ENTRY(syscall_cryp_random_number_generate),
	SYSCALL_ENTRY(syscall_authenc_init),
	SYSCALL_ENTRY(syscall_authenc_update_aad),
	SYSCALL_ENTRY(syscall_authenc_update_payload),
	SYSCALL_ENTRY(syscall_authenc_enc_final),
	SYSCALL_ENTRY(syscall_authenc_dec_final),
	SYSCALL_ENTRY(syscall_asymm_operate),
	SYSCALL_ENTRY(syscall_asymm_verify),
	SYSCALL_ENTRY(syscall_storage_obj_open),
	SYSCALL_ENTRY(syscall_storage_obj_create),
	SYSCALL_ENTRY(syscall_storage_obj_del),
	SYSCALL_ENTRY(syscall_storage_obj_rename),
	SYSCALL_ENTRY(syscall_storage_alloc_enum),
	SYSCALL_ENTRY(syscall_storage_free_enum),
	SYSCALL_ENTRY(syscall_storage_reset_enum),
	SYSCALL_ENTRY(syscall_storage_start_enum),
	SYSCALL_ENTRY(syscall_storage_next_enum),
	SYSCALL_ENTRY(syscall_storage_obj_read),
	SYSCALL_ENTRY(syscall_storage_obj_write),
	SYSCALL_ENTRY(syscall_storage_obj_trunc),
	SYSCALL_ENTRY(syscall_storage_obj_seek),
	SYSCALL_ENTRY(syscall_obj_generate_key),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_not_supported),
	SYSCALL_ENTRY(syscall_cache_operation),
};
           

繼續閱讀