ECALL Switch/Ordinary模式

目录

SGX初始化中,我们就碰到过切换上下文进入Enclave的场景

以【ECMD_INIT_ENCLAVE】为例,先大概描述一下切换上下文进入Enclave的具体过程

普及:ECALL索引值和tRTS内ECALL符号表

Switch模式进入Enclave执行ECMD_INIT_ENCLAVE任务【CEnclave::ecall】

先取一个【CTrustThread】用于ECALL Switch【CTrustThreadPool::acquire_thread】

如果不支持EDMM,就另外拿取一个TCS【CTrustThreadPool::_acquire_thread】

回到【CTrustThreadPool::acquire_thread】

回到【CEnclave::ecall】

提取【tcs_t】结构体,进一步执行ECALL【do_ecall】

进一步执行ECALL,切换上下文【enter_enclave(uRTS)/__morestack】

第一次进入Enclave(EENTER硬件指令),【ECMD_INIT_ENCLAVE】任务

当前已经在tRTS了,进一步去完成【ECMD_INIT_ENCLAVE】任务【enter_enclave(tRTS)】

对于用户编写的的ECALL函数,ECALL Switch过程是什么样的呢?

初始化栈保护机制(tRTS)

处理线程数据(、tRTS pthread),然后进一步ECALL【do_ecall(tRTS)】

查ECALL表,找到ECALL索引值对应的虚拟地址,然后执行之【trts_ecall】

ECALL Switch的过程到此就结束了


SGX初始化中,我们就碰到过切换上下文进入Enclave的场景

在SGX初始化过程中,我们其实就碰到了需要切换上下文进入Enclave完成【ECMD_INIT_ENCLAVE】任务,这个任务主要是为了在tRTS内完成一些必要的SGX初始化工作。在《再回顾SGX初始化(三)》中我们提到过。

又比如在支持EDMM时,我们可能需要动态生成TCS,那么也需要切换上下文进入Enclave完成【ECMD_MKTCS】任务,用于动态生成TCS。在《再回顾SGX初始化(四)》、《构建动态TCS页》中我们提到过。

以【ECMD_INIT_ENCLAVE】为例,先大概描述一下切换上下文进入Enclave的具体过程

流程:【CEnclave::ecall(uRTS)】->【do_ecall(uRTS)】->【enter_enclave/__morestack(uRTS, AS)】->【enclave_entry(tRTS, AS)】->【enter_enclave(tRTS)】->【do_init_enclave(tRTS)】

【ECMD_INIT_ENCLAVE】任务是SGX初始化中重要的一步。不过,在tRTS里如何具体处理【ECMD_INIT_ENCLAVE】任务还请看《再回顾SGX初始化(三)》,这里主要是为了讲述ECALL Switch或者说如果切换上下文进入Enclave。

我们使用【CEnclave::ecall】作为一个常用的接口来切换上下文进入Enclave,虽然【CEnclave::ecall】只是一个封装。

int status = enclave->ecall(ECMD_INIT_ENCLAVE, NULL, reinterpret_cast<void *>(&info));

普及:ECALL索引值和tRTS内ECALL符号表

【CEnclave::ecall】的proc参数可选项如下,负数代表了进入Enclave的特殊目的是什么。

补充:【sgx_ecall(uRTS)】最终也是调用的【CEnclave::ecall】,增加的动作包括在【CEnclave::ecall】之前对Enclave的引用计数加一,在【CEnclave::ecall】之后对Enclave的引用计数减一。

而自然数(≥0的整数,这里的ECMD_ECALL只是一个示意,比如某个ECALL的Index值可能是7)则代表每一个用户编写的ECALL的Index索引值,这个Index索引值可以在tRTS中存储的ECALL符号表【g_ecall_table】中找到对应ECALL函数的虚拟地址,在tRTS中通过调用这个ECALL的虚拟地址完成ECALL的执行,并且在uRTS中直接使用ELRANGE中的虚拟地址会由PMH硬件和、EPCM数据结构判断这个访问控制是非法的,也就是SGX的中止页面语义。

/* ECALL command */
#define ECMD_ECALL           0
#define ECMD_INIT_ENCLAVE   -1
#define ECMD_ORET           -2
#define ECMD_EXCEPT         -3
#define ECMD_MKTCS          -4
#define ECMD_UNINIT_ENCLAVE -5
#define ECMD_ECALL_PTHREAD  (-6) //linux-sgx v2.8所做的修改,Commit ID:9ddec08

