Intel SDM 3D (SGX部分)【按需翻译】

索引

《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3D》36~42章(32~38章,2021年)

《Intel® Software Guard Extensions Programming Reference》1~7章(2014年前)

第37章 Enclave访问控制和数据结构

37.7 SGX ENCLAVE控制结构体(SECS)

SECS数据结构体需要4KB对齐。

37.7.1 ATTRIBUTES(属性)

ATTRIBUTES数据结构由SECS、REPORT和KEYREQUEST结构中使用的Bit粒度字段组成。 CPUID.(EAX = 12H,ECX = 1)提供了位图指示是否允许在ATTRIBUTES对应位置1。

37.7.2 SECS.MISCSELECT域

CPUID.(EAX = 12H, ECX = 0):EBX [31:0]枚举了AEX发生时处理器可以将哪些扩展信息保存到SSA的MISC区域中。 Enclave开发者可以通过SIGSTRUCT指定如何设置SECS.MISCSELECT字段。 MISCSELECT的位向量指示在AEX生成时选择哪些扩展信息保存在SSA帧的MISC区域中。 表37-4列出了扩展信息的位向量定义。

如果CPUID.(EAX = 12H,ECX = 0):EBX [31:0] = 0,则SECS.MISCSELECT字段必须全为零。

SECS.MISCSELECT字段确定SSA帧的MISC区域的大小,请参见第37.9.2节。

37.7.2 SECS.CET_ATTRIBUTES字段

Enclave开发者可以使用SECS.CET_ATTRIBUTES字段来启用Enclave中的各种CET属性。 当CPUID.(EAX = 12, ECX = 1):EAX [6]为1时,此字段存在。当CPUID.(EAX = 7, ECX = 0):ECX.CET_SS为1时,位1:0被定义。 当CPUID.(EAX = 7,ECX = 0):EDX.CET_IBT为1时,位5:2被定义。

37.8 线程控制结构体(TCS)

Enclave中,每一个正处于执行状态的线程都与一个线程控制结构体绑定。它需要4K字节对齐。

37.9 STATE SAVE AREA (SSA) FRAME

当在Enclave中运行时发生AEX时,架构层面的状态将保存在线程的当前SSA帧中,该帧由TCS.CSSA指向。SSA帧必须与页面对齐,并且包含以下区域:

  • XSAVE域从SSA帧的底部开始,该区域包含XSAVE/FXSAVE兼容的非压缩格式的扩展功能寄存器状态。
  • GPRSGX域。它用于保存处理器通用寄存器(RAX…R15)、RIP、外部RSP和RBP、RFLAGS和AEX信息。 GPRSGX域在SSA帧的尾端内存对齐。
  • MISC域(!if CPUID(EAX = 12H, ECX = 0):EBX [31:0]!= 0)。 MISC域与GRPSGX域相邻,并且可能包含零个或多个扩展信息元件,这些扩展信息在发生AEX时将被保存。如果没有MISC域,则GPRSGX和XSAVE域之间的区域是软件可以使用的填充区。如果存在MISC区域,则MISC和XSAVE区域之间的区域是软件可以使用的填充区。

如果设置了CPUID.(EAX = 12H, ECX = 0):EBX [31:0]中的一位或多位,则扩展信息的一个或多个组成部分可以写入MISC区域。最终写入MISC区域的组件由SECS.MISCSELECT中的设置位决定。

37.9.1  GPRSGX域

GPRSGX域的布局如表2-8所示。

37.9.1.1 EXITINFO

EXITINFO包含用于向软件报告Enclave的退出原因。 它是一个4字节的字段,如表2-9所示。 VALID位仅为Enclave内部报告的异常情况而设置。有关Enclave内部报告的异常,请参见表2-10。 如果不是Enclave内部报告异常情况,则清除VECTOR和EXIT_TYPE。

37.9.1.2 VECTOR域定义

表2-10包含VECTOR字段。 该字段包含有关Enclave内部发生的某些异常的信息。这些向量值与用于指向常规异常处理程序的值相同。Enclave内部报告仅支持下列展示的值。

37.9.2 MISC域

表2-11中显示了MISC域的布局。 MISC域中可用的组件数对应CPUID.(EAX=12H, ECX=0):EBX[31:0]的设置位。CPUID.(EAX=12H, ECX=0):EBX[31:0]中的每个设置位都具有对应组件的已事先定义大小,如表2-11所示。Enclave开发者必须同时查阅CPUID.(EAX=12H, ECX=0):EBX[31:0]、SECS.MISCSELECT和表2-11的Offset/Size,以确定MISC区域的大小。第一个组件EXINFO从GPRSGX区域的下方开始存储。 MISC区域中的其他组件在MISC区域中向下(向低地址)增长。

MISC区域的大小计算如下:

  • 如果CPUID.(EAX=12H, ECX=0):EBX[31:0] = 0,则不支持MISC区域。
  • 如果CPUID.(EAX=12H, ECX=0):EBX[31:0] != 0,则MISC区域的大小是从SECS.MISCSELECT中设置的最高位以及在表2-11中定义的偏移量和大小信息得出的 。 例如,如果在SECS.MISCSELECT中所设置的最高位是第0位,则MISC区域大小仅仅为OFFSET(EXINFO) + Sizeof(EXINFO)。

37.10 页信息(PAGEINFO)

PAGEINFO是一种架构层面的数据结构,用作EPC管理指令的参数。 它需要32字节对齐。

37.11 安全信息(SECINFO)

SECINFO数据结构体包含了关于Enclave页的元数据。

37.12 分页加密元数据(PCMD)

PCMD结构用于跟踪换出(Page-out)页面对应的加密元数据。 与PAGEINFO结合使用时,它为处理器提供了足够的信息来验证、解密和重新加载这个被换出的EPC页面。

PCMD结构的大小(128字节)是架构层面(确定)的。对此,EWB会写上(PCMD)字段和MAC值,ELDB/U会读取(PCMD)字段并检查MAC。

PCMD的格式如下:

37.13 Enclave签名结构体(SIGSTRUCT)

SIGSTRUCT包含有关Enclave签名者的Enclave信息,并且必须4K字节对齐。

SIGSTRUCT包含ENCLAVEHASH作为FIPS PUB 180-4中所定义的SHA256摘要。摘要是长度为32的字节字符串,其中8个HASH双字各自的最高有效字节都位于最左侧的字节位置。

SIGSTRUCT包含四个3072位整数(MODULUS,SIGNATURE,Q1,Q2)。每个这样的整数表示成长度为384的字节字符串,其中最高有效字节处于“offset + 383”的位置,而最低有效字节处于“offset”的位置。 

(3072位整数的)签名需要是一个RSA签名,其中:a)RSA模数(MODULUS)是3072位整数; b)公开的指数设置为3; c)签名过程使用EMSA-PKCS1-v1.5格式,并按PKCS#1 v2.1/RFC 3447中的规定对“DigestInfo”值进行DER编码。

3072位的整数Q1和Q2见如下定义:

q1 = floor(Signature^2 / Modulus);

q2 = floor((Signature^3 - q1 * Signature * Modulus) / Modulus);

SIGSTRUCT必须页对齐

在表2-19的第5列中,“ Y”表示此字段应包含在开发人员生成的签名中。

37.14 EINIT令牌结构体(EINITTOKEN)

EINIT使用EINIT令牌来验证Enclave是否被允许启动。

EINIT令牌必须512字节对齐。 

37.15 报告(REPORT)

REPORT结构是EREPORT指令的输出,必须对齐512字节。

37.15.1 REPORTDATA

REPORTDATA结构指定64字节输入缓冲区的地址,并且这个缓冲区将被EREPORT指令用于生成加密报告。它需要128字节对齐。

37.16 报告的目标信息(TARGETINFO)

此结构体是EREPORT指令叶的输入参数。TARGETINFO的地址在RBX中指定为有效地址。 它用于识别Enclave,使之能密码学验证EREPORT返回的REPORT结构。 TARGETINFO需要512字节对齐。

37.17 密钥请求(KEYREQUEST)

此结构是EGETKEY指令的输入参数。它作为RBX中记录的有效地址进行传递,并且需要512字节对齐。它用于选择适当的密钥以及派生该密钥所需的任何其他参数。

37.17.1 密钥请求的密钥名称

37.17.2 密钥请求策略结构体

37.19 Enclave Page Cache Map(EPCM)

EPCM是处理器用来跟踪EPC内容的安全数据结构。EPCM对于当前加载到EPC中的每个页面仅保留一个条目。EPCM不能通过软件访问,并且EPCM字段的布局需要参照具体实现。

第38章 Enclave操作

38.5 EPC和EPC页的管理

38.5.9裁剪页面

在支持SGX2的处理器上,作为EMODT(硬件指令)的特殊用法,Intel SGX支持删除Enclave页。页类型PT_TRIM意味着该页已从Enclave的地址空间中裁剪,并且该页不再可以访问。PT_TRIM状态的页不允许被做任何修改;该页必须先删除,当Enclave再次使用该页面之前由OS重新分配。可以批量化的进行页面重新分配操作,以提高其效率。

裁剪Enclave页的协议如下:

1. Enclave发信号通知OS某个页不再使用。

2. OS对该页调用EMODT,请求将页的类型更改为PT_TRIM。

2.1 SECS和VA页面无法用这种方式裁剪,因此要求页面的初始类型必须为PT_REG或PT_TCS

2.2. EMODT只能作用于VALID页面

3. OS执行ETRACK指令,从所有处理器(CPU核)中删除TLB地址

4.Enclave内发出EACCEPT指令。(由可信的Enclave表示接受此次修改操作)

5.OS现在可以将该页永久删除(通过调用EREMOVE)。

第40章 指令的相关参考资料

本章介绍英特尔®Software Guard Extensions所提供的内核态(Ring0)和用户态(Ring3)的硬件指令。 一般情况下,各种SGX硬件指令功能是作为ENCLS(特权)和ENCLU(用户)指令的叶功能而存在。 调用ENCLS和ENCLU指令助记符,并指定EAX寄存器为特定值,就可以使用各种叶功能。

40.2 Intel SGX指令的相关参考资料

ENCLS——执行指定叶编号的Enclave内核态功能

描述

ENCLS指令可以调用指定的内核态的Intel SGX叶功能来管理和调试Enclave。 程序通过输入寄存器EAX来指定叶功能。 寄存器RBX,RCX和RDX表明当前叶功能的具体用法,这些寄存器可以用于输入、输出或者不使用。在64位模式下,该指令将忽略RAX寄存器的高32位。

如果CR0.PE为0或RFLAGS.VM为1,或者该指令是在SMM内部执行,则该指令会导致#UD错误。 此外,如果当前不是内核态时,执行该指令会导致#UD。

尝试调用未定义的叶功能会导致#GP(0)。

如果CR0.PG为0,那么尝试调用ENCLS会导致#GP(0)。

在VMX中,非root权限下进行操作时,如果VM执行控制标识中的“Enable ENCLS exiting” 为0,那么可以随意执行ENCLS。 如果“Enable ENCLS exiting”值为1,那么由“ENCLS-exiting bitmap”表明ENCLS各个叶功能能否能被执行。 “ENCLS-exiting bitmap”中的每个Bit(的索引)对应了ENCLS叶功能的索引值(也就是EAX值)。

通过设置Enable_ENCLS_EXITING,并设置“ENCLS-exiting bitmap”的Bit(可通过0202EH / 0202FH这对编码,进行访问),处于VMX Root模式的程序可以拦截来自VMX非Root模式对各种ENCLS叶功能的调用。如果IA32_VMX_PROCBASED_CTLS2 [15]读出来的值为1,那么处理器将实施Enable_ENCLS_EXITING这个VM执行控制字段。

DS段用来创建线性地址。

地址和操作数在非64位模式下为32位(IA32_EFER.LMA = 0 || CS.L = 0),在64位模式下为64位(IA32_EFER.LMA = 1 || CS.L = 1)。 CS.D值对地址的计算没有影响。

段前缀的覆写将被忽略。 地址大小前缀(67H)的覆写将被忽略。

REX前缀在64位模式下将被忽略。

操作

IN_64BIT_MODE <- 0;
IF TSX_ACTIVE
    Then GOTO TSX_ABORT_PROCESSING; FI;

IF ( CR0.PE = 0 or RFLAGS.VM = 1 or IN_SMM or CPUID.SGX_LEAF.0:EAX.SE1 = 0 ) 
    Then #UD; FI;

IF (CPL > 0) 
    Then #UD; FI;

IF ( (in VMX non-root operation) and ( Enable_ENCLS_EXITING = 1) )
    Then 
        IF ( ((EAX < 63) and (ENCLS_EXITING_Bitmap[EAX] = 1)) or (EAX> 62 and ENCLS_EXITING_Bitmap[63] = 1) )
            Then 
            Set VMCS.EXIT_REASON = ENCLS;
            Deliver VM exit;
        FI;
FI;

IF (IA32_FEATURE_CONTROL.LOCK = 0 or IA32_FEATURE_CONTROL.SGX_ENABLE = 0) 
    Then #GP(0); FI;

IF (EAX is invalid leaf number) 
    Then #GP(0); FI;

IF (CR0.PG = 0) 
    Then #GP(0); FI;

IN_64BIT_MODE <- IA32_EFER.LMA AND CS.L ? 1 : 0;

IF (IN_64BIT_MODE = 0 and (DS[S] = 1) and (DS[bit 11] = 0) and DS[bit 10] = 1) 
    Then #GP(0); FI;

Jump to leaf specific flow

受影响的标志

请分别查看叶功能中的说明

保护模式异常(Exception)

#UD         如果LOCK/OSIZE/REP/VEX前缀中任意一个被使用。

                如果当前特权级不是0。

                如果CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0。(译注:代表硬件不支持SGX)

                如果逻辑核处于SMM.

#GP(0)     如果IA32_FEATURE_CONTROL.LOCK = 0。

                如果IA32_FEATURE_CONTROL.SGX_ENABLE = 0。

                如果EAX值指向一个不支持的叶功能。

                如果数据段向下增长。

                如果CR0.PG=0。

实地址模式异常

#UD         ENCLS指令在实模式无法识别。

虚拟8086模式异常

#UD         ENCLS指令在虚拟8086模式无法识别。

兼容模式异常

和保护模式的异常一样。

64位模式异常

#UD         如果LOCK/OSIZE/REP/VEX前缀中任意一个被使用。

                如果当前特权级不是0。

                如果CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0。(译注:代表硬件不支持SGX)

                如果逻辑核处于SMM.

#GP(0)     如果IA32_FEATURE_CONTROL.LOCK = 0。

                如果IA32_FEATURE_CONTROL.SGX_ENABLE = 0。

                如果EAX值指向一个不支持的叶功能。

ENCLU——执行指定叶编号的Enclave用户态功能

描述

ENCLU指令调用指定的用户态的Intel SGX叶功能。 程序通过设置寄存器EAX值,来指定叶功能。 寄存器RBX,RCX和RDX指明叶功能的特定用途,可以作为输入、输出或者不使用。 在64位模式下,该指令将忽略RAX寄存器的高32位。

如果CR0.PE为0或RFLAGS.VM为1,或者在SMM内部执行,则该指令会导致#UD。 另外,在当前特权级别不为3时尝试执行该指令会导致#UD。

尝试调用未定义的叶功能会导致#GP(0)。

在禁用分页机制或MS-DOS兼容模式下,尝试执行ENCLU指令会导致#GP。

DS段用来创建线性地址。

地址和操作数在非64位模式下为32位(IA32_EFER.LMA = 0 || CS.L = 0),在64位模式下为64位(IA32_EFER.LMA = 1 || CS.L = 1)。 CS.D值对地址的计算没有影响。

段前缀的覆写将被忽略。 地址大小前缀(67H)的覆写将被忽略。

REX前缀在64位模式下将被忽略。

操作

IN_64BIT_MODE <- 0;

IF TSX_ACTIVE
    Then GOTO TSX_ABORT_PROCESSING; FI;

IF ( CR0.PE= 0 or RFLAGS.VM = 1 or IN_SMM or CPUID.SGX_LEAF.0:EAX.SE1 = 0 ) 
    Then #UD; FI;

IF (CR0.TS = 1) 
    Then #NM; FI;

IF (CPL != 3) 
    Then #UD; FI;

IF (IA32_FEATURE_CONTROL.LOCK = 0 or IA32_FEATURE_CONTROL.SGX_ENABLE = 0) 
    Then #GP(0); FI;

IF (EAX is invalid leaf number) 
    Then #GP(0); FI;

IF (CR0.PG = 0 or CR0.NE = 0) 
    Then #GP(0); FI;

IN_64BIT_MODE <- IA32_EFER.LMA AND CS.L ? 1 : 0;

(*Check not in 16-bit mode and DS is not a 16-bit segment*)
IF (IN_64BIT_MODE = 0 and ((CS.D = 0) or (DS.B = 0) ) 
    Then #GP(0); FI;

IF (CR_ENCLAVE_MODE = 1 and ((EAX = EENTER) or (EAX = ERESUME) ) )
    Then #GP(0); FI;

IF (CR_ENCLAVE_MODE = 0 and ((EAX = EGETKEY) or (EAX = EREPORT) or (EAX = EEXIT) or (EAX = EACCEPT) or (EAX = EACCEPTCOPY) or (EAX = EMODPE) ) )
    Then #GP(0); FI;

Jump to leaf specific flow

受影响的标志

请分别查看叶功能中的说明

保护模式异常(Exception)

#UD         如果LOCK/OSIZE/REP/VEX前缀中任意一个被使用。

                如果当前特权级不是3。

                如果CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0。(译注:代表硬件不支持SGX)

                如果逻辑核处于SMM.

#GP(0)     如果IA32_FEATURE_CONTROL.LOCK = 0。

                如果IA32_FEATURE_CONTROL.SGX_ENABLE = 0。

                如果EAX输入值指向一个不支持的叶功能。

                如果EAX输入值指向EENTER/ERESUME,并且ENCLAVE_MODE=1。

                如果EAX输入值指向EGETKEY/EREPORT/EEXIT/EACCEPT/EACCEPTCOPY/EMODPE,并且ENCLAVE_MODE=0。

                如果操作是16位模式。

                如果数据段是16位模式。

                如果CR0.PG=0或者CR0.NE=0。

#NM        如果CR0.TS=1。

实地址模式异常

#UD         ENCLS指令在实模式无法识别。

虚拟8086模式异常

#UD         ENCLS指令在虚拟8086模式无法识别。

兼容模式异常

和保护模式的异常一样。

64位模式异常

#UD         如果LOCK/OSIZE/REP/VEX前缀中任意一个被使用。

                如果当前特权级不是3。

                如果CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0。(译注:代表硬件不支持SGX)

                如果逻辑核处于SMM.

#GP(0)     如果IA32_FEATURE_CONTROL.LOCK = 0。

                如果IA32_FEATURE_CONTROL.SGX_ENABLE = 0。

                如果EAX输入值指向一个不支持的叶功能。

                如果EAX输入值指向EENTER/ERESUME,并且ENCLAVE_MODE=1。

                如果EAX输入值指向EGETKEY/EREPORT/EEXIT/EACCEPT/EACCEPTCOPY/EMODPE,并且ENCLAVE_MODE=0。

                如果CR0.NE=0。

#NM        如果CR0.TS=1。

40.3 Intel SGX内核态叶功能参考资料

本节介绍了ENCLS指令助记符可用的叶函数。通常,每个指令叶功能都需要EAX来指定叶功能索引,并且/或使用其他隐式寄存器来指定叶功能特定的输入参数。指令操作数编码表提供了每种隐式寄存器用法,及其相关输入/输出语义的详细信息。

在许多情况下,输入参数是EPC内部或外部的内存对象相关联的有效地址,这些存储对象的内存寻址语义也汇总在单独的表中。

EADD——向未初始化的Enclave添加一个页

描述

这个叶功能将源页面从非Enclave内存复制到EPC中,将EPC页面与EPC中驻留的SECS页面相关联,并将线性地址和安全属性存储在EPCM中。Enclave偏移量和安全属性作为关联内容的一部分被度量并扩展到SECS.MRENCLAVE。此指令只能在当前特权级别为0时执行。

RBX包含PAGEINFO结构的有效地址,而RCX包含EPC页面的有效地址。下表提供了额外的信息,关于EADD叶功能的内存参数。

遇到如下情况指令会出错:

并发限制

操作

IF (DS:RBX is not 32Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

TMP_SRCPGE <- DS:RBX.SRCPGE;
TMP_SECS <- DS:RBX.SECS;
TMP_SECINFO <- DS:RBX.SECINFO;
TMP_LINADDR <- DS:RBX.LINADDR;

IF (DS:TMP_SRCPGE is not 4KByte aligned or DS:TMP_SECS is not 4KByte aligned or DS:TMP_SECINFO is not 64Byte aligned or TMP_LINADDR is not 4KByte aligned)
    Then #GP(0); FI;

IF (DS:TMP_SECS does not resolve within an EPC)
    Then #PF(DS:TMP_SECS); FI;

SCRATCH_SECINFO <- DS:TMP_SECINFO;

(* 检查错误配置的SECINFO标志 *)
IF (SCRATCH_SECINFO reserved fields are not zero or ! (SCRATCH_SECINFO.FLAGS.PT is PT_REG or SCRATCH_SECINFO.FLAGS.PT is PT_TCS) ) 
    Then #GP(0); FI;

(* 为并发性检查EPC页 *)
IF (EPC page in use) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX).VALID != 0) 
    Then #PF(DS:RCX); FI;

