Intel® Software Guard Extensions Programming Reference [on-demand translation]

content

Chapter 2 Enclave Access Control and Data Structures

2.8 Thread Control Structure (TCS)

2.10 PAGEINFO

2.11 Security Information (SECINFO)

2.12 Paging Encrypted Metadata (PCMD)

2.13 Enclave Signature Structure (SIGSTRUCT)

2.14 EINIT token structure (EINITTOKEN)

2.19 Enclave Page Cache Map(EPCM)

Chapter 3 Enclave Operations

3.5 Management of EPC and EPC pages

3.5.9 Cropping pages

Chapter 5 Instructions Related References

5.2 Related References for Intel SGX Instructions

ENCLS - executes the Enclave kernel state function of the specified leaf number

ENCLU - executes the Enclave userland function of the specified leaf number

5.3 Intel SGX kernel state leaf function reference

EADD - add a page to an uninitialized Enclave

EAUG - add pages to an already initialized Enclave

EBLOCK - marks a page in an EPC as locked

ECREATE - Creates a SECS page in the Enclave Page Cache

EDBGRD - read from Enclave in debug mode

EDBGWR - write to Enclave in debug mode

EEXTEND - measure expansion of uninitialized Enclave by 256Bit each time

EINIT - initializes an Enclave for execution

ELDB/ELDU - load an EPC page and mark its status

Chapter 2 Enclave Access Control and Data Structures

2.8 Thread Control Structure (TCS)

In an Enclave, each executing thread is bound to a thread control structure. It requires 4K byte alignment.

2.10 PAGEINFO

PAGEINFO is an architectural-level data structure used as a parameter for EPC management instructions. It requires 32 byte alignment.

2.11 Security Information (SECINFO)

The SECINFO data structure contains metadata about the Enclave page.

2.12 Paging Encrypted Metadata (PCMD)

The PCMD structure is used to track the encrypted metadata corresponding to the Page-out page. When combined with PAGEINFO, it provides the processor with enough information to verify, decrypt and reload this swapped out EPC page.

The size of the PCMD structure (128 bytes) is architecturally (determined). For this, the EWB will write the (PCMD) field and the MAC value, and the ELDB/U will read the (PCMD) field and check the MAC.

The format of PCMD is as follows:

2.13 Enclave Signature Structure (SIGSTRUCT)

SIGSTRUCT contains Enclave information about the signer of the Enclave and must be 4K byte aligned.

SIGSTRUCT contains ENCLAVEHASH as a SHA256 digest as defined in FIPS PUB 180-4. The digest is a byte string of length 32 in which the most significant bytes of each of the 8 HASH doublewords are in the leftmost byte position.

SIGSTRUCT contains four 3072-bit integers (MODULUS, SIGNATURE, Q1, Q2). Each such integer is represented as a byte string of length 384, with the most significant byte at the position "offset + 383" and the least significant byte at the position "offset". 

The signature (of a 3072-bit integer) needs to be an RSA signature, where: a) the RSA modulus (MODULUS) is a 3072-bit integer; b) the exposed exponent is set to 3; c) the signing process uses the EMSA-PKCS1-v1.5 format , and DER-encodes the "DigestInfo" value as specified in PKCS#1 v2.1/RFC 3447.

The 3072-bit integers Q1 and Q2 are defined as follows:

q1 = floor(Signature^2 / Modulus);

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

SIGSTRUCT must be page aligned

In column 5 of Table 2-19, "Y" indicates that this field should be included in developer-generated signatures.

2.14 EINIT token structure (EINITTOKEN)

EINIT uses the EINIT token to verify that the Enclave is allowed to start.

EINIT tokens must be 512-byte aligned. 

2.19 Enclave Page Cache Map(EPCM)

EPCM is a secure data structure used by processors to keep track of EPC content. The EPCM keeps only one entry for each page currently loaded into the EPC. The EPCM cannot be accessed by software, and the layout of the EPCM fields needs to refer to the specific implementation.

Chapter 3 Enclave Operations

3.5 Management of EPC and EPC pages

3.5.9 Cropping pages

