Asynchronous usercall specification.
An asynchronous usercall allows an enclave to submit a usercall without exiting the enclave. This is necessary since enclave entries and exists are slow (see academic work on SCONE, HotCalls). In addition, the enclave can perform other tasks while it waits for the usercall to complete. Those tasks may include issuing other usercalls, either synchronously or asynchronously.
Two MPSC queues are allocated per enclave. One queue is used by any enclave thread to submit usercalls to userspace. Userspace will read the calls from this queue and handle them. Another queue is used by userspace to return completed usercalls to the enclave.
Each call is identified by an enclave-specified
id. Userspace must
provide the same
id when returning. The enclave must not submit multiple
concurrent usercalls with the same
id, but it may reuse an
id once the
original usercall with that
id has returned.
TODO: Add diagram.
When the enclave needs to wait on a queue, it executes the
usercall synchronously, specifying
EV_RETURNQ_NOT_EMPTY, or both in the
event_mask. Userspace will wake
any or all threads waiting on the appropriate event when it is triggered.
When userspace needs to wait on a queue, it will park the current thread (or do whatever else is appropriate for the synchronization model currently in use by userspace). Any synchronous usercall will wake the blocked thread (or otherwise signal that either queue is ready).
A circular buffer used as a FIFO queue with atomic reads and writes.
The return value of a usercall. The elements correspond to the RSI and RDX registers in the synchronous calling convention.
A usercall. The elements correspond to the RDI, RSI, RDX, R8, and R9 registers in the synchronous calling convention.