(* 为并发性检查SECS *)
IF (SECS is not available for EADD) 
    Then #GP(0); FI;

IF (EPCM(DS:TMP_SECS).VALID = 0 or EPCM(DS:TMP_SECS).PT != PT_SECS) 
    Then #PF(DS:TMP_SECS); FI;

(* 从源页面拷贝4KBytes到EPC页*)
DS:RCX[32767:0] <- DS:TMP_SRCPGE[32767:0];

CASE (SCRATCH_SECINFO.FLAGS.PT) 
{
    PT_TCS:
        IF (DS:RCX.RESERVED != 0) #GP(0); FI;
        IF ( (DS:TMP_SECS.ATTIBUTES.MODE64BIT = 0) and ((DS:TCS.FSLIMIT & 0FFFH != 0FFFH) or (DS:TCS.GSLIMIT & 0FFFH != 0FFFH) )) #GP(0); FI;
        BREAK;
    PT_REG:
        IF (SCRATCH_SECINFO.FLAGS.W = 1 and SCRATCH_SECINFO.FLAGS.R = 0) #GP(0); FI;
        BREAK;
ESAC;

(* 检查Enclave偏移是否在Enclave线性地址空间内 *)
IF (TMP_LINADDR < DS:TMP_SECS.BASEADDR or TMP_LINADDR >= DS:TMP_SECS.BASEADDR + DS:TMP_SECS.SIZE) 
    Then #GP(0); FI;

(* 检查度量资源的并发性 *)
IF (Measurement being updated) 
    Then #GP(0); FI;

(* 检查待添加页的Enclave是否已经处于被初始化过的状态 *)
IF (DS:TMP_SECS already initialized) 
    Then #GP(0); FI;

(* 对于TCS页,强制EPCM.rwx位置为0并且禁止调试访问 *)
IF (SCRATCH_SECINFO.FLAGS.PT = PT_TCS) 
    THEN
        SCRATCH_SECINFO.FLAGS.R <- 0;
        SCRATCH_SECINFO.FLAGS.W <- 0;
        SCRATCH_SECINFO.FLAGS.X <- 0;
        (DS:RCX).FLAGS.DBGOPTIN <- 0; // force TCS.FLAGS.DBGOPTIN off
        DS:RCX.CSSA <- 0;
        DS:RCX.AEP <- 0;
        DS:RCX.STATE <- 0;
FI;

(* 向MRENCLAVE添加Enclave偏移和安全属性 *)
TMP_ENCLAVEOFFSET <- TMP_LINADDR - DS:TMP_SECS.BASEADDR;
TMPUPDATEFIELD[63:0] <- 0000000044444145H; // “EADD”
TMPUPDATEFIELD[127:64] <- TMP_ENCLAVEOFFSET;
TMPUPDATEFIELD[511:128] <- SCRATCH_SECINFO[375:0]; // 48 bytes
DS:TMP_SECS.MRENCLAVE <- SHA256UPDATE(DS:TMP_SECS.MRENCLAVE, TMPUPDATEFIELD)
INC enclave’s MRENCLAVE update counter;

(* 向MRENCLAVE添加Enclave偏移和安全属性 *)
EPCM(DS:RCX).R <- SCRATCH_SECINFO.FLAGS.R;
EPCM(DS:RCX).W <- SCRATCH_SECINFO.FLAGS.W;
EPCM(DS:RCX).X <- SCRATCH_SECINFO.FLAGS.X;
EPCM(DS:RCX).PT <- SCRATCH_SECINFO.FLAGS.PT;
EPCM(DS:RCX).ENCLAVEADDRESS <- TMP_LINADDR;

(* 通过存储DS:TMP_SECS的SECS ID,将EPCPAGE与SECS相关联 *)
Update EPCM(DS:RCX) SECS identifier to reference DS:TMP_SECS identifier;

(* 设置EPCM项字域 *)
EPCM(DS:RCX).BLOCKED <- 0;
EPCM(DS:RCX).PENDING <- 0;
EPCM(DS:RCX).MODIFIED <- 0;
EPCM(DS:RCX).VALID <- 1;

受影响的Flags

保护模式异常

#GP(0)              如果内存操作数的有效地址超出DS段限制。

                          如果内存操作数没有正确地对齐。

                          如果Enclave内存操作数位于EPC之外。

                          如果Enclave内存操作数的类型有错。

                          如果内存操作数被上锁。

                          如果Enclave已被初始化。(译注:在创建SECS、将页添加到EPC并度量之后,会调用EINIT指令判断建立过程是否可信,并且将Enclave标记为已被初始化,此时不能再使用EADD来添加Enclave页,而需要改用EAUG)

                          如果Enclave的MRENCLAVE已上锁。

                          如果TCS页面保留位被置位了。

#PF(fault code) 如果在访问内存操作数时发生页面错误。

                          如果该EPC页面已经被标记为有效。

64位模式异常

#GP(0)              如果内存操作数并非规范的形式。

                          如果内存操作数没有正确地对齐。

                          如果Enclave内存操作数位于EPC之外。

                          如果Enclave内存操作数是个错误的类型。

                          如果内存操作数被上锁。

                          如果Enclave已被初始化。

                          如果Enclave的MRENCLAVE已上锁。

                          如果TCS页面保留位被置位了。

#PF(fault code) 如果在访问内存操作数时发生页面错误。

                          如果该EPC页面已经被标记为有效。

EAUG——向一个已经被初始化的Enclave添加页

描述

此叶功能将EPC内存页清零,将该EPC页与存储在EPC中的SECS页进行关联,并将线性地址和安全属性存储在EPCM中。 作为关联过程的一部分,该EPC页的安全属性会被(暂时地)配置为拒绝访问,直到调用EACCEPT叶或EACCEPTCOPY叶来确认将新页面添加到Enclave为止。 仅当当前特权级别为0时才能执行该指令。

RBX包含PAGEINFO结构的有效地址,而RCX包含EPC页面的有效地址。 下表提供了有关EAUG叶功能的内存参数的其他信息。

遇到如下情况,指令会报错:

并发限制

操作

IF (DS:RBX is not 32Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

TMP_SECS <- DS:RBX.SECS;
TMP_LINADDR <- DS:RBX.LINADDR;

IF ( DS:TMP_SECS is not 4KByte aligned or TMP_LINADDR is not 4KByte aligned )
    Then #GP(0); FI;

IF ( (DS:RBX.SRCPAGE is not 0) or (DS:RBX:SECINFO is not 0) )
    Then #GP(0); FI;

IF (DS:TMP_SECS does not resolve within an EPC)
    Then #PF(DS:SECS); FI;

(* Check the EPC page for concurrency *)
IF (EPC page in use) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX).VALID != 0) 
    Then #PF(DS:RCX); FI;

(* Check the SECS for concurrency *)
IF (SECS is not available for EAUG) 
    Then #GP(0); FI;

IF (EPCM(DS:TMP_SECS).VALID = 0 or EPCM(DS:TMP_SECS).PT != PT_SECS) 
    Then #PF(DS:TMP_SECS); FI;

(* Check if the enclave to which the page will be added is in the Initialized state *)
IF (DS:TMP_SECS is not initialized) 
    Then #GP(0); FI;

(* Check the enclave offset is within the enclave linear address space *)
IF ( (TMP_LINADDR < DS:TMP_SECS.BASEADDR) or (TMP_LINADDR >= DS:TMP_SECS.BASEADDR + DS:TMP_SECS.SIZE) )
    Then #GP(0); FI;

(* Clear the content of EPC page*)
DS:RCX[32767:0] <- 0;

(* Set EPCM security attributes *)
EPCM(DS:RCX).R <- 1;
EPCM(DS:RCX).W <- 1;
EPCM(DS:RCX).X <- 0;
EPCM(DS:RCX).PT <- PT_REG;
EPCM(DS:RCX).ENCLAVEADDRESS <- TMP_LINADDR;
EPCM(DS:RCX).BLOCKED <- 0;
EPCM(DS:RCX).PENDING <- 1;
EPCM(DS:RCX).MODIFIED <- 0;

(* associate the EPCPAGE with the SECS by storing the SECS identifier of DS:TMP_SECS *)
Update EPCM(DS:RCX) SECS identifier to reference DS:TMP_SECS identifier;

(* Set EPCM valid fields *)
EPCM(DS:RCX).VALID <- 1;

受影响的标志

保护模式异常

#GP(0)                如果内存操作数有效地址超出DS段限制。

                            如果内存操作数未正确对齐。

                            如果内存操作数被锁定。

                            如果Enclave未初始化。

#PF(fault code)    如果在访问内存操作数时发生页面错误。

保护模式异常

#GP(0)                如果内存操作数不是规范的格式。

                            如果内存操作数未正确对齐。

                            如果内存操作数被锁定。

                            如果Enclave未初始化。

#PF(fault code)    如果在访问内存操作数时发生页面错误。

EBLOCK——标记一个EPC中的页为锁定状态

描述

此叶功能使EPC页面被标记为“BLOCKED”。仅当当前特权级别为0时才能执行该指令。

RCX的内容是EPC页面的有效地址。DS段用于创建线性地址。不支持段覆盖。

RAX中会返回错误代码。

下表提供了有关EBLOCK叶功能的内存参数的其他信息。

错误码如下:

并发限制

操作

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

RFLAGS.ZF,CF,PF,AF,OF,SF <- 0;
RAX <- 0;

(* Check concurrency with other Intel SGX instructions *)
IF (ETRACK executed concurrently) 
    Then 
        RAX <- SGX_ENTRYEPOCH_LOCKED;
        RFLAGS.ZF <- 1;
        goto Done;
    ELSIF (Other Intel SGX instructions reading or writing EPCM) 
        RAX <- SGX_LOCKFAIL;
        RFLAGS.ZF <- 1;
        goto Done;
    FI;
FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then 
        RFLAGS.ZF <- 1;
        RAX <- SGX_PG_INVLD;
        goto Done;
FI;

IF ( (EPCM(DS:RCX).PT != PT_REG) and (EPCM(DS:RCX).PT != PT_TCS) and (EPCM(DS:RCX).PT != PT_TRIM) )
    Then 
        RFLAGS.CF <- 1;
        IF (EPCM(DS:RCX).PT = PT_SECS) 
            THEN RAX <- SGX_PG_IS_SECS;
            ELSE RAX <- SGX_NOTBLOCKABLE;
        FI;
        goto Done;
FI;

(* Check if the page is already blocked and report blocked state *)
TMP_BLKSTATE <- EPCM(DS:RCX).BLOCKED;

(* at this point, the page must be valid and PT_TCS or PT_REG or PT_TRIM*)
IF (TMP_BLKSTATE = 1) ) 
    Then 
        RFLAGS.CF <- 1;
        RAX <- SGX_BLKSTATE;
    ELSE
        EPCM(DS:RCX).BLOCKED <- 1
FI;

Done:

受影响的标志

如果SECS正被使用或无效,则设置ZF,否则将其ZF清零。 如果页面已被阻止或不可阻止,则设置CF,否则将其清零。 清零PF,AF,OF,SF。

受保护模式异常

#GP(0)                如果内存操作数有效地址超出DS段限制。

                            如果内存操作数未正确对齐。

                            如果指定的EPC资源正在被使用。

#PF(fault code)    如果在访问内存操作数时发生页面错误。

                            如果内存操作数不是EPC页面。

64位模式异常

#GP(0)                如果内存操作数不是规范格式。

                            如果内存操作数未正确对齐。

                            如果指定的EPC资源正在被使用。

#PF(fault code)    如果在访问内存操作数时发生页面错误。

                            如果内存操作数不是EPC页面。

ECREATE——在Enclave Page Cache中创建一个SECS页

ENCLS[ECREATE]是Enclave构建过程中执行的第一条指令。ECREATE将EPC外部的SECS结构复制到EPC内部的SECS页面。EPC内部的SECS数据结构是软件无法访问的。

ECREATE将在受保护的SECS中设置字段,并在EPC中将页面标记为有效。ECREATE初始化或检查未使用的字段。

软件在源结构中设置以下字段:SECS:BASEADDR, SECS:SIZE(以字节为单位)和ATTRIBUTES。SECS:BASEADDR必须按照SECS.SIZE边界进行自然对齐。SECS.SIZE最小是2页(8192字节)。

源操作数RBX包含一个PAGEINFO结构的有效地址。PAGEINFO包含源SECS的有效地址和SECEINFO的有效地址。PAGEINFO中的SECS字段未被使用(译注:后者SECS是指EPC页所需要关联的SECS,而SECS本身不需要关联SECS)。

RCX寄存器是目标SECS的有效地址。它是EPC中的一个空槽的地址。SECS结构必须是页面对齐的。SECINFO标记必须将页面指定为SECS页面。

如果SECS目标页面正被使用或已经有效或在EPC之外,那么ECREATE会出错。 如果地址未对齐或PAGEINFO中未使用的字段不为零,那么ECREATE也会出错 。

如果存储SSA帧所需的空间容量大于SECS.SSAFRAMESIZE中指定的空间容量,则会产生#GP(0)。 SSA帧所需的空间容量根据DS:TMP_SECS.ATTRIBUTES.XFRM大小进行计算。 有关大小计算的详细信息,请参见第6.7节。

并发限制

操作

IF (DS:RBX is not 32Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

TMP_SRCPGE <- DS:RBX.SRCPGE;
TMP_SECINFO <- DS:RBX.SECINFO;

IF (DS:TMP_SRCPGE is not 4KByte aligned or DS:TMP_SECINFO is not 64Byte aligned)
    Then #GP(0); FI;

IF (DS:RBX.LINADDR ! = 0 or DS:RBX.SECS != 0)
    Then #GP(0); FI;

(* Check for misconfigured SECINFO flags*)
IF (DS:TMP_SECINFO reserved fields are not zero or DS:TMP_SECINFO.FLAGS.PT != PT_SECS) ) 
    Then #GP(0); FI;

TMP_SECS <- RCX;

IF (EPC entry in use) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX).VALID = 1) 
    Then #PF(DS:RCX); FI;

(* Copy 4KBytes from source page to EPC page*)
DS:RCX[32767:0] <- DS:TMP_SRCPGE[32767:0];

(* Check lower 2 bits of XFRM are set *)
IF ( ( DS:TMP_SECS.ATTRIBUTES.XFRM BitwiseAND 03H) != 03H) 
    Then #GP(0); FI;

IF (XFRM is illegal)
    Then #GP(0); FI;

(* Make sure that the SECS does not have any unsupported MISCSELECT options*)
IF ( !(CPUID.(EAX=12H, ECX=0):EBX[31:0] & DS:TMP_SECS.MISCSELECT[31:0]) )
    THEN
        EPCM(DS:TMP_SECS).EntryLock.Release();
        #GP(0);
FI;

( * Compute size of MISC area *)
TMP_MISC_SIZE <- compute_misc_region_size();

(* Compute the size required to save state of the enclave on async exit, see Section 6.7.2.2*)
TMP_XSIZE <- compute_xsave_size(DS:TMP_SECS.ATTRIBUTES.XFRM) + GPR_SIZE + TMP_MISC_SIZE;