这里举例说明0以上每一个整数都对应了一个ECALL函数,也就是说这个Index整数本质上就是一个索引值,用来在【g_ecall_table】索引具体的ecall地址。

【g_ecall_table】如下所示:

//位于SampleCode/SampleEnclave/Enclave/Enclave_t.c
SGX_EXTERNC const struct {
	size_t nr_ecall;
	struct {void* ecall_addr; uint8_t is_priv; uint8_t is_switchless;} ecall_table[32];
} g_ecall_table = {
	32,
	{
		{(void*)(uintptr_t)sgx_ecall_type_char, 0, 0},
		{(void*)(uintptr_t)sgx_ecall_type_int, 0, 0},
		{(void*)(uintptr_t)sgx_ecall_type_float, 0, 0},
		{(void*)(uintptr_t)sgx_ecall_type_double, 0, 0},
		{(void*)(uintptr_t)sgx_ecall_type_size_t, 0, 0},
		...
	}
};

比如用户编写的【ecall_type_char】对应的Index就是【proc==0】。我们在uRTS中使用0索引值,切换上下文进入到Enclave后,在tRTS的【g_ecall_table】中查到【sgx_ecall_type_char】的虚拟地址,额外提醒一下【sgx_ecall_type_char】是Enclave内部的(也是我们用户编写的)【ecall_type_char】函数的壳。

//位于SampleCode/SampleEnclave/App/Enclave_u.c
sgx_status_t ecall_type_char(sgx_enclave_id_t eid, char val)
{
	sgx_status_t status;
	ms_ecall_type_char_t ms;
	ms.ms_val = val;
	status = sgx_ecall(eid, 0, &ocall_table_Enclave, &ms);
	return status;
}
//位于SampleCode/SampleEnclave/Enclave/Enclave_t.c
static sgx_status_t SGX_CDECL sgx_ecall_type_char(void* pms)
{
	CHECK_REF_POINTER(pms, sizeof(ms_ecall_type_char_t));
	//
	// fence after pointer checks
	//
	sgx_lfence();
	ms_ecall_type_char_t* ms = SGX_CAST(ms_ecall_type_char_t*, pms);
	sgx_status_t status = SGX_SUCCESS;

	ecall_type_char(ms->ms_val);

	return status;
}

再比如(用户编写的)【ecall_type_int】对应的Index就是【proc==1】。我们在uRTS中使用1索引值,切换上下文进入到Enclave后,在tRTS的g_ecall_table中查到【sgx_ecall_type_int】的虚拟地址,【sgx_ecall_type_int】是Enclave内部的【ecall_type_int】函数的壳。

//位于SampleCode/SampleEnclave/Enclave/Enclave_u.c
sgx_status_t ecall_type_int(sgx_enclave_id_t eid, int val)
{
	sgx_status_t status;
	ms_ecall_type_int_t ms;
	ms.ms_val = val;
	status = sgx_ecall(eid, 1, &ocall_table_Enclave, &ms);
	return status;
}
//位于SampleCode/SampleEnclave/Enclave/Enclave_t.c
static sgx_status_t SGX_CDECL sgx_ecall_type_int(void* pms)
{
	CHECK_REF_POINTER(pms, sizeof(ms_ecall_type_int_t));
	//
	// fence after pointer checks
	//
	sgx_lfence();
	ms_ecall_type_int_t* ms = SGX_CAST(ms_ecall_type_int_t*, pms);
	sgx_status_t status = SGX_SUCCESS;

	ecall_type_int(ms->ms_val);

	return status;
}

Switch模式进入Enclave执行ECMD_INIT_ENCLAVE任务【CEnclave::ecall】

【sgx_ecall(uRTS)】最终也是调用的【CEnclave::ecall】,增加的动作包括在【CEnclave::ecall】之前对Enclave的引用计数加一,在【CEnclave::ecall】之后对Enclave的引用计数减一。

sgx_status_t CEnclave::ecall(const int proc, const void *ocall_table, void *ms, const bool is_switchless)

【CEnclave::ecall】中首先需要上一个读写锁,这是因为可能同时有多个ECALL发生,这旨在保护CEnclave的成员变量(后面很多情况其实都需要开始考虑并发问题了)。当执行【ECMD_INIT_ENCLAVE】任务时,我们还没有初始化过Swtichless模式。

