[翻译]Intel软件开发指南翻译卷3第4部分 第40章
第40章 飞地退出事件
一些事件,例如异常和中断的发生(但与该事件异步)可能导致控制在飞地模式之外转换。(其中大部分还会导致特权级别的改变)为了保护飞地的完整性和安全性,处理器将在处理程序调用此类事件之前退出飞地(和飞地模式)。出于这个原因,这种事件被称为飞地退出事件(EEE); EEE包括外部中断,不可屏蔽的中断,系统管理中断,异常和VM出口。
响应EEE而离开飞地的过程称为异步飞地退出(AEX)。 为了保护飞地的保密性,AEX将某些寄存器的状态保存在飞地存储器中,然后用合成状态的固定值加载这些寄存器。
40.1兼容性切换到退出的AEX栈
AEX以预先确定的合成状态加载寄存器。 这些寄存器稍后可以按照飞地退出事件定义的形式推送到适当的堆栈上。为了在调用处理程序处理区域退出事件后恢复区域执行,需要在异步区域出口将区域外的蹦床代码地址加载到RIP中。这个蹦床代码最终通过ENCLU(ERESUME)叶子函数返回到飞地。 在退出飞地之前,RSP和RBP登记册在飞地入境之前恢复它的值。
堆栈的使用需要用与非SGX模式相同的规则进行选择:
1.如果有权限级别更改,堆栈将成为与新环相关的堆栈。
2.如果没有特权级别更改,则使用当前应用程序堆栈。
3. 如果使用IA-32e IST机制,则使用该方法选择退出堆栈。

在所有情况下,选择退出堆栈和推送到它的信息与非sgx操作一致。图40-1显示了使用堆栈开关退出后的应用程序和退出堆栈。没有堆栈开关的出口使用应用堆栈。把ERESUME叶索引值放入RAX,TCS指针然后放在RBX中,AEP(见下面)放入RCX中,以便在退出后恢复飞地。
在AEX上,AEP(异步退出指针)被加载到RIP中。 AEP指向一个蹦床代码序列,其中包括后来用于重新进入飞地的ERESUME指令。
在将RFLAGS推入出口堆栈之前,清除以下RFLAGS位:CF,PF,AF,ZF,SF,OF,RF。 其余的位保持不变。
40.2 AEX地址储存
状态保存区域保存AEX时的处理器状态。要允许在飞地内处理事件,并在AEX之后重新输入事件。SSA可以是多个SSA帧的堆栈,如图40-2所示。

在TCS和SECS中,要使用的SSA帧的位置由以下变量控制:
1.状态保存区域(SECS.SSAFRAMESIZE)中帧的大小:这定义了状态保存区域中单个帧中的4K字节页数。 SSA帧的大小必须足够大以保持GPR状态,XSAVE状态和MISC状态。
2.飞地的基地址(SECS.BASEADDR):它定义飞地的基线性地址,从中计算出到SSA堆栈基地的偏移量。
3. 状态保存区域插槽数(TCS.NSSA):这定义了状态保存区域堆栈中的插槽(帧)总数。
4. 当前状态保存区域插槽(TCS.CSSA):这定义了要在下一个出口使用的插槽。
5. 状态保存区域(TCS.OSSA):这定义了一组状态保存区域插槽的基地址与该区域的基地址的偏移量。
发生AEX时,硬件通过检查TCS.CSSA选择要使用的SSA帧。 处理器状态保存到SSA帧中(见第40.4节)并加载合成状态(如第40.3.1节所述)以避免泄漏秘密,RSP和RP在包围入口之前恢复到其值,并且TCS.CSSA 递增。正如后面将要描述的那样,如果一个异常占据最后一个插槽,就不可能重新进入飞地来处理飞地内部的异常。随后的ERESUME从当前的SSA框架中恢复处理器状态,并释放SSA框架
SSA的XSAVE部分的格式与XSAVE / XRSTOR指令使用的格式相同。在EENTER上,CSSA必须小于NSSA,确保至少有一个可用于退出的状态保存区域插槽。 如果在执行EENTER时没有空闲的SSA帧,输入将失败。
40.3异步飞地出口的合成状态
40.3.1异步飞地出口的处理器合成状态
表40-1显示了在AEX上加载的合成状态。 显示的值是处理器处于32位模式时的低32位和处理器处于64位模式时的64位。

