Module fortanix_sgx_abi::async
source · [−]Expand description
Asynchronous usercall specification.
An asynchronous usercall allows an enclave to submit a usercall without exiting the enclave. This is necessary since enclave entries and exits 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.
An optional third queue can be used to cancel usercalls. To cancel an async
usercall, the enclave should send the usercall’s id and number on this
queue. If the usercall has already been processed, the enclave may still
receive a successful result for the usercall. Otherwise, the userspace will
cancel the usercall’s execution and return an Interrupted
error on the
return queue to notify the enclave of the cancellation. Note that usercalls
that do not return Result
cannot be cancelled and if the enclave sends
a cancellation for such a usercall, the userspace should simply ignore it.
Additionally, userspace may choose to ignore cancellations for non-blocking
usercalls. Userspace should be able to cancel a usercall that has been sent
by the enclave but not yet received by the userspace, i.e. if cancellation
is received before the usercall itself. To avoid keeping such cancellations
forever and preventing the enclave from re-using usercall ids, userspace
should synchronize cancel queue with the usercall queue such that the
following invariant is maintained: whenever the enclave writes an id to the
usercall or cancel queue, the enclave will not reuse that id until the
usercall queue’s read pointer has advanced to the write pointer at the time
the id was written.
TODO: Add diagram.
Enclave/userspace synchronization
When the enclave needs to wait on a queue, it executes the wait()
usercall synchronously, specifying EV_USERCALLQ_NOT_FULL
,
EV_RETURNQ_NOT_EMPTY
, EV_CANCELQ_NOT_FULL
, or any combination
thereof 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).
Structs
Cancel a usercall previously sent to userspace.
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.