先取一个【CTrustThread】用于ECALL Switch【CTrustThreadPool::acquire_thread】

我们先取得一个【CTrustThread】(对应了一个TCS,前面提到过)。做法是从【CEnclave::m_thread_pool】中取得一个【CTrustThread】对象(实际上一个【CTrustThread】对象对应一个TCS,后面直接用【TCS_CTT】,【CTrustThread】首字母缩写,来指代【CTrustThread】)。

我们当前的ECALL是一个特殊的ECALL,是为了完成【ECMD_INIT_ENCLAVE】任务。

平台情况所选择用来完成ECMD_INIT_ENCLAVE任务的线程
SGX支持EDMM等特性,那么就支持通用线程【CTrustThreadPool::m_utility_thread】这个特殊的【TCS_CTT]

我们就用通用线程【m_utility_thread】来完成【ECMD_INIT_ENCLAVE】任务。

如果不支持通用线程【CTrustThreadPool::m_utility_thread】调用【CTrustThreadPool::_acquire_thread】获得一个【TCS_CTT】来完成【ECMD_INIT_ENCLAVE】任务。

如果不支持EDMM,就另外拿取一个TCS【CTrustThreadPool::_acquire_thread】

具体做法如下:

先后顺序操作
A. 从TCS_CTT缓存【m_thread_list】寻找可用【TCS_CTT】

首先试图从一个“【TCS_CTT】缓存”(【CTrustThreadPool::m_thread_list】,可以类比内核对堆管理时候的那个堆块的缓存,这里的缓存并不是指CPU内部的Cache)获取一个【TCS_CTT】,这样省去了获取【TCS_CTT】的很多繁琐的操作。这个缓存是线程ID到【TCS_CTT】的映射关系。

因此先获取一个线程ID,这个线程ID是和一个全局Key【g_tid_key】绑定的,当【g_tid_key】未绑定任何线程ID时,就用当前线程与【g_tid_key】绑定。然后到TCS_CTT缓存处【CTrustThreadPool::m_thread_list】去找指定线程ID对应的【TCS_CTT】,并且这个【TCS_CTT】不能是【CTrustThreadPool::m_utility_thread】(不过当前我们碰不到这个情况)。

B. 从【TCS_CTT】空闲集【m_free_thread_vector】寻找可用【TCS_CTT】如果【m_thread_list】里面没有可用的对象缓存,那么就要去【m_free_thread_vector】(前面有提到过,代表空闲的【TCS_CTT】集)里面取一个出来,同时如果是从空闲【TCS_CTT】集里面取出来的对象,那么将这个【TCS_CTT】和前面获取的线程ID进行绑定,放到【TCS_CTT】缓存【CTrustThreadPool::m_thread_list】中,方便后续使用。
C. 回收【TCS_CTT】缓存中空闲项,用作【TCS_CTT】

如果连【m_free_thread_vector】中也没有可用的【TCS_CTT】,那么就进一步对【m_thread_list这个缓存中引用数【CTrustThread::m_reference】为0的【TCS_CTT】放回到【m_free_thread_vector】中(调用【CThreadPoolUnBindMode::garbage_collect】,因为我们使用Switchless扩展特性,因此采用的非Bind模式的TCS池)。然后再把空闲的【TCS_CTT】给用起来去完成【ECMD_INIT_ENCLAVE】任务。

这里的和A的区别在于,A是对已经绑定线程ID的引用数不为0的【TCS_CTT】行使用,而这里是是对引用数为0的【TCS_CTT】进行使用。

D. 没有任何可用【TCS_CTT】如果没有【TCS_CTT】缓存空闲项可回收,那么返回NULL。

回到【CTrustThreadPool::acquire_thread】

我们对取得的【TCS_CTT】的引用数加1。

回到【CEnclave::ecall】

此时我们已经取得了【TCS_CTT】。之后对【CEnclave::m_ocall_table】更新为传参【ocall_table】(此时【ocall_table】为NULL,因为我们仅仅是为了【ECMD_INIT_ENCLAVE】任务)。紧接着调用【do_ecall】。

提取【tcs_t】结构体,进一步执行ECALL【do_ecall】

