再回顾SGX初始化(四)——收尾及Switchless初始化

编程入门 行业动态 更新时间:2024-10-28 09:27:23

再回顾SGX<a href=https://www.elefans.com/category/jswz/34/1770206.html style=初始化(四)——收尾及Switchless初始化"/>

再回顾SGX初始化(四)——收尾及Switchless初始化

目录

裁剪页放到Trimmed列表(需要支持EDMM)

设置内存访问控制属性

填充TCS最小池

Switchless初始化

到此,SGX初始化就全部结束了


继《再回顾SGX初始化(三)——uRTS维护Enclave、tRTS完成Enclave构建收尾确认工作》之后,我们又回到了uRTS的__create_enclave函数。此时uRTS、tRTS两边都已经完成了Enclave初始化工作,也就是说Enclave内外两边都已经搞定了Enclave初始化所需要的工作。

那么就继续__create_enclave函数的漫漫长征路。

裁剪页放到Trimmed列表(需要支持EDMM)

if (SGX_SUCCESS != (ret = loader.post_init_action_commit(layout_start, layout_end, 0)))

由于前面uRTS已经发出裁剪请求,并且Enclave已经EACCEPT了。

那么就发SGX_IOC_ENCLAVE_NOTIFY_ACCEPT信号给SGX驱动,让SGX驱动将裁剪页放到Trimmed列表(意味着裁剪页现在开始可以被自由移除),并且这些裁剪页也会从用于管理已分配Enclave虚拟页的基数树上删除掉。

/*** sgx_ioc_page_notify_accept() - Pages defined in range will be moved to* the trimmed list, i.e. they can be freely removed from now. These pages* should have PT_TRIM page type and should have been eaccepted priorly* @arg range address of pages*/
long sgx_ioc_page_notify_accept(struct file *filep, unsigned int cmd, unsigned long arg)

设置内存访问控制属性

if(SGX_SUCCESS != (ret = loader.set_memory_protection()))

使用ELF解析器(使用mprotect)设置ELRANGE中各个Section的访问属性以及各个Segment对应的访问属性【ElfParser::set_memory_protection,先对每个Section按照最开始记录的Section对象中声明的虚拟地址空间访问属性进行mprotect设置,再对每个Segment按照ElfW(Phdr).p_flags记录的那样进行虚拟地址空间访问属性设置】。

如果元数据版本较新,并且当前环境支持EDMM,那么将PT_GNU_RELRO、PT_LOAD(不可写的并且可能会有重定位过程的)段交由SGX驱动(SGX_IOC_ENCLAVE_EMODPR,SGX会调用EMODPR)将Enclave Page设置为读执行(RX)权限,相比于mprotect是对页表机制里面的访问属性进行设置,Ring0权限的EMODPR硬件指令会对管理EPC属性的EPCM进行设置。rsrv内存用EMODPR改为RW。不支持EDMM等情况,就不进行改动。

对上下文相关的内存,用mprotect将内存访问控制属性设置为RW。其中rsrv内存在不支持EDMM情况下,不要用mprotect改变它的属性。

针对EREMOVE掉的页,需要用mprotect设置为PROT_NONE,不然这个页一旦被访问,会发生总线异常(sigbus exception),因为这个EPC页已经被EREMOVE硬件指令给从当前Enclave中去除,EPCM也没有再维护EREMOVE掉的页的信息。

上面所涉及到的ELRANGE的页本身在ECREATE、EADD、EREMOVE时就设置或更改了基本的EPCM项,这里主要是进行调整,以及在进程虚拟地址空间用mprotect进行访问控制设置。

if(!get_enclave_creator()->is_EDMM_supported(get_enclave_id()) && (layout->entry.id == LAYOUT_ID_RSRV_MIN ||layout->entry.id ==  LAYOUT_ID_RSRV_INIT))//Don't change the rsrv memory's attributes if platform isn't support EDMMcontinue;//Here: URTS will change rsrv memory's attributes to RW forcely although it's signed by sign_tool as RWX (<ReservedMemExecutable>1</ReservedMemExecutable>).

填充TCS最小池

ret = enclave->fill_tcs_mini_pool_fn();

如果支持EDMM,就填充一下TCS最小池(就是说我们最小要填充指定数量【CTrustThreadPool.m_tcs_min_pool,源自config.xml文件里的说明】的TCS池项,这些数量是必须的,而额外的动态TCS这里不做填充)。这个函数的做法挺有趣,在第一次调用该函数的时候,起一个pthread线程,完成TCS最小池的填充,之后这个线程会休眠,当下次调用该函数时,唤醒这个线程去填充TCS最小池,这里是一个循环,每唤醒一次就循环一轮。这种做法的其中一个原因也是因为后续有时也会进行填充TCS最小池。

最终填充TCS最小池的操作是由如下函数完成

sgx_status_t CTrustThreadPool::fill_tcs_mini_pool()

如果有动态当前未分配具体空间的TCS,并且已有的空闲TCS,还不足最小数量的要求,那么就需要构建动态TCS【之前是个未分配空间的TCS】填充到TCS最小池。《构建动态TCS页》讲述了动态TCS构建过程。

然后唤醒一下其他线程,其他线程(比如主线程)可能一直等待新的空闲的TCS。并且有时空闲TCS数量不足最小池的大小,使得我们需要再填充TCS最小池。不过我们这里是第一次填充TCS最小池,为的就是让TCS最小池至少先足数。

Switchless初始化

见《Switchless模式的初始化》

到此,SGX初始化就全部结束了

最后将【CLoader::m_enclave_id】,赋值给创建SGX的API中的参数【global_eid】,让编程人员后续可以使用这个【global_eid】调用ECALL函数,主要原因也是因为一个进程可以创建多个Enclave,这个ID是为了区分一个进程内的多个Enclave。

ret = sgx_create_enclave_ex(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL, SGX_CREATE_ENCLAVE_EX_SWITCHLESS, enclave_ex_p);

有空我调整一下章节的编排

更多推荐

再回顾SGX初始化(四)——收尾及Switchless初始化

本文发布于:2024-03-23 20:54:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1742719.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:初始化   收尾   再回   Switchless   SGX

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!