On processors that support SGX2, Intel SGX supports deletion of Enclave pages as a special usage of EMODT (hardware instruction). The page type PT_TRIM means that the page has been trimmed from the Enclave's address space and the page is no longer accessible. A page in the PT_TRIM state is not allowed to be modified; the page must be deleted and reallocated by the OS before the Enclave can use the page again. Page reallocation operations can be performed in batches to improve their efficiency.

The protocol for trimming an Enclave page is as follows:

1. The enclave signals to the OS that a page is no longer in use.

2. The OS calls EMODT on the page, requesting to change the type of the page to PT_TRIM.

2.1 SECS and VA pages cannot be cropped in this way, so it is required that the initial type of the page must be PT_REG or PT_TCS

2.2. EMODT only works on VALID pages

3. The OS executes the ETRACK instruction to remove the TLB address from all processors (CPU cores)

4. Issue the EACCEPT instruction in the Enclave. (Accepted by the trusted Enclave to accept this modification)

5. The OS can now permanently delete the page (by calling EREMOVE).

 

Chapter 5 Instructions Related References

This chapter introduces the kernel mode (Ring0) and user mode (Ring3) hardware instructions provided by Intel® Software Guard Extensions. In general, various SGX hardware instruction functions exist as leaf functions of ENCLS (privileged) and ENCLU (user) instructions. Various leaf functions can be used by calling the ENCLS and ENCLU instruction mnemonics and specifying the EAX register to a specific value.

5.2 Related References for Intel SGX Instructions

ENCLS - executes the Enclave kernel state function of the specified leaf number

describe

The ENCLS instruction can call the specified kernel-mode Intel SGX leaf function to manage and debug the Enclave. The program specifies the leaf function by entering the register EAX. Registers RBX, RCX and RDX indicate the specific usage of the current leaf function, these registers can be used for input, output or not used. In 64-bit mode, the instruction ignores the upper 32 bits of the RAX register.

If CR0.PE is 0 or RFLAGS.VM is 1, or the instruction is SMM internally, the instruction will result in a #UD error. Additionally, executing this instruction will result in #UD if it is not currently in kernel mode.

Attempting to call an undefined leaf function results in #GP(0).

If CR0.PG is 0, then attempting to call ENCLS results in #GP(0).

In VMX, when operating under non-root privileges, if the "Enable ENCLS exiting" in the VM execution control flag is 0, you can execute ENCLS at will. If the "Enable ENCLS exiting" value is 1, then the "ENCLS-exiting bitmap" indicates whether each leaf function of ENCLS can be executed. Each Bit in the "ENCLS-exiting bitmap" corresponds to the index value of the ENCLS leaf function (that is, the EAX value).

By setting Enable_ENCLS_EXITING and setting the "ENCLS-exiting bitmap" Bit (accessible through the 0202EH/0202FH pair of codes), a program in VMX Root mode can intercept calls to various ENCLS leaf functions from VMX non-Root mode. If IA32_VMX_PROCBASED_CTLS2 [15] reads a value of 1, then the processor will implement the Enable_ENCLS_EXITING VM execution control field.

The DS segment is used to create linear addresses.

Address and operand are 32-bit in non-64-bit mode (IA32_EFER.LMA = 0 || CS.L = 0) and 64-bit in 64-bit mode (IA32_EFER.LMA = 1 || CS.L = 1) . The CS.D value has no effect on the calculation of the address.

Overrides of segment prefixes are ignored. Overrides of the address size prefix (67H) will be ignored.

The REX prefix will be ignored in 64-bit mode.

operate

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

Affected signs

Please see the description in the leaf function separately

Protected mode exception (Exception)

#UD if any of the LOCK/OSIZE/REP/VEX prefixes are used.

If the current privilege level is not 0.

If CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0. (Annotation: means the hardware does not support SGX)

If the logic core is in SMM.

#GP(0) if IA32_FEATURE_CONTROL.LOCK = 0.

If IA32_FEATURE_CONTROL.SGX_ENABLE = 0.

If the EAX value points to an unsupported leaf function.

If the data segment grows downward.