ret = do_ecall(proc, m_ocall_table, ms, trust_thread);
//位于psw/urts/linux/sig_handler.cpp
int do_ecall(const int fn, const void *ocall_table, const void *ms, CTrustThread *trust_thread)

从【TCS_CTT】里面提取出【tcs_t】结构体后,调用【enter_enclave】这个汇编函数。

进一步执行ECALL,切换上下文【enter_enclave(uRTS)/__morestack】

status = enter_enclave(tcs, fn, ocall_table, ms, trust_thread);
//位于psw/urts/linux/sig_handler.cpp
//trust_thread is saved at stack for ocall.
#define enter_enclave __morestack

extern "C" int enter_enclave(const tcs_t *tcs, const long fn, const void *ocall_table, const void *ms, CTrustThread *trust_thread);

如果不了解汇编可以查看《Red Hat Enterprise Linux 3》《x86 and amd64 instruction reference

//位于psw/urts/linux/enter_enclave.S
DECLARE_GLOBAL_FUNC __morestack


//__morestack:
EENTER_PROLOG
    movl    frame_arg1, %edi                    /* fn */
#if defined(__x86_64__)
    /* we defined fn as int, so we do sign extend.*/
    movslq  %edi,   %rdi
#endif
    mov frame_arg3, %xsi                        /* ms */

.Ldo_eenter:
    # clean the upper bits of YMM registers
    lea_symbol  g_clean_ymm, %xbx
    movl (%xbx), %ecx
    cmpl $0, %ecx
    je   1f
    vzeroupper
1:
    mov frame_arg0, %xbx                        /* tcs addr */
    lea_pic .Lasync_exit_pointer, %xcx          /* aep addr */
    mov $SE_EENTER, %xax                        /* EENTER leaf */

.Leenter_inst:
    ENCLU

...;some code

.size __morestack, .-__morestack

【DECLARE_GLOBAL_FUNC】是他们写的一个宏,目的是为了将这个汇编代码段标记为一个“全局函数”。其中【_CET_ENDBR】是根据环境选择endbr64或endbr32(Terminate an Indirect Branch in 64/32-bit Mode),详细信息可以在《Control-flow Enforcement Technology Specification》中搜索“endbr”。

【EENTER_PROLOG】也是一个宏,包括了CFI的相关选项的配置,通用目的寄存器和传参的保存,并预留一个栈槽用于保存一个指向xsave数据的栈空间,大小是【g_xsave_size】值(esp需要64字节对齐),留出一个影子栈空间给参数用,ES段中保存扩展X特性寄存器。将xsave数据通过XSAVEC指令(【g_xsave_enabled==1】,代表支持X特性)或FXSAVE(【g_xsave_enabled==0】)进行保存(调用【save_xregs】,传参是之前预留的xsave数据的栈空间)。总的来说这个宏的目的就是为了保存寄存器状态、X特性状态等。

接着回来讲【__morestack】做了什么。

【EENTER_PROLOG】之后,会开始设置XDI、XSI、YMM、XAX、XBX、XCX(如下表),然后调用ENCLU硬件指令。如果不了解ENCLU,可以参考《SGX软件栈(二)——硬件指令

调用ENCLU硬件指令时  ,寄存器的值
XAX2,代表EENTER功能叶。
XBX

frame_arg0,代表tcs_t对象的地址。

XCX.Lasync_exit_pointer(AEP)的地址。代表异步退出以后,处理完异常后,重新试图进入Enclave的跳板。类似于我们调用函数返回后的CALLER中的下一条指令地址。
XDIframe_arg1,对应参数fn(我们这里是ECMD_INIT_ENCLAVE)
XSIframe_arg3,对应ms(marshalling structure,编排好的结构体)
YMM根据XFRM_YMM_BITMASK来确定,是不是需要调用vzeroupper硬件指令清零YMM寄存器高位

第一次进入Enclave(EENTER硬件指令),【ECMD_INIT_ENCLAVE】任务

此时我们就进入Enclave环境了,并且此时是我们第一次进入Enclave。同时EENTER的进入点是【enclave_entry】(也就是【EnclaveBase+TCS.OENTRY】,Enclave文件的元数据中的TCS布局都已经把这些都安排好了。在形成Enclave文件时,由SignTool来完成),这也是我们在lds文件中标记的全局符号。

