Opcode/Instruction | Op/En | 64/32 bit Mode Support | CPUID Feature Flag | Description |
---|---|---|---|---|
EAX = 00H ENCLS[ECREATE] | IR | V/V | SGX1 | This leaf function begins an enclave build by creating an SECS page in EPC. |
Op/En | EAX | RBX | RCX |
IR | ECREATE (In) | Address of a PAGEINFO (In) | Address of the destination SECS page (In) |
ENCLS[ECREATE] is the first instruction executed in the enclave build process. ECREATE copies an SECS structure outside the EPC into an SECS page inside the EPC. The internal structure of SECS is not accessible to software.
ECREATE will set up fields in the protected SECS and mark the page as valid inside the EPC. ECREATE initializes or checks unused fields.
Software sets the following fields in the source structure: SECS:BASEADDR, SECS:SIZE in bytes, ATTRIBUTES, CONFIGID, and CONFIGSVN. SECS:BASEADDR must be naturally aligned on an SECS.SIZE boundary. SECS.SIZE must be at least 2 pages (8192).
The source operand RBX contains an effective address of a PAGEINFO structure. PAGEINFO contains an effective address of a source SECS and an effective address of an SECINFO. The SECS field in PAGEINFO is not used.
The RCX register is the effective address of the destination SECS. It is an address of an empty slot in the EPC. The SECS structure must be page aligned. SECINFO flags must specify the page as an SECS page.
PAGEINFO | PAGEINFO.SRCPGE | PAGEINFO.SECINFO | EPCPAGE |
Read access permitted by Non Enclave | Read access permitted by Non Enclave | Read access permitted by Non Enclave | Write access permitted by Enclave |
ECREATE will fault if the SECS target page is in use; already valid; outside the EPC. It will also fault if addresses are not aligned; unused PAGEINFO fields are not zero.
If the amount of space needed to store the SSA frame is greater than the amount specified in SECS.SSAFRAMESIZE, a #GP(0) results. The amount of space needed for an SSA frame is computed based on DS:TMP_SECS.ATTRIBUTES.XFRM size. Details of computing the size can be found Section 39.7.
Leaf | Parameter | Base Concurrency Restrictions | ||
---|---|---|---|---|
On Conflict | ||||
ECREATE ECREATE SECS [DS:RCX] Exclusive #GP ECREATE SECS [DS:RCX] | SECS [DS:RCX] |
Leaf | Parameter | Additional Concurrency Restrictions | |||||
---|---|---|---|---|---|---|---|
vs. EACCEPT, EACCEPTCOPY, vs. EADD, EEXTEND, EINIT vs. ETRACK, ETRACKC Access vs. ETRACK, ETRACKC Access On Conflict Access vs. ETRACK, ETRACKC Access On Conflict EMODPE, EMODPR, EMODT | vs. EADD, EEXTEND, EINIT vs. EADD, EEXTEND, EINIT vs. ETRACK, ETRACKC | vs. ETRACK, ETRACKC | |||||
Access On Conflict Access On Conflict Access Access On Conflict Access On Conflict | |||||||
ECREATE | SECS [DS:RCX] | Concurrent | Concurrent | Concurrent |
Name | Type | Size (Bits) | Description |
---|---|---|---|
TMP_SRCPGE | Effective Address | 32/64 | Effective address of the SECS source page. |
TMP_SECS | Effective Address | 32/64 | Effective address of the SECS destination page. |
TMP_SECINFO | Effective Address | 32/64 | Effective address of an SECINFO structure which contains security attributes of the SECS page to be added. |
TMP_XSIZE | SSA Size | 64 | The size calculation of SSA frame. |
TMP_MISC_SIZE | MISC Field Size | 64 | Size of the selected MISC field components. |
TMPUPDATEFIELD | SHA256 Buffer | 512 | Buffer used to hold data being added to TMP_SECS.MRENCLAVE. |
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
IF (<<VMX non-root operation>> AND <<ENABLE_EPC_VIRTUALIZATION_EXTENSIONS>>)
THEN
VMCS.Exit_reason := SGX_CONFLICT;
VMCS.Exit_qualification.code := EPC_PAGE_CONFLICT_EXCEPTION;
VMCS.Exit_qualification.error := 0;
VMCS.Guest-physical_address :=
<< translation of DS:TMP_SECS produced by paging >>;
VMCS.Guest-linear_address := DS:TMP_SECS;
Deliver VMEXIT;
ELSE
#GP(0);
FI;
FI;
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;
(* Check legality of CET_ATTRIBUTES *)
IF ((DS:TMP_SECS.ATTRIBUTES.CET = 0 and DS:TMP_SECS.CET_ATTRIBUTES ≠ 0) ||
(DS:TMP_SECS.ATTRIBUTES.CET = 0 and DS:TMP_SECS.CET_LEG_BITMAP_OFFSET ≠ 0) ||
(CPUID.(EAX=7, ECX=0):EDX[CET_IBT] = 0 and DS:TMP_SECS.CET_LEG_BITMAP_OFFSET ≠ 0) ||
(CPUID.(EAX=7, ECX=0):EDX[CET_IBT] = 0 and DS:TMP_SECS.CET_ATTRIBUTES[5:2] ≠ 0) ||
(CPUID.(EAX=7, ECX=0):ECX[CET_SS] = 0 and DS:TMP_SECS.CET_ATTRIBUTES[1:0] ≠ 0) ||
(DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 1 and
(DS:TMP_SECS.BASEADDR + DS:TMP_SECS.CET_LEG_BITMAP_OFFSET) not canonical) ||
(DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 0 and
(DS:TMP_SECS.BASEADDR + DS:TMP_SECS.CET_LEG_BITMAP_OFFSET) & 0xFFFFFFFF00000000) ||
(DS:TMP_SECS.CET_ATTRIBUTES.reserved fields not 0) or
(DS:TMP_SECS.CET_LEG_BITMAP_OFFSET) is not page aligned))
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 39.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 ≥ 2 ^ (CPUID.(EAX=12H, ECX=0):.EDX[7:0]) ) ) THEN #GP(0); FI;
IF ( (DS:TMP_SECS.ATTRIBUTES.MODE64BIT = 1) and (DS:TMP_SECS.SIZE ≥ 2 ^ (CPUID.(EAX=12H, ECX=0):.EDX[15:8]) ) ) 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;
(* Verify that CONFIGID/CONFIGSVN are not set with attribute *)
IF ( ((DS:TMP_SECS.CONFIGID ≠ 0) or (DS:TMP_SECS.CONFIGSVN ≠0)) AND (DS:TMP_SECS.ATTRIBUTES.KSS == 0 ))
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;
IF (CPUID.(EAX=7, ECX=0):EDX[CET_IBT] = 1)
THEN
TMPUPDATEFIELD[223:160] := DS:TMP_SECS.CET_LEG_BITMAP_OFFSET;
ELSE
TMPUPDATEFIELD[223:160] := 0;
FI;
TMPUPDATEFIELD[511:160] := 0;
DS:TMP_SECS.MRENCLAVE := SHA256UPDATE(DS:TMP_SECS.MRENCLAVE, TMPUPDATEFIELD)
INC enclave’s MRENCLAVE update counter;
(* Set EID *)
DS:TMP_SECS.EID := LockedXAdd(CR_NEXT_EID, 1);
(* Initialize the virtual child count to zero *)
DS:TMP_SECS.VIRTCHILDCNT := 0;
(* Load ENCLAVECONTEXT with Address out of paging of SECS *)
<< store translation of DS:RCX produced by paging in SECS(DS:RCX).ENCLAVECONTEXT >>
(* 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).PR := 0;
EPCM(DS:RCX).VALID := 1;
None
#GP(0) | If a memory operand effective address is outside the DS segment limit. |
If a memory operand is not properly aligned. | |
If the reserved fields are not zero. | |
If PAGEINFO.SECS is not zero. | |
If PAGEINFO.LINADDR is not zero. | |
If the SECS destination is locked. | |
If SECS.SSAFRAMESIZE is insufficient. | |
#PF(error | code) If a page fault occurs in accessing memory operands. |
If the SECS destination is outside the EPC. |
#GP(0) | If a memory address is non-canonical form. |
If a memory operand is not properly aligned. | |
If the reserved fields are not zero. | |
If PAGEINFO.SECS is not zero. | |
If PAGEINFO.LINADDR is not zero. | |
If the SECS destination is locked. | |
If SECS.SSAFRAMESIZE is insufficient. | |
#PF(error | code) If a page fault occurs in accessing memory operands. |
If the SECS destination is outside the EPC. |