If CR0.PG=0.

real address mode exception

The #UD ENCLS directive is not recognized in real mode.

Virtual 8086 mode exception

The #UD ENCLS instruction is not recognized in virtual 8086 mode.

Compatibility mode exception

Same as protected mode exceptions.

64-bit mode exception

 

#UD if any of the LOCK/OSIZE/REP/VEX prefixes are used.

If the current privilege level is not 0.

If CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0. (Annotation: means the hardware does not support SGX)

If the logic core is in SMM.

#GP(0) if IA32_FEATURE_CONTROL.LOCK = 0.

If IA32_FEATURE_CONTROL.SGX_ENABLE = 0.

If the EAX value points to an unsupported leaf function.

ENCLU - executes the Enclave userland function of the specified leaf number

describe

The ENCLU instruction invokes the specified user mode Intel SGX leaf function. The program specifies the leaf function by setting the value of the register EAX. The registers RBX, RCX and RDX indicate the specific use of the leaf function, which can be used as input, output or not used. In 64-bit mode, the instruction ignores the upper 32 bits of the RAX register.

This instruction causes #UD if CR0.PE is 0 or RFLAGS.VM is 1, or if executed inside SMM. Also, attempting to execute the instruction when the current privilege level is not 3 results in #UD.

Attempting to call an undefined leaf function results in #GP(0).

Attempting to execute the ENCLU instruction while the paging mechanism is disabled or in MS-DOS compatibility mode results in #GP.

The DS segment is used to create linear addresses.

Address and operand are 32-bit in non-64-bit mode (IA32_EFER.LMA = 0 || CS.L = 0) and 64-bit in 64-bit mode (IA32_EFER.LMA = 1 || CS.L = 1) . The CS.D value has no effect on the calculation of the address.

Overrides of segment prefixes are ignored. Overrides of the address size prefix (67H) will be ignored.

The REX prefix will be ignored in 64-bit mode.

operate

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

Affected signs

Please see the description in the leaf function separately

Protected mode exception (Exception)

#UD if any of the LOCK/OSIZE/REP/VEX prefixes are used.

If the current privilege level is not 3.

If CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0. (Annotation: means the hardware does not support SGX)

If the logic core is in SMM.

#GP(0) if IA32_FEATURE_CONTROL.LOCK = 0.

If IA32_FEATURE_CONTROL.SGX_ENABLE = 0.

If the EAX input value points to an unsupported leaf function.

If the EAX input value points to EENTER/ERESUME and ENCLAVE_MODE=1.

If the EAX input value points to EGETKEY/EREPORT/EEXIT/EACCEPT/EACCEPTCOPY/EMODPE, and ENCLAVE_MODE=0.

If the operation is in 16-bit mode.

If the data segment is in 16-bit mode.

If CR0.PG=0 or CR0.NE=0.

#NM if CR0.TS=1.

real address mode exception

The #UD ENCLS directive is not recognized in real mode.

Virtual 8086 mode exception

The #UD ENCLS instruction is not recognized in virtual 8086 mode.

Compatibility mode exception

Same as protected mode exceptions.

64-bit mode exception

#UD if any of the LOCK/OSIZE/REP/VEX prefixes are used.

If the current privilege level is not 3.

If CPUID.(EAX=12H,ECX=0):EAX.SGX1 [bit 0] = 0. (Annotation: means the hardware does not support SGX)

If the logic core is in SMM.

#GP(0) if IA32_FEATURE_CONTROL.LOCK = 0.

If IA32_FEATURE_CONTROL.SGX_ENABLE = 0.

If the EAX input value points to an unsupported leaf function.

If the EAX input value points to EENTER/ERESUME and ENCLAVE_MODE=1.

If the EAX input value points to EGETKEY/EREPORT/EEXIT/EACCEPT/EACCEPTCOPY/EMODPE, and ENCLAVE_MODE=0.

If CR0.NE=0.

#NM if CR0.TS=1.

5.3 Intel SGX kernel state leaf function reference