(* Ensure that the declared area is large enough to hold XSAVE and GPR stat *)
IF ( ( DS:TMP_SECS.SSAFRAMESIZE*4096 < TMP_XSIZE) 
    Then #GP(0); FI;

IF ( (DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 1) and (DS:TMP_SECS.BASEADDR is not canonical) )
    Then #GP(0); FI;

IF ( (DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 0) and (DS:TMP_SECS.BASEADDR and 0FFFFFFFF00000000H) )
    Then #GP(0); FI;

IF ( (DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 0) and (DS:TMP_SECS.SIZE and 0FFFFFFFF00000000H) )
    Then #GP(0); FI;

IF ( (DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 1) and (DS:TMP_SECS.SIZE and 0FFFFFFE000000000H) )
    Then #GP(0); FI;

(* Enclave size must be at least 8192 bytes and must be power of 2 in bytes*)
IF (DS:TMP_SECS.SIZE < 8192 or popcnt(DS:TMP_SECS.SIZE) > 1) 
    Then #GP(0); FI;

(* Ensure base address of an enclave is aligned on size*)
IF ( ( DS:TMP_SECS.BASEADDR and (DS:TMP_SECS.SIZE-1) ) 
    Then #GP(0); FI;

(* Ensure the SECS does not have any unsupported attributes*)
IF ( ( DS:TMP_SECS.ATTRIBUTES and (~CR_SGX_ATTRIBUTES_MASK) ) 
    Then #GP(0); FI;

IF ( ( DS:TMP_SECS reserved fields are not zero) 
    Then #GP(0); FI;

Clear DS:TMP_SECS to Uninitialized;
DS:TMP_SECS.MRENCLAVE <- SHA256INITIALIZE(DS:TMP_SECS.MRENCLAVE);
DS:TMP_SECS.ISVSVN <- 0;
DS:TMP_SECS.ISVPRODID <- 0;

(* Initialize hash updates etc*)
Initialize enclave’s MRENCLAVE update counter;

(* Add “ECREATE” string and SECS fields to MRENCLAVE *)
TMPUPDATEFIELD[63:0] <- 0045544145524345H; // “ECREATE”
TMPUPDATEFIELD[95:64] <- DS:TMP_SECS.SSAFRAMESIZE;
TMPUPDATEFIELD[159:96] <- DS:TMP_SECS.SIZE;
TMPUPDATEFIELD[511:160] <- 0; 
SHA256UPDATE(DS:TMP_SECS.MRENCLAVE, TMPUPDATEFIELD)
INC enclave’s MRENCLAVE update counter;

(* Set EID *)
DS:TMP_SECS.EID <- LockedXAdd(CR_NEXT_EID, 1);

(* Set the EPCM entry, first create SECS identifier and store the identifier in EPCM *)
EPCM(DS:TMP_SECS).PT <- PT_SECS;
EPCM(DS:TMP_SECS).ENCLAVEADDRESS <- 0;
EPCM(DS:TMP_SECS).R <- 0;
EPCM(DS:TMP_SECS).W <- 0;
EPCM(DS:TMP_SECS).X <- 0;

(* Set EPCM entry fields *)
EPCM(DS:RCX).BLOCKED <- 0;
EPCM(DS:RCX).PENDING <- 0;
EPCM(DS:RCX).MODIFIED <- 0;
EPCM(DS:RCX).VALID <- 1;

EDBGRD——从调式模式的Enclave读取

描述

这个叶功能将调试模式Enclave的EPC页面中的一个四字/双字复制到RBX寄存器中。在64位模式下读取8个字节,在非64位模式下读取4个字节。无法覆写读取的数据的大小。

EPC内部源位置的有效地址由寄存器RCX中提供。

遇到如下情况,指令出错:

该指令将忽略Enclave页面上的EPCM RWX属性。 因此,通过EDGBRD违反EPCM RWX属性不会导致#GP。

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

IF ( (TMP_MODE64 = 1) and (DS:RCX is not 8Byte Aligned) )
    Then #GP(0); FI;

IF ( (TMP_MODE64 = 0) and (DS:RCX is not 4Byte Aligned) )
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* make sure no other Intel SGX instruction is accessing EPCM *)
IF (Other EPCM modifying instructions executing) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then #PF(DS:RCX); FI;

(* make sure that DS:RCX (SOURCE) is pointing to a PT_REG or PT_TCS or PT_VA *) 
IF ( (EPCM(DS:RCX).PT != PT_REG) and (EPCM(DS:RCX).PT != PT_TCS) and (EPCM(DS:RCX).PT != PT_VA))
    Then #PF(DS:RCX); FI;

(* If source is a TCS, then make sure that the offset into the page is not beyond the TCS size*)
IF ( ( EPCM(DS:RCX). PT = PT_TCS) and ((DS:RCX) & 0xFFF >= SGX_TCS_LIMIT) ) (*访问尾数据可能超出这个限制?*)
    Then #GP(0); FI;

(* make sure the enclave owning the PT_REG or PT_TCS page allow debug *) 
IF ( (EPCM(DS:RCX).PT = PT_REG) or (EPCM(DS:RCX).PT = PT_TCS) )
    Then 
        TMP_SECS <- GET_SECS_ADDRESS;
        IF (TMP_SECS.ATTRIBUTES.DEBUG = 0) 
            Then #GP(0); FI;
        IF ( (TMP_MODE64 = 1) )
            Then RBX[63:0] <- (DS:RCX)[63:0]; 
            ELSE EBX[31:0] <- (DS:RCX)[31:0];
        FI;
    ELSE
        TMP_64BIT_VAL[63:0] <- (DS:RCX)[63:0] & (~07H); // Read contents from VA slot
        IF (TMP_MODE64 = 1) 
            THEN
                IF (TMP_64BIT_VAL != 0H) 
                    THEN RBX[63:0] <- 0FFFFFFFFFFFFFFFFH;
                    ELSE RBX[63:0] <- 0H;
                FI;
            ELSE
                IF (TMP_64BIT_VAL != 0H) 
                    THEN EBX[31:0] <- 0FFFFFFFFH;
                    ELSE EBX[31:0] <- 0H;
                FI;
        FI;
FI;

受影响的标志

保护模式异常

#GP(0)                    如果RCX中的地址违反了DS限制或访问权限。

                                如果DS段不可用。

                                如果RCX指向的内存位置未进行4字节对齐。

                                如果RCX中的地址指向属于非调试模式Enclave的页面。

                                如果RCX中的地址指向的页面不是PT_TCS,PT_REG或PT_VA。

                                如果RCX中的地址指向TCS内超出SGX_TCS_LIMIT的位置。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

64位模式异常

#GP(0)                    如果RCX非规范格式。

                                如果RCX指向的内存位置未进行8字节对齐。

                                如果RCX中的地址指向属于非调试模式Enclave的页面。

                                如果RCX中的地址指向的页面不是PT_TCS,PT_REG或PT_VA。

                                如果RCX中的地址指向TCS内超出SGX_TCS_LIMIT的位置。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

EDBGWR——向调式模式的Enclave写入

描述

这个叶功能将EBX/RBX中的内容复制到调试模式的Enclave的EPC页面。64位模式写入8个字节,非64位模式写入4个字节。无法覆写数据大小。

EPC内部源位置的有效地址由寄存器RCX中提供。

遇到如下情况,指令出错:

该指令将忽略Enclave页面上的EPCM RWX属性。 因此,通过EDGBWR违反EPCM RWX属性不会导致#GP。

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

IF ( (TMP_MODE64 = 1) and (DS:RCX is not 8Byte Aligned) )
    Then #GP(0); FI;

IF ( (TMP_MODE64 = 0) and (DS:RCX is not 4Byte Aligned) )
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* make sure no other Intel SGX instruction is accessing EPCM *)
IF (Other EPCM modifying instructions executing) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then #PF(DS:RCX); FI;

(* make sure that DS:RCX (DST) is pointing to a PT_REG or PT_TCS *) 
IF ( (EPCM(DS:RCX).PT != PT_REG) and (EPCM(DS:RCX).PT != PT_TCS) )
    Then #PF(DS:RCX); FI;

(* If destination is a TCS, then make sure that the offset into the page can only point to the FLAGS field*)
IF ( ( EPCM(DS:RCX). PT = PT_TCS) and ((DS:RCX) & 0xFF8H != offset_of_FLAGS & 0FF8H) )
    Then #GP(0); FI;
 
(* Locate the SECS for the enclave to which the DS:RCX page belongs *) 
TMP_SECS <- GET_SECS_PHYS_ADDRESS(EPCM(DS:RCX).ENCLAVESCES);

(* make sure the enclave owning the PT_REG or PT_TCS page allow debug *) 
IF (TMP_SECS.ATTRIBUTES.DEBUG = 0) 
    Then #GP(0); FI;

IF ( (TMP_MODE64 = 1) )
    Then (DS:RCX)[63:0] <- RBX[63:0]; 
    ELSE (DS:RCX)[31:0] <- EBX[31:0]; 
FI;

受影响的标志

保护模式异常

#GP(0)                    如果RCX中的地址违反了DS限制或访问权限。

                                如果DS段不可用。

                                如果RCX指向的内存位置未进行4字节对齐。

                                如果RCX中的地址指向属于非调试模式Enclave的页面。

                                如果RCX中的地址指向的页面不是PT_TCS或PT_REG。

                                如果RCX中的地址指向TCS内非FLAGS字的位置。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

64位模式异常

#GP(0)                    如果RCX非规范格式。

                                如果RCX指向的内存位置未进行8字节对齐。

                                如果RCX中的地址指向属于非调试模式Enclave的页面。

                                如果RCX中的地址指向的页面不是PT_TCS或PT_REG。

                                如果RCX中的地址指向TCS内非FLAGS字的位置。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

EEXTEND——每次以256Bit对未初始化的Enclave进行度量扩展

描述

此叶功能使用EXTEND字符串的度量值(包含"EEXTEND" || ENCLAVEOFFSET || PADDING || Enclave页的256字节)更新SECS的MRENCLAVE度量寄存器。仅当当前特权级别为0并且Enclave未初始化时,才能执行该指令。

RCX包含待度量的EPC页的256字节区域的有效地址。DS段用于创建线性地址。不支持段覆盖。

遇到如下情况,指令出错:

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

IF (DS:RCX is not 256Byte Aligned) 
    Then GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* make sure no other Intel SGX instruction is accessing EPCM *)
IF (Other instructions accessing EPCM) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then #PF(DS:RCX); FI;

(* make sure that DS:RCX (DST) is pointing to a PT_REG or PT_TCS *) 
IF ( (EPCM(DS:RCX).PT != PT_REG) and (EPCM(DS:RCX).PT != PT_TCS) )
    Then #PF(DS:RCX); FI;

TMP_SECS <- Get_SECS_ADDRESS();

(* make sure no other instruction is accessing MRENCLAVE or ATTRIBUETS.INIT *) 
IF ( (Other instruction accessing MRENCLAVE) or (Other instructions checking or updating the initialized state of the SECS)) 
    Then #GP(0); FI;

(* Calculate enclave offset *)
TMP_ENCLAVEOFFSET <- EPCM(DS:RCX).ENCLAVEADDRESS - TMP_SECS.BASEADDR;
TMP_ENCLAVEOFFSET <- TMP_ENCLAVEOFFSET + (DS:RCX & 0FFFH)

(* Add EEXTEND message and offset to MRENCLAVE *)
TMPUPDATEFIELD[63:0] <- 00444E4554584545H; // “EEXTEND”
TMPUPDATEFIELD[127:64] <- TMP_ENCLAVEOFFSET;
TMPUPDATEFIELD[511:128] <- 0; // 48 bytes
TMP_SECS.MRENCLAVE <- SHA256UPDATE(TMP_SECS.MRENCLAVE, TMPUPDATEFIELD)
INC enclave’s MRENCLAVE update counter;

(*Add 256 bytes to MRENCLAVE, 64 byte at a time *) 
TMP_SECS.MRENCLAVE <- SHA256UPDATE(TMP_SECS.MRENCLAVE, DS:RCX[511:0] );
TMP_SECS.MRENCLAVE <- SHA256UPDATE(TMP_SECS.MRENCLAVE, DS:RCX[1023: 512] );
TMP_SECS.MRENCLAVE <- SHA256UPDATE(TMP_SECS.MRENCLAVE, DS:RCX[1535: 1024] );
TMP_SECS.MRENCLAVE <- SHA256UPDATE(TMP_SECS.MRENCLAVE, DS:RCX[2047: 1536] );
INC enclave’s MRENCLAVE update counter by 4;

受影响的标志

保护模式异常

#GP(0)                    如果RCX中的地址违反了DS限制或访问权限。

                                如果RCX指向的内存位置未进行256字节对齐。

                                如果另一个指令在访问MRENCLAVE。

                                如果另一个指令在检查或更新SECS。

                                如果Enclave已经被初始化。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向的页不是PT_TCS或PT_REG。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

64位模式异常

#GP(0)                    如果RCX不是规范格式。

                                如果RCX指向的内存位置未进行256字节对齐。

                                如果另一个指令在访问MRENCLAVE。

                                如果另一个指令在检查或更新SECS。

                                如果Enclave已经被初始化。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX中的地址指向的页不是PT_TCS或PT_REG。

                                如果RCX中的地址指向非EPC页面。

                                如果RCX中的地址指向无效的EPC页面。

EINIT——初始化一个Enclave用于执行

描述

此叶功能是在Enclave构建过程中执行的最后一条指令。在EINIT指令调用之后,MRENCLAVE的度量就完成了,并且可以使用EENTER指令进入这个已经准备好的Enclave中开始执行用户代码。

EINIT会用到SIGSTRUCT和EINITTOKEN的有效地址。SIGSTRUCT包含了Enclave相关的MRENCLAVE、ATTRIBUTES、ISSVVN、3072位RSA密钥和使用此密钥的签名。 SIGSTRUCT必须填充两个值q1和q2。 这些是使用以下公式计算的:

q1 = floor(Signature^2 / Modulus);

q2 = floor((Signature^3 - q1 * Signature * Modulus) / Modulus);

 EINITTOKEN包含MRENCLAVE,MRSIGNER和ATTRIBUTES。 这些值必须与SECS中相应的值匹配。 如果EINITTOKEN是使用调试模式启动密钥创建的,则Enclave也必须处于调试模式。

EINIT执行以下步骤,如图5-1所示:

验证是否使用内含的公钥对SIGSTRUCT进行了签名。

检查SECS.MRENCLAVE的计算结果是否等于SIGSTRUCT.HASHENCLAVE。

检查SIGSTRUCT.ATTRIBUTES中保留位均设置为0,并且SIGSTRUCT.ATTRIBUTESMASK中保留位均设置为1。

检查SIGSTRUCT.ATTRIBUTES中Intel独占位未被设置,除非这是个由Intel签名的SIGSTRUCT。

检查SIGSTRUCT.ATTRIBUTES是否等于使用SECS.ATTRIBUTES对SIGSTRUCT.ATTRIBUTEMASK进行逻辑与运算的结果。

如果EINITTOKEN.VALID为0,则检查SIGSTRUCT是否由Intel签名。

如果EINITTOKEN.VALID为1,则检查EINITTOKEN的有效性。

如果EINITTOKEN.VALID为1,则检查EINITTOKEN.MRENCLAVE是否等于SECS.MRENCLAVE。

如果EINITTOKEN.VALID为1,并且EINITTOKEN.ATTRIBUTES.DEBUG为1,则SECS.ATTRIBUTES.DEBUG必须为1。

提交SECS.MRENCLAVE,并根据SIGSTRUCT设置SECS.MRSIGNER、SECS.ISVSVN和SECS.ISVPRODID。

更新SECS,标记为已初始化。

EINIT定期轮询某些异步事件。 如果检测到此类事件,它将设置失败代码(ZF = 1并且RAX = SGX_UNMASKED_EVENT),并且RIP递增以指向下一条指令。 这些事件是INTR、NMI、SMI、INIT、VMX_TIMER、MCAKIND、MCE_SMI和CMCI_SMI。 如果挂起的事件被禁止(例如,由于MOV/POP SS阻塞和STI阻塞而导致INTR被禁止),则EINIT不会失败。

并发限制

操作

(* make sure SIGSTRUCT and SECS are aligned *)
IF ( (DS:RBX is not 4KByte Aligned) or (DS:RCX is not 4KByte Aligned) )
    Then #GP(0); FI;

(* make sure the EINITTOKEN is aligned *)
IF (DS:RDX is not 512Byte Aligned) 
    Then #GP(0); FI;

(* make sure the SECS is inside the EPC *)
IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;

TMP_SIG[14463:0] <- DS:RBX[14463:0]; // 1808 bytes
TMP_TOKEN[2423:0] <- DS:RDX[2423:0]; // 304 bytes

(* Verify SIGSTRUCT Header. *)
IF ( (TMP_SIG.HEADER != 06000000E10000000000010000000000h) or ((TMP_SIG.VENDOR != 0) and (TMP_SIG.VENDOR != 00008086h) ) or (TMP_SIG HEADER2 != 01010000600000006000000001000000h) or (TMP_SIG.EXPONENT != 00000003h) or (Reserved space is not 0’s) )
    THEN 
        RFLAGS.ZF <- 1;
        RAX <- SGX_INVALID_SIG_STRUCT;
        goto EXIT;
FI;

(* Open “Event Window” Check for Interrupts. Verify signature using embedded public key, q1, and q2. Save upper 352 bytes of the PKCS1.5 encoded message into the TMP_SIG_PADDING*)
IF (interrupt was pending) {
    RFLAG.ZF <- 1;
    RAX <- SGX_UNMASKED_EVENT;
    goto EXIT;
FI
IF (signature failed to verify) {
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_SIGNATURE;
    goto EXIT;
FI;
(*Close “Event Window” *)

(* make sure no other Intel SGX instruction is modifying SECS*)
IF (Other instructions modifying SECS) 
    Then #GP(0); FI;

IF ( (EPCM(DS:RCX). VALID = 0) or (EPCM(DS:RCX).PT != PT_SECS) )
    Then #PF(DS:RCX); FI;

(* make sure no other instruction is accessing MRENCLAVE or ATTRIBUETS.INIT *) 
IF ( (Other instruction modifying MRENCLAVE) or (Other instructions modifying the SECS’s Initialized state)) 
    Then #GP(0); FI;

(* Calculate finalized version of MRENCLAVE *)
(* SHA256 algorithm requires one last update that compresses the length of the hashed message into the output SHA256 digest *)
TMP_ENCLAVE <- SHA256FINAL( (DS:RCX).MRENCLAVE, enclave’s MRENCLAVE update count *512);

(* Verify MRENCLAVE from SIGSTRUCT *)
IF (TMP_SIG.ENCLAVEHASH != TMP_MRENCLAVE)
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_MEASUREMENT;
    goto EXIT;
FI;

TMP_MRSIGNER <- SHA256(TMP_SIG.MODULUS)

(* if INTEL_ONLY ATTRIBUTES are set, SIGSTRUCT must be signed using the Intel Key *)
INTEL_ONLY_MASK <- 0000000000000020H;
IF ( ( (DS:RCX.ATTRIBUTES & INTEL_ONLY_MASK) != 0) and (TMP_MRSIGNER != CSR_INTELPUBKEYHASH) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_ATTRIBUTE;
    goto EXIT;
FI;

(* Verify SIGSTRUCT.ATTRIBUTE requirements are met *)
IF ( (DS:RCX.ATTRIBUTES & TMP_SIG.ATTRIBUTEMASK) != (TMP_SIG.ATTRIBUTE & TMP_SIG.ATTRIBUTEMASK) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_ATTRIBUTE;
    goto EXIT;
FI;

( *Verify SIGSTRUCT.MISCSELECT requirements are met *)
IF ( (DS:RCX.MISCSELECT & TMP_SIG.MISCMASK) != (TMP_SIG.MISCSELECT & TMP_SIG.MISCMASK) )
    THEN
        RFLAGS.ZF <- 1;
        RAX <- SGX_INVALID_ATTRIBUTE;
        goto EXIT
FI;

(* if EINITTOKEN.VALID[0] is 0, verify the enclave is signed by Intel *)
IF (TMP_TOKEN.VALID[0] = 0)
    IF (TMP_MRSIGNER != CSR_INTELPUBKEYHASH)
        RFLAG.ZF <- 1;
        RAX <- SGX_INVALID_EINITTOKEN;
        goto EXIT;
    FI;
    goto COMMIT;
FI;

(* Debug Launch Enclave cannot launch Production Enclaves *)
IF ( (DS:RDX.MASKEDATTRIBUTESLE.DEBUG = 1) and (DS:RCX.ATTRIBUTES.DEBUG = 0) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_EINITTOKEN;
    goto EXIT;
FI;

(* Check reserve space in EINIT token includes reserved regions and upper bits in valid field *)
IF (TMP_TOKEN reserved space is not clear)
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_EINITTOKEN;
    goto EXIT;
FI;

(* EINIT token must be <= CR_CPUSVN *)
IF (TMP_TOKEN.CPUSVN > CR_CPUSVN)
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_CPUSVN;
    goto EXIT;
FI;

(* Derive Launch key used to calculate EINITTOKEN.MAC *)
HARDCODED_PKCS1_5_PADDING[15:0] <- 0100H;
HARDCODED_PKCS1_5_PADDING[2655:16] <- SignExtend330Byte(-1); // 330 bytes of 0FFH
HARDCODED_PKCS1_5_PADDING[2815:2656] <- 2004000501020403650148866009060D30313000H;

TMP_KEYDEPENDENCIES.KEYNAME <- LAUNCH_KEY;
TMP_KEYDEPENDENCIES.ISVPRODID <- TMP_TOKEN.ISVPRODIDLE;
TMP_KEYDEPENDENCIES.ISVSVN <- TMP_TOKEN.ISVSVN;
TMP_KEYDEPENDENCIES.OWNEREPOCH <- CSR_SGXOWNEREPOCH;
TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_TOKEN.MASKEDATTRIBUTESLE;
TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- 0;
TMP_KEYDEPENDENCIES.MRENCLAVE <- 0;
TMP_KEYDEPENDENCIES.MRSIGNER <- 0;
TMP_KEYDEPENDENCIES.KEYID <- TMP_TOKEN.KEYID;
TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
TMP_KEYDEPENDENCIES.CPUSVN <- TMP_TOKEN.CPUSVN;
TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_TOKEN.MASKEDMISCSELECTLE;
TMP_KEYDEPENDENCIES.MISCMASK <- 0;
TMP_KEYDEPENDENCIES.PADDING <- HARDCODED_PKCS1_5_PADDING;

(* Calculate the derived key*) 
TMP_EINITTOKENKEY <- derivekey(TMP_KEYDEPENDENCIES);

(* Verify EINITTOKEN was generated using this CPU's Launch key and that it has not been modified since issuing by the Launch Enclave. Only 192 bytes of EINITOKEN are CMACed *)
IF (TMP_TOKEN.MAC != CMAC(TMP_EINITTOKENKEY, TMP_TOKEN[1535:0] ) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_EINIT_TOKEN;
    goto EXIT;
FI;

(* Verify EINITTOKEN (RDX) is for this enclave *)
IF (TMP_TOKEN.MRENCLAVE != TMP_MRENCLAVE) or (TMP_TOKEN.MRSIGNER != TMP_MRSIGNER) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_MEASUREMENT;
    goto EXIT;
FI;

(* Verify ATTRIBUTES in EINITTOKEN are the same as the enclave’s *)
IF (TMP_TOKEN.ATTRIBUTES != DS:RCX.ATTRIBUTES)
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_EINIT_ATTRIBUTE;
    goto EXIT;
FI;

COMMIT:
(* Commit changes to the SECS; Set ISVPRODID, ISVSVN, MRSIGNER, INIT ATTRIBUTE fields in SECS (RCX) *) 
    DS:RCX.MRENCLAVE <- TMP_MRENCLAVE;

(* MRSIGNER stores a SHA256 in little endian implemented natively on x86 *) 
    DS:RCX.MRSIGNER <- TMP_MRSIGNER;
    DS:RCX.ISVPRODID <- TMP_SIG.ISVPRODID;
    DS:RCX.ISVSVN <- TMP_SIG.ISVSVN;
    DS:RCX.PADDING <- TMP_SIG_PADDING;

(* Mark the SECS as initialized *)
    Update DS:RCX to initialized;

(* Set RAX and ZF for success*) 
    RFLAG.ZF <- 0;
    RAX <- 0;
    EXIT:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果成功,ZF清零,如果失败,ZF置位。RAX保存错误代码。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数未对齐。

                                如果其他指令修改了SECS。

                                如果Enclave已经被初始化。

                                如果SECS.MRENCLAVE正在被使用。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX解析后不是一个EPC页。

                                如果内存地址不是一个有效的、未初始化的SECS。

64位模式异常

#GP(0)                    如果内存操作数未对齐。

                                如果其他指令修改了SECS。

                                如果Enclave已经被初始化。

                                如果SECS.MRENCLAVE正在被使用。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果RCX解析后不是一个EPC页。

                                如果内存地址不是一个有效的、未初始化的SECS。

ELDB/ELDU——加载一个EPC页,并标记它的状态

描述

此叶功能将页面从常规主内存复制到EPC。作为复制过程的一部分,会对页面进行密码学的认证和解密。仅当当前特权级别为0时才能执行该指令。

复制完成后,ELDB叶功能会将EPC中目标页面对应的EPCM项的BLOCK位设置为1。复制完成后,可以调用ELDU叶功能清除EPC中目标页面对应的EPCM项的BLOCK位。

RBX包含PAGEINFO结构的有效地址;RCX包含目标EPC页面的有效地址;RDX保留版本数组槽(记录了页面的版本号)的有效地址。

下表提供了有关ELDB/ELDU叶功能的内存参数的其他信息。

错误码如下:

并发限制

操作

(* Check PAGEINFO and EPCPAGE alignment *)
IF ( (DS:RBX is not 32Byte Aligned) or (DS:RCX is not 4KByte Aligned) )
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* Check VASLOT alignment *)
IF (DS:RDX is not 8Byte aligned)
    Then #GP(0); FI;

IF (DS:RDX does not resolve within an EPC)
    Then #PF(DS:RDX); FI;

TMP_SRCPGE <- DS:RBX.SRCPGE;
TMP_SECS <- DS:RBX.SECS;
TMP_PCMD <- DS:RBXPCMD;

(* Check alignment of PAGEINFO (RBX)linked parameters. Note: PCMD pointer is overlaid on top of PAGEINFO.SECINFO field *)
IF ( (DS:TMP_PCMD is not 128Byte aligned) or (DS:TMP_SRCPGE is not 4KByte aligned) )
    Then #GP(0); FI;

(* Check concurrency of EPC and VASLOT by other Intel SGX instructions *)
IF ( (other instructions accessing EPC) or (Other instructions modifying VA slot) ) 
    Then #GP(0); FI;

(* Verify EPCM attributes of EPC page, VA, and SECS *)
IF (EPCM(DS:RCX).VALID = 1) 
    Then #PF(DS:RCX); FI;

IF ( (EPCM(DS:RDX & ~0FFFH).VALID = 0) or (EPCM(DS:RDX & ~0FFFH).PT != PT_VA) )
    Then #PF(DS:RDX); FI;

(* Copy PCMD into scratch buffer *)
SCRATCH_PCMD[1023: 0] <- DS:TMP_PCMD[1023:0];

(* Zero out TMP_HEADER*)
TMP_HEADER[sizeof(TMP_HEADER)-1: 0] <- 0;

TMP_HEADER.SECINFO <- SCRATCH_PCMD.SECINFO;
TMP_HEADER.RSVD <- SCRATCH_PCMD.RSVD;
TMP_HEADER.LINADDR <- DS:RBX.LINADDR;

(* Verify various attributes of SECS parameter *)
IF ( (TMP_HEADER.SECINFO.FLAGS.PT = PT_REG) or (TMP_HEADER.SECINFO.FLAGS.PT = PT_TCS) or (TMP_HEADER.SECINFO.FLAGS.PT = PT_TRIM) )
    Then 
        IF ( DS:TMP_SECS is not 4KByte aligned) 
            THEN #GP(0) FI;
        IF (DS:TMP_SECS does not resolve within an EPC) 
            THEN #PF(DS:TMP_SECS) FI;
        IF ( Other instructions modifying SECS) 
            THEN #GP(0) FI;
        IF ( (EPCM(DS:TMP_SECS).VALID = 0) or (EPCM(DS:TMP_SECS).PT != PT_SECS) )
            THEN #PF(DS:TMP_SECS) FI;
    ELSIF ( (TMP_HEADER.SECINFO.FLAGS.PT = PT_SECS) or (TMP_HEADER.SECINFO.FLAGS.PT = PT_VA) ) 
        IF ( ( TMP_SECS != 0) )
            THEN #GP(0) FI;
    ELSE
        #GP(0) 
FI;

IF ( (TMP_HEADER.SECINFO.FLAGS.PT = PT_REG) or (TMP_HEADER.SECINFO.FLAGS.PT = PT_TCS) or (TMP_HEADER.SECINFO.FLAGS.PT = PT_TRIM) )
    Then 
        TMP_HEADER.EID <- DS:TMP_SECS.EID;
    ELSE
        (* These pages do not have any parent, and hence no EID binding *)
        TMP_HEADER.EID <- 0;
FI;

(* Copy 4KBytes SRCPGE to secure location *)
DS:RCX[32767: 0] <- DS:TMP_SRCPGE[32767: 0];
TMP_VER <- DS:RDX[63:0];

(* Decrypt and MAC page. AES_GCM_DEC has 2 outputs, {plain text, MAC} *)
(* Parameters for AES_GCM_DEC {Key, Counter, ..} *)
{DS:RCX, TMP_MAC} <- AES_GCM_DEC(CR_BASE_PK, TMP_VER << 32, TMP_HEADER, 128, DS:RCX, 4096);

IF ( (TMP_MAC != DS:TMP_PCMD.MAC) )
    Then
        RFLAGS.ZF <- 1;
        RAX <- SGX_MAC_COMPARE_FAIL;
        goto ERROR_EXIT;
FI;

(* Check version before committing *)
IF (DS:RDX != 0)
    Then #GP(0); 
    ELSE
        DS:RDX <- TMP_VER;
FI;

(* Commit EPCM changes *)
EPCM(DS:RCX).PT <- TMP_HEADER.SECINFO.FLAGS.PT;
EPCM(DS:RCX).RWX <- TMP_HEADER.SECINFO.FLAGS.RWX;
EPCM(DS:RCX).PENDING <- TMP_HEADER.SECINFO.FLAGS.PENDING;
EPCM(DS:RCX).MODIFIED <- TMP_HEADER.SECINFO.FLAGS.MODIFIED;
EPCM(DS:RCX).ENCLAVEADDRESS <- TMP_HEADER.LINADDR;

IF ( (EAX = 07H) and (TMP_HEADER.SECINFO.FLAGS.PT is NOT PT_SECS or PT_VA))
    Then 
        EPCM(DS:RCX).BLOCKED <- 1;
    ELSE
        EPCM(DS:RCX).BLOCKED <- 0;
FI;

EPCM(DS:RCX). VALID <- 1;

RAX <- 0;
RFLAGS.ZF <- 0;

ERROR_EXIT:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果失败,ZF置位,不然ZF清零。并且RAX保存错误代码。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果指令中的EPC资源被其它对象所使用。

                                如果指令验证MAC失败。

                                如果版本数组槽正在被使用。

                                如果参数未通过一致性检查。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数理应在EPC中,但事实上解析完发现不是一个EPC页。

                                如果任一EPC内存操作数不是一个正确的页类型。

                                如果目标EPC页已被标记位有效。

64位模式异常

#GP(0)                    如果内存操作数并非标准格式。

                                如果内存操作数未被正确对齐。

                                如果指令中的EPC资源被其它对象所使用。

                                如果指令验证MAC失败。

                                如果版本数组槽正在被使用。

                                如果参数未通过一致性检查。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数理应在EPC中,但事实上解析完发现不是一个EPC页。

                                如果任一EPC内存操作数不是一个正确的页类型。

                                如果目标EPC页已被标记位有效。

EMODPR——限定EPC页权限

描述

此叶子功能限制了已初始化的Enclave中的EPC页面对应的访问权限。SECINFO参数的RWX位被视为权限掩码;与页面权限限定无关的值将无效。 仅当当前特权级别为0时才能执行该指令。

RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。

下表提供了有关EMODPR叶子功能的内存参数的其他信息。

遇到如下情况指令会出错:

并发限制

操作

IF (DS:RBX is not 64Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;

SCRATCH_SECINFO <- DS:RBX;

(* Check for mis-configured SECINFO flags*)
IF ( (SCRATCH_SECINFO reserved fields are not zero ) or !(SCRATCH_SECINFO.FLAGS.R is 0 or SCRATCH_SECINFO.FLAGS.W is not 0) )
    Then #GP(0); FI;

(* Check concurrency with SGX1 or SGX2 instructions on the EPC page *)
IF (SGX1 or other SGX2 instructions accessing EPC page) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX).VALID is 0 )
    Then #PF(DS:RCX); FI;

(* Check the EPC page for concurrency *)
IF (EPC page in use by another SGX2 instruction) 
    Then 
        RFLAGS <- 1;
        RAX <- SGX_LOCKFAIL;
        goto Done;
FI;

IF ( (EPCM(DS:RCX).PENDING is not 0 or (EPCM(DS:RCX).MODIFIED is not 0) )
    Then 
        RFLAGS <- 1;
        RAX <- SGX_PAGE_NOT_MODIFIABLE;
        goto Done;
FI;

IF (EPCM(DS:RCX).PT is not PT_REG)
    Then #PF(DS:RCX); FI;

TMP_SECS <- GET_SECS_ADDRESS

IF (TMP_SECS.ATTRIBUTES.INIT = 0)
    Then #GP(0); FI;

(* Check concurrency with ETRACK *)
IF (ETRACK executed concurrently)
    Then #GP(0); FI;

(* Update EPCM permissions *)
EPCM(DS:RCX).R <- EPCM(DS:RCX).R & SCRATCH_SECINFO.FLAGS.R;
EPCM(DS:RCX).W <- EPCM(DS:RCX).W & SCRATCH_SECINFO.FLAGS.W;
EPCM(DS:RCX).X <- EPCM(DS:RCX).X & SCRATCH_SECINFO.FLAGS.X;

RFLAGS.ZF <- 0;
RAX <- 0;

Done:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果页处于不可修改的状态或者其他SGX2指令在并发执行,ZF置位,不然ZF清零。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果内存操作数被上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果内存操作数被上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

EMODT——改变EPC页的类型

描述

此叶子功能修改EPC页面的类型。不允许以所要求的新类型访问EPC页面(通过配置安全属性),直到调用了EACCEPT叶功能确认修改操作为止。仅当当前特权级别为0时才能执行该指令。

RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。下表提供了有关EMODT叶子功能的内存参数的其他信息。

遇到如下情况指令会出错:

并发限制

操作

IF (DS:RBX is not 64Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;

SCRATCH_SECINFO <- DS:RBX;

(* Check for mis-configured SECINFO flags*)
IF ( (SCRATCH_SECINFO reserved fields are not zero ) or !(SCRATCH_SECINFO.FLAGS.PT is PT_TCS or SCRATCH_SECINFO.FLAGS.PT is PT_TRIM) )
    Then #GP(0); FI;

(* Check concurrency with SGX1 instructions on the EPC page *)
IF (other SGX1 instructions accessing EPC page) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX).VALID is 0 or !(EPCM(DS:RCX).PT is PT_REG or EPCM(DS:RCX).PT is PT_TCS))
    Then #PF(DS:RCX); FI;

(* Check the EPC page for concurrency *)
IF (EPC page in use by another SGX2 instruction) 
    Then #GP(0); FI;

(* Check for mis-configured SECINFO flags*)
IF ( (EPCM(DS:RCX).R = 0) and (SCRATCH_SECINFO.FLAGS.R = 0) and (SCRATCH_SECINFO.FLAGS.W != 0) )) 
    Then 
        RFLAGS <- 1;
        RAX <- SGX_LOCKFAIL;
        goto Done;
FI;

IF ( (EPCM(DS:RCX).PENDING is not 0 or (EPCM(DS:RCX).MODIFIED is not 0) )
    Then 
        RFLAGS <- 1;
        RAX <- SGX_PAGE_NOT_MODIFIABLE;
        goto Done;
FI;

TMP_SECS <- GET_SECS_ADDRESS

IF (TMP_SECS.ATTRIBUTES.INIT = 0)
    Then #GP(0); FI;

(* Check concurrency with ETRACK *)
IF (ETRACK executed concurrently)
    Then #GP(0); FI;

(* Update EPCM fields *)
EPCM(DS:RCX).MODIFIED <- 1;
EPCM(DS:RCX).R <- 0;
EPCM(DS:RCX).W <- 0;
EPCM(DS:RCX).X <- 0;
EPCM(DS:RCX).PT <- SCRATCH_SECINFO.FLAGS.PT;

RFLAGS.ZF <- 0;
RAX <- 0;

Done:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果页处于不可修改的状态或者其他SGX2指令在并发执行,ZF置位,不然ZF清零。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果内存操作数被上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果内存操作数被上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

EPA——添加版本数组

描述

此叶功能在EPC页面中创建一个空的版本数组,其逻辑地址由DS:RCX给出,并为该页面设置EPCM属性。在执行该指令时,必须将寄存器RBX设置为PT_VA。

下表提供了有关EPA叶功能的内存参数的其他信息。

并发限制

操作

IF (RBX != PT_VA or DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* Check concurrency with other Intel SGX instructions *)
IF (Other Intel SGX instructions accessing the page) 
    THEN #GP(0); FI;

(* Check EPC page must be empty *)
IF (EPCM(DS:RCX). VALID != 0)
    THEN #PF(DS:RCX); FI;

(* Clears EPC page *)
DS:RCX[32767:0] <- 0;
EPCM(DS:RCX).PT <- PT_VA;
EPCM(DS:RCX).ENCLAVEADDRESS <- 0;
EPCM(DS:RCX).BLOCKED <- 0;
EPCM(DS:RCX).PENDING <- 0;
EPCM(DS:RCX).MODIFIED <- 0;
EPCM(DS:RCX).RWX <- 0;
EPCM(DS:RCX).VALID <- 1;

受影响的标志

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果其他的SGX指令在访问这个EPC页。

                                如果RBX没设置为PT_VA。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页已经是有效的了。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果其他的SGX指令在访问这个EPC页。

                                如果RBX没设置为PT_VA。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页已经是有效的了。

EREMOVE——从EPC中移除一个页

描述

此叶功能使EPC页面与其SECS解除关联,并标记为未使用。 仅当当前特权级别为0时才能执行此指令叶。

RCX的内容是EPC页面的有效地址。 DS段用于创建线性地址。 不支持段覆盖。

如果操作数未正确对齐、并非引用EPC页面、该页面正在被另一个线程使用或者该页面所属的Enclave中有其他线程在运行,则该指令失败。 另外,如果操作数指向所关联的SECS,则指令将失败。

在如下情况下,指令会失败:

错误码如下:

并发限制

操作

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

TMP_SRCPGE <- DS:RBX.SRCPGE;
TMP_SECS <- DS:RBX.SECS;
TMP_SECINFO <- DS:RBX.SECINFO;
TMP_LINADDR <- DS:RBX.LINADDR;

SCRATCH_SECINFO <- DS:RBX.TMP_SECINFO;

(* Check the EPC page for concurrency *)
IF (EPC page being referenced by another Intel SGX instruction) 
    Then #GP(0); FI;

(* if DS:RCX is already unused, nothing to do*)
IF ( (EPCM(DS:RCX).VALID = 0) or (EPCM(DS:RCX).PT = PT_TRIM AND EPCM(DS:RCX).MODIFIED = 0))
    Then goto DONE; 
FI;

IF (EPCM(DS:RCX).PT = PT_VA) 
    Then 
        EPCM(DS:RCX).VALID <- 0;
        goto DONE; 
FI;

IF (EPCM(DS:RCX).PT = PT_SECS) 
    Then 
        IF (DS:RCX has an EPC page associated with it) 
            Then 
                RFLAGS.ZF <- 1;
                RAX <- SGX_CHILD_PRESENT;
                goto ERROR_EXIT;
        FI;
        EPCM(DS:RCX).VALID <- 0;
        goto DONE; 
FI;

TEMP_SECS <- Get_SECS_ADDRESS();

IF (Other threads active using SECS) 
    Then 
        RFLAGS.ZF <- 1;
        RAX <- SGX_ENCLAVE_ACT;
        goto ERROR_EXIT;
FI;

DONE:
RAX <- 0;
RFLAGS.ZF <- 0;

ERROR_EXIT:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果成功,ZF清零,如果失败,ZF置位。RAX保存错误代码。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果其他的SGX指令在访问这个EPC页。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果其他的SGX指令在访问这个EPC页。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

ETRACK——激活EBLOCK检查

描述

此叶功能为硬件提供了一种机制,以跟踪软件是否已成功完成所需的TLB地址清除。 仅当当前特权级别为0时才能执行该指令。

RCX的内容是EPC页面的有效地址。

下表提供了有关ETRACK叶子函数的内存参数的其他信息。

错误代码如下:

并发限制

操作

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

(* Check concurrency with other Intel SGX instructions *)
IF (Other Intel SGX instructions using tracking facility on this SECS) 
    Then #GP(0); FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then #PF(DS:RCX); FI;

IF (EPCM(DS:RCX).PT != PT_SECS) 
    Then #PF(DS:RCX); FI;

(* All processors must have completed the previous tracking cycle*)
IF ( (DS:RCX).TRACKING != 0) ) 
    Then 
        RFLAGS.ZF <- 1;
        RAX <- SGX_PREV_TRK_INCMPL;
        goto Done;
    ELSE
        RAX <- 0;
        RFLAGS.ZF <- 0;
FI;

Done:
RFLAGS.ZF,CF,PF,AF,OF,SF <- 0;

受影响的标志

如果SECS处于使用状态或者无效了,那么ZF置位,不然清零。CF、PF、AF、OF、SF被清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果其他线程并发地使用这个SECS上的追踪设施。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果这个特定的EPC资源在使用当中。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

EWB——使一个EPC页无效,并将它写入主内存中

描述

此叶功能将页面从EPC复制到常规主内存中。 复制过程中,页面会使用加密进行保护。 仅当当前特权级别为0时才能执行该指令。

下表提供了有关EPA叶功能的内存参数的其他信息。

并发限制

操作

IF ( (DS:RBX is not 32Byte Aligned) or (DS:RCX is not 4KByte Aligned) )
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC)
    Then #PF(DS:RCX); FI;

IF (DS:RDX is not 8Byte Aligned)
    Then #GP(0); FI;

IF (DS:RDX does not resolve within an EPC)
    Then #P(DS:RDX); FI;

(* EPCPAGE and VASLOT should not resolve to the same EPC page*)
IF (DS:RCX and DS:RDX resolve to the same EPC page)
    Then GP(0); FI;

TMP_SRCPGE <- DS:RBX.SRCPGE;

(* Note PAGEINFO.PCMD is overlaid on top of PAGEINFO.SECINFO *)
TMP_PCMD <- DS:RBX.PCMD;

If (DS:RBX.LINADDR != 0) OR (DS:RBX.SECS != 0) 
    Then #GP(0); FI;

IF ( (DS:TMP_PCMD is not 128Byte Aligned) or (DS:TMP_SRCPGE is not 4KByte Aligned) )
    Then GP(0); FI;

(* Check for concurrent Intel SGX instruction access to the page *)
IF (Other Intel SGX instruction is accessing page) 
    THEN #GP(0); FI;

(*Check if the VA Page is being removed or changed*)
IF (VA Page is being modified)
    THEN #GP(0); FI;

(* Verify that EPCPAGE and VASLOT page are valid EPC pages and DS:RDX is VA *)
IF (EPCM(DS:RCX).VALID = 0) 
    THEN #PF(DS:RCX); FI;

IF ( (EPCM(DS:RDX & ~0FFFH).VALID = 0) or (EPCM(DS:RDX & ~0xFFF).PT is not PT_VA) )
    THEN #PF(DS:RDX); FI;

(* Perform page-type-specific exception checks *)
IF ( (EPCM(DS:RCX).PT is PT_REG) or (EPCM(DS:RCX).PT is PT_TCS) or (EPCM(DS:RCX).PT is PT_TRIM ) )
    THEN
        TMP_SECS = Obtain SECS through EPCM(DS:RCX)
        (* Check that EBLOCK has occurred correctly *)
        IF (EBLOCK is not correct)
            THEN #GP(0); FI;
FI;

RFLAGS.ZF,CF,PF,AF,OF,SF <- 0;
RAX <- 0;

(* Perform page-type-specific checks *)
IF ( (EPCM(DS:RCX).PT is PT_REG) or (EPCM(DS:RCX).PT is PT_TCS) or (EPCM(DS:RCX).PT is PT_TRIM ))
    THEN
        (* check to see if the page is evictable *)
        IF (EPCM(DS:RCX).BLOCKED = 0) 
            THEN
                RAX <- SGX_PAGE NOT_BLOCKED;
                RFLAGS.ZF <- 1;
                GOTO ERROR_EXIT;
        FI;
        (* Check if tracking done correctly *)
        IF (Tracking not correct)
            THEN
                RAX <- SGX_NOT_TRACKED;
                RFLAGS.ZF <- 1;
                GOTO ERROR_EXIT;
        FI;

        (* Obtain EID to establish cryptographic binding between the paged-out page and the enclave *)
        TMP_HEADER.EID <- TMP_SECS.EID;

        (* Obtain EID as an enclave handle for software *)
        TMP_PCMD_ENCLAVEID <- TMP_SECS.EID;
    ELSE IF (EPCM(DS:RCX).PT is PT_SECS)
        (*check that there are no child pages inside the enclave *)
        IF (DS:RCX has an EPC page associated with it)
            THEN
                RAX <- SGX_CHILD_PRESENT;
                RFLAGS.ZF <- 1;
                GOTO ERROR_EXIT;
        FI:
        TMP_HEADER.EID <- 0; 
        (* Obtain EID as an enclave handle for software *)
        TMP_PCMD_ENCLAVEID <- (DS:RCX).EID;
    ELSE IF (EPCM(DS:RCX).PT is PT_VA)
        TMP_HEADER.EID <- 0; // Zero is not a special value
        (* No enclave handle for VA pages*)
        TMP_PCMD_ENCLAVEID <- 0;
FI;

(* Zero out TMP_HEADER*)
TMP_HEADER[ sizeof(TMP_HEADER)-1 : 0] <- 0;

TMP_HEADER.LINADDR <- EPCM(DS:RCX).ENCLAVEADDRESS;
TMP_HEADER.SECINFO.FLAGS.PT <- EPCM(DS:RCX).PT;
TMP_HEADER.SECINFO.FLAGS.RWX <- EPCM(DS:RCX).RWX;
TMP_HEADER.SECINFO.FLAGS.PENDING <- EPCM(DS:RCX).PENDING;
TMP_HEADER.SECINFO.FLAGS.MODIFIED <- EPCM(DS:RCX).MODIFIED;

(* Encrypt the page, DS:RCX could be encrypted in place. AES-GCM produces 2 values, {ciphertext, MAC}. *)
(* AES-GCM input parameters: key, GCM Counter, MAC_HDR, MAC_HDR_SIZE, SRC, SRC_SIZE)*)
{DS:TMP_SRCPGE, DS:TMP_PCMD.MAC} <- AES_GCM_ENC(CR_BASE_PK), (TMP_VER << 32), TMP_HEADER, 128, DS:RCX, 4096);

(* Write the output *)
Zero out DS:TMP_PCMD.SECINFO 
DS:TMP_PCMD.SECINFO.FLAGS.PT <- EPCM(DS:RCX).PT;
DS:TMP_PCMD.SECINFO.FLAGS.RWX <- EPCM(DS:RCX).RWX;
DS:TMP_PCMD.SECINFO.FLAGS.PENDING <- EPCM(DS:RCX).PENDING;
DS:TMP_PCMD.SECINFO.FLAGS.MODIFIED <- EPCM(DS:RCX).MODIFIED;
DS:TMP_PCMD.RESERVED <- 0;
DS:TMP_PCMD.ENCLAVEID <- TMP_PCMD_ENCLAVEID;
DS:RBX.LINADDR <- EPCM(DS:RCX).ENCLAVEADDRESS;

(*Check if version array slot was empty *)
IF ([DS.RDX]) 
    THEN
        RAX <- SGX_VA_SLOT_OCCUPIED
        RFLAGS.CF <- 1;
FI;

(* Write version to Version Array slot *)
[DS.RDX] <- TMP_VER; 

(* Free up EPCM Entry *)
EPCM.(DS:RCX).VALID <- 0;
EXIT:

受影响的标志

如果页没有上锁、追踪(是否清除了TLB)、存在Child,那么ZF置位,不然清零。

如果VA槽被占用了,那么CF置位,不然清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果EPC页和VASLOT解析之后发现是同一页。

                                如果其他SGX指令在并发访问目标EPC页、VA页或者SECS页。

                                如果追踪资源正在使用当中。

                                如果EPC页或版本数组页无效。

                                如果参数一致性检查失败。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果其中一个内存操作数是一个不正确的页类型。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果EPC页和VASLOT解析之后发现是同一页。

                                如果其他SGX指令在并发访问目标EPC页、VA页或者SECS页。

                                如果追踪资源正在使用当中。

                                如果EPC页或版本数组页无效。

                                如果参数一致性检查失败。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果其中一个内存操作数是一个不正确的页类型。

40.4 Intel SGX用户态叶功能参考资料

40.4.1 指令总结表中的指令栏

本节介绍了ENCLU指令助记符中可用的叶功能。 通常,每个指令叶都需要EAX来指定叶功能的索引值,同时也可能使用其他寄存器来指定叶功能的参数。“指令操作数编码表”提供了隐式编码的寄存器用法及其相关的输入/输出语义信息。

在许多情况下,输入参数指定了EPC内/外的内存对象的有效地址,这些内存对象的存储寻址语义也汇总到了单独的表中。

EACCEPT——接受对EPC页的修改

描述

此叶功能通过验证SECINFO中指定的安全属性与EPCM中页面的安全属性匹配来接受对运行中的飞地中页面的更改。 该指令叶只能在Enclave内执行。

RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。 下表提供了有关EACCEPT叶子功能的内存参数的其他信息。

遇到如下情况,指令会出错:

并发限制

操作

IF (DS:RBX is not 64Byte Aligned)
    Then #GP(0); FI;

IF (DS:RBX is not within CR_ELRANGE) 
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC) 
    Then #PF(DS:RBX); FI;

IF ( (EPCM(DS:RBX).VALID = 0) or (EPCM(DS:RBX).R = 0) or (EPCM(DS:RBX).PENDING != 0) or (EPCM(DS:RBX).MODIFIED != 0) or (EPCM(DS:RBX).BLOCKED != 0) or (EPCM(DS:RBX).PT != PT_REG) or (EPCM(DS:RBX).ENCLAVESECS != CR_ACTIVE_SECS) or
(EPCM(DS:RBX).ENCLAVEADDRESS != DS:RBX) )
    Then #PF(DS:RBX); FI;

SCRATCH_SECINFO <- DS:RBX;

(* Check for mis-configured SECINFO flags*)
IF (SCRATCH_SECINFO reserved fields are not zero ) )
    Then #GP(0); FI;