40.3.2扩展功能的综合状态
当CR4.OSXSAVE = 1,并且SECS.XFRM的相应位置位时,扩展功能(由XCR0 [63:2]控制的功能)将被设置为各自的INIT状态。INIT状态是由XRSTOR指令加载的状态,它包含了指令掩码和XSAVE标题的XSTATE_BV字段,每个字段包含值XFRM。(当AEX在32位模式中发生时,32位模式中不存在的特性不变。)
40.3.3 MISC特性的合成状态
SECS.MISCSELECT表示的状态在保存到SSA后也可能被合成状态覆盖。 由MISCSELECT [0]表示的状态不会被覆盖,但如果退出事件是页面错误,则会清除CR2的低12位。
40.4 AEX流程
在飞地退出事件(中断、异常、VM出口或SMIs)中,处理器状态被安全地保存在飞地内,然后一个合成状态被加载并退出飞地。然后,EEE按照通常的退出定义方式进行。以下部分描述了AEX的
1. 保存在当前SSA帧中的确切处理器状态取决于飞地是32位还是64位。在32位模式下(IA32_EFER。LMA = 0 || CS。L = 0)存储的遗留寄存器的32位(EAX、EBX、ECX、EDX、ESP、EBP、ESI、EDI、EIP和EFLAGS)都被存储。遗留的32位寄存器和64位寄存器(R8…R15)并不存储。在64位模式下(IA32_EFER.LMA = 1 && CS.L = 1),通用处理器寄存器(RAX,RBX,RCX,RDX,RSP,RBP,RSI,RDI,R8 ... R15,RIP和 RFLAGS)被存储。
由SECS.ATTRIBUTES.XFRM指定的那些扩展功能的状态存储在当前SSA帧的XSAVE区域中。 x87和XMM部分(第1个512字节)的布局取决于IA32_EFER.LMA和CS.L的当前值:
如果IA32_EFER.LMA = 0 || CS.L = 0,与XSAVE / FXSAVE使用这些值具有相同的格式(32位)。
如果IA32_EFER.LMA = 1 && CS.L = 1,当REX.W = 1时,XSAVE / FXSAVE会使用这些值的格式(64位)。
AEX保存在EXITINFO字段中。 有关各个字段的详细信息和值,请参见表38-9。
由SECS.MISCSELECT指定的这些杂项特征的状态(见第38.7.2节)存储在当前SSA帧的MISC区域中。
2. 合成状态是为许多处理器寄存器创建的,以呈现飞地状态的不透明视图。表40-1显示了用于AEX的GPRs、x87、SSE、FS、GS、调试和性能监视的值。其他扩展功能(由XCR0 [62:2]控制的功能)的合成状态在SECS.ATTRIBUTES.XFRM的相应位置被设置为各自的INIT状态。INIT状态是HEADER.XSTATE_BV [n]为0时由XRSTOR指令的行为定义的状态。由SECS.MISCSELECT指定的这些功能的综合状态取决于其他功能。SECS.MISCSELECT [0]控制的其他状态不需要合成状态。
3. 在飞地进入时被压制的任何代码和数据断点在离开飞地时都是不受抑制的。
4. RFLAGS.TF被设置为它在最近的飞地入口时的值(用于调试的输入的情况除外;参见第43.2节)。 在SSA中,RFLAGS.TF被设置为0。
5. RFLAGS.RF在合成状态下设置为0。在SSA中,保存的值与在非SGX情况(RF的架构值)中保存在堆栈中的值相同。因此,由于中断、陷阱和代码断点而引起的AEX将RF(不加修改的)保存到SSA中,而由于其他故障导致的AEX则将SSA中的RF保存为1。如果引起AEX的事件发生在REP-prefixed指令的中间迭代中,那么RF = 1将保存在SSA上,而不管其优先级如何。
6. 任何性能监视活动(包括PEBS)或性能分析活动(LBR,使用Intel PT跟踪使用Intel PT)都是不受限制的。从AnyThread计数到MyThread计数的任何计数(在一个逻辑处理器上)都被提升为AnyThread计数。
40.4.1 AEX操作细节

