# ELDB/ELDU/ELDBC/ELDUC — Load an EPC Page and Mark its State

Opcode/Instruction | Op/En | 64/32 bit Mode Support | CPUID Feature Flag | Description
--- | --- | --- | --- | ---
EAX = 07H ENCLS[ELDB] | IR | V/V | SGX1 | This leaf function loads, verifies an EPC page and marks the page as blocked.
EAX = 08H ENCLS[ELDU] | IR | V/V | SGX1 | This leaf function loads, verifies an EPC page and marks the page as unblocked.
EAX = 12H ENCLS[ELDBC] | IR | V/V | EAX[6] | This leaf function behaves lie ELDB but with improved conflict handling for oversubscription.
EAX = 13H ENCLS[ELDUC] | IR | V/V | EAX[6] | This leaf function behaves like ELDU but with improved conflict handling for oversubscription.

## Instruction Operand Encoding ¶

Op/En | EAX | RBX | RCX | RDX
IR | (In) r (In) LDU Return error Return error |  | Address of the PAGEINFO (In) | Address of the EPC page (In) | Address of the version-array slot (In)

### Description ¶

This leaf function copies a page 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 when current privilege level is 0.

The ELDB leaf function sets the BLOCK bit in the EPCM entry for the destination page in the EPC after copying. The ELDU leaf function clears the BLOCK bit in the EPCM entry for the destination page in the EPC after copying.

RBX contains the effective address of a PAGEINFO structure; RCX contains the effective address of the destination EPC page; RDX holds the effective address of the version array slot that holds the version of the page.

The ELDBC/ELDUC leafs are very similar to ELDB and ELDU. They provide an error code on the concurrency conflict for any of the pages which need to acquire a lock. These include the destination, SECS, and VA slot.

The table below provides additional information on the memory parameter of ELDB/ELDU leaf functions.

## ELDB/ELDU/ELDBC/ELBUC Memory Parameter Semantics ¶

PAGEINFO | PAGEINFO.SRCPGE | PAGEINFO.PCMD | PAGEINFO.SECS | EPCPAGE | Version-Array Slot
Non-enclave read access | Non-enclave read access | Non-enclave read access | Enclave read/write access | Read/Write access permitted by Enclave | Read/Write access permitted by Enclave

The error codes are:

Error Code (see Table 38-4) | Description
--- | ---
No Error | ELDB/ELDU successful.
SGX_MAC_COMPARE_FAIL | If the MAC check fails.

Table 38-28. ELDB/ELDU/ELDBC/ELBUC Return Value in RAX

### Concurrency Restrictions ¶

Leaf | Parameter | Base Concurrency Restrictions
--- | --- | ---
Access | On Conflict | SGX_CONFLICT VM Exit Qualification
ELDB/ELDU | Target [DS:RCX] | Exclusive | #GP | EPC_PAGE_CONFLICT_EXCEPTION
VA [DS:RDX] | Shared | #GP |
SECS [DS:RBX]PAGEINFO.SECS | Shared | #GP |
ELDBC/ELBUC | Target [DS:RCX] | Exclusive | SGX_EPC_PAGE_ CONFLICT | EPC_PAGE_CONFLICT_ERROR
VA [DS:RDX] | Shared | SGX_EPC_PAGE_ CONFLICT |
SECS [DS:RBX]PAGEINFO.SECS | Shared | SGX_EPC_PAGE_ CONFLICT |

Table 38-29. Base Concurrency Restrictions of ELDB/ELDU/ELDBC/ELBUC

Leaf | Parameter | Additional Concurrency Restrictions
--- | --- | ---
vs. EACCEPT, EACCEPTCOPY, EMODPE, EMODPR, EMODT | vs. EADD, EEXTEND, EINIT | vs. ETRACK, ETRACKC
Access | On Conflict | Access | On Conflict | Access | On Conflict
ELDB/ELDU | Target [DS:RCX] | Concurrent |  | Concurrent |  | Concurrent |
VA [DS:RDX] | Concurrent |  | Concurrent |  | Concurrent |
SECS [DS:RBX]PAGEINFO.SECS | Concurrent |  | Concurrent |  | Concurrent |
ELDBC/ELBUC | Target [DS:RCX] | Concurrent |  | Concurrent |  | Concurrent |
VA [DS:RDX] | Concurrent |  | Concurrent |  | Concurrent |
SECS [DS:RBX]PAGEINFO.SECS | Concurrent |  | Concurrent |  | Concurrent |

Table 38-30. Additional Concurrency Restrictions of ELDB/ELDU/ELDBC/ELBUC

### Operation ¶

## Temp Variables in ELDB/ELDU/ELDBC/ELBUC Operational Flow ¶

Name | Type | Size (Bits) | Description
--- | --- | --- | ---
TMP_SRCPGE | Memory page | 4KBytes |
TMP_SECS | Memory page | 4KBytes |
TMP_PCMD | PCMD | 128 Bytes |
TMP_HEADER | MACHEADER | 128 Bytes |
TMP_VER | UINT64 | 64 |
TMP_MAC | UINT128 | 128 |
TMP_PK | UINT128 | 128 | Page encryption/MAC key.
SCRATCH_PCMD | PCMD | 128 Bytes |