IF (DS:RCX is not 512Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not within CR_ELRANGE) 
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;
 
(* Check that the combination of requested PT, PENDING and MODIFIED is legal *)
IF (NOT ( ((SCRATCH_SECINFO.FLAGS.PT is PT_REG) and (SCRATCH_SECINFO.FLAGS.MODIFIED is 0)) or ((SCRATCH_SECINFO.FLAGS.PT is PT_TCS or PT_TRIM) and (SCRATCH_SECINFO.FLAGS.PENDING is 0) and (SCRATCH_SECINFO.FLAGS.MODIFIED is 1)) ) )
    Then #GP(0); FI

(* Check security attributes of the destination EPC page *)
If ( (EPCM(DS:RCX).VALID is 0) or (EPCM(DS:RCX).BLOCKED is not 0) or ((EPCM(DS:RCX).PT is not PT_REG) and (EPCM(DS:RCX).PT is not PT_TCS) and (EPCM(DS:RCX).PT is not PT_TRIM)) or
(EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS))
    Then #PF((DS:RCX); FI;

(* Check the destination EPC page for concurrency *)
IF ( EPC page in use ) 
    Then #GP(0); FI;

(* Re-Check security attributes of the destination EPC page *)
IF ( (EPCM(DS:RCX).VALID is 0) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) )
    Then #PF(DS:RCX); FI;