//位于sdk/trts/linux/trts_pic.S
/* 
 * ---------------------------------------------------------------------
 * Function: enclave_entry
 *      The entry point of the enclave.
 *
 * Registers:
 *      XAX - TCS.CSSA
 *      XBX - the address of a TCS
 *      XCX - the address of the instruction following the EENTER
 *      XDI - the reason of entering the enclave
 *      XSI - the pointer to the marshalling structure
 */
DECLARE_GLOBAL_FUNC enclave_entry

可以看到除了XAX,寄存器的值代表的内容都是一致的。

当进入Enclave是为了处理异常时,XAX从ENCLU叶号替换成了【TCS.CSSA】(Current Slot Index of an SSA frame)的用途。我们这里并不是处理异常的情况,所以值为0,也可以说是因为我们刚进入Enclave,并没有之前因为AEX退出Enclave而使用SSA对Enclave内部寄存器进行保存。

如果进入Enclave是为了处理异常,比如说发生AEX,然后进入uRTS,OS完成初步异常处理,有些异常可能需要Enclave内部才能处理,那么就需要进入Enclave专门处理这个异常。

CoSMIX: a compiler-based system for secure memory instrumentation and execution in enclaves》里面介绍的还不错。

进入Enclave的目的可以参考《进入Enclave的目的归类》。

首先对Flag寄存器标志位进行清除,使得初始化为如下。Flag可以参考《FLAGS register

Flag
OF0
SF0
AF0
CF0
ZF1
PF1
DF0

根据进入Enclave目的的不同,我们还需要分别对栈空间地址进行选择,(进入Enclave处理异常情况,还需要额外对CSSA进行保存)

进入Enclave目的操作
常规(刚进入Enclave,包括【ECMD_INIT_ENCLAVE】任务)XSP、XBP的值就是【XBX(tcs_t对象地址)- 1<<16 - STATIC_STACK_SIZE】,也就是说我们给刚进入Enclave的线程定一个栈空间
进入Enclave处理异常

需要跳转到【.Ldo_handler】将CSSA存到XDX寄存器上。同时栈空间的XSP、XBP寄存器也是设置为【XBX(tcs_t对象地址)- 1<<16 - STATIC_STACK_SIZE】

之前退出过并重进入Enclave使用之前的栈空间,将XSP、XBP设置为之前的栈空间

清除EFLAGS中的AC位(调用CLEAN_XFLAGS)。

将不可信世界的XSP压栈,将CSSA、TCS、XSI、XDI压栈。使用预制的SYNTHETIC_STATE(编译时指明放在.niprod Section)来重置X特性寄存器调用XRSTOR【g_xsave_enabled==1,代表支持X特性】、FXRSTOR硬件指令【g_xsave_enabled==0,代表不支持X特性】,目的是为了清理X特性寄存器。

调用tRTS内的【enter_enclave】这个C语言函数(前面用汇编主要是为了对上下文环境的切换),传参情况如下

传参传参所处位置
Index(fn、proc)64位放到XDI;32位处于栈中
ms64位放到XSI;32位处于栈中
TCS64位放到XDX;32位处于栈中
CSSA64位放到XCI;32位处于栈中

当前已经在tRTS了,进一步去完成【ECMD_INIT_ENCLAVE】任务【enter_enclave(tRTS)】

extern "C" int enter_enclave(int index, void *ms, void *tcs, int cssa) __attribute__((section(".nipx")));

查询【g_enclave_state】状态(调用【sgx_is_enclave_crashed】,该函数被编译到.nipx节)判断Enclave是否崩溃状态,这个值初始为【ENCLAVE_INIT_NOT_STARTED】,因此目前不是【CRASH】状态。

else if(index == ECMD_INIT_ENCLAVE) { error = do_init_enclave(ms, tcs); }

然后调用【do_init_enclave】,去真正的执行【ECMD_INIT_ENCLAVE】任务。

在tRTS里如果处理【ECMD_INIT_ENCLAVE】任务还请看《再回顾SGX初始化(三)》,这里主要是为了讲述ECALL Switch或者说如果切换上下文进入Enclave。

对于用户编写的的ECALL函数,ECALL Switch过程是什么样的呢?

一开始的流程依然是【sgx_ecall(uRTS)】->【sgx_ecall(uRTS)】->【CEnclave::ecall(uRTS)】->【do_ecall(uRTS)】->【enter_enclave/__morestack(uRTS, AS)】->【enclave_entry(tRTS, AS)】->【enter_enclave(tRTS)】。