(* 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:RBX.PCMD;

(* 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 by other Intel SGX instructions *)

IF (other instructions accessing EPC)

THEN

IF ((EAX==07h) OR (EAX==08h)) (* ELDB/ELDU *)

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:RCX produced by paging >>;

VMCS.Guest-linear_address := DS:RCX;

Deliver VMEXIT;

ELSE

#GP(0);

FI;

ELSE (* ELDBC/ELDUC *)

IF (<<VMX non-root operation>> AND

<<ENABLE_EPC_VIRTUALIZATION_EXTENSIONS>>)

THEN

VMCS.Exit_reason := SGX_CONFLICT;

VMCS.Exit_qualification.code := EPC_PAGE_CONFLICT_ERROR;

VMCS.Exit_qualification.error := SGX_EPC_PAGE_CONFLICT;

VMCS.Guest-physical_address :=

<< translation of DS:RCX produced by paging >>;

VMCS.Guest-linear_address := DS:RCX;

Deliver VMEXIT;

ELSE

RFLAGS.ZF := 1;

RFLAGS.CF := 0;

RAX := SGX_EPC_PAGE_CONFLICT;

GOTO ERROR_EXIT;

FI;

FI;

FI;

(* Check concurrency of EPC and VASLOT by other Intel SGX instructions *)

IF (Other instructions modifying VA slot) THEN

IF ((EAX==07h) OR (EAX==08h)) (* ELDB/ELDU *)

THEN #GP(0);

ELSE (* ELDBC/ELDUC *)

RFLAGS.ZF := 1;

RFLAGS.CF := 0;

RAX := SGX_EPC_PAGE_CONFLICT;

GOTO ERROR_EXIT;

FI;

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) or

(TMP_HEADER.SECINFO.FLAGS.PT = PT_SS_FIRST and CPUID.(EAX=12H, ECX=1):EAX[6] = 1) or

(TMP_HEADER.SECINFO.FLAGS.PT = PT_SS_REST and CPUID.(EAX=12H, ECX=1):EAX[6] = 1))

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 ( Another instruction is currently modifying the SECS) THEN

IF ((EAX==07h) OR (EAX==08h)) (* ELDB/ELDU *)

THEN #GP(0);

ELSE (* ELDBC/ELDUC *)

RFLAGS.ZF := 1;

RFLAGS.CF := 0;

RAX := SGX_EPC_PAGE_CONFLICT;

GOTO ERROR_EXIT;

FI;

FI;

TMP_HEADER.EID := DS:TMP_SECS.EID;

ELSE

(* TMP_HEADER.SECINFO.FLAGS.PT is PT_SECS or PT_VA which do not have a parent SECS, and hence no EID binding *)

TMP_HEADER.EID := 0;

IF (DS:TMP_SECS ≠ 0)

THEN #GP(0) FI;

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;

(* Clear VA Slot *)

DS:RDX := 0

(* 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).PR := TMP_HEADER.SECINFO.FLAGS.PR;

EPCM(DS:RCX).ENCLAVEADDRESS := TMP_HEADER.LINADDR;

IF ( ((EAX = 07H) or (EAX = 12H)) 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;

IF (TMP_HEADER.SECINFO.FLAGS.PT is PT_SECS)

<< store translation of DS:RCX produced by paging in SECS(DS:RCX).ENCLAVECONTEXT >>

FI;

EPCM(DS:RCX). VALID := 1;

RAX := 0;

RFLAGS.ZF := 0;

ERROR_EXIT:

RFLAGS.CF,PF,AF,OF,SF := 0;

### Flags Affected ¶

Sets ZF if unsuccessful, otherwise cleared and RAX returns error code. Clears CF, PF, AF, OF, SF.

### Protected Mode Exceptions ¶

#GP(0) | If a memory operand effective address is outside the DS segment limit.
If a memory operand is not properly aligned.
If the instruction’s EPC resource is in use by others.
If the instruction fails to verify MAC.
If the version-array slot is in use.
If the parameters fail consistency checks.
#PF(error | code) If a page fault occurs in accessing memory operands.
If a memory operand expected to be in EPC does not resolve to an EPC page.
If one of the EPC memory operands has incorrect page type.
If the destination EPC page is already valid.

### 64-Bit Mode Exceptions ¶

#GP(0) | If a memory operand is non-canonical form.
If a memory operand is not properly aligned.
If the instruction’s EPC resource is in use by others.
If the instruction fails to verify MAC.
If the version-array slot is in use.
If the parameters fail consistency checks.
#PF(error | code) If a page fault occurs in accessing memory operands.
If a memory operand expected to be in EPC does not resolve to an EPC page.
If one of the EPC memory operands has incorrect page type.
If the destination EPC page is already valid.