summaryrefslogtreecommitdiffstats
path: root/vendor/fortanix-sgx-abi
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/fortanix-sgx-abi')
-rw-r--r--vendor/fortanix-sgx-abi/.cargo-checksum.json2
-rw-r--r--vendor/fortanix-sgx-abi/Cargo.toml36
-rw-r--r--vendor/fortanix-sgx-abi/src/lib.rs164
3 files changed, 149 insertions, 53 deletions
diff --git a/vendor/fortanix-sgx-abi/.cargo-checksum.json b/vendor/fortanix-sgx-abi/.cargo-checksum.json
index 54731bac0..71c7c4425 100644
--- a/vendor/fortanix-sgx-abi/.cargo-checksum.json
+++ b/vendor/fortanix-sgx-abi/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"2f11a404e7361ab1b4bfd6bf5189c18091df9dcedda93dce14dcb01b59a2d85a","src/lib.rs":"2493f0264dfaaac19471aa5cb3da8011ead8f804f3ac722195478894a7d011d1"},"package":"c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6"} \ No newline at end of file
+{"files":{"Cargo.toml":"5ef38d3c4329644a02d5fe6019ea401cdd64d31c1a26fd16cf30c7d2dd87873f","src/lib.rs":"2da4a01e8baae15069a6ea32610602f1741e8deccad696f7f7d3e69035da2962"},"package":"57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"} \ No newline at end of file
diff --git a/vendor/fortanix-sgx-abi/Cargo.toml b/vendor/fortanix-sgx-abi/Cargo.toml
index 1a3b9c168..28e2993bb 100644
--- a/vendor/fortanix-sgx-abi/Cargo.toml
+++ b/vendor/fortanix-sgx-abi/Cargo.toml
@@ -3,26 +3,41 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
name = "fortanix-sgx-abi"
-version = "0.3.3"
+version = "0.5.0"
authors = ["Fortanix, Inc."]
-description = "An interface for Intel SGX enclaves. This is the interface for the\n`x86_64-fortanix-unknown-sgx` target.\n\nThis is a small yet functional interface suitable for writing larger enclaves. \nIn contrast to other enclave interfaces, this interface is primarly designed \nfor running entire applications in an enclave.\n\nThis crate fully describes the type-level interface complete with \ndocumentation. For implementors, this crate contains all the type definitions\nand a macro with the function definitions.\n"
+description = """
+An interface for Intel SGX enclaves. This is the interface for the
+`x86_64-fortanix-unknown-sgx` target.
+
+This is a small yet functional interface suitable for writing larger enclaves.
+In contrast to other enclave interfaces, this interface is primarly designed
+for running entire applications in an enclave.
+
+This crate fully describes the type-level interface complete with
+documentation. For implementors, this crate contains all the type definitions
+and a macro with the function definitions.
+"""
homepage = "https://edp.fortanix.com/"
documentation = "https://edp.fortanix.com/docs/api/fortanix_sgx_abi/"
-keywords = ["sgx", "enclave"]
+keywords = [
+ "sgx",
+ "enclave",
+]
categories = ["os"]
license = "MPL-2.0"
repository = "https://github.com/fortanix/rust-sgx"
+
[package.metadata.docs.rs]
features = ["docs"]
+
[dependencies.compiler_builtins]
version = "0.1.0"
optional = true
@@ -34,4 +49,7 @@ package = "rustc-std-workspace-core"
[features]
docs = []
-rustc-dep-of-std = ["core", "compiler_builtins/rustc-dep-of-std"]
+rustc-dep-of-std = [
+ "core",
+ "compiler_builtins/rustc-dep-of-std",
+]
diff --git a/vendor/fortanix-sgx-abi/src/lib.rs b/vendor/fortanix-sgx-abi/src/lib.rs
index 362defb8f..3511ae34b 100644
--- a/vendor/fortanix-sgx-abi/src/lib.rs
+++ b/vendor/fortanix-sgx-abi/src/lib.rs
@@ -15,7 +15,7 @@
//! The Fortanix SGX ABI (compiler target `x86_64-fortanix-unknown-sgx`) is an
//! interface for Intel SGX enclaves. It is a small yet functional interface
//! suitable for writing larger enclaves. In contrast to other enclave
-//! interfaces, this interface is primarly designed for running entire
+//! interfaces, this interface is primarily designed for running entire
//! applications in an enclave.
//!
//! The Fortanix SGX ABI specification consists of two parts:
@@ -82,7 +82,7 @@
html_root_url = "https://edp.fortanix.com/docs/api/")]
use core::ptr::NonNull;
-use core::sync::atomic::AtomicUsize;
+use core::sync::atomic::{AtomicU64, AtomicUsize};
macro_rules! invoke_with_abi_spec [
( $m:ident ) => [ $m![
@@ -186,6 +186,9 @@ pub struct ByteBuffer {
pub len: usize
}
+#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+unsafe impl Send for ByteBuffer {}
+
/// Error code definitions and space allocation.
///
/// Only non-zero positive values are valid errors. The variants are designed
@@ -222,7 +225,7 @@ pub enum Error {
UserRangeEnd = 0x7fff_ffff,
}
-/// A value indicating that the operation was succesful.
+/// A value indicating that the operation was successful.
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
pub const RESULT_SUCCESS: Result = 0;
@@ -301,7 +304,7 @@ impl Usercalls {
/// Read up to `len` bytes from stream `fd`.
///
/// `buf` must point to a buffer in userspace with a size of at least
- /// `len`. On a succesful return, the number of bytes written is returned.
+ /// `len`. On a successful return, the number of bytes written is returned.
/// The enclave must check that the returned length is no more than `len`.
/// If `len` is `0`, this call should block until the stream is ready for
/// reading. If `len` is `0` or end of stream is reached, `0` may be
@@ -330,7 +333,7 @@ impl Usercalls {
/// Write up to `len` bytes to stream `fd`.
///
/// `buf` must point to a buffer in userspace with a size of at least
- /// `len`. On a succesful return, the number of bytes written is returned.
+ /// `len`. On a successful return, the number of bytes written is returned.
/// The enclave must check that the returned length is no more than `len`.
/// If `len` is `0`, this call should block until the stream is ready for
/// writing. If `len` is `0` or the stream is closed, `0` may be returned.
@@ -453,6 +456,10 @@ pub const EV_RETURNQ_NOT_EMPTY: u64 = 0b0000_0000_0000_0010;
/// An event that enclaves can use for synchronization.
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
pub const EV_UNPARK: u64 = 0b0000_0000_0000_0100;
+/// An event that will be triggered by userspace when the cancel queue is not
+/// or no longer full.
+#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+pub const EV_CANCELQ_NOT_FULL: u64 = 0b0000_0000_0000_1000;
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
pub const WAIT_NO: u64 = 0;
@@ -464,9 +471,10 @@ pub const WAIT_INDEFINITE: u64 = !0;
/// ## TCS event queues
///
/// Userspace will maintain a queue for each running TCS with events to be
-/// delivered. Each event is characterized by a bitset. Userspace or the
-/// enclave (using the `send` usercall) can put events on this queue. If the
-/// enclave isn't waiting for an event when an event is queued, the event
+/// delivered. Each event is characterized by a bitset with at least one bit
+/// set. Userspace or the enclave (using the `send` usercall) can put events on
+/// this queue.
+/// If the enclave isn't waiting for an event when an event is queued, the event
/// remains on the queue until it delivered to the enclave in a later `wait`
/// usercall. If an enclave is waiting for an event, and the queue contains an
/// event that is a subset of the waited-for event mask, that event is removed
@@ -481,7 +489,7 @@ impl Usercalls {
/// this with the number of entries into [`thread_entry`]. If no free TCSes
/// are immediately available, this may return an error.
///
- /// This function will never be succesful in [libraries]. See the
+ /// This function will never be successful in [libraries]. See the
/// [`library`] documentation on how to use threads with libraries.
///
/// [`thread_entry`]: entry/executable/fn.thread_entry.html
@@ -503,14 +511,18 @@ impl Usercalls {
/// Wait for an event to occur, or check if an event is currently pending.
///
- /// `timeout` must be [`WAIT_NO`] or [`WAIT_INDEFINITE`]. If it is another
- /// value, userspace will return an error.
+ /// `timeout` must be [`WAIT_NO`] or [`WAIT_INDEFINITE`] or a positive
+ /// value smaller than u64::MAX specifying number of nanoseconds to wait.
///
/// If `timeout` is [`WAIT_INDEFINITE`], this call will block and return
/// once a matching event is queued on this TCS. If `timeout` is
/// [`WAIT_NO`], this call will return immediately, and the return value
/// will indicate if an event was pending. If it was, it has been dequeued.
- /// If not, the [`WouldBlock`] error value will be returned.
+ /// If not, the [`WouldBlock`] error value will be returned. If `timeout`
+ /// is a value other than [`WAIT_NO`] and [`WAIT_INDEFINITE`], this call
+ /// will block until either a matching event is queued in which case the
+ /// return value will indicate the event, or the timeout is reached in
+ /// which case the [`TimedOut`] error value will be returned.
///
/// A matching event is one whose bits are equal to or a subset of
/// `event_mask`. If `event_mask` is `0`, this call will never return due
@@ -534,6 +546,7 @@ impl Usercalls {
/// [`WAIT_INDEFINITE`]: constant.WAIT_INDEFINITE.html
/// [`EV_RETURNQ_NOT_EMPTY`]: constant.EV_RETURNQ_NOT_EMPTY.html
/// [`WouldBlock`]: enum.Error.html#variant.WouldBlock
+ /// [`TimedOut`]: enum.Error.html#variant.TimedOut
pub fn wait(event_mask: u64, timeout: u64) -> (Result, u64) { unimplemented!() }
/// Send an event to one or all TCSes.
@@ -568,7 +581,7 @@ impl Usercalls {
/// Request user memory.
///
/// Request an allocation in user memory of size `size` and with alignment
- /// `align`. If succesful, a pointer to this memory will be returned. The
+ /// `align`. If successful, a pointer to this memory will be returned. The
/// enclave must check the pointer is correctly aligned and that the entire
/// range of memory pointed to is outside the enclave.
///
@@ -589,7 +602,7 @@ impl Usercalls {
/// 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
+/// 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
@@ -605,18 +618,40 @@ impl Usercalls {
/// 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.
///
/// [MPSC queues]: struct.FifoDescriptor.html
/// [allocated per enclave]: ../struct.Usercalls.html#method.async_queues
/// [SCONE]: https://www.usenix.org/conference/osdi16/technical-sessions/presentation/arnautov
/// [HotCalls]: http://www.ofirweisse.com/ISCA17_Ofir_Weisse.pdf
+/// [`Interrupted`]: enum.Error.html#variant.Interrupted
+/// [`Result`]: type.Result.html
///
/// # 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`], or both in the `event_mask`. Userspace will wake
+/// [`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
@@ -627,34 +662,70 @@ impl Usercalls {
/// [`wait()`]: ../struct.Usercalls.html#method.wait
/// [`EV_USERCALLQ_NOT_FULL`]: ../constant.EV_USERCALLQ_NOT_FULL.html
/// [`EV_RETURNQ_NOT_EMPTY`]: ../constant.EV_RETURNQ_NOT_EMPTY.html
+/// [`EV_CANCELQ_NOT_FULL`]: ../constant.EV_CANCELQ_NOT_FULL.html
pub mod async {
use super::*;
- use core::sync::atomic::AtomicUsize;
+ use core::sync::atomic::{AtomicU64, AtomicUsize};
- /// An identified usercall.
#[repr(C)]
- #[derive(Copy, Clone)]
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
- pub struct Usercall {
- /// `0` indicates this slot is empty.
- pub id: u64,
- /// The elements correspond to the RDI, RSI, RDX, R8, and R9 registers
- /// in the synchronous calling convention.
- pub args: (u64, u64, u64, u64, u64)
+ pub struct WithId<T> {
+ pub id: AtomicU64,
+ pub data: T,
+ }
+
+ /// A usercall.
+ /// The elements correspond to the RDI, RSI, RDX, R8, and R9 registers
+ /// in the synchronous calling convention.
+ #[repr(C)]
+ #[derive(Copy, Clone, Default)]
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ pub struct Usercall(pub u64, pub u64, pub u64, pub u64, pub u64);
+
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ impl From<Usercall> for (u64, u64, u64, u64, u64) {
+ fn from(u: Usercall) -> Self {
+ let Usercall(p1, p2, p3, p4, p5) = u;
+ (p1, p2, p3, p4, p5)
+ }
+ }
+
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ impl From<(u64, u64, u64, u64, u64)> for Usercall {
+ fn from(p: (u64, u64, u64, u64, u64)) -> Self {
+ Usercall(p.0, p.1, p.2, p.3, p.4)
+ }
}
- /// The return value of an identified usercall.
+ /// The return value of a usercall.
+ /// The elements correspond to the RSI and RDX registers in the
+ /// synchronous calling convention.
#[repr(C)]
- #[derive(Copy, Clone)]
+ #[derive(Copy, Clone, Default)]
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
- pub struct Return {
- /// `0` indicates this slot is empty.
- pub id: u64,
- /// The elements correspond to the RSI and RDX registers in the
- /// synchronous calling convention.
- pub value: (u64, u64)
+ pub struct Return(pub u64, pub u64);
+
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ impl From<Return> for (u64, u64) {
+ fn from(r: Return) -> Self {
+ let Return(r1, r2) = r;
+ (r1, r2)
+ }
}
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ impl From<(u64, u64)> for Return {
+ fn from(r: (u64, u64)) -> Self {
+ Return(r.0, r.1)
+ }
+ }
+
+ /// Cancel a usercall previously sent to userspace.
+ #[repr(C)]
+ #[derive(Copy, Clone, Default)]
+ #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
+ pub struct Cancel;
+
/// A circular buffer used as a FIFO queue with atomic reads and writes.
///
/// The read offset is the element that was most recently read by the
@@ -679,7 +750,7 @@ pub mod async {
/// 1. Load the current offsets.
/// 2. If the queue is full, wait, then go to step 1.
/// 3. Add 1 to the write offset and do an atomic compare-and-swap (CAS)
- /// with the current offsets. If the CAS was not succesful, go to step
+ /// with the current offsets. If the CAS was not successful, go to step
/// 1\.
/// 4. Write the data, then the `id`.
/// 5. If the queue was empty in step 1, signal the reader to wake up.
@@ -695,14 +766,15 @@ pub mod async {
/// 5. If `id` is `0`, go to step 4 (spin). Spinning is OK because data is
/// expected to be written imminently.
/// 6. Read the data, then store `0` in the `id`.
- /// 7. Store the new read offset.
- /// 8. If the queue was full in step 1, signal the writer to wake up.
+ /// 7. Store the new read offset, retrieving the old offsets.
+ /// 8. If the queue was full before step 7, signal the writer to wake up.
#[repr(C)]
#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
pub struct FifoDescriptor<T> {
/// Pointer to the queue memory. Must have a size of
- /// `len * size_of::<T>()` bytes and have alignment `align_of::<T>`.
- pub data: *mut T,
+ /// `len * size_of::<WithId<T>>()` bytes and have alignment
+ /// `align_of::<WithId<T>>`.
+ pub data: *mut WithId<T>,
/// The number of elements pointed to by `data`. Must be a power of two
/// less than or equal to 2³¹.
pub len: usize,
@@ -735,11 +807,13 @@ pub mod async {
impl Usercalls {
/// Request FIFO queues for asynchronous usercalls. `usercall_queue`
/// and `return_queue` must point to valid user memory with the correct
- /// size and alignment for their types. On return, userspace will have
- /// filled these structures with information about the queues. A single
- /// set of queues will be allocated per enclave. Once this usercall has
- /// returned succesfully, calling this usercall again is equivalent to
- /// calling `exit(true)`.
+ /// size and alignment for their types. `cancel_queue` is optional, but
+ /// if specified (not null) it must point to valid user memory with
+ /// correct size and alignment.
+ /// On return, userspace will have filled these structures with
+ /// information about the queues. A single set of queues will be
+ /// allocated per enclave. Once this usercall has returned successfully,
+ /// calling this usercall again is equivalent to calling `exit(true)`.
///
/// May fail if the platform does not support asynchronous usercalls.
///
@@ -747,7 +821,11 @@ pub mod async {
/// [`FifoDescriptor`] is outside the enclave.
///
/// [`FifoDescriptor`]: async/struct.FifoDescriptor.html
- pub fn async_queues(usercall_queue: *mut FifoDescriptor<Usercall>, return_queue: *mut FifoDescriptor<Return>) -> Result { unimplemented!() }
+ pub fn async_queues(
+ usercall_queue: *mut FifoDescriptor<Usercall>,
+ return_queue: *mut FifoDescriptor<Return>,
+ cancel_queue: *mut FifoDescriptor<Cancel>
+ ) -> Result { unimplemented!() }
}
}