在【enter_enclave(tRTS)】中,由于我们目标是执行一个用户编写的ECALL,因此我们的Index是≥0的。稍微提一下,前面说到的ECMD_INIT_ENCLAVE、ECMD_ORET、ECMD_MKTCS、ECMD_UNINIT_ENCLAVE、ECMD_EXCEPT都有专门的处理函数。

对于试图执行用户编写的ECALL。我们首先初始化栈保护机制,然后调用【do_ecall】来在tRTS内执行ECALL。

extern "C" int enter_enclave(int index, void *ms, void *tcs, int cssa)
{
    ...
    // Initialize stack guard if necessary
    init_stack_guard(tcs);
    error = do_ecall(index, ms, tcs);
    ...
}

初始化栈保护机制(tRTS)

static void __attribute__((section(".nipx"))) init_stack_guard(void *tcs)

通过线程上下文获取当前的线程数据(记录了线程栈信息、线程局部存储信息等)。如果没有对当前TCS的线程数据中的栈保护页初始化过,那么tRTS内部读取一个随机数来初始化栈保护页。我们前面提到过【ECMD_INIT_ENCLAVE】任务时,通用线程的线程数据被初始化过,但我们此时很可能用的是一个线程数据没有被初始化过的TCS。

处理线程数据(、tRTS pthread),然后进一步ECALL【do_ecall(tRTS)】

sgx_status_t do_ecall(int index, void *ms, void *tcs)

检查Enclave状态。

检查线程数据是否被初始化过。检查是否是UnBind TCS策略。检查这个TCS之前是不是给tRTS pthread线程用过,并且这个tRTS pthread线程现在已经退出了【SGX_PTHREAD_EXIT】。检查这个TCS是不是给tRTS pthread用的。按需初始化一下线程数据【do_init_thread】。

SGXv2.8起Enclave内新增pthread库》从linux-sgx v2.8开始,支持在tRTS创建pthread线程,这个会涉及SGX内部开辟空间和分配TCS给这个pthread线程,同时SGX内部创建pthread线程也需要OCALL到uRTS,来创建好pthread线程并重新进入到tRTS中。

判断当前是不是Root ECALL。通过当前线程栈是否从栈基址开始增长来判断。像ECALL->OCALL->ECALL这种嵌套情况下,后面的ECALL就不是Root ECALL了,如果不是Root ECALL,那么TCS对应的线程栈上就有多个栈空间存在。如果不是Root ECALL,直接【trts_ecall】,只有Root ECALL需要开启tRTS pthread支持,因为非Root ECALL之前在Root ECALL阶段已经做过一次了。

由于从SGX v2.8开始支持tRTS pthread,因此这里默认试图开启tRTS pthread【调用_pthread_enabled】,构建一个空的TLS信息结构体【pthread_info_tls】(【pthread_info】类型)。(如果【_pthread_enabled】开启失败,直接【trts_ecall】)

pthread_info结构体成员变量

赋值说明

m_local_storage

NULL 

m_pthread

NULL 

m_state

SGX_SUCCESS

TCS的TLS状态

m_mark

初始为全零。紧接着存储【setjmp】获取的当前的上下文,作为一个上下文保存点。

未来【longjmp】函数会跳转到这里,此时伪装成【setjmp】返回,但是返回值非零。返回值非零,意味着ECALL内部调用了【pthread_exit】让该线程终止,因此需要清理线程栈,并把线程TCS的TLS状态置为【SGX_PTHREAD_EXIT】

TCS的TLS上下文,【jmp_buf】类型

然后就调用【trts_ecall】进一步执行ECALL。这里有个小细节就是,用了【random_stack_advance】函数在栈空间中塞了一段无意义的随机大小的缓冲区,使得【trts_ecall】用到的EBP变得随机。

ECALL执行完成返回后,或者是【trts_ecall】执行完,也或者tRTS pthread调用【pthread_exit】然后跳转到【setjmp】“Fake”返回,总归是返回了。对于【pthread_exit】返回,将线程TCS的TLS状态置为【SGX_PTHREAD_EXIT】,标记下一次Root ECALL需要重置TCS。