(* Verify that accept request matches current EPC page settings *)
IF ( (EPCM(DS:RCX).ENCLAVEADDRESS != DS:RCX) or (EPCM(DS:RCX).PENDING != SCRATCH_SECINFO.FLAGS.PENDING) or (EPCM(DS:RCX).MODIFIED != SCRATCH_SECINFO.FLAGS.MODIFIED) or (EPCM(DS:RCX).R != SCRATCH_SECINFO.FLAGS.R) or (EPCM(DS:RCX).W != SCRATCH_SECINFO.FLAGS.W) or (EPCM(DS:RCX).X != SCRATCH_SECINFO.FLAGS.X) or (EPCM(DS:RCX).PT != SCRATCH_SECINFO.FLAGS.PT) )
    Then
        RFLAGS <- 1;
        RAX <- SGX_PAGE_ATTRIBUTES_MISMATCH;
        goto DONE;
FI;

(* Check that all required threads have left enclave *)
IF (Tracking not correct)
    THEN
        RFLAGS.ZF <- 1;
        RAX <- SGX_NOT_TRACKED;
        goto DONE;
FI;

(* Get pointer to the SECS to which the EPC page belongs *)
TMP_SECS = << Obtain physical address of SECS through EPCM(DS:RCX)>>

(* For TCS pages, perform additional checks *)
IF (SCRATCH_SECINFO.FLAGS.PT = PT_TCS) 
    Then
        IF (DS:RCX.RESERVED != 0) #GP(0); FI;
FI;

(* Check that TCS.FLAGS.DBGOPTIN, TCS stack, and TCS status are correctly initialized *)
IF ( ((DS:RCX).FLAGS.DBGOPTIN is not 0) or ((DS:RCX).CSSA >= (DS:RCX).NSSA) or ((DS:RCX).AEP is not 0) or ((DS:RCX).STATE is not 0) 
    Then #GP(0); FI;

(* Check consistency of FS & GS Limit *)
IF ( (TMP_SECS.ATTRIBUTES.MODE64BIT is 0) and ((DS:RCX.FSLIMIT & 0xFFF != 0xFFF) or (DS:RCX.GSLIMIT & 0xFFF != 0xFFF)) )
    Then #GP(0); FI;

(* Clear PENDING/MODIFIED flags to mark accept operation complete *)
EPCM(DS:RCX).PENDING <- 0;
EPCM(DS:RCX).MODIFIED <- 0;

(* Clear EAX and ZF to indicate successful completion *)
RFLAGS.ZF <- 0;
RAX <- 0;

Done:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果页(的修改操作)不能被接受,那么ZF置位,不然清零。将CF、PF、AF、OF、SF清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页的页类型或安全属性不正确。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页的页类型或安全属性不正确。

EACCEPTCOPY——初始化一个挂起的页

描述

此叶函数将现有EPC页面的内容复制到未初始化的EPC页面(由EAUG创建)。 初始化之后,该指令还可以修改与目标EPC页面相关联的访问权限。 该指令叶只能在Enclave内执行。

RBX包含SECINFO结构的有效地址,而RCX和RDX各自包含EPC页面的有效地址。 下表提供了有关EACCEPTCOPY叶子函数的内存参数的其他信息。

遇到如下情况,指令会出错:

并发限制

操作

IF (DS:RBX is not 64Byte Aligned)
    Then #GP(0); FI;

IF ( (DS:RCX is not 4KByte Aligned) or (DS:RDX is not 4KByte Aligned) )
    Then #GP(0); FI;

IF ((DS:RBX is not within CR_ELRANGE) or (DS:RCX is not within CR_ELRANGE) or (DS:RDX is not within CR_ELRANGE))
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC) 
    Then #PF(DS:RBX); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;

IF (DS:RDX does not resolve within an EPC) 
    Then #PF(DS:RDX); FI;

IF ( (EPCM(DS:RBX).VALID = 0) or (EPCM(DS:RBX).R = 0) or (EPCM(DS:RBX).PENDING != 0) or (EPCM(DS:RBX).MODIFIED != 0) or (EPCM(DS:RBX).BLOCKED != 0) or (EPCM(DS:RBX).PT != PT_REG) or (EPCM(DS:RBX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RBX).ENCLAVEADDRESS != DS:RBX) )
    Then #PF(DS:RBX); FI;

SCRATCH_SECINFO <- DS:RBX;

(* Check for mis-configured SECINFO flags*)
IF ( (SCRATCH_SECINFO reserved fields are not zero ) or ((SCRATCH_SECINFO.FLAGS.R=0) AND(SCRATCH_SECINFO.FLAGS.W!=0 ) or (SCRATCH_SECINFO.FLAGS.PT is not PT_REG) ) 
    Then #GP(0); FI;

(* Check security attributes of the source EPC page *)
IF ( (EPCM(DS:RDX).VALID = 0) or (EPCM(DS:RDX).PENDING != 0) or (EPCM(DS:RDX).MODIFIED != 0) or (EPCM(DS:RDX).BLOCKED != 0) or (EPCM(DS:RDX).PT != PT_REG) or (EPCM(DS:RDX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RDX).ENCLAVEADDRESS != DS:RDX))
    Then #PF(DS:RDX); FI;

(* Check security attributes of the destination EPC page *)
IF ( (EPCM(DS:RCX).VALID = 0) or (EPCM(DS:RCX).PENDING != 1) or (EPCM(DS:RCX).MODIFIED != 0) or (EPCM(DS:RCX).PT != PT_REG) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) )
    Then 
        RFLAGS <- 1;
        RAX <- SGX_PAGE_ATTRIBUTE_MISMATCH; 
        goto Done;
FI;

(* Check the destination EPC page for concurrency *)
IF (destination EPC page in use ) 
    Then #GP(0); FI;

(* Re-Check security attributes of the destination EPC page *)
IF ( (EPCM(DS:RCX).VALID = 0) or (EPCM(DS:RCX).PENDING != 1) or (EPCM(DS:RCX).MODIFIED != 0) or (EPCM(DS:RCX).R != 1) or (EPCM(DS:RCX).W != 1) or (EPCM(DS:RCX).X != 0) or (EPCM(DS:RCX).PT != SCRATCH_SECINFO.FLAGS.PT) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RCX).ENCLAVEADDRESS != DS:RCX))
    Then #PF(DS:RCX); FI;

(* Copy 4KBbytes form the source to destination EPC page*)
DS:RCX[32767:0] <- DS:RDX[32767:0];

(* Update EPCM permissions *)
EPCM(DS:RCX).R <- EPCM(DS:RCX).R | SCRATCH_SECINFO.FLAGS.R;
EPCM(DS:RCX).W <- EPCM(DS:RCX).W | SCRATCH_SECINFO.FLAGS.W;
EPCM(DS:RCX).X <- EPCM(DS:RCX).X | SCRATCH_SECINFO.FLAGS.X;
EPCM(DS:RCX).PENDING <- 0;

RFLAGS.ZF <- 0;
RAX <- 0;

Done:
RFLAGS.CF,PF,AF,OF,SF <- 0;

受影响的标志

如果页未被修改,那么ZF置位,不然清零。将CF、PF、AF、OF、SF清零。

保护模式异常

#GP(0)                    如果内存操作数的有效地址在DS段限长之外。

                                如果内存操作数未被正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页的页类型或安全属性不正确。

64位模式异常

#GP(0)                    如果内存操作数不是规范格式。

                                如果内存操作数未被正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果内存操作数不是一个EPC页。

                                如果EPC页的页类型或安全属性不正确。

EENTER——进入一个Enclave

描述

ENCLU [EENTER]指令将执行流转到Enclave。 指令结束时,逻辑处理器将在RIP(= EnclaveBase + TCS.OENTRY)上以Enclave模式执行。如果目标地址不在CS段内(32位)或不规范(64位),则结果为#GP(0)。

EENTER是一个序列化指令。遇到如下情况,指令会出错:

EENTER执行以下操作:

  • EENTER时,RSP和RBP会被保存到当前的SSA帧中,并在EEXIT或中断时自动恢复。
  • RCX中包含的AEP存储到TCS中供AEX使用。FS和GS(包括隐藏部分)会被保存,并且会使用TCS.OFSBASE/GSBASE(32位和64位模式)和TCS.OFSLIMIT/GSLIMIT(仅限32位模式)作为新值。产生的段必须是DS段的子集。
  • 如果CR4.OSXSAVE == 1,则保存XCR0并将其替换为SECS.ATTRIBUTES.XFRM。RFLAGS.TF的效力取决于进入Enclave时是Opt-in还是是Opt-out(请参阅第7.1.2节):

—Opt-out进入时,TF将被保存,然后清零(在EEXIT或AEX时被恢复)。在Enclave内,尝试通过POPF指令设置TF只会将TF清零(请参见第7.2.6节)。

—Opt-in进入时,在EENTER之后,立即在指令边界上挂起单步调试异常(请参见第7.2.3节)。

  • 所有与ELRANGE不重叠的代码断点也会被抑制。如果进入方式是Opt-out,则将抑制与ELRANGE重叠的所有代码和数据断点。
  • Opt-out时,会修改或抑制许多性能监视的计数器和行为(请参见第7.2.4节):

—除增加和触发FIXED_CTR1和FIXED_CTR2外,当前线程上的所有性能监视活动均被抑制。

— PEBS被抑制。

—将其他线程上的AnyThread降级为MyThread模式,并在该线程上设置IA32_PERF_GLOBAL_STATUS [60]

—如果硬件线程的opt-out进入导致所有性能监视被禁止,则处理器将设置IA32_PERF_GLOBAL_STATUS [60]和A32_PERF_GLOBAL_STATUS [63]。

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

(* Make sure DS is usable, expand up *)
IF (TMP_MODE64 = 0 and (DS not usable or ( ( DS[S] = 1) and (DS[bit 11] = 0) and DS[bit 10] = 1) ) ) )
    Then #GP(0); FI;

(* Check that CS, SS, DS, ES.base is 0 *)
IF (TMP_MODE64 = 0)
    Then 
        IF(CS.base != 0 or DS.base != 0) #GP(0); FI;
        IF(ES usable and ES.base != 0) #GP(0); FI;
        IF(SS usable and SS.base != 0) #GP(0); FI;
        IF(SS usable and SS.B = 0) #GP(0); FI;
FI;

IF (DS:RBX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC)
    Then #PF(DS:RBX); FI;

(* Check AEP is canonical*)
IF (TMP_MODE64 = 1 and (DS:RCX is not canonical) )
    Then #GP(0); FI;

(* Check concurrency of TCS operation*)
IF (Other Intel SGX instructions is operating on TCS) 
    Then #GP(0); FI;

(* TCS verification *)
IF (EPCM(DS:RBX).VALID = 0) 
    Then #PF(DS:RBX); FI;

IF (EPCM(DS:RBX).BLOCKED = 1) 
    Then #PF(DS:RBX); FI;

IF ( (EPCM(DS:RBX).ENCLAVEADDRESS != DS:RBX) or (EPCM(DS:RBX).PT != PT_TCS) )
    Then #PF(DS:RBX); FI;

IF ((EPCM(DS:RBX).PENDING = 1) or (EPCM(DS:RBX).MODIFIED = 1))
    Then #PF(DS:RBX); FI;

IF ( (DS:RBX).OSSA is not 4KByte Aligned)
    Then #GP(0); FI;