本节中的伪代码描述了当AEX在飞地模式中发生时所执行的内部操作。这些操作发生在正常中断或异常处理发生之前。
(*保存RIP以备后用*)
TMP_RIP = Linear Address of Resume RIP
(* 处理器是否处于64位模式? *)
TMP_MODE64 ((IA32_EFER.LMA = 1) && (CS.L = 1));
(*保存所有寄存器,当保存EFLAGS时,TF位被设置为0并且RF位会被设置为在非SGX情况下将保存在堆栈中的内容*)
IF (TMP_MODE64 = 0)
THEN
Save EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI, EFLAGS, EIP into the current SSA frame using
CR_GPR_PA; (* 请参阅表41-4以获取用于描述英特尔SGX内部操作的CREG列表 *)
SSA.RFLAGS.TF 0;
ELSE (* TMP_MODE64 = 1 *)
Save RAX, RBX, RCX, RDX, RSP, RBP, RSI, RDI, R8-R15, RFLAGS, RIP into the current SSA frame using
CR_GPR_PA;
SSA.RFLAGS.TF 0;
FI;
Save FS and GS BASE into SSA using CR_GPR_PA;
(* 将XSAVE状态存储到当前SSA框架的XSAVE区域,使用在CRAXSAVE_PAGE_i确定并在区域入口时间缓存的物理地址. *)
For each XSAVE state i defined by (SECS.ATTRIBUTES.XFRM[i] = 1, destination address cached in
CR_XSAVE_PAGE_i)
SSA.XSAVE.i XSAVE_STATE_i;
(* 清除XSAVE_HEADER的字节8至23,即XHEADER_BV之后的下16个字节 *)
CR_XSAVE_PAGE_0.XHEADER_BV[191:64] 0;
(* Clear bits in XHEADER_BV[63:0] that are not enabled in ATTRIBUTES.XFRM *)
CR_XSAVE_PAGE_0.XHEADER_BV[63:0]
CR_XSAVE_PAGE_0.XHEADER_BV[63:0] & SECS(CR_ACTIVE_SECS).ATTRIBUTES.XFRM;
Apply synthetic state to GPRs, RFLAGS, extended features, etc.
(* 使用CR_GPR_PA在飞地入口时间确定并缓存物理地址,从当前SSA帧的GPR区域恢复RSP和RBP。*)
RSP CR_GPR_PA.URSP;
RBP CR_GPR_PA.URBP;
(* 恢复FS和GS *)
FS.selector CR_SAVE_FS.selector;
FS.base CR_SAVE_FS.base;
FS.limit CR_SAVE_FS.limit;
FS.access_rights CR_SAVE_FS.access_rights;
GS.selector CR_SAVE_GS.selector;
GS.base CR_SAVE_GS.base;
GS.limit CR_SAVE_GS.limit;
GS.access_rights CR_SAVE_GS.access_rights;
(* 检查异常代码并更新飞地内部状态*)
exception_code Exception or interrupt vector;
(* 在SSA中指出退出原因 *)
IF (exception_code = (#DE OR #DB OR #BP OR #BR OR #UD OR #MF OR #AC OR #XM ))
THEN
CR_GPR_PA.EXITINFO.VECTOR exception_code;
IF (exception code = #BP)
THEN CR_GPR_PA.EXITINFO.EXIT_TYPE 6;
ELSE CR_GPR_PA.EXITINFO.EXIT_TYPE 3;
FI;
CR_GPR_PA.EXITINFO.VALID 1;
ELSE IF (exception_code is #PF or #GP )
THEN
(* 使用CR_ACTIVE_SECS检查SECS.MISCSELECT *)
IF (SECS.MISCSELECT[0] is set)
THEN
CR_GPR_PA.EXITINFO.VECTOR exception_code;
CR_GPR_PA.EXITINFO.EXIT_TYPE 3;
IF (exception_code is #PF)
THEN
SSA.MISC.EXINFO. MADDR CR2;
SSA.MISC.EXINFO.ERRCD PFEC;
SSA.MISC.EXINFO.RESERVED 0;
ELSE
SSA.MISC.EXINFO. MADDR 0;
SSA.MISC.EXINFO.ERRCD GPEC;
SSA.MISC.EXINFO.RESERVED 0;
FI;
CR_GPR_PA.EXITINFO.VALID 1;
FI;
ELSE
CR_GPR_PA.EXITINFO.VECTOR 0;
CR_GPR_PA.EXITINFO.EXIT_TYPE 0
CR_GPR_PA.REASON.VALID 0;
FI;
(* 执行将在AEP恢复 *)
RIP CR_TCS_PA.AEP;
(* 将EAX设置为ERESUME叶子索引 *)
EAX 3;
(* 将TCS LA放入RBX以供ERESUME以后使用 *)
RBX CR_TCS_LA;
(* 将AEP放入RCX以供ERESUME稍后使用 *)
RCX CR_TCS_PA.AEP;
(* 增加SSA框架# *)
CR_TCS_PA.CSSA CR_TCS_PA.CSSA + 1;
(*还原XCR0 *)
IF (CR4.OSXSAVE = 1)
THEN XCR0 CR_SAVE_XCR0; FI;
Un-suppress all code breakpoints that are outside ELRANGE
(* 更新线程上下文以显示不在飞地模式*)
CR_ENCLAVE_MODE 0;
(* 确保一致的翻译. *)
Flush linear context including TLBs and paging-structure caches
IF (CR_DBGOPTIN = 0)
THEN
Un-suppress all breakpoints that overlap ELRANGE
(* 清除抑制的断点匹配 *)
Restore suppressed breakpoint matches
(* 还原 TF *)
RFLAGS.TF CR_SAVE_TF;
Un-suppress monitor trap flag;
Un-suppress branch recording facilities;
Un-suppress all suppressed performance monitoring activity;
Promote any sibling-thread counters that were demoted from AnyThread to MyThread during enclave
entry back to AnyThread;
FI;
IF the “monitor trap flag” VM-execution control is 1
THEN Pend MTF VM Exit at the end of exit; FI;
(* 清除#PF上低12位的CR2 *)
IF (Exception code is #PF)
THEN CR2 CR2 & ~0xFFF; FI;
(* end_of_flow *)
(* 继续执行正常的事件处理。 *)
原文: 原文请参考附件
译者简述:上一期最后的话是相当的打脸,真的是拖更好久了,小编也不发什么誓了,大三考研复习的东西真的好多,总之大家一起加油吧。