/* 
* Set the TCS's tls state variable to "SGX_PTHREAD_EXIT":
*  1. Pthread() create thread exits normally.
*  2. ECALL() is exited by calling pthread_exit().
*
* In future, the TCS will always be initialized no matter it's used by a new normal root ECALL() or it's used by a new pthread() create thread.
*
* As example: (In bind mode)
* 1. This TCS is used by pthread created thread. So the TCS's state will be set as "SGX_PTHREAD_EXIT" after the thread exits.
* 2. Then the same TCS is used by a normal root ECALL, the TCS will still be initialized because it's state was set as "SGX_PTHREAD_EXIT".
*
*/
_pthread_tls_store_state(SGX_PTHREAD_EXIT);

然后销毁TLS资源,调用【_pthread_tls_destructors】。

唤醒处于【pthread_join】的那个线程,调用【_pthread_wakeup_join】。

查ECALL表,找到ECALL索引值对应的虚拟地址,然后执行之【trts_ecall】

static sgx_status_t trts_ecall(uint32_t ordinal, void *ms)

如果是这个Enclave全局的第一次ECALL。先确保这个ECALL必须是Root ECALL。将所有静态TCS,链接到【g_tcs_node】链表(静态TCS地址用【g_tcs_cookie】异或加密)。然后在tRTS里面将【PT_LOAD】、【PT_GNU_RELRO】段和【ReservedMemMinSize】的虚拟地址访问控制权限用【trts_mprotect】设置好。全局对象的初始化,从动态段找到初始化函数数组,并逐一进行初始化操作。这些动作只需要执行一次,只在第一次ECALL才执行。

然后调用【get_func_addr】。对于常规ECALL,检查ECALL是否被允许,然后查ECALL表【g_ecall_table】,找到ECALL索引值对应的虚拟地址。对于tRTS pthread,返回【_pthread_thread_run】地址,这个函数最终会执行tRTS中【pthread_create】指定的入口函数。

用一下【sgx_lfence】,然后执行得到的虚拟地址,也就是现在才开始执行ECALL真正的内容。

ECALL Switch的过程到此就结束了