(* Check proposed FS and GS *)
IF ( ( (DS:RBX).OFSBASE is not 4KByte Aligned) or ( (DS:RBX).OGSBASE is not 4KByte Aligned) )
    Then #GP(0); FI;

(* Get the SECS for the enclave in which the TCS resides *)
TMP_SECS <- Address of SECS for TCS;

(* Check proposed FS/GS segments fall within DS *)
IF (TMP_MODE64 = 0)
    Then 
        TMP_FSBASE <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR;
        TMP_FSLIMIT <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR + (DS:RBX).FSLIMIT;
        TMP_GSBASE <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR;
        TMP_GSLIMIT <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR + (DS:RBX).GSLIMIT;

    (* if FS wrap-around, make sure DS has no holes*)
    IF (TMP_FSLIMIT < TMP_FSBASE)
        THEN 
            IF (DS.limit < 4GB) THEN #GP(0); FI;
        ELSE
            IF (TMP_FSLIMIT > DS.limit) THEN #GP(0); FI;
    FI;
    
    (* if GS wrap-around, make sure DS has no holes*)
    IF (TMP_GSLIMIT < TMP_GSBASE)
        THEN 
            IF (DS.limit < 4GB) THEN #GP(0); FI;
        ELSE
            IF (TMP_GSLIMIT > DS.limit) THEN #GP(0); FI;
    FI;
ELSE
    TMP_FSBASE <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR;
    TMP_GSBASE <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR;
    IF ( (TMP_FSBASE is not canonical) or (TMP_GSBASE is not canonical))
        THEN #GP(0); FI;
FI;

(* Ensure that the FLAGS field in the TCS does not have any reserved bits set *)
IF ( ( (DS:RBX).FLAGS && 0xFFFFFFFFFFFFFFFE) != 0) 
    Then #GP(0); FI;

(* SECS must exist and enclave must have previously been EINITted *)
IF (the enclave is not already initialized) 
    Then #GP(0); FI;

(* make sure the logical processor’s operating mode matches the enclave *)
IF ( (TMP_MODE64 != TMP_SECS.ATTRIBUTES.MODE64BIT) )
    Then #GP(0); FI;

IF (CR4.OSFXSR = 0)
    Then #GP(0); FI;

(* Check for legal values of SECS.ATTRIBUTES.XFRM *)
IF (CR4.OSXSAVE = 0)
    Then 
        IF (TMP_SECS.ATTRIBUES.XFRM != 03H) THEN #GP(0); FI;
    ELSE
        IF ( (TMP_SECS.ATTRIBUES.XFRM & XCR0) != TMP_SECS.ATTRIBUES.XFRM) THEN #GP(0); FI;
FI;

(* Make sure the SSA contains at least one more frame *)
IF ( (DS:RBX).CSSA >= (DS:RBX).NSSA) 
    Then #GP(0); FI;

(* Compute linear address of SSA frame *)
TMP_SSA <- (DS:RBX).OSSA + TMP_SECS.BASEADDR + 4096 * TMP_SECS.SSAFRAMESIZE * (DS:RBX).CSSA;
TMP_XSIZE <- compute_XSAVE_frame_size(TMP_SECS.ATTRIBUTES.XFRM);

FOR EACH TMP_SSA_PAGE = TMP_SSA to TMP_SSA + TMP_XSIZE
    (* Check page is read/write accessible *)
    Check that DS:TMP_SSA_PAGE is read/write accessible; 
    If a fault occurs, release locks, abort and deliver that fault;

    IF (DS:TMP_SSA_PAGE does not resolve to EPC page) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF (EPCM(DS:TMP_SSA_PAGE).VALID = 0) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF (EPCM(DS:TMP_SSA_PAGE).BLOCKED = 1) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF ((EPCM(DS:TMP_SSA_PAGE).PENDING = 1) or (EPCM(DS:TMP_SSA_PAGE).MODIFIED = 1))
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF ( ( EPCM(DS:TMP_SSA_PAGE).ENCLAVEADDRESS != DS:TMPSSA_PAGE) or (EPCM(DS:TMP_SSA_PAGE).PT != PT_REG) or (EPCM(DS:TMP_SSA_PAGE).ENCLAVESECS != EPCM(DS:RBX).ENCLAVESECS) or (EPCM(DS:TMP_SECS).R = 0) or (EPCM(DS:TMP_SECS).W = 0) )
        Then #PF(DS:TMP_SSA_PAGE); FI;
    CR_XSAVE_PAGE_n <- Physical_Address(DS:TMP_SSA_PAGE);
ENDFOR

(* Compute address of GPR area*)
TMP_GPR <- TMP_SSA + 4096 * DS:TMP_SECS.SSAFRAMESIZE -- sizeof(GPRSGX_AREA);
If a fault occurs; release locks, abort and deliver that fault;

IF (DS:TMP_GPR does not resolve to EPC page) 
    Then #PF(DS:TMP_GPR); FI;
IF (EPCM(DS:TMP_GPR).VALID = 0) 
    Then #PF(DS:TMP_GPR); FI;
IF (EPCM(DS:TMP_GPR).BLOCKED = 1) 
    Then #PF(DS:TMP_GPR); FI;
IF ((EPCM(DS:TMP_GPR).PENDING = 1) or (EPCM(DS:TMP_GPR).MODIFIED = 1))
    Then #PF(DS:TMP_GPR); FI;
IF ( ( EPCM(DS:TMP_GPR).ENCLAVEADDRESS != DS:TMP_GPR) or (EPCM(DS:TMP_GPR).PT != PT_REG) or (EPCM(DS:TMP_GPR).ENCLAVESECS != EPCM(DS:RBX).ENCLAVESECS) or (EPCM(DS:TMP_GPR).R = 0) or (EPCM(DS:TMP_GPR).W = 0) )
    Then #PF(DS:TMP_GPR); FI;

IF (TMP_MODE64 = 0)
    Then 
        IF (TMP_GPR + (GPR_SIZE -1) is not in DS segment) Then #GP(0); FI;
FI;

CR_GPR_PA <- Physical_Address (DS: TMP_GPR);

(* Validate TCS.OENTRY *)
TMP_TARGET <- (DS:RBX).OENTRY + TMP_SECS.BASEADDR;
IF (TMP_MODE64 = 1)
    Then 
        IF (TMP_TARGET is not canonical) Then #GP(0); FI;
    ELSE
        IF (TMP_TARGET > CS limit) Then #GP(0); FI;
FI;

(* Ensure the enclave is not already active and this thread is the only one using the TCS*)
IF (DS:RBX.STATE = ACTIVE)) 
    Then #GP(0); FI;

CR_ENCALVE_MODE <- 1;
CR_ACTIVE_SECS <- TMP_SECS;
CR_ELRANGE <- (TMPSECS.BASEADDR, TMP_SECS.SIZE);

(* Save state for possible AEXs *)
CR_TCS_PA <- Physical_Address (DS:RBX);
CR_TCS_LA <- RBX;
CR_TCS_LA.AEP <- RCX;

(* Save the hidden portions of FS and GS *)
CR_SAVE_FS_selector <- FS.selector;
CR_SAVE_FS_base <- FS.base;
CR_SAVE_FS_limit <- FS.limit;
CR_SAVE_FS_access_rights <- FS.access_rights;
CR_SAVE_GS_selector <- GS.selector;
CR_SAVE_GS_base <- GS.base;
CR_SAVE_GS_limit <- GS.limit;
CR_SAVE_GS_access_rights <- GS.access_rights;

(* If XSAVE is enabled, save XCR0 and replace it with SECS.ATTRIBUTES.XFRM*)
IF (CR4.OSXSAVE = 1) 
    CR_SAVE_XCR0 <- XCR0;
    XCR0 <- TMP_SECS.ATTRIBUTES.XFRM;
FI;

(* Set CR_ENCLAVE_ENTRY_IP *)
CR_ENCLAVE_ENTRY_IP <- CRIP“
RIP <- NRIP;
RAX <- (DS:RBX).CSSA;

(* Save the outside RSP and RBP so they can be restored on interrupt or EEXIT *)
DS:TMP_SSA.U_RSP <- RSP; 
DS:TMP_SSA.U_RBP <- RBP; 

(* Do the FS/GS swap *)
FS.base <- TMP_FSBASE;
FS.limit <- DS:RBX.FSLIMIT;
FS.type <- 0001b;
FS.W <- DS.W;
FS.S <- 1;
FS.DPL <- DS.DPL;
FS.G <- 1;
FS.B <- 1;
FS.P <- 1;
FS.AVL <- DS.AVL;
FS.L <- DS.L;
FS.unusable <- 0;
FS.selector <- 0BH;

GS.base <- TMP_GSBASE;
GS.limit <- DS:RBX.GSLIMIT;
GS.type <- 0001b;
GS.W <- DS.W;
GS.S <- 1;
GS.DPL <- DS.DPL;
GS.G <- 1;
GS.B <- 1;
GS.P <- 1;
GS.AVL <- DS.AVL;
GS.L <- DS.L;
GS.unusable <- 0;
GS.selector <- 0BH;

CR_DBGOPTIN <- TSC.FLAGS.DBGOPTIN;
Suppress_all_code_breakpoints_that_are_outside_ELRANGE;

IF (CR_DBGOPTIN = 0) 
    THEN
        Suppress_all_code_breakpoints_that_overlap_with_ELRANGE;
        CR_SAVE_TF <- RFLAGS.TF;
        RFLAGS.TF <- 0;
        Suppress_monitor_trap_flag for the source of the execution of the enclave;
        Clear_all_pending_debug_exceptions;
        Clear_pending_MTF_VM_exit;
    ELSE
        IF (RFLAGS.TF = 1) 
            Then Pend_Single-Step_#DB_at_the_end_of_ENTER; FI;
        IF (VMCS.MTF = 1) 
            Then Pend_MTF_VM_exit_at_the_end_of_ENTER; FI;
FI;

Flush_linear_context;
Allow_front_end_to_begin_fetch_at_new_RIP;

受影响的标志

RFLAGS.TF在opt-out 进入时会被清零。

保护模式异常

#GP(0)                     如果DS:RBX没有页面对齐。

                                如果Enclave未初始化。

                                如果TCS指定的部分或全部FS或GS段在DS段之外或未正确对齐。

                                如果线程未处于INACTIVE状态。

                                如果CS、DS、ES或SS的基址都不都是零。

                                如果在Enclave内执行。

                                如果在TCS FLAG中置位了任何保留字段。

                                如果目标地址不在CS段中。

                                如果CR4.OSFXSR = 0。

                                如果CR4.OSXSAVE = 0并且SECS.ATTRIBUTES.XFRM != 0x3。

                                如果CR4.OSXSAVE = 1并且SECS.ATTRIBUTES.XFRM不是XCR0的子集。

#PF(fault code)        如果在访问内存时发生页面错误。

                                如果DS:RBX没有指向有效的TCS。

                                如果当前SSA帧的一页或多页不可读/不可写,或者无法解析为有效的PT_REG类型的EPC页。

#NM                         如果置位了CR0.TS。

64位模式异常

#GP(0)                     如果DS:RBX没有页面对齐。

                                如果Enclave未初始化。

                                如果线程未处于INACTIVE状态。

                                如果CS、DS、ES或SS的基址都不都是零。

                                如果在Enclave内执行。

                                如果TCS指定的FS或GS段的部分或全部处于DS段之外或未正确对齐。

                                如果目标地址非法。

                                如果CR4.OSFXSR = 0。

                                如果CR4.OSXSAVE = 0并且SECS.ATTRIBUTES.XFRM != 0x3。

                                如果CR4.OSXSAVE = 1并且SECS.ATTRIBUTES.XFRM不是XCR0的子集。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果DS:RBX没有指向有效的TCS。

                                如果当前SSA帧的一页或多页不可读/不可写,或者无法解析为有效的PT_REG类型的EPC页。

#NM                         如果置位了CR0.TS。

EEXIT——退出一个Enclave

描述

ENCLU[EEXIT]指令退出当前正在执行的Enclave并跳转到RBX中指定的位置。RCX接收当前的AEP。如果RBX不在CS之内(32位模式)或是不规范的(64位模式),则会产生#GP(0)。

如果RBX指定的地址在Enclave内,则该指令将正常完成。 获取的下一条指令位于Enclave外,但将尝试从Enclave内部进行获取。下个目标指令会开始具备中止页面语义的效果。

如果任何寄存器中包含机密信息,则Enclave软件有责任清除这些寄存器。

如果在进入Enclave时修改了XCR0,则该指令会将其恢复成最近一次EENTER或ERESUME时保存的值。

如果opt-out退出,则从先前EENTER时保存的值恢复RFLAGS.TF。

代码和数据断点不受抑制。

性能监视计数器不受抑制。

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

IF (TMP_MODE64 = 1)
    Then 
        IF (RBX is not canonical) Then #GP(0); FI;
    ELSE
        IF (RBX > CS limit) Then #GP(0); FI;
FI;

TMP_RIP <- CRIP;
RIP <- RBX;

(* Return current AEP in RCX *)
RCX <- CR_TCS_PA.AEP;

(* Do the FS/GS swap *)
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;

(* Restore XCR0 if needed *)
IF (CR4.OSXSAVE = 1) 
    XCR0 <- CR_SAVE__XCR0;
FI;

Unsuppress_all_code_breakpoints_that_are_outside_ELRANGE;

IF (CR_DBGOPTIN = 0) 
    THEN
        UnSuppress_all_code_breakpoints_that_overlap_with_ELRANGE;
        Restore suppressed breakpoint matches;
        RFLAGS.TF <- CR_SAVE_TF;
        UnSuppress_montior_trap_flag;
        UnSuppress_LBR_Generation;
        UnSuppress_performance monitoring_activity;
        Restore performance monitoring counter AnyThread demotion to MyThread in enclave back to AnyThread
FI;

IF (RFLAGS.TF = 1) 
    Pend Single-Step #DB at the end of EEXIT;
FI;

IF (VMCS.MTF = 1) 
    Pend MTF VM exit at the end of EEXIT;
FI;

CR_ENCLAVE_MODE <- 0;
CR_TCS_PA.STATE <- INACTIVE;

(* Assure consistent translations *)
Flush_linear_context;

受影响的标志

从以前EENTER或ERESUME时保存的值恢复RFLAGS.TF。

保护模式异常

#GP(0)                    如果在Enclave之外执行。

                                如果RBX在CS段之外。

#PF(fault code)       如果在访问内存时发生页面错误。

64位模式异常

#GP(0)                    如果在Enclave之外执行。

                                如果RBX不规范。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

EGETKEY——检索一个密码学密钥

描述

ENCLU[EGETKEY]指令从处理器特定的密钥层次结构返回128位秘密密钥。寄存器RBX包含KEYREQUEST结构的有效地址,指令将对其进行解释以确定所请求的密钥。 下面的“请求密钥”小节提供了可以请求的密钥的描述信息。RCX寄存器包含用于返回给调用者密钥的有效地址。RBX和RCX中的两个地址都应位于安全区域内。

EGETKEY派生密钥会使用处理器唯一值并基于许多可能的输入来创建特定密钥。 该指令叶只能在Enclave内执行。

验证操作数后,指令确定要生成哪个密钥并执行以下操作:

  • 该指令根据表5-43组合出密钥的派生数据
  • 使用派生数据和包特定值计算派生密钥
  • 将计算出的密钥输出到RCX中的地址

如果操作数未正确对齐,则指令将以#GP(0)失败。指令成功完成时将清除RFLAGS.{ZF,CF,AF,OF,SF,PF}。如果用户尝试基于无效的CPUSVN或ISVSVN来请求密钥(当用户请求被接受时,请参见下表)、请求其未被授权的密钥或请求未被硬件支持的密钥,那么该指令将返回错误代码。这些检查可以以任何顺序执行。因此,当通过错误编号表示一个错误原因(例如,无效属性)时,并不意味着没有其他错误了。因此,对于同一个Enclave,不同的处理器可能会给出不同的错误编号。软件的正确性不应依赖于本节中记录的检查顺序。在这种情况下,将ZF标志置1,并在RAX中设置相应的错误位(SGX_INVALID_SVN、SGX_INVALID_ATTRIBUTE、SGX_INVALID_KEYNAME),并且RCX指定地址中的数据不会被修改。

请求密钥

KEYREQUEST结构(请参阅第2.17.1节)标识要提供的密钥。 Keyrequest.KeyName字段标识请求的密钥类型。

派生密钥

密钥派生基于Enclave特定值(请参见表5-43)和一个处理器密钥的组合。根据所请求的密钥,字段值可以来源于定义或KeyReques。 表5-43中的“Yes”表示该字段的值来源于默认位置,在源行号中定义,而“Request”表示该字段的值来源于KeyRequest字段。

允许指定CPU或ISV编号的SVN的密钥还有其他额外的要求。调用者可能不会为除当前CPU或ISV以外的SVN去请求密钥。

根据硬编码PKCS填充常数(352字节字符串)派生某些密钥:

HARDCODED_PKCS1_5_PADDING [15:0] ß 0100H;

HARDCODED_PKCS1_5_PADDING [2655:16] ß SignExtend330Byte(-1); // 330个字节的0FFH

HARDCODED_PKCS1_5_PADDING [2815:2656] ß 2004000501020403650148866009060D30313000H;

错误编码如下:

并发限制

操作

(* Make sure KEYREQUEST is properly aligned and inside the current enclave *)
IF ( (DS:RBX is not 128Byte aligned) or (DS:RBX is within CR_ELRANGE) ) 
    THEN #GP(0); FI;

(* Make sure DS:RBX is an EPC address and the EPC page is valid *)
IF ( (DS:RBX does not resolve to an EPC address) or (EPCM(DS:RBX).VALID = 0) ) 
    THEN #PF(DS:RBX); FI;

IF (EPCM(DS:RBX).BLOCKED = 1) ) 
    THEN #PF(DS:RBX); FI;

(* Check page parameters for correctness *)
IF ( (EPCM(DS:RBX).PT != PT_REG) or (EPCM(DS:RBX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RBX).PENDING = 1) or (EPCM(DS:RBX).MODIFIED = 1) or (EPCM(DS:RBX).ENCLAVEADDRESS != (DS:RBX & ~0FFFH) ) or (EPCM(DS:RBX).R = 0) ) 
    THEN #PF(DS:RBX); 
FI;

(* Make sure OUTPUTDATA is properly aligned and inside the current enclave *)
IF ( (DS:RCX is not 16Byte aligned) or (DS:RCX is within CR_ELRANGE) ) 
    THEN #GP(0); FI;

(* Make sure DS:RCX is an EPC address and the EPC page is valid *)
IF ( (DS:RCX does not resolve to an EPC address) or (EPCM(DS:RCX).VALID = 0) ) 
    THEN #PF(DS:RCX); FI;

IF (EPCM(DS:RCX).BLOCKED = 1) ) 
    THEN #PF(DS:RCX); FI;

(* Check page parameters for correctness *)
IF ( (EPCM(DS:RCX).PT != PT_REG) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RCX).PENDING = 1) or (EPCM(DS:RCX).MODIFIED = 1) or (EPCM(DS:RCX).ENCLAVEADDRESS != (DS:RCX & ~0FFFH) ) or (EPCM(DS:RCX).W = 0) ) 
    THEN #PF(DS:RCX); 
FI;

(* Verify RESERVED spaces in KEYREQUEST are valid *)
IF ( (DS:RBX).RESERVED != 0) or (DS:RBX.KEYPOLICY.RESERVED != 0) ) 
    THEN #GP(0); FI;

TMP_CURRENTSECS <- CR_ACTIVE_SECS;

(* Determine which enclave attributes that must be included in the key. Attributes that must always be include INIT & DEBUG *)
REQUIRED_SEALING_MASK[127:0] <- 00000000 00000000 00000000 00000003H;
TMP_ATTRIBUTES <- (DS:RBX.ATTRIBUTEMASK | REQUIRED_SEALING_MASK) & TMP_CURRENTSECS.ATTRIBUTES;