This section describes the leaf functions available with the ENCLS instruction mnemonic. Typically, each instruction leaf function requires EAX to specify the leaf function index, and/or use other implicit registers to specify leaf function specific input parameters. The instruction operand encoding table provides details of each implicit register usage, and its associated input/output semantics.

In many cases, the input parameters are the effective addresses associated with memory objects inside or outside the EPC, the memory addressing semantics of which are also summarized in separate tables.

EADD - add a page to an uninitialized Enclave

describe

This leaf function copies source pages from non-Enclave memory into EPC, associates EPC pages with SECS pages residing in EPC, and stores linear addresses and security attributes in EPCM. Enclave offsets and security attributes are measured as part of the associated content and extended to SECS.MRENCLAVE. This instruction can only be executed when the current privilege level is 0.

RBX contains the effective address of the PAGEINFO structure, while RCX contains the effective address of the EPC page. The following table provides additional information about the memory parameters of the EADD leaf function.

The command will fail in the following situations:

Concurrency limit

operate

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;

(* Check for mis-configured SECINFO flags*)
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;

(* 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 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;

(* Copy 4KBytes from source page to EPC page*)
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;

(* 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;

(* Check concurrency of measurement resource*)
IF (Measurement being updated) 
    Then #GP(0); FI;

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

(* For TCS pages, force EPCM.rwx bits to 0 and no debug access *)
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;

(* Add enclave offset and security attributes to MRENCLAVE *)
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;

(* Add enclave offset and security attributes to MRENCLAVE *)
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;

(* 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 entry fields *)
EPCM(DS:RCX).BLOCKED <- 0;
EPCM(DS:RCX).PENDING <- 0;
EPCM(DS:RCX).MODIFIED <- 0;
EPCM(DS:RCX).VALID <- 1;

Affected Flags

none

protected mode exception

#GP(0) If the effective address of the memory operand exceeds the DS segment limit.

If the memory operands are not properly aligned.

If the Enclave memory operand is outside the EPC.

If the Enclave memory operand is of the wrong type.

If the memory operand is locked.

If the Enclave has already been initialized. (Annotation: After creating SECS, adding pages to EPC and measuring, the EINIT instruction will be called to determine whether the establishment process is credible, and the Enclave will be marked as initialized. At this time, EADD cannot be used to add Enclave pages, but changes are required. with EAUG)

If the MRENCLAVE of the Enclave is locked.

If the TCS page reserved bit is set.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the EPC page has been marked as valid.

64-bit mode exception

#GP(0) if the memory operand is not in canonical form.

If the memory operands are not properly aligned.

If the Enclave memory operand is outside the EPC.

If the Enclave memory operand is of the wrong type.

If the memory operand is locked.

If the Enclave has already been initialized.

If the MRENCLAVE of the Enclave is locked.

If the TCS page reserved bit is set.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the EPC page has been marked as valid.

EAUG - add pages to an already initialized Enclave

describe

This leaf function zeroes out the EPC memory page, associates the EPC page with the SECS page stored in the EPC, and stores the linear address and security attributes in the EPCM. As part of the association process, the EPC page's security attributes are (temporarily) configured to deny access until the EACCEPT leaf or EACCEPTCOPY leaf is called to confirm the addition of the new page to the Enclave. This instruction can only be executed if the current privilege level is 0.

RBX contains the effective address of the PAGEINFO structure, while RCX contains the effective address of the EPC page. The following table provides additional information about the memory parameters of the EAUG leaf function.

In the following cases, the command will report an error:

Concurrency limit

operate

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;

Affected signs

none

protected mode exception

#GP(0) If the memory operand effective address exceeds the DS segment limit.

If the memory operands are not properly aligned.

If the memory operand is locked.

If the Enclave is not initialized.

#PF(fault code) If a page fault occurs while accessing a memory operand.

protected mode exception

#GP(0) If the memory operand is not in the canonical format.

If the memory operands are not properly aligned.

If the memory operand is locked.

If the Enclave is not initialized.

#PF(fault code) If a page fault occurs while accessing a memory operand.

EBLOCK - marks a page in an EPC as locked

describe

This leaf feature causes EPC pages to be marked "BLOCKED". This instruction can only be executed if the current privilege level is 0.

The content of the RCX is the valid address of the EPC page. The DS segment is used to create linear addresses. Segment overrides are not supported.

An error code is returned in RAX.

The following table provides additional information about the memory parameters of the EBLOCK leaf function.

The error code is as follows:

Concurrency limit

operate

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:

Affected signs

ZF is set if SECS is being used or invalid, otherwise its ZF is cleared. Set CF if the page has been blocked or unblockable, otherwise clear it. Clear PF, AF, OF, SF.

protected mode exception

#GP(0) If the memory operand effective address exceeds the DS segment limit.

If the memory operands are not properly aligned.

If the specified EPC resource is in use.

#PF(fault code) If a page fault occurs while accessing a memory operand.

. . . . If the memory operand is not an EPC page.

64-bit mode exception

#GP(0) If the memory operand is not in canonical format.

If the memory operands are not properly aligned.

If the specified EPC resource is in use.

#PF(fault code) If a page fault occurs while accessing a memory operand.

. . . . If the memory operand is not an EPC page.

ECREATE - Creates a SECS page in the Enclave Page Cache

ENCLS[ECREATE] is the first instruction executed during the Enclave build. ECREATE copies the SECS structure outside the EPC to the SECS page inside the EPC. The SECS data structures inside the EPC are not accessible to software.

ECREATE will set the field in the protected SECS and mark the page as valid in the EPC. ECREATE initializes or checks for unused fields.

The software sets the following fields in the source structure: SECS:BASEADDR, SECS:SIZE (in bytes) and ATTRIBUTES. SECS:BASEADDR must be naturally aligned on SECS.SIZE boundaries. SECS.SIZE is a minimum of 2 pages (8192 bytes).

The source operand RBX contains the effective address of a PAGEINFO structure. PAGEINFO contains the effective address of the source SECS and the effective address of SECEINFO. The SECS field in PAGEINFO is not used.

The RCX register is the effective address of the target SECS. It is the address of an empty slot in the EPC. SECS structures must be page-aligned. The SECINFO tag must designate the page as a SECS page.

ECREATE will error if the SECS target page is in use or already valid or outside the EPC. ECREATE will also error if the address is misaligned or if the unused field in PAGEINFO is non-zero.

If the amount of space required to store the SSA frame is greater than the amount of space specified in SECS.SSAFRAMESIZE, #GP(0) is generated. The space capacity required for the SSA frame is calculated from the DS:TMP_SECS.ATTRIBUTES.XFRM size. See Section 6.7 for details on size calculations.

Concurrency limit

operate

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 - read from Enclave in debug mode

describe

This leaf function copies a quadword/dword from the EPC page of the debug mode Enclave into the RBX register. Reads 8 bytes in 64-bit mode and 4 bytes in non-64-bit mode. The size of the data read cannot be overwritten.

The effective address of the source location inside the EPC is provided in register RCX.

In the following cases, the command fails:

This directive will ignore the EPCM RWX attribute on the Enclave page. Therefore, violating EPCM RWX properties via EDGBRD does not result in #GP.

Concurrency limit

operate

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) ) (*Accessing tail data may exceed this 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;

Affected signs

none

protected mode exception

#GP(0) If the address in the RCX violates DS restrictions or access rights.

. . . . If the DS segment is not available.

If the memory location pointed to by RCX is not 4-byte aligned.

If the address in the RCX points to a page belonging to a non-debug mode Enclave.

If the address in RCX points to a page other than PT_TCS, PT_REG or PT_VA.

If the address in RCX points to a location within TCS beyond SGX_TCS_LIMIT.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

64-bit mode exception

#GP(0) If the RCX is not in canonical format.

If the memory location pointed to by RCX is not 8-byte aligned.

If the address in the RCX points to a page belonging to a non-debug mode Enclave.

If the address in RCX points to a page other than PT_TCS, PT_REG or PT_VA.

If the address in RCX points to a location within TCS beyond SGX_TCS_LIMIT.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

EDBGWR - write to Enclave in debug mode

describe

This leaf function copies the contents of the EBX/RBX to the EPC page of the Enclave in debug mode. 8 bytes are written in 64-bit mode and 4 bytes in non-64-bit mode. Unable to overwrite data size.

The effective address of the source location inside the EPC is provided in register RCX.

 

In the following cases, the command fails:

 

This directive will ignore the EPCM RWX attribute on the Enclave page. Therefore, violating EPCM RWX properties via EDGBWR will not result in #GP.

Concurrency limit

 

 

operate

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;

Affected signs

none

protected mode exception

#GP(0) If the address in the RCX violates DS restrictions or access rights.

. . . . If the DS segment is not available.

If the memory location pointed to by RCX is not 4-byte aligned.

If the address in the RCX points to a page belonging to a non-debug mode Enclave.

If the address in RCX points to a page other than PT_TCS or PT_REG.

If the address in the RCX points to a non-FLAGS word location within the TCS.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

64-bit mode exception

#GP(0) If the RCX is not in canonical format.

If the memory location pointed to by RCX is not 8-byte aligned.

If the address in the RCX points to a page belonging to a non-debug mode Enclave.

If the address in RCX points to a page other than PT_TCS or PT_REG.

If the address in the RCX points to a non-FLAGS word location within the TCS.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

EEXTEND - measure expansion of uninitialized Enclave by 256Bit each time

describe

This leaf function updates the SECS's MRENCLAVE metric register with the metric value of the EXTEND string (containing "EEXTEND" || ENCLAVEOFFSET || PADDING || 256 bytes of the Enclave page). This instruction can only be executed if the current privilege level is 0 and the Enclave is not initialized.

RCX contains the effective address of the 256-byte region of the EPC page to be measured. The DS segment is used to create linear addresses. Segment overrides are not supported.

In the following cases, the command fails:

Concurrency limit

 

operate

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;

Affected signs

none

protected mode exception

#GP(0) If the address in the RCX violates DS restrictions or access rights.

If the memory location pointed to by RCX is not 256-byte aligned.

If another instruction is accessing MRENCLAVE.

If another instruction is checking or updating SECS.

If the Enclave has already been initialized.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in RCX points to a page other than PT_TCS or PT_REG.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

64-bit mode exception

#GP(0) If RCX is not in canonical format.

If the memory location pointed to by RCX is not 256-byte aligned.

If another instruction is accessing MRENCLAVE.

If another instruction is checking or updating SECS.

If the Enclave has already been initialized.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the address in RCX points to a page other than PT_TCS or PT_REG.

If the address in the RCX points to a non-EPC page.

If the address in the RCX points to an invalid EPC page.

EINIT - initializes an Enclave for execution

describe

This leaf function is the last instruction executed during the Enclave build process. After the EINIT instruction is called, the measurement of the MRENCLAVE is complete, and the EENTER instruction can be used to enter this prepared Enclave to start executing user code.

EINIT will use the effective address of SIGSTRUCT and EINITTOKEN. SIGSTRUCT contains the Enclave-related MRENCLAVE, ATTRIBUTES, ISSVVN, 3072-bit RSA key and the signature using this key. SIGSTRUCT must be filled with two values ​​q1 and q2. These are calculated using the following formula:

q1 = floor(Signature^2 / Modulus);

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

EINITTOKEN contains MRENCLAVE, MRSIGNER and ATTRIBUTES. These values ​​must match the corresponding values ​​in SECS. If the EINITTOKEN was created with the debug mode launch key, the Enclave must also be in debug mode.

EINIT performs the following steps, as shown in Figure 5-1:

Verify that SIGSTRUCT was signed with the included public key.

Check that SECS.MRENCLAVE evaluates to SIGSTRUCT.HASHENCLAVE.

Check that the reserved bits in SIGSTRUCT.ATTRIBUTES are all set to 0, and the reserved bits in SIGSTRUCT.ATTRIBUTESMASK are all set to 1.

Check that the Intel-exclusive bit in SIGSTRUCT.ATTRIBUTES is not set, unless this is an Intel-signed SIGSTRUCT.

Checks if SIGSTRUCT.ATTRIBUTES is equal to the result of logically ANDing SIGSTRUCT.ATTRIBUTEMASK with SECS.ATTRIBUTES.

If EINITTOKEN.VALID is 0, check if SIGSTRUCT is signed by Intel.

If EINITTOKEN.VALID is 1, then check the validity of EINITTOKEN.

If EINITTOKEN.VALID is 1, check if EINITTOKEN.MRENCLAVE is equal to SECS.MRENCLAVE.

If EINITTOKEN.VALID is 1 and EINITTOKEN.ATTRIBUTES.DEBUG is 1, then SECS.ATTRIBUTES.DEBUG must be 1.

Commit SECS.MRENCLAVE and set SECS.MRSIGNER, SECS.ISVSVN and SECS.ISVPRODID according to SIGSTRUCT.

Update SECS, marked as initialized.

EINIT periodically polls for certain asynchronous events. If such an event is detected, it sets a failure code (ZF=1 and RAX=SGX_UNMASKED_EVENT), and RIP is incremented to point to the next instruction. These events are INTR, NMI, SMI, INIT, VMX_TIMER, MCAKIND, MCE_SMI, and CMCI_SMI. EINIT does not fail if pending events are disabled (for example, INTR is disabled due to MOV/POP SS blocking and STI blocking).

 

Concurrency limit

 

operate

(* 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;

Affected signs

If successful, ZF is cleared. If it fails, ZF is set and RAX saves the error code. CF, PF, AF, OF, SF are cleared.

protected mode exception

#GP(0) if memory operands are not aligned.

If other directives modify SECS.

If the Enclave has already been initialized.

If SECS.MRENCLAVE is being used.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the RCX is not an EPC page after parsing.

If the memory address is not a valid, uninitialized SECS.

64-bit mode exception

#GP(0) if memory operands are not aligned.

If other directives modify SECS.

If the Enclave has already been initialized.

If SECS.MRENCLAVE is being used.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the RCX is not an EPC page after parsing.

If the memory address is not a valid, uninitialized SECS.

ELDB/ELDU - load an EPC page and mark its status

describe

This leaf function copies pages from regular main memory to the EPC. As part of the copying process, the page is cryptographically authenticated and decrypted. This instruction can only be executed if the current privilege level is 0.

After the copy is complete, the ELDB leaf function will set the BLOCK bit of the EPCM entry corresponding to the target page in the EPC to 1. After the copying is completed, the ELDU leaf function can be called to clear the BLOCK bit of the EPCM item corresponding to the target page in the EPC.

RBX contains the effective address of the PAGEINFO structure; RCX contains the effective address of the target EPC page; RDX reserves the effective address of the version array slot (recording the version number of the page).

The following table provides additional information about the memory parameters of the ELDB/ELDU leaf function.

The error code is as follows:

Concurrency limit

operate

 

(* 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;

Affected signs

If it fails, ZF is set, otherwise ZF is cleared. And RAX saves the error code. CF, PF, AF, OF, SF are cleared.

protected mode exception

#GP(0) If the effective address of the memory operand is outside the DS segment limit.

If the memory operands are not properly aligned.

If the EPC resource in the instruction is used by other objects.

If the command fails to verify the MAC.

If the version array slot is being used.

If the parameter fails the consistency check.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the memory operand is supposed to be in the EPC, but in fact it is not an EPC page after parsing.

If either EPC memory operand is not a correct page type.

If the target EPC page has been marked bit valid.

64-bit mode exception

#GP(0) If the memory operand is not in standard format.

If the memory operands are not properly aligned.

If the EPC resource in the instruction is used by other objects.

If the command fails to verify the MAC.

If the version array slot is being used.

If the parameter fails the consistency check.

#PF(fault code) If a page fault occurs while accessing a memory operand.

If the memory operand is supposed to be in the EPC, but in fact it is not an EPC page after parsing.

If either EPC memory operand is not a correct page type.

If the target EPC page has been marked bit valid.

Posted by Bunkermaster on Tue, 10 May 2022 15:04:44 +0300