Contents Contents .............................................................................................................................. 3 1 Introduction .................................................................................................................. 6 1.1 About eCall / ERA GLONASS ................................................................................................................. 7 1.2 eCall definitions .................................................................................................................................... 7 2 IVS system and eCall conformity ................................................................................. 8 2.1 eCall AT interface summary .................................................................................................................. 9 2.2 Table of timings (eCall Release 2 and 3) .............................................................................................. 10 3 eCall control through AT interface ............................................................................ 11 3.1 AT+UECALLSTAT ................................................................................................................................ 12 3.1.1 Read configuration: AT+UECALLSTAT? ....................................................................................... 12 3.1.2 Force the configuration in cache: AT+UECALLSTAT=0/1/2 ........................................................... 13 3.1.3 Restore configuration in cache: AT+UECALLSTAT=3 .................................................................... 13 3.2 AT+UECALLTYPE ................................................................................................................................ 14 3.3 AT+CECALL ........................................................................................................................................ 16 3.4 AT+UDCONF=90 ................................................................................................................................ 17 3.4.1 eCall test number: AT+UDCONF=90,1[,<ToN>,<number>] ......................................................... 17 3.4.2 eCall reconfiguration number: AT+UDCONF=90,2[,<ToN>,<number>] ....................................... 17 3.4.3 eCall T3242 duration: AT+UDCONF=90,11,<timer_duration> ..................................................... 17 3.4.4 eCall T3243 duration: AT+UDCONF=90,12,<timer_duration> ..................................................... 17 3.5 AT+UECALLDATA ............................................................................................................................... 18 3.5.1 Activation: AT+UECALLDATA=1,<push/pull mode>,<MSD data> ................................................ 18 3.5.2 In-band Modem status events: +UUECALLDATA: <urc_id> .......................................................... 18 3.5.3 MSD update: AT+UECALLDATA=2,<update mode>,<MSD data> ............................................... 19 3.5.4 Examples ..................................................................................................................................... 19 3.6 AT+UECALLVOICE .............................................................................................................................. 20 3.6.1 Internal voice control ................................................................................................................... 21 3.6.2 Configurable internal HLAP timers (eCall Release 4) ..................................................................... 23 4 eCall examples ............................................................................................................ 25 4.1 eCall session dynamic view: end-to-end In-band signaling .................................................................. 25 4.1.1 MSD transfer in push mode ......................................................................................................... 25 4.1.2 MSD update in TX idling mode .................................................................................................... 26 4.2 eCall control examples ........................................................................................................................ 27 4.2.1 Simple MSD transfer in push mode ............................................................................................. 27 4.2.2 MSD update on PULL request, with transmitter reset and microphone control ............................ 28 4.2.3 Answer to PSAP callback ............................................................................................................. 29 4.3 eCall configuration examples .............................................................................................................. 30 4.3.1 eCall initiation (eCall Release 2 vs 3) ............................................................................................ 30 4.3.2 eCall-only mode with an eCall-enabled USIM .............................................................................. 31 eCall / ERA GLONASS - Application Note UBX-13001924 - R09 Contents Page 4 of 62 4.3.3 Force the eCall-only mode with a not eCall-enabled USIM .......................................................... 32 4.3.4 Force the eCall without registration restrictions with a not eCall-enabled USIM ........................... 32 5 ERA-GLONASS additional features and use cases .................................................... 33 5.1 MSD transfer by SMS .......................................................................................................................... 33 5.1.1 MSD SMS transmission in PDU mode .......................................................................................... 33 5.2 SIM/eUICC profile switch .................................................................................................................... 35 5.2.1 Example of management of eCall transaction with temporary eUICC swap to emergency profile 35 6 eCall / ERA GLONASS In-band Modem simulation system ...................................... 37 6.1 PSAP simulator ................................................................................................................................... 37 6.1.1 Software & hardware requirements ............................................................................................. 37 6.2 IVS system .......................................................................................................................................... 38 6.2.1 Software & hardware requirements ............................................................................................. 38 6.3 m-center software .............................................................................................................................. 38 6.3.1 IVS simulator ............................................................................................................................... 39 6.3.2 PSAP simulator ............................................................................................................................ 43 6.4 eCall / ERA GLONASS system setup .................................................................................................... 45 6.4.1 PSAP simulator connecting with the PSAP GSM modem .............................................................. 45 6.4.2 Starting the PSAP simulator ......................................................................................................... 45 6.4.3 IVS simulator connecting with the IVS GSM modem .................................................................... 45 6.4.4 Starting the IVS simulator ............................................................................................................ 45 6.4.5 IVS In-band Modem setup without IVS simulator ......................................................................... 47 6.5 Running the eCall simulation .............................................................................................................. 47 6.5.1 eCall simulation example (without IVS simulator) ......................................................................... 47 6.5.2 Callback example ........................................................................................................................ 49 Appendix .......................................................................................................................... 50 A List of Acronyms ......................................................................................................... 50 B PAN European eCall IVS test list ................................................................................ 51 B.1 NAD Protocol ...................................................................................................................................... 51 B.2 In-band modem conformance ............................................................................................................ 51 B.3 High-level application protocol ........................................................................................................... 52 C ERA-GLONASS IVS test list ......................................................................................... 54 C.1 IVS functional and data transfer protocols test methods ..................................................................... 54 C.1.1 IVS tests in regard to functional requirements ............................................................................. 54 C.1.2 IVS tests in regard to requirements of data exchange protocols ................................................... 54 C.2 IVS tests for compliance with the established requirements for electromagnetic compatibility and resistance to climatic and mechanical loads ................................................................................................... 55 C.2.1 IVS tests for compliance with the established requirements for electromagnetic compatibility ..... 55 C.2.2 IVS tests for compliance with the established requirements for resistance to climatic loads .......... 55 C.2.3 IVS tests for compliance with the established requirements for resistance to mechanical loads .... 56 C.3 IVS tests for conformity to quality requirements for loudspeaker communication in vehicle cabin ....... 56 eCall / ERA GLONASS - Application Note UBX-13001924 - R09 Contents Page 5 of 62 C.4 IVS tests for conformity to accident detection requirements .............................................................. 56 C.5 IVS tests for wireless communication modules .................................................................................... 57 C.5.1 IVS tests in regard to implementation of GSM modem functions ................................................. 57 C.5.2 IVS tests in regard to implementation of UMTS modem functions ............................................... 57 C.5.3 IVS tests in regard to implementation of in-band modem functions ............................................. 58 C.6 IVS tests for navigation modules ......................................................................................................... 58 D eCall flag ..................................................................................................................... 59 Related documents .......................................................................................................... 60 Revision history ................................................................................................................ 61 Contact .............................................................................................................................. 62
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值