(* Compute MISCSELECT fields to be included *)
TMP_MISCSELECT <- DS:RBX.MISCMASK & TMP_CURRENTSECS.MISCSELECT
CASE (DS:RBX.KEYNAME)
    SEAL_KEY:
        IF (DS:RBX.CPUSVN is beyond current CPU configuration)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_CPUSVN;
                goto EXIT;
        FI;
        IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ISVSVN;
                goto EXIT;
        FI;
        // Include enclave identity?
        TMP_MRENCLAVE <- 0;
        IF (DS:RBX.KEYPOLICY.MRENCLAVE = 1)
            THEN TMP_MRENCLAVE <- TMP_CURRENTSECS.MRENCLAVE;
        FI;

        // Include enclave author?
        TMP_MRSIGNER <- 0;
        IF (DS:RBX.KEYPOLICY.MRSIGNER = 1)
            THEN TMP_MRSIGNER <- TMP_CURRENTSECS.MRSIGNER;
        FI;
        //Determine values key is based on
        TMP_KEYDEPENDENCIES.KEYNAME <- SEAL_KEY;
        TMP_KEYDEPENDENCIES.ISVPRODID <- TMP_CURRENTSECS.ISVPRODID;
        TMP_KEYDEPENDENCIES.ISVSVN <- DS:RBX.ISVSVN;
        TMP_KEYDEPENDENCIES.OWNEREPOCH <- CSR_SEOWNEREPOCH;
        TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_ATTRIBUTES;
        TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- DS:RBX.ATTRIBUTEMASK;
        TMP_KEYDEPENDENCIES.MRENCLAVE <- TMP_MRENCLAVE;
        TMP_KEYDEPENDENCIES.MRSIGNER <- TMP_MRSIGNER;
        TMP_KEYDEPENDENCIES.KEYID <- DS:RBX.KEYID;
        TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
        TMP_KEYDEPENDENCIES.CPUSVN <- DS:RBX.CPUSVN;
        TMP_KEYDEPENDENCIES.PADDING <- TMP_CURRENTSECS.PADDING;
        TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_MISCSELECT;
        TMP_KEYDEPENDENCIES.MISCMASK <- ~DS:RBX.MISCMASK;
        BREAK;
    REPORT_KEY:
        //Determine values key is based on
        TMP_KEYDEPENDENCIES.KEYNAME <- REPORT_KEY;
        TMP_KEYDEPENDENCIES.ISVPRODID <- 0;
        TMP_KEYDEPENDENCIES.ISVSVN <- 0;
        TMP_KEYDEPENDENCIES.OWNEREPOCH <- CSR_SEOWNEREPOCH;
        TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_CURRENTSECS.ATTRIBUTES;
        TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- 0;
        TMP_KEYDEPENDENCIES.MRENCLAVE <- TMP_CURRENTSECS.MRENCLAVE;
        TMP_KEYDEPENDENCIES.MRSIGNER <- 0;
        TMP_KEYDEPENDENCIES.KEYID <- DS:RBX.KEYID;
        TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
        TMP_KEYDEPENDENCIES.CPUSVN <- CR_CPUSVN;
        TMP_KEYDEPENDENCIES.PADDING <- HARDCODED_PKCS1_5_PADDING;
        TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_CURRENTSECS.MISCSELECT;
        TMP_KEYDEPENDENCIES.MISCMASK <- 0;
        BREAK;
    EINITTOKEN_KEY:
        (* Check ENCLAVE has LAUNCH capability *)
        IF (TMP_CURRENTSECS.ATTRIBUTES.LAUNCHKEY = 0)
            THEN 
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ATTRIBUTE;
                goto EXIT;
        FI;
        IF (DS:RBX.CPUSVN is beyond current CPU configuration)
            THEN 
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_CPUSVN;
                goto EXIT;
        FI;
        IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ISVSVN;
                goto EXIT;
        FI;
        (* Determine values key is based on *)
        TMP_KEYDEPENDENCIES.KEYNAME <- EINITTOKEN_KEY;
        TMP_KEYDEPENDENCIES.ISVPRODID <- TMP_CURRENTSECS.ISVPRODID
        TMP_KEYDEPENDENCIES.ISVSVN <- DS:RBX.ISVSVN;
        TMP_KEYDEPENDENCIES.OWNEREPOCH <- CSR_SEOWNEREPOCH;
        TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_ATTRIBUTES;
        TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- 0;
        TMP_KEYDEPENDENCIES.MRENCLAVE <- 0;
        TMP_KEYDEPENDENCIES.MRSIGNER <- 0;
        TMP_KEYDEPENDENCIES.KEYID <- DS:RBX.KEYID; 
        TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
        TMP_KEYDEPENDENCIES.CPUSVN <- DS:RBX.CPUSVN;
        TMP_KEYDEPENDENCIES.PADDING <- TMP_CURRENTSECS.PADDING;
        TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_MISCSELECT;
        TMP_KEYDEPENDENCIES.MISCMASK <- 0;
        BREAK;
    PROVISION_KEY: // Check ENCLAVE has PROVISIONING capability
        IF (TMP_CURRENTSECS.ATTRIBUTES.PROVISIONKEY = 0)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ATTRIBUTE;
                goto EXIT;
        FI;
        IF (DS:RBX.CPUSVN is beyond current CPU configuration)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_CPUSVN;
                goto EXIT;
        FI;
        IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ISVSVN;
                goto EXIT;
        FI;
        (* Determine values key is based on *)
        TMP_KEYDEPENDENCIES.KEYNAME <- PROVISION_KEY;
        TMP_KEYDEPENDENCIES.ISVPRODID <- TMP_CURRENTSECS.ISVPRODID;
        TMP_KEYDEPENDENCIES.ISVSVN <- DS:RBX.ISVSVN;
        TMP_KEYDEPENDENCIES.OWNEREPOCH <- 0;
        TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_ATTRIBUTES;
        TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- DS:RBX.ATTRIBUTEMASK;
        TMP_KEYDEPENDENCIES.MRENCLAVE <- 0;
        TMP_KEYDEPENDENCIES.MRSIGNER <- TMP_CURRENTSECS.MRSIGNER;
        TMP_KEYDEPENDENCIES.KEYID <- 0;
        TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- 0;
        TMP_KEYDEPENDENCIES.CPUSVN <- DS:RBX.CPUSVN;
        TMP_KEYDEPENDENCIES.PADDING <- TMP_CURRENTSECS.PADDING;
        TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_MISCSELECT;
        TMP_KEYDEPENDENCIES.MISCMASK <- ~DS:RBX.MISCMASK;
        BREAK;
    PROVISION_SEAL_KEY:
        (* Check ENCLAVE has PROVISIONING capability *)
        IF (TMP_CURRENTSECS.ATTRIBUTES.PROVISIONKEY = 0) 
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ATTRIBUTE;
                goto EXIT;
        FI;
        IF (DS:RBX.CPUSVN is beyond current CPU configuration)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_CPUSVN;
                goto EXIT;
        FI;
        IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)
            THEN
                RFLAGS.ZF <- 1;
                RAX <- SGX_INVALID_ISVSVN;
                goto EXIT;
        FI;
        (* Determine values key is based on *)
        TMP_KEYDEPENDENCIES.KEYNAME <- PROVISION_SEAL_KEY;
        TMP_KEYDEPENDENCIES.ISVPRODID <- TMP_CURRENTSECS.ISVPRODID;
        TMP_KEYDEPENDENCIES.ISVSVN <- DS:RBX.ISVSVN;
        TMP_KEYDEPENDENCIES.OWNEREPOCH <- 0;
        TMP_KEYDEPENDENCIES.ATTRIBUTES <- TMP_ATTRIBUTES;
        TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- DS:RBX.ATTRIBUTEMASK;
        TMP_KEYDEPENDENCIES.MRENCLAVE <- 0;
        TMP_KEYDEPENDENCIES.MRSIGNER <- TMP_CURRENTSECS.MRSIGNER;
        TMP_KEYDEPENDENCIES.KEYID <- 0;
        TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
        TMP_KEYDEPENDENCIES.CPUSVN <- DS:RBX.CPUSVN;
        TMP_KEYDEPENDENCIES.PADDING <- TMP_CURRENTSECS.PADDING;
        TMP_KEYDEPENDENCIES.MISCSELECT <- TMP_MISCSELECT;
        TMP_KEYDEPENDENCIES.MISCMASK <- ~DS:RBX.MISCMASK;
        BREAK;
    DEFAULT:
        (* The value of KEYNAME is invalid *)
        RFLAGS.ZF <- 1;
        RAX <- SGX_INVALID_KEYNAME;
        goto EXIT:
ESAC;

(* Calculate the final derived key and output to the address in RCX *)
TMP_OUTPUTKEY <- derivekey(TMP_KEYDEPENDENCIES);
DS:RCX[15:0] <- TMP_OUTPUTKEY;
RAX <- 0;
RFLAGS.ZF <- 0;

EXIT:
RFLAGS.CF <- 0;
RFLAGS.PF <- 0;
RFLAGS.AF <- 0;
RFLAGS.OF <- 0;
RFLAGS.SF <- 0; 

受影响的标志

如果成功将ZF清零,否则置位ZF。 CF,PF,AF,OF,SF被清零。

保护模式异常

#GP(0)                    如果内存操作数有效地址在当前Enclave之外。

                                如果有效地址未正确对齐。

                                如果有效地址超出了DS段的限制。

                                如果KEYREQUEST格式无效。

#PF(fault code)       如果在访问内存时发生页面错误。

64位模式异常

#GP(0)                    如果内存操作数有效地址在当前Enclave之外。

                                如果有效地址未正确对齐。

                                如果有效地址不规范。

                                如果KEYREQUEST格式无效。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

EMODPE——扩展一个EPC页的权限

描述

此叶功能扩展了运行中的Enclave的EPC页面的访问权限。 SECINFO参数的RWX位被视为权限掩码;提供与扩展页面权限无关的值将无效。该指令叶只能在Enclave内执行。

RBX包含SECINFO结构的有效地址,而RCX包含EPC页面的有效地址。下表提供了有关EMODPE叶子函数的内存参数的其他信息。

遇到如下情况指令会出错:

并发限制

操作

IF (DS:RBX is not 64Byte Aligned)
    Then #GP(0); FI;

IF (DS:RCX is not 4KByte Aligned)
    Then #GP(0); FI;

IF ((DS:RBX is not within CR_ELRANGE) or (DS:RCX is not within CR_ELRANGE) )
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC) 
    Then #PF(DS:RBX); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #PF(DS:RCX); FI;

IF ( (EPCM(DS:RBX).VALID = 0) or (EPCM(DS:RBX).R = 0) or (EPCM(DS:RBX).PENDING != 0) or (EPCM(DS:RBX).MODIFIED != 0) or (EPCM(DS:RBX).BLOCKED != 0) or (EPCM(DS:RBX).PT != PT_REG) or (EPCM(DS:RBX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RBX).ENCLAVEADDRESS != DS:RBX) )
    Then #PF(DS:RBX); FI;

SCRATCH_SECINFO <- DS:RBX;

(* Check for mis-configured SECINFO flags*)
IF (SCRATCH_SECINFO reserved fields are not zero ) 
    Then #GP(0); FI;

(* Check security attributes of the EPC page *)
IF ( (EPCM(DS:RCX).VALID = 0) or (EPCM(DS:RCX).PENDING != 0) or (EPCM(DS:RCX).MODIFIED != 0) or (EPCM(DS:RCX).BLOCKED != 0) or (EPCM(DS:RCX).PT != PT_REG) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) )
    Then #PF(DS:RCX); FI;

(* Check the EPC page for concurrency *)
IF (EPC page in use by another SGX2 instruction) 
    Then #GP(0); FI;

(* Re-Check security attributes of the EPC page *)
IF ( (EPCM(DS:RCX).VALID = 0) or (EPCM(DS:RCX).PENDING != 0) or (EPCM(DS:RCX).MODIFIED != 0) or (EPCM(DS:RCX).BLOCKED != 0) or (EPCM(DS:RCX).PT != PT_REG) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RCX).ENCLAVEADDRESS != DS:RCX))
    Then #PF(DS:RCX); FI;

(* Check for mis-configured SECINFO flags*)
IF ( (EPCM(DS:RCX).R = 0) and (SCRATCH_SECINFO.FLAGS.R = 0) and (SCRATCH_SECINFO.FLAGS.W != 0) )) 
    Then #GP(0); FI;

(* Update EPCM permissions *)
EPCM(DS:RCX).R <- EPCM(DS:RCX).R | SCRATCH_SECINFO.FLAGS.R;
EPCM(DS:RCX).W <- EPCM(DS:RCX).W | SCRATCH_SECINFO.FLAGS.W;
EPCM(DS:RCX).X <- EPCM(DS:RCX).X | SCRATCH_SECINFO.FLAGS.X;

受影响的标志

保护模式异常

#GP(0)                    如果内存操作数有效地址超出了DS段的限制。

                                如果内存操作数未正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

64位模式异常

#GP(0)                    如果内存操作数格式不规范。

                                如果内存操作数未正确对齐。

                                如果内存操作数上锁了。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

EREPORT——创建一个Enclave的密码学报告

描述

该叶函数创建描述该Enclave内容的加密报告。 该指令叶只能在Enclave内执行。 其他Enclave可以使用该加密报告来确定此Enclave在同一平台上运行。

RBX包含Enclave的MRENCLAVE值的有效地址,并将被用来验证指令输出的REPORT(会用到EGETKEY命令产出的REPORT密钥)。 RCX包含64字节REPORTDATA结构的有效地址,该结构允许指令调用者将数据与调用者Enclave相关联。 RDX包含指令输出的REPORT的地址。

该指令叶执行以下操作:

  1. 验证三个操作数(RBX,RCX,RDX)是否在Enclave内;
  2. 根据位于RBX(TARGETINFO)中的值,为目标Enclave计算一个报告密钥;
  3. 组装Enclave SECS数据以完成REPORT结构(包括使用RCX(REPORTDATA)操作数提供的数据);
  4. 根据REPORT结构计算密码学哈希;
  5. 将计算出的哈希添加到REPORT结构中;
  6. 将完成的REPORT结构输出到RDX(OUTPUTDATA)中的地址;

如果操作数未正确对齐,则指令失败

用于提供密钥耗尽保护的CR_REPORT_KEYID,作为统计学唯一值,在平台启动时由SGX TCB中的可信实体进行填充。

遇到如下情况指令会出错:

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

(* Address verification for TARGETINFO (RBX) *)
IF ( (DS:RBX is not 128Byte Aligned) or (DS:RBX is not within CR_ELRANGE) )
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC) 
    Then #PF(DS:RBX); FI;

IF (EPCM(DS:RBX). VALID = 0)
    Then #PF(DS:RBX); FI;

IF (EPCM(DS:RBX).BLOCKED = 1) ) 
    THEN #PF(DS:RBX); FI;

(* Check page parameters for correctness *)
IF ( (EPCM(DS:RBX).PT != PT_REG) or (EPCM(DS:RBX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RBX).PENDING = 1) or (EPCM(DS:RBX).MODIFIED = 1) or (EPCM(DS:RBX).ENCLAVEADDRESS != (DS:RBX & ~0FFFH) ) or (EPCM(DS:RBX).R = 0) )
    THEN #PF(DS:RBX);  
FI;

(* Address verification for REPORTDATA (RCX) *)
IF ( (DS:RCX is not 128Byte Aligned) or (DS:RCX is not within CR_ELRANGE) )
    Then #GP(0); FI;

IF (DS:RCX does not resolve within an EPC) 
    Then #P(DS:RCX); FI;

IF (EPCM(DS:RCX). VALID = 0)
    Then #PF(DS:RCX); FI;

IF (EPCM(DS:RCX).BLOCKED = 1) ) 
    THEN #PF(DS:RCX); FI;

(* Check page parameters for correctness *)
IF ( (EPCM(DS:RCX).PT != PT_REG) or (EPCM(DS:RCX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RCX).PENDING = 1) or (EPCM(DS:RCX).MODIFIED = 1) or (EPCM(DS:RCX).ENCLAVEADDRESS != (DS:RCX & ~0FFFH) ) or (EPCM(DS:RCX).R = 0) ) 
    THEN #PF(DS:RCX); 
FI;

(* Address verification for OUTPUTDATA (RDX) *)
IF ( (DS:RDX is not 512Byte Aligned) or (DS:RDX is not within CR_ELRANGE) )
    Then #GP(0); FI;

IF (DS:RDX does not resolve within an EPC) 
    Then #PF(DS:RDX); FI;

IF (EPCM(DS:RDX). VALID = 0)
    Then #PF(DS:RDX); FI;

IF (EPCM(DS:RDX).BLOCKED = 1) ) 
    THEN #PF(DS:RDX); FI;

(* Check page parameters for correctness *)
IF ( (EPCM(DS:RDX).PT != PT_REG) or (EPCM(DS:RDX).ENCLAVESECS != CR_ACTIVE_SECS) or (EPCM(DS:RDX).ENCLAVEADDRESS != (DS:RDX & ~0FFFH) ) or (EPCM(DS:RDX).W = 0) ) 
    THEN #PF(DS:RDX); 
FI;

(* REPORT MAC needs to be computed over data which cannot be modified *)
TMP_REPORT.CPUSVN <- CR_CPUSVN;
TMP_REPORT.ISVPRODID <- TMP_CURRENTSECS.ISVPRODID;
TMP_REPORT.ISVSVN <- TMP_CURRENTSECS..ISVSVN;
TMP_REPORT.ATTRIBUTES <- TMP_CURRENTSECS.ATTRIBUTES;
TMP_REPORT.REPORTDATA <- DS:RCX[511:0];
TMP_REPORT.MRENCLAVE <- TMP_CURRENTSECS.MRENCLAVE;
TMP_REPORT.MRSIGNER <- TMP_CURRENTSECS.MRSIGNER;
TMP_REPORT.MRRESERVED <- 0;
TMP_REPORT.KEYID[255:0] <- CR_REPORT_KEYID;
TMP_REPORT.MISCSELECT <- TMP_CURRENTSECS.MISCSELECT;

(* Derive the report key *)
TMP_KEYDEPENDENCIES.KEYNAME <- REPORT_KEY;
TMP_KEYDEPENDENCIES.ISVPRODID <- 0;
TMP_KEYDEPENDENCIES.ISVSVN <- 0;
TMP_KEYDEPENDENCIES.OWNEREPOCH <- CSR_SGX_OWNEREPOCH;
TMP_KEYDEPENDENCIES.ATTRIBUTES <- DS:RBX.ATTRIBUTES;
TMP_KEYDEPENDENCIES.ATTRIBUTESMASK <- 0;
TMP_KEYDEPENDENCIES.MRENCLAVE <- DS:RBX.MEASUREMENT;
TMP_KEYDEPENDENCIES.MRSIGNER <- 0;
TMP_KEYDEPENDENCIES.KEYID <- TMP_REPORT.KEYID;
TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES <- CR_SEAL_FUSES;
TMP_KEYDEPENDENCIES.CPUSVN <- CR_CPUSVN;
TMP_KEYDEPENDENCIES.PADDING <- TMP_CURRENTSECS.PADDING;
TMP_KEYDEPENDENCIES.MISCSELECT <- DS:RBX.MISCSELECT;
TMP_KEYDEPENDENCIES.MISCMASK <- 0;

(* Calculate the derived key*)
TMP_REPORTKEY <- derive_key(TMP_KEYDEPENDENCIES);

(* call cryptographic CMAC function, CMAC data are not including MAC&KEYID *)
TMP_REPORT.MAC <- cmac(TMP_REPORTKEY, TMP_REPORT[3071:0] );
DS:RDX[3455: 0] <- TMP_REPORT;

受影响的标志

保护模式异常

#GP(0)                    如果RCX地址超出了DS段的限制。

                                如果内存操作数未正确对齐。

                                如果内存操作数不在当前的Enclave中。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

64位模式异常

#GP(0)                    如果RCX格式不规范。

                                如果内存操作数未正确对齐。

                                如果内存操作数不在当前的Enclave中。

#PF(fault code)       如果在访问内存操作数时发生页面错误。

ERESUME——重新进入一个Enclave

描述

ENCLU[ERESUME]指令使用先前存储在SSA中的机器状态,并使Enclave从中断中(由于异常或中断)恢复执行。

遇到如下情况指令会出错:

如果设置了CR0.TS,则ERESUME会生成#NM异常。

ERESUME执行以下操作:

  • ERESUME时将RSP和RBP保存到当前SSA帧中,并在EEXIT时或由于中断事件发生而异步退出时自动恢复。
  • RCX中包含的AEP会被存储到TCS中供AEX使用。将FS和GS(包括隐藏部分)保存起来,并使用TCS.OFSBASE/GSBASE(32位和64位模式)和TCS.OFSLIMIT/GSLIMIT(仅限32位模式)构建新值。产生的段必须是DS段的子集。
  • 如果CR4.OSXSAVE == 1,则保存XCR0并将其替换为SECS.ATTRIBUTES.XFRM。RFLAGS.TF的效果取决于进入Enclave时是opt-in还是opt-out(请参阅第7.1.2节):

—opt-out进入时,将保存TF并随后清零(在EEXIT或AEX时将其还原)。在Enclave内时,通过POPF指令设置TF的任何尝试都只会清零TF(请参见第7.2.6节)。

—Opt-in进入时,在EENTER之后,立即在指令边界上挂起单步调试异常(请参见第7.2.3节)。

  • 所有与ELRANGE不重叠的代码断点也会被抑制。如果进入方式是Opt-out,则将抑制与ELRANGE重叠的所有代码和数据断点。
  • Opt-out时,会修改或抑制许多性能监视的计数器和行为(请参见第7.2.4节):

—除增加和触发FIXED_CTR1和FIXED_CTR2外,当前线程上的所有性能监视活动均被抑制。

— PEBS被抑制。

—将其他线程上的AnyThread降级为MyThread模式,并在该线程上设置IA32_PERF_GLOBAL_STATUS [60]

—如果硬件线程的opt-out进入导致所有性能监视被禁止,则处理器将设置IA32_PERF_GLOBAL_STATUS [60]和A32_PERF_GLOBAL_STATUS [63]。

并发限制

操作

TMP_MODE64 <- ((IA32_EFER.LMA = 1) && (CS.L = 1));

(* Make sure DS is usable, expand up *)
IF (TMP_MODE64 = 0 and (DS not usable or ( ( DS[S] = 1) and (DS[bit 11] = 0) and DS[bit 10] = 1) ) ) )
    Then #GP(0); FI;

(* Check that CS, SS, DS, ES.base is 0 *)
IF (TMP_MODE64 = 0)
    Then 
        IF(CS.base != 0 or DS.base != 0) GP(0); FI;
        IF(ES usable and ES.base != 0) GP(0); FI;
        IF(SS usable and SS.base != 0) GP(0); FI;
        IF(SS usable and SS.B = 0) GP(0); FI;
FI;

IF (DS:RBX is not 4KByte Aligned)
    Then #GP(0); FI;

IF (DS:RBX does not resolve within an EPC)
    Then #PF(DS:RBX); FI;

(* Check AEP is canonical*)
IF (TMP_MODE64 = 1 and (DS:RCX is not canonical) )
    Then #GP(0); FI;

(* Check concurrency of TCS operation*)
IF (Other Intel SGX instructions is operating on TCS) 
    Then #GP(0); FI;

(* TCS verification *)
IF (EPCM(DS:RBX).VALID = 0) 
    Then #PF(DS:RBX); FI;

IF (EPCM(DS:RBX).BLOCKED = 1) 
    Then #PF(DS:RBX); FI;

IF ((EPCM(DS:RBX).PENDING = 1) or (EPCM(DS:RBX).MODIFIED = 1))
    Then #PF(DS:RBX); FI;

IF ( (EPCM(DS:RBX).ENCLAVEADDRESS != DS:RBX) or (EPCM(DS:RBX).PT != PT_TCS) )
    Then #PF(DS:RBX); FI;

IF ( (DS:RBX).OSSA is not 4KByte Aligned)
    Then #GP(0); FI;

(* Check proposed FS and GS *)
IF ( ( (DS:RBX).OFSBASE is not 4KByte Aligned) or ( (DS:RBX).OGSBASE is not 4KByte Aligned) )
    Then #GP(0); FI;

(* Get the SECS for the enclave in which the TCS resides *)
TMP_SECS <- Address of SECS for TCS;

(* Make sure that the FLAGS field in the TCS does not have any reserved bits set *)
IF ( ( (DS:RBX).FLAGS && 0xFFFFFFFFFFFFFFFE) != 0) 
    Then #GP(0); FI;

(* SECS must exist and enclave must have previously been EINITted *)
IF (the enclave is not already initialized) 
    Then #GP(0); FI;

(* make sure the logical processor’s operating mode matches the enclave *)
IF ( (TMP_MODE64 != TMP_SECS.ATTRIBUTES.MODE64BIT) )
    Then #GP(0); FI;

IF (CR4.OSFXSR = 0)
    Then #GP(0); FI;

(* Check for legal values of SECS.ATTRIBUTES.XFRM *)
IF (CR4.OSXSAVE = 0)
    Then 
        IF (TMP_SECS.ATTRIBUES.XFRM != 03H) THEN #GP(0); FI;
    ELSE
        IF ( (TMP_SECS.ATTRIBUES.XFRM & XCR0) != TMP_SECS.ATTRIBUES.XFRM) THEN #GP(0);                 
        FI;
FI;

(* Make sure the SSA contains at least one active frame *)
IF ( (DS:RBX).CSSA = 0) 
    Then #GP(0); FI;

(* Compute linear address of SSA frame *)
TMP_SSA <- (DS:RBX).OSSA + TMP_SECS.BASEADDR + 4096 * TMP_SECS.SSAFRAMESIZE * ( (DS:RBX).CSSA - 1);
TMP_XSIZE <- compute_XSAVE_frame_size(TMP_SECS.ATTRIBUTES.XFRM);

FOR EACH TMP_SSA_PAGE = TMP_SSA to TMP_SSA + TMP_XSIZE
    (* Check page is read/write accessible *)
    Check that DS:TMP_SSA_PAGE is read/write accessible; 
    If a fault occurs, release locks, abort and deliver that fault;
    IF (DS:TMP_SSA_PAGE does not resolve to EPC page) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF (EPCM(DS:TMP_SSA_PAGE).VALID = 0) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF (EPCM(DS:TMP_SSA_PAGE).BLOCKED = 1) 
        Then #PF(DS:TMP_SSA_PAGE); FI;
    IF ((EPCM(DS:TMP_SSA_PAGE).PENDING = 1) or (EPCM(DS:TMP_SSA_PAGE_.MODIFIED = 1))
        THEN #PF(DS:TMP_SSA_PAGE); FI;
    IF ( ( EPCM(DS:TMP_SSA_PAGE).ENCLAVEADDRESS != DS:TMPSSA_PAGE) or (EPCM(DS:TMP_SSA_PAGE).PT != PT_REG) or (EPCM(DS:TMP_SSA_PAGE).ENCLAVESECS != EPCM(DS:RBX).ENCLAVESECS) or (EPCM(DS:TMP_SECS).R = 0) or (EPCM(DS:TMP_SECS).W = 0) )
Then #PF(DS:TMP_SSA_PAGE); FI;
    CR_XSAVE_PAGE_n <- Physical_Address(DS:TMP_SSA_PAGE);
ENDFOR

(* Compute address of GPR area*)
TMP_GPR <- TMP_SSA + 4096 * DS:TMP_SECS.SSAFRAMESIZE -- sizeof(GPRSGX_AREA);
Check that DS:TMP_SSA_PAGE is read/write accessible; 
If a fault occurs, release locks, abort and deliver that fault;
IF (DS:TMP_GPR does not resolve to EPC page) 
    Then #PF(DS:TMP_GPR); FI;
IF (EPCM(DS:TMP_GPR).VALID = 0)
    Then #PF(DS:TMP_GPR); FI;
IF (EPCM(DS:TMP_GPR).BLOCKED = 1) 
    Then #PF(DS:TMP_GPR); FI;
IF ((EPCM(DS:TMP_GPR).PENDING = 1) or (EPCM(DS:TMP_GPR).MODIFIED = 1))
    THEN #PF(DS:TMP_GPR); FI;
IF ( ( EPCM(DS:TMP_GPR).ENCLAVEADDRESS != DS:TMP_GPR) or (EPCM(DS:TMP_GPR).PT != PT_REG) or (EPCM(DS:TMP_GPR).ENCLAVESECS != EPCM(DS:RBX).ENCLAVESECS) or (EPCM(DS:TMP_GPR).R = 0) or (EPCM(DS:TMP_GPR).W = 0) )
    Then #PF(DS:TMP_GPR); FI;

IF (TMP_MODE64 = 0)
    Then 
        IF (TMP_GPR + (GPR_SIZE -1) is not in DS segment) Then #GP(0); FI;
FI;

CR_GPR_PA <- Physical_Address (DS: TMP_GPR);

TMP_TARGET <- (DS:TMP_GPR).RIP;
IF (TMP_MODE64 = 1)
    Then 
        IF (TMP_TARGET is not canonical) Then #GP(0); FI;
    ELSE
        IF (TMP_TARGET > CS limit) Then #GP(0); FI;
FI;

(* Check proposed FS/GS segments fall within DS *)
IF (TMP_MODE64 = 0)
    Then 
        TMP_FSBASE <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR;
        TMP_FSLIMIT <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR + (DS:RBX).FSLIMIT;
        TMP_GSBASE <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR;
        TMP_GSLIMIT <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR + (DS:RBX).GSLIMIT;
        (* if FS wrap-around, make sure DS has no holes*)
        IF (TMP_FSLIMIT < TMP_FSBASE)
            THEN 
                IF (DS.limit < 4GB) THEN #GP(0); FI;
            ELSE
                IF (TMP_FSLIMIT > DS.limit) THEN #GP(0); FI;
        FI;
        (* if GS wrap-around, make sure DS has no holes*)
        IF (TMP_GSLIMIT < TMP_GSBASE)
            THEN 
                IF (DS.limit < 4GB) THEN #GP(0); FI;
            ELSE
                IF (TMP_GSLIMIT > DS.limit) THEN #GP(0); FI;
        FI;
    ELSE
        TMP_FSBASE <- (DS:RBX).OFSBASE + TMP_SECS.BASEADDR;
        TMP_GSBASE <- (DS:RBX).OGSBASE + TMP_SECS.BASEADDR;
        IF ( (TMP_FSBASE is not canonical) or (TMP_GSBASE is not canonical))
            THEN #GP(0); FI;
FI;

(* Ensure the enclave is not already active and this thread is the only one using the TCS*)
IF (DS:RBX.STATE = ACTIVE))
    Then #GP(0); FI;

(* SECS.ATTRIBUTES.XFRM selects the features to be saved. *)
(* CR_XSAVE_PAGE_n: A list of 1 or more physical address of pages that contain the XSAVE area. *)
XRSTOR(TMP_MODE64, SECS.ATTRIBUTES.XFRM, CR_XSAVE_PAGE_n);

IF (XRSTOR failed with #GP) 
    THEN
        DS:RBX.STATE <- INACTIVE;
        #GP(0);
FI;

CR_ENCALVE_MODE <- 1;
CR_ACTIVE_SECS <- TMP_SECS;
CR_ELRANGE <- (TMP_SECS.BASEADDR, TMP_SECS.SIZE);

(* Save sate for possible AEXs *)
CR_TCS_PA <- Physical_Address (DS:RBX);
CR_TCS_LA <- RBX;
CR_TCS_LA.AEP <- RCX;

(* Save the hidden portions of FS and GS *)
CR_SAVE_FS_selector <- FS.selector;
CR_SAVE_FS_base <- FS.base;
CR_SAVE_FS_limit <- FS.limit;
CR_SAVE_FS_access_rights <- FS.access_rights;
CR_SAVE_GS_selector <- GS.selector;
CR_SAVE_GS_base <- GS.base;
CR_SAVE_GS_limit <- GS.limit;
CR_SAVE_GS_access_rights <- GS.access_rights;

(* Set CR_ENCLAVE_ENTRY_IP *)
CR_ENCLAVE_ENTRY_IP <- CRIP"
RIP <- TMP_TARGET;
Restore_GPRs from DS:TMP_GPR;

(*Restore the RFLAGS values from SSA*)
RFLAGS.CF <- DS:TMP_GPR.RFLAGS.CF;
RFLAGS.PF <- DS:TMP_GPR.RFLAGS.PF;
RFLAGS.AF <- DS:TMP_GPR.RFLAGS.AF;
RFLAGS.ZF <- DS:TMP_GPR.RFLAGS.ZF;
RFLAGS.SF <- DS:TMP_GPR.RFLAGS.SF;
RFLAGS.DF <- DS:TMP_GPR.RFLAGS.DF;
RFLAGS.OF <- DS:TMP_GPR.RFLAGS.OF;
RFLAGS.NT <- DS:TMP_GPR.RFLAGS.NT;
RFLAGS.AC <- DS:TMP_GPR.RFLAGS.AC;
RFLAGS.ID <- DS:TMP_GPR.RFLAGS.ID;
RFLAGS.RF <- DS:TMP_GPR.RFLAGS.RF;
RFLAGS.VM <- 0;
IF (RFLAGS.IOPL = 3) 
    Then RFLAGS.IF = DS:TMP_GPR.IF; FI;
IF (TCS.FLAGS.OPTIN = 0) 
    Then RFLAGS.TF = 0; FI;

(* If XSAVE is enabled, save XCR0 and replace it with SECS.ATTRIBUTES.XFRM*)
IF (CR4.OSXSAVE = 1) 
    CR_SAVE_XCR0 <- XCR0;
    XCR0 <- TMP_SECS.ATTRIBUTES.XFRM;
FI;

(* Pop the SSA stack*)
(DS:RBX).CSSA <- (DS:RBX).CSSA -1;

(* Do the FS/GS swap *)
FS.base <- TMP_FSBASE;
FS.limit <- DS:RBX.FSLIMIT;
FS.type <- 0001b;
FS.W <- DS.W;
FS.S <- 1;
FS.DPL <- DS.DPL;
FS.G <- 1;
FS.B <- 1;
FS.P <- 1;
FS.AVL <- DS.AVL;
FS.L <- DS.L;
FS.unusable <- 0;
FS.selector <- 0BH;

GS.base <- TMP_GSBASE;
GS.limit <- DS:RBX.GSLIMIT;
GS.type <- 0001b;
GS.W <- DS.W;
GS.S <- 1;
GS.DPL <- DS.DPL;
GS.G <- 1;
GS.B <- 1;
GS.P <- 1;
GS.AVL <- DS.AVL;
GS.L <- DS.L;
GS.unusable <- 0;
GS.selector <- 0BH;

CR_DBGOPTIN <- TSC.FLAGS.DBGOPTIN;
Suppress_all_code_breakpoints_that_are_outside_ELRANGE;

IF (CR_DBGOPTIN = 0) 
    THEN
        Suppress_all_code_breakpoints_that_overlap_with_ELRANGE;
        CR_SAVE_TF <- RFLAGS.TF;
        RFLAGS.TF <- 0;
        Suppress_monitor_trap_flag for the source of the execution of the enclave;
        Clear_all_pending_debug_exceptions;
        Clear_pending_MTF_VM_exit;
    ELSE
        Clear all pending debug exceptions;
        Clear pending MTF VM exits;
FI;

(* Assure consistent translations *)
Flush_linear_context;
Clear_Monitor_FSM;
Allow_front_end_to_begin_fetch_at_new_RIP;

受影响的标志

opt-out进入时,RFLAGS.TF会被清零。

保护模式异常

#GP(0)                     如果DS:RBX没有页面对齐。

                                如果Enclave未初始化。

                                如果线程未处于INACTIVE状态。

                                如果CS、DS、ES或SS的基址都不都是零。

                                如果在Enclave内执行。

                                如果部分或全部TCS指定的FS或GS段位于DS段之外。

                                如果在TCS FLAG中置位了任何保留字段。

                                如果目标地址不在CS段中。

                                如果CR4.OSFXSR = 0。

                                如果CR4.OSXSAVE = 0并且SECS.ATTRIBUTES.XFRM != 0x3。

                                如果CR4.OSXSAVE = 1并且SECS.ATTRIBUTES.XFRM不是XCR0的子集。

#PF(fault code)        如果在访问内存时发生页面错误。

                                如果DS:RBX没有指向有效的TCS。

                                如果当前SSA帧的一页或多页不可读/不可写,或者无法解析为有效的PT_REG类型的EPC页。

#NM                         如果置位了CR0.TS。

64位模式异常

#GP(0)                     如果DS:RBX没有页面对齐。

                                如果Enclave未初始化。

                                如果线程未处于INACTIVE状态。

                                如果CS、DS、ES或SS的基址都不都是零。

                                如果在Enclave内执行。

                                如果部分或全部TCS指定的FS或GS段处于DS段之外。

                                如果在TCS FLAG中置位了任何保留字段。

                                如果目标地址不规范。

                                如果CR4.OSFXSR = 0。

                                如果CR4.OSXSAVE = 0并且SECS.ATTRIBUTES.XFRM != 0x3。

                                如果CR4.OSXSAVE = 1并且SECS.ATTRIBUTES.XFRM不是XCR0的子集。

#PF(fault code)        如果在访问内存操作数时发生页面错误。

                                如果DS:RBX没有指向有效的TCS。

                                如果当前SSA帧的一页或多页不可读/不可写,或者无法解析为有效的PT_REG类型的EPC页。

#NM                         如果置位了CR0.TS。

第42章 Enclave代码调试和配置

42.1 配置和控制

42.1.2 工具链Opt-in

TCS.FLAGS.DBGOPTIN位控制着某些调试和配置特征与Enclave的交互,包括代码/数据断点、TF、RF、监视器陷入标志、BTF、LBR、BTM、BTS和性能监视。 通过EADD添加EPC页面时,该位会被强制设为零。 调试器可以通过EDBGWR将调试模式的Enclave的TCS中的此位进行置位。

将TCS.FLAGS.DBGOPTIN设置为0时,通过TCS进入Enclave称为Opt-out进入。 相反,将TCS.FLAGS.DBGOPTIN设置为1时,通过TCS进入Enclave称为Opt-in进入。

42.2 单步调试

42.2.3 单步调试ENCLU指令页

非特权的Intel SGX指令ENCLU的交互取决于叶。

在某些情况下,通过ENCLU的EENTER/ERESUME叶函数进入Enclave可能会清除RFLAGS.TF位,并抑制监视器陷阱标志。在这种情况下,通过EEXIT叶子函数或通过AEX从Enclave退出时,将恢复RFLAGS.TF位和监视器陷阱标志的有效性。有关清除/抑制的详细信息以及跨EENTER/ERESUME/EEXIT/AEX的单步事件的精确挂起操作,将在第7.2.4节中详细介绍。

如果在EREPORT或EGETKEY叶的开始处设置了RFLAGS.TF位,那么单步调试异常将在ENCLU指令调用之后立即在指令边界上挂起。此外,如果从VMX 客户虚拟机调用了该指令,并且在调用时声明了监视器陷阱标志,并且如果之前进入Enclave时未抑制该监视器陷阱标志,那么在指令调用之后,MTF VM退出时将会立即在指令边界上挂起。

与IA32和Intel 64体系结构一致,挂起的MTF VM退出将优先于挂起的调试异常。此外,如果在同一指令边界上接收到SMI、INIT或#MC,则该事件将优先于挂起的MTF VM退出和挂起的调试异常。在这种情况下,将以与IA32和Intel 64架构一致的方式处理挂起的MTF VM退出和/或挂起的调试异常。

如果所关注的指令出现故障,则控制流程转到错误处理程序,并且任何单步调试异常不会生效。在这种情况下,如果从VMX客户虚拟机执行指令,并且如果VMM已声明监视器陷阱标志,则在通过IDT传递了错误之后(即,在OS句柄的第一个指令之前),MTF VM退出将处于挂起状态。如果VM退出在指令边界之前发生,则MTF VM退出将丢失。

42.2.6 Opt-out入口之后关于设置TF的限制

从opt-out的EENTER或ERESUME到下一次Enclave退出,不允许Enclave设置RFLAGS.TF。 在这种情况下,如果在DBGOPTIN = 0的情况下通过TCS进入了Enclave,则POPF指令调用时,RFLAGS.TF将被强制置为0。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值