]> git.proxmox.com Git - rustc.git/blame - vendor/fortanix-sgx-abi/src/lib.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / vendor / fortanix-sgx-abi / src / lib.rs
CommitLineData
0731742a
XL
1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#![cfg_attr(
7 not(feature = "docs"),
8 doc = "**You are viewing the internals documentation."
9)]
10#![cfg_attr(
11 not(feature = "docs"),
12 doc = "You probably want to compile the documentation with the “docs” feature.**"
13)]
14#![cfg_attr(not(feature = "docs"), doc = "---")]
15//! The Fortanix SGX ABI (compiler target `x86_64-fortanix-unknown-sgx`) is an
16//! interface for Intel SGX enclaves. It is a small yet functional interface
17//! suitable for writing larger enclaves. In contrast to other enclave
f2b60f7d 18//! interfaces, this interface is primarily designed for running entire
0731742a
XL
19//! applications in an enclave.
20//!
21//! The Fortanix SGX ABI specification consists of two parts:
22//!
23//! 1. The calling convention (see FORTANIX-SGX-ABI.md)
24//! 2. The execution environment and [usercalls](struct.Usercalls.html) (this document)
25//!
26//! Whereas the calling convention describes how information is passed to and
27//! from the enclave, this document ascribes meaning to those values.
28//!
29//! The execution environment and usercalls have been designed with the
30//! following goals in mind:
31//!
32//! 1. *Compatible with most Rust code:* Rust code that doesn't link to other C
33//! libraries and that doesn't use files (see no. 5) should compile out of
34//! the box.
35//! 2. *Designed for SGX:* The SGX environment is unique and not compatible
36//! with other application environments out there. The primitives specified
37//! in this document are designed to work well with SGX, not to be similar
38//! to or compatible with primitives known from other environments.
39//! 3. *Designed for network services:* The most interesting usecase for SGX is
40//! to run applications remotely in an untrusted environment, e.g. the
41//! cloud. Therefore, there is a primary focus on supporting functionality
42//! needed in those situations.
43//! 4. *No filesystem:* Encrypted filesystems are hard. Especially in SGX,
44//! consistency and freshness are big concerns. In this initial version,
45//! there is no filesystem support, which is fine for most network services,
46//! which would want to keep their state with a database service anyway.
47//! Support might be added in the future.
48//! 5. *Not POSIX:* The POSIX API is huge and contains many elements that are
49//! not directly supported by the SGX instruction set, such as fork and
50//! mmap. It is explicitly a non-goal of this specification to support all
51//! of POSIX.
52//! 6. *Designed to be portable:* Enclaves don't interact directly with the OS,
53//! so there should be no need to recompile an enclave when running it with
54//! a different OS. This specification does not require any particular
55//! primitives or behavior from the OS.
56//!
57//! Like on regular operating systems, there are two types of enclaves:
58//! *executable*-type and *library*-type. The main difference between the two
59//! different types is how the enclave may be entered. Once an enclave TCS is
60//! entered, the different types act virtually identically. More information on
61//! the two different types, TCSs, and enclave entry may be found in the
62//! [`entry`](entry/index.html) module.
63//!
64//! Once an enclave TCS is entered, it may performs *synchronous usercalls* as
65//! described in the calling convention. The TCS maintains its execution state
66//! between doing a usercall and returning from the usercall. Only when the TCS
67//! exits, either through a non-usercall exit or through the
68//! [`exit`](struct.Usercalls.html#method.exit) usercall, is the TCS state
69//! destroyed. This is depicted in the following diagram.
70//!
3dfed10e 71//! ![Enclave execution lifecycle](https://edp.fortanix.com/img/docs/enclave-execution-lifecycle.png)
0731742a
XL
72//!
73//! Enclaves may also perform *asynchronous usercalls*. This is detailed in the
74//! [`async`](async/index.html) module. Most usercalls can be submitted either
75//! synchronously or asynchronously.
76#![allow(unused)]
77#![no_std]
78#![cfg_attr(feature = "rustc-dep-of-std", feature(staged_api))]
79#![cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
3dfed10e
XL
80#![doc(html_logo_url = "https://edp.fortanix.com/img/docs/edp-logo.svg",
81 html_favicon_url = "https://edp.fortanix.com/favicon.ico",
82 html_root_url = "https://edp.fortanix.com/docs/api/")]
0731742a
XL
83
84use core::ptr::NonNull;
f2b60f7d 85use core::sync::atomic::{AtomicU64, AtomicUsize};
0731742a
XL
86
87macro_rules! invoke_with_abi_spec [
88 ( $m:ident ) => [ $m![
89
90/// Specification of TCS and entry function requirements.
91///
92/// Once an enclave has called the
93/// [`exit`](../../struct.Usercalls.html#method.exit) usercall, if userspace
94/// enters a TCS normally, the enclave must panic. If userspace returns a
95/// usercall on a TCS, the enclave may decide whether to handle it normally or
96/// to panic.
97pub mod entry {
98 /// Specifies the entry points for libraries.
99 ///
100 /// The specification for library support is **experimental** and is
101 /// subject to change.
102 ///
103 /// When a user application wishes to call into the enclave library,
104 /// userspace may use any available TCS. Libraries may keep state between
105 /// invocations, but the library must not assume that subsequent calls will
106 /// go to the same TCS.
107 ///
108 /// The use of asynchronous usercalls with libraries is not recommended, as
109 /// userspace will not be able to wake up the appropriate thread in a
110 /// multi-threaded library scenario.
111 ///
112 /// Automatically launching threads using the
113 /// [`launch_thread`](../../struct.Usercalls.html#method.launch_thread)
114 /// usercall is not supported. Libraries that want to leverage
115 /// multi-threading must rely on application support to call into the
116 /// enclave from different threads.
117 pub mod library {
118 /// The entry point of every TCS.
119 ///
120 /// If a library wishes to expose multiple different functions, it must
121 /// implement this by multiplexing on one of the input parameters. It
122 /// is recommended to use `p1` for this purpose.
123 ///
124 /// The `_ignore` parameter may be set to any value by userspace. The
125 /// value observed by the enclave may be different from the value
126 /// passed by userspace and must therefore be ignored by the enclave.
127 pub fn entry(p1: u64, p2: u64, p3: u64, _ignore: u64, p4: u64, p5: u64) -> (u64, u64) { unimplemented!() }
128 }
129
130 /// Specifies the entry points for executables.
131 pub mod executable {
132 use ByteBuffer;
133
134 /// The main entry point of the enclave. This will be the entry point
135 /// of the first TCS.
136 ///
137 /// The enclave must not return from this entry. Instead, it must call
138 /// the [`exit`](../../struct.Usercalls.html#method.exit) usercall. If
139 /// the enclave does return from this TCS, and userspace subsequently
140 /// re-enters this TCS, the enclave must panic.
141 ///
142 /// Arbitrary “command-line arguments” may be passed in from userspace.
143 /// The enclave must ensure that the all buffers pointed to are
144 /// outside the enclave. The enclave should deallocate each
145 /// [`ByteBuffer`] as specified by the type. The enclave should
146 /// deallocate the main buffer by calling
147 /// [`free`]`(args, len * size_of::<ByteBuffer>, 1)`.
148 ///
149 /// [`free`]: ../../struct.Usercalls.html#method.free
150 /// [`ByteBuffer`]: ../../struct.ByteBuffer.html
151 pub fn main_entry(args: *const ByteBuffer, len: usize) -> ! { unimplemented!() }
152
153 /// The entry point of additional threads of the enclave, for non-first
154 /// TCSs.
155 ///
156 /// When returning from this TCS, userspace may re-enter this TCS after
157 /// another call to [`launch_thread`].
158 ///
159 /// The enclave must keep track of whether it expects another thread to
160 /// be launched, e.g. by keeping track of how many times it called
161 /// [`launch_thread`]. If a TCS with this entry point is entered even
3dfed10e 162 /// though the enclave didn't request it, the enclave must panic.
0731742a
XL
163 ///
164 /// [`launch_thread`]: ../../struct.Usercalls.html#method.launch_thread
165 pub fn thread_entry() { unimplemented!() }
166 }
167}
168
169/// An arbitrary-sized buffer of bytes in userspace, allocated by userspace.
170///
171/// This type is used when userspace may return arbitrary-sized data from a
3dfed10e
XL
172/// usercall. When reading from the buffer, if `len` is not `0`, the enclave
173/// must ensure the entire buffer is in the user memory range. Once the enclave
174/// is done with the buffer, it should deallocate the buffer buffer by calling
0731742a
XL
175/// [`free`]`(data, len, 1)`.
176///
3dfed10e
XL
177/// If `len` is `0`, the enclave should ignore `data`. It should not call
178/// `free`.
179///
0731742a
XL
180/// [`free`]: ./struct.Usercalls.html#method.launch_thread
181#[repr(C)]
182#[derive(Copy, Clone)]
183#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
184pub struct ByteBuffer {
185 pub data: *const u8,
186 pub len: usize
187}
188
f2b60f7d
FG
189#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
190unsafe impl Send for ByteBuffer {}
191
0731742a
XL
192/// Error code definitions and space allocation.
193///
194/// Only non-zero positive values are valid errors. The variants are designed
195/// to map to [std::io::ErrorKind]. See the source for the value mapping.
196///
197/// [std::io::ErrorKind]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html
198#[repr(i32)]
199#[derive(Copy, Clone, Eq, PartialEq)]
200#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
201pub enum Error {
202 PermissionDenied = 0x01,
203 NotFound = 0x02,
204 Interrupted = 0x04,
205 WouldBlock = 0x0b,
206 AlreadyExists = 0x11,
207 InvalidInput = 0x16,
208 BrokenPipe = 0x20,
209 AddrInUse = 0x62,
210 AddrNotAvailable = 0x63,
211 ConnectionAborted = 0x67,
212 ConnectionReset = 0x68,
213 NotConnected = 0x6b,
214 TimedOut = 0x6e,
215 ConnectionRefused = 0x6f,
216 InvalidData = 0x2000_0000,
217 WriteZero = 0x2000_0001,
218 UnexpectedEof = 0x2000_0002,
219 /// This value is reserved for `Other`, but all undefined values also map
220 /// to `Other`.
221 Other = 0x3fff_ffff,
222 /// Start of the range of values reserved for user-defined errors.
223 UserRangeStart = 0x4000_0000,
224 /// End (inclusive) of the range of values reserved for user-defined errors.
225 UserRangeEnd = 0x7fff_ffff,
226}
227
f2b60f7d 228/// A value indicating that the operation was successful.
0731742a
XL
229#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
230pub const RESULT_SUCCESS: Result = 0;
231
232/// The first return value of usercalls that might fail.
233///
234/// [`RESULT_SUCCESS`](constant.RESULT_SUCCESS.html) or an error code from the
235/// [`Error`](enum.Error.html) type.
236#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
237pub type Result = i32;
238
239/// The list of all usercalls.
240///
241/// *This is not a real structure, it's just a convenient way to group
242/// functions with `rustdoc`.*
243///
244/// The usercall number is passed in the first register. Up to 4 arguments may
245/// be passed in the remaining registers. Unspecified arguments and return
246/// values must be 0. Userspace must check the arguments and the enclave must
247/// check the return value.
248///
249/// The usercall number may be one of the predefined numbers associated with
250/// one of the usercalls defined below, or, if bit
251/// [`USERCALL_USER_DEFINED`](constant.USERCALL_USER_DEFINED.html) is set, an
252/// otherwise arbitrary number with an application-defined meaning.
253///
254/// Raw pointers must always point to user memory. When receiving raw pointers
255/// from userspace, the enclave must verify that the entire pointed-to memory
256/// space is outside the enclave memory range. It must then copy all data in
257/// user memory to enclave memory before operating on it.
258#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
259pub struct Usercalls;
260
261/// Usercall numbers with this bit set will never be defined by this specification.
262#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
263pub const USERCALL_USER_DEFINED: u64 = 0x8000_0000;
264
265/// A file descriptor.
266#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
267pub type Fd = u64;
268
269/// Standard input file descriptor. Input read this way is not secure.
270#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
271pub const FD_STDIN: Fd = 0;
272/// Standard output file descriptor. This is not a secure output channel.
273#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
274pub const FD_STDOUT: Fd = 1;
275/// Standard error file descriptor. This is not a secure output channel.
276#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
277pub const FD_STDERR: Fd = 2;
278
279/// # Streams
280///
281/// The enclave must not assume anything about data read or written using these
282/// calls. Data written may be piped directly to `/dev/null` by userspace, or
283/// it may be published in the local newspaper. Similarly, data read may be
284/// arbitrarily deleted, inserted, or changed. The enclave must use additional
285/// security primitives such as sealing or TLS to obtain stronger guarantees.
286///
287/// When a stream is read from by multiple threads simultaneously, the read
288/// calls may be serialized in any order. This means the data returned by a
289/// read call appeared that way in the stream, and every single byte in the
290/// stream will be read and be read only once. However, the order in which all
291/// stream data is returned is not defined. The same applies when
292/// simultaneously submitting multiple read calls for the same stream
293/// asynchronously. This all applies similarly to writing to a stream.
294///
295/// To make sure to be able to re-assemble the stream, the enclave can take one
296/// of the following approaches:
297///
298/// 1. Submit all read calls to a single stream on a single thread.
299/// 2. Serializing read calls by synchronizing access to a single stream.
300///
301/// In addition, the enclave should use cryptographic integrity protection of
302/// the stream data to ensure the stream data has not been tampered with.
303impl Usercalls {
304 /// Read up to `len` bytes from stream `fd`.
305 ///
306 /// `buf` must point to a buffer in userspace with a size of at least
f2b60f7d 307 /// `len`. On a successful return, the number of bytes written is returned.
0731742a 308 /// The enclave must check that the returned length is no more than `len`.
3dfed10e
XL
309 /// If `len` is `0`, this call should block until the stream is ready for
310 /// reading. If `len` is `0` or end of stream is reached, `0` may be
311 /// returned.
0731742a
XL
312 ///
313 /// The enclave may mix calls to [`read`](#method.read) and
314 /// [`read_alloc`](#method.read_alloc).
315 pub fn read(fd: Fd, buf: *mut u8, len: usize) -> (Result, usize) { unimplemented!() }
316
317 /// Read some data from stream `fd`, letting the callee choose the amount.
318 ///
319 /// `buf` must point to a [`ByteBuffer`] in userspace, and `buf.data` must
320 /// contain `null`. On success, userspace will allocate memory for the read
321 /// data and populate `ByteBuffer` appropriately. The enclave must handle
322 /// and deallocate the buffer according to the `ByteBuffer` documentation.
323 ///
324 /// Since every read operation using this usercall requires two usercalls,
325 /// it is recommended to only call this usercall asynchronously.
326 ///
327 /// The enclave may mix calls to [`read`](#method.read) and
328 /// [`read_alloc`](#method.read_alloc).
329 ///
330 /// [`ByteBuffer`]: ./struct.ByteBuffer.html
331 pub fn read_alloc(fd: Fd, buf: *mut ByteBuffer) -> Result { unimplemented!() }
332
333 /// Write up to `len` bytes to stream `fd`.
334 ///
335 /// `buf` must point to a buffer in userspace with a size of at least
f2b60f7d 336 /// `len`. On a successful return, the number of bytes written is returned.
0731742a 337 /// The enclave must check that the returned length is no more than `len`.
3dfed10e
XL
338 /// If `len` is `0`, this call should block until the stream is ready for
339 /// writing. If `len` is `0` or the stream is closed, `0` may be returned.
0731742a
XL
340 pub fn write(fd: Fd, buf: *const u8, len: usize) -> (Result, usize) { unimplemented!() }
341
342 /// Flush stream `fd`, ensuring that all intermediately buffered contents
343 /// reach their destination.
344 pub fn flush(fd: Fd) -> Result { unimplemented!() }
345
346 /// Close stream `fd`.
347 ///
348 /// Once the stream is closed, no further data may be read or written.
349 /// Userspace may reuse the `fd` in the future for a different stream.
350 pub fn close(fd: Fd) { unimplemented!() }
351}
352
353/// # Networking
354///
355/// In keeping with the design goals for this specification, the
356/// networking/socket interface doesn't use `sockaddr` types and doesn't
357/// have a separate API for name resolution. Userspace can't be trusted to
358/// do name resolution correctly, and even if it did, *userspace can't be
359/// trusted to actually connect streams to the correct address* specified by
360/// the enclave. Therefore, addresses specified should merely be treated as a
361/// suggestion, and additional measures must be taken by an enclave to verify
362/// the stream is connected to the correct peer, e.g. TLS.
363///
364/// The networking API works with strings as addresses. All byte buffers
365/// representing network addresses should contain a valid UTF-8 string. The
366/// enclave should panic if it is passed an invalid string by userspace. It is
367/// suggested that userspace supports at least the following notations:
368///
369/// * `hostname:port-number` (e.g. `example.com:123`)
370/// * `dotted-octet-ipv4-address:port-number` (e.g. `192.0.2.1:123`)
371/// * `[ipv6-address]:port-number` (e.g. `[2001:db8::1]:123`)
372///
373/// Additionally, other forms may be accepted, for example service names:
374///
375/// * `fully-qualified-service-name` (e.g. `_example._tcp.example.com`)
376/// * `address:service-name` (e.g. `address:example`)
377///
378/// # Errors
379///
380/// Networking calls taking an address may return the [`InvalidInput`] error if
381/// the address could not be interpreted by userspace.
382///
383/// [`InvalidInput`]: enum.Error.html#variant.InvalidInput
384impl Usercalls {
385 /// Setup a listening socket.
386 ///
387 /// The socket is bound to the address specified in `addr`. `addr` must be
388 /// a buffer in user memory with a size of at least `len`.
389 ///
390 /// On success, a file descriptor is returned which may be passed to
391 /// [`accept_stream`](#method.accept_stream) or [`close`](#method.close).
392 ///
393 /// The enclave may optionally request the local socket address be returned
394 /// in `local_addr`. On success, if `local_addr` is not NULL, userspace
395 /// will allocate memory for the address and populate [`ByteBuffer`]
396 /// appropriately. The enclave must handle and deallocate the buffer
397 /// according to the `ByteBuffer` documentation.
398 ///
399 /// The enclave must not make any security decisions based on the local
400 /// address received.
401 ///
402 /// [`ByteBuffer`]: ./struct.ByteBuffer.html
403 pub fn bind_stream(addr: *const u8, len: usize, local_addr: *mut ByteBuffer) -> (Result, Fd) { unimplemented!() }
404
405 /// Accept a new connection from a listening socket.
406 ///
407 /// `fd` should be a file descriptor previously returned from
408 /// [`bind_stream`](#method.bind_stream).
409 ///
410 /// The enclave may optionally request the local or peer socket addresses
411 /// be returned in `local_addr` or `peer_addr`, respectively. On success,
412 /// if `local_addr` and/or `peer_addr` is not NULL, userspace will allocate
413 /// memory for the address and populate the respective [`ByteBuffer`]
414 /// appropriately.
415 ///
416 /// The enclave must handle and deallocate each buffer according to the
417 /// `ByteBuffer` documentation.
418 ///
419 /// The enclave must not make any security decisions based on the local or
420 /// peer address received.
421 ///
422 /// [`ByteBuffer`]: ./struct.ByteBuffer.html
423 pub fn accept_stream(fd: Fd, local_addr: *mut ByteBuffer, peer_addr: *mut ByteBuffer) -> (Result, Fd) { unimplemented!() }
424
425 /// Create a new stream connection to the specified address.
426 ///
427 /// The enclave may optionally request the local or peer socket addresses
428 /// be returned in `local_addr` or `peer_addr`, respectively. On success,
429 /// if `local_addr` and/or `peer_addr` is not NULL, userspace will allocate
430 /// memory for the address and populate the respective [`ByteBuffer`]
431 /// appropriately.
432 ///
433 /// The enclave must handle and deallocate each buffer according to the
434 /// `ByteBuffer` documentation.
435 ///
436 /// The enclave must not make any security decisions based on the local or
437 /// peer address received.
438 ///
439 /// [`ByteBuffer`]: ./struct.ByteBuffer.html
440 pub fn connect_stream(addr: *const u8, len: usize, local_addr: *mut ByteBuffer, peer_addr: *mut ByteBuffer) -> (Result, Fd) { unimplemented!() }
441}
442
443/// The absolute address of a TCS in the current enclave.
444// FIXME: `u8` should be some `extern type` instead.
445#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
446pub type Tcs = NonNull<u8>;
447
448/// An event that will be triggered by userspace when the usercall queue is not
449/// or no longer full.
450#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
451pub const EV_USERCALLQ_NOT_FULL: u64 = 0b0000_0000_0000_0001;
452/// An event that will be triggered by userspace when the return queue is not
453/// or no longer empty.
454#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
455pub const EV_RETURNQ_NOT_EMPTY: u64 = 0b0000_0000_0000_0010;
456/// An event that enclaves can use for synchronization.
457#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
458pub const EV_UNPARK: u64 = 0b0000_0000_0000_0100;
f2b60f7d
FG
459/// An event that will be triggered by userspace when the cancel queue is not
460/// or no longer full.
461#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
462pub const EV_CANCELQ_NOT_FULL: u64 = 0b0000_0000_0000_1000;
0731742a
XL
463
464#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
465pub const WAIT_NO: u64 = 0;
466#[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
467pub const WAIT_INDEFINITE: u64 = !0;
468
469/// # Execution control
470///
471/// ## TCS event queues
472///
473/// Userspace will maintain a queue for each running TCS with events to be
f2b60f7d
FG
474/// delivered. Each event is characterized by a bitset with at least one bit
475/// set. Userspace or the enclave (using the `send` usercall) can put events on
476/// this queue.
477/// If the enclave isn't waiting for an event when an event is queued, the event
0731742a
XL
478/// remains on the queue until it delivered to the enclave in a later `wait`
479/// usercall. If an enclave is waiting for an event, and the queue contains an
480/// event that is a subset of the waited-for event mask, that event is removed
481/// from the queue and execution control is returned to the enclave.
482///
483/// Events not defined in this specification should not be generated.
484impl Usercalls {
485 /// In [executables](entry/executable/index.html), this will instruct
486 /// userspace to enter another TCS in another thread. This TCS should have
487 /// the [`thread_entry`] entrypoint. As documented in [`thread_entry`], the
488 /// enclave should keep track of how many threads it launched and reconcile
489 /// this with the number of entries into [`thread_entry`]. If no free TCSes
490 /// are immediately available, this may return an error.
491 ///
f2b60f7d 492 /// This function will never be successful in [libraries]. See the
0731742a
XL
493 /// [`library`] documentation on how to use threads with libraries.
494 ///
495 /// [`thread_entry`]: entry/executable/fn.thread_entry.html
496 /// [libraries]: entry/library/index.html
497 /// [`library`]: entry/library/index.html
498 pub fn launch_thread() -> Result { unimplemented!() }
499
500 /// Signals to userspace that this enclave needs to be destroyed.
501 ///
502 /// The enclave must not rely on userspace to terminate other threads still
503 /// running. Similarly, the enclave must not trust that it will no longer
504 /// be entered by userspace, and it must safeguard against that in the
505 /// entrypoints.
506 ///
507 /// If `panic` is set to `true`, the enclave has exited due to a panic
508 /// condition. If the enclave was running in debug mode, the enclave may
509 /// have output a debug message according to the calling convention.
510 pub fn exit(panic: bool) -> ! { unimplemented!() }
511
512 /// Wait for an event to occur, or check if an event is currently pending.
513 ///
f2b60f7d
FG
514 /// `timeout` must be [`WAIT_NO`] or [`WAIT_INDEFINITE`] or a positive
515 /// value smaller than u64::MAX specifying number of nanoseconds to wait.
0731742a
XL
516 ///
517 /// If `timeout` is [`WAIT_INDEFINITE`], this call will block and return
518 /// once a matching event is queued on this TCS. If `timeout` is
519 /// [`WAIT_NO`], this call will return immediately, and the return value
520 /// will indicate if an event was pending. If it was, it has been dequeued.
f2b60f7d
FG
521 /// If not, the [`WouldBlock`] error value will be returned. If `timeout`
522 /// is a value other than [`WAIT_NO`] and [`WAIT_INDEFINITE`], this call
523 /// will block until either a matching event is queued in which case the
524 /// return value will indicate the event, or the timeout is reached in
525 /// which case the [`TimedOut`] error value will be returned.
0731742a
XL
526 ///
527 /// A matching event is one whose bits are equal to or a subset of
528 /// `event_mask`. If `event_mask` is `0`, this call will never return due
529 /// to an event. If `timeout` is also [`WAIT_INDEFINITE`], this call will
530 /// simply never return.
531 ///
532 /// Enclaves must not assume that this call only returns in response to
533 /// valid events generated by the enclave. This call may return for invalid
534 /// event sets, or before `timeout` has expired even though no event is
535 /// pending.
536 ///
537 /// When executed synchronously, this gives userspace an opportunity to
538 /// schedule something else in a cooperative multitasking environment.
539 ///
540 /// When executed asynchronously, this may trigger an
541 /// [`EV_RETURNQ_NOT_EMPTY`] event on this or other TCSes. It is not
542 /// recommended to execute this call asynchronously with a `timeout` value
543 /// other than [`WAIT_NO`].
544 ///
545 /// [`WAIT_NO`]: constant.WAIT_NO.html
546 /// [`WAIT_INDEFINITE`]: constant.WAIT_INDEFINITE.html
547 /// [`EV_RETURNQ_NOT_EMPTY`]: constant.EV_RETURNQ_NOT_EMPTY.html
548 /// [`WouldBlock`]: enum.Error.html#variant.WouldBlock
f2b60f7d 549 /// [`TimedOut`]: enum.Error.html#variant.TimedOut
0731742a
XL
550 pub fn wait(event_mask: u64, timeout: u64) -> (Result, u64) { unimplemented!() }
551
552 /// Send an event to one or all TCSes.
553 ///
554 /// If `tcs` is `None`, send the event `event_set` to all TCSes of this
555 /// enclave, otherwise, send it to the TCS specified in `tcs`.
556 ///
557 /// # Error
558 ///
559 /// This will return the [`InvalidInput`] error if `tcs` is set but doesn't
560 /// specify a valid TCS address.
561 ///
562 /// [`InvalidInput`]: enum.Error.html#variant.InvalidInput
563 pub fn send(event_set: u64, tcs: Option<Tcs>) -> Result { unimplemented!() }
564}
565
566/// # Miscellaneous
567impl Usercalls {
568 /// This returns the number of nanoseconds since midnight UTC on January 1,
569 /// 1970\. The enclave must not rely on the accuracy of this time for
570 /// security purposes, such as checking credential expiry or preventing
571 /// rollback.
572 pub fn insecure_time() -> u64 { unimplemented!() }
573}
574
575/// # Memory
576///
577/// The enclave must not use any memory outside the enclave, except for memory
578/// explicitly returned from usercalls. You can obtain arbitrary memory in
579/// userspace using [`alloc`](#method.alloc).
580impl Usercalls {
581 /// Request user memory.
582 ///
583 /// Request an allocation in user memory of size `size` and with alignment
f2b60f7d 584 /// `align`. If successful, a pointer to this memory will be returned. The
0731742a
XL
585 /// enclave must check the pointer is correctly aligned and that the entire
586 /// range of memory pointed to is outside the enclave.
3dfed10e
XL
587 ///
588 /// It is an error to call this function with `size` equal to `0`.
0731742a
XL
589 pub fn alloc(size: usize, alignment: usize) -> (Result, *mut u8) { unimplemented!() }
590
591 /// Free user memory.
592 ///
593 /// This must be called to deallocate memory in userspace. The pointer
594 /// `ptr` must have previously been returned by a usercall. The `size` and
595 /// `alignment` specified must exactly match what was allocated. This
596 /// function must be called exactly once for each user memory buffer.
3dfed10e
XL
597 ///
598 /// Calling this function with `size` equal to `0` is a no-op.
0731742a
XL
599 pub fn free(ptr: *mut u8, size: usize, alignment: usize) { unimplemented!() }
600}
601
602/// Asynchronous usercall specification.
603///
604/// An asynchronous usercall allows an enclave to submit a usercall without
f2b60f7d 605/// exiting the enclave. This is necessary since enclave entries and exits are
0731742a
XL
606/// slow (see academic work on [SCONE], [HotCalls]). In addition, the enclave
607/// can perform other tasks while it waits for the usercall to complete. Those
608/// tasks may include issuing other usercalls, either synchronously or
609/// asynchronously.
610///
611/// Two [MPSC queues] are [allocated per enclave]. One queue is used by any
612/// enclave thread to submit usercalls to userspace. Userspace will read the
613/// calls from this queue and handle them. Another queue is used by userspace
614/// to return completed usercalls to the enclave.
615///
616/// Each call is identified by an enclave-specified `id`. Userspace must
617/// provide the same `id` when returning. The enclave must not submit multiple
618/// concurrent usercalls with the same `id`, but it may reuse an `id` once the
619/// original usercall with that `id` has returned.
620///
f2b60f7d
FG
621/// An optional third queue can be used to cancel usercalls. To cancel an async
622/// usercall, the enclave should send the usercall's id and number on this
623/// queue. If the usercall has already been processed, the enclave may still
624/// receive a successful result for the usercall. Otherwise, the userspace will
625/// cancel the usercall's execution and return an [`Interrupted`] error on the
626/// return queue to notify the enclave of the cancellation. Note that usercalls
627/// that do not return [`Result`] cannot be cancelled and if the enclave sends
628/// a cancellation for such a usercall, the userspace should simply ignore it.
629/// Additionally, userspace may choose to ignore cancellations for non-blocking
630/// usercalls. Userspace should be able to cancel a usercall that has been sent
631/// by the enclave but not yet received by the userspace, i.e. if cancellation
632/// is received before the usercall itself. To avoid keeping such cancellations
633/// forever and preventing the enclave from re-using usercall ids, userspace
634/// should synchronize cancel queue with the usercall queue such that the
635/// following invariant is maintained: whenever the enclave writes an id to the
636/// usercall or cancel queue, the enclave will not reuse that id until the
637/// usercall queue's read pointer has advanced to the write pointer at the time
638/// the id was written.
639///
0731742a
XL
640/// *TODO*: Add diagram.
641///
642/// [MPSC queues]: struct.FifoDescriptor.html
643/// [allocated per enclave]: ../struct.Usercalls.html#method.async_queues
644/// [SCONE]: https://www.usenix.org/conference/osdi16/technical-sessions/presentation/arnautov
645/// [HotCalls]: http://www.ofirweisse.com/ISCA17_Ofir_Weisse.pdf
f2b60f7d
FG
646/// [`Interrupted`]: enum.Error.html#variant.Interrupted
647/// [`Result`]: type.Result.html
0731742a
XL
648///
649/// # Enclave/userspace synchronization
650///
651/// When the enclave needs to wait on a queue, it executes the [`wait()`]
652/// usercall synchronously, specifying [`EV_USERCALLQ_NOT_FULL`],
f2b60f7d
FG
653/// [`EV_RETURNQ_NOT_EMPTY`], [`EV_CANCELQ_NOT_FULL`], or any combination
654/// thereof in the `event_mask`. Userspace will wake
0731742a
XL
655/// any or all threads waiting on the appropriate event when it is triggered.
656///
657/// When userspace needs to wait on a queue, it will park the current thread
658/// (or do whatever else is appropriate for the synchronization model currently
659/// in use by userspace). Any synchronous usercall will wake the blocked thread
660/// (or otherwise signal that either queue is ready).
661///
662/// [`wait()`]: ../struct.Usercalls.html#method.wait
663/// [`EV_USERCALLQ_NOT_FULL`]: ../constant.EV_USERCALLQ_NOT_FULL.html
664/// [`EV_RETURNQ_NOT_EMPTY`]: ../constant.EV_RETURNQ_NOT_EMPTY.html
f2b60f7d 665/// [`EV_CANCELQ_NOT_FULL`]: ../constant.EV_CANCELQ_NOT_FULL.html
0731742a
XL
666pub mod async {
667 use super::*;
f2b60f7d 668 use core::sync::atomic::{AtomicU64, AtomicUsize};
0731742a 669
0731742a 670 #[repr(C)]
0731742a 671 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
f2b60f7d
FG
672 pub struct WithId<T> {
673 pub id: AtomicU64,
674 pub data: T,
675 }
676
677 /// A usercall.
678 /// The elements correspond to the RDI, RSI, RDX, R8, and R9 registers
679 /// in the synchronous calling convention.
680 #[repr(C)]
681 #[derive(Copy, Clone, Default)]
682 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
683 pub struct Usercall(pub u64, pub u64, pub u64, pub u64, pub u64);
684
685 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
686 impl From<Usercall> for (u64, u64, u64, u64, u64) {
687 fn from(u: Usercall) -> Self {
688 let Usercall(p1, p2, p3, p4, p5) = u;
689 (p1, p2, p3, p4, p5)
690 }
691 }
692
693 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
694 impl From<(u64, u64, u64, u64, u64)> for Usercall {
695 fn from(p: (u64, u64, u64, u64, u64)) -> Self {
696 Usercall(p.0, p.1, p.2, p.3, p.4)
697 }
0731742a
XL
698 }
699
f2b60f7d
FG
700 /// The return value of a usercall.
701 /// The elements correspond to the RSI and RDX registers in the
702 /// synchronous calling convention.
0731742a 703 #[repr(C)]
f2b60f7d 704 #[derive(Copy, Clone, Default)]
0731742a 705 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
f2b60f7d
FG
706 pub struct Return(pub u64, pub u64);
707
708 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
709 impl From<Return> for (u64, u64) {
710 fn from(r: Return) -> Self {
711 let Return(r1, r2) = r;
712 (r1, r2)
713 }
0731742a
XL
714 }
715
f2b60f7d
FG
716 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
717 impl From<(u64, u64)> for Return {
718 fn from(r: (u64, u64)) -> Self {
719 Return(r.0, r.1)
720 }
721 }
722
723 /// Cancel a usercall previously sent to userspace.
724 #[repr(C)]
725 #[derive(Copy, Clone, Default)]
726 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
727 pub struct Cancel;
728
0731742a
XL
729 /// A circular buffer used as a FIFO queue with atomic reads and writes.
730 ///
731 /// The read offset is the element that was most recently read by the
732 /// receiving end of the queue. The write offset is the element that was
733 /// most recently written by the sending end. If the two offsets are equal,
734 /// the queue is either empty or full.
735 ///
736 /// The size of the buffer is such that not all the bits of the offset are
737 /// necessary to encode the current offset. The next highest unused bit is
738 /// used to keep track of the number of times the offset has wrapped
739 /// around. If the offsets are the same and the bit is the same in the read
740 /// and write offsets, the queue is empty. If the bit is different in the
741 /// read and write offsets, the queue is full.
742 ///
743 /// The following procedures will operate the queues in a multiple producer
744 /// single consumer (MPSC) fashion.
745 ///
746 /// ## Push operation
747 ///
748 /// To push an element onto the queue:
749 ///
750 /// 1. Load the current offsets.
751 /// 2. If the queue is full, wait, then go to step 1.
752 /// 3. Add 1 to the write offset and do an atomic compare-and-swap (CAS)
f2b60f7d 753 /// with the current offsets. If the CAS was not successful, go to step
0731742a
XL
754 /// 1\.
755 /// 4. Write the data, then the `id`.
756 /// 5. If the queue was empty in step 1, signal the reader to wake up.
757 ///
758 /// ## Pop operation
759 ///
760 /// To pop an element off the queue:
761 ///
762 /// 1. Load the current offsets.
763 /// 2. If the queue is empty, wait, then go to step 1.
764 /// 3. Add 1 to the read offset.
765 /// 4. Read the `id` at the new read offset.
766 /// 5. If `id` is `0`, go to step 4 (spin). Spinning is OK because data is
767 /// expected to be written imminently.
768 /// 6. Read the data, then store `0` in the `id`.
f2b60f7d
FG
769 /// 7. Store the new read offset, retrieving the old offsets.
770 /// 8. If the queue was full before step 7, signal the writer to wake up.
0731742a
XL
771 #[repr(C)]
772 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
773 pub struct FifoDescriptor<T> {
774 /// Pointer to the queue memory. Must have a size of
f2b60f7d
FG
775 /// `len * size_of::<WithId<T>>()` bytes and have alignment
776 /// `align_of::<WithId<T>>`.
777 pub data: *mut WithId<T>,
0731742a
XL
778 /// The number of elements pointed to by `data`. Must be a power of two
779 /// less than or equal to 2³¹.
780 pub len: usize,
781 /// Actually a `(u32, u32)` tuple, aligned to allow atomic operations
782 /// on both halves simultaneously. The first element (low dword) is
783 /// the read offset and the second element (high dword) is the write
784 /// offset.
785 pub offsets: *const AtomicUsize,
786 }
787
788 // not using `#[derive]` because that would require T: Clone
789 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
790 impl<T> Clone for FifoDescriptor<T> {
791 fn clone(&self) -> Self {
792 *self
793 }
794 }
795
796 // not using `#[derive]` because that would require T: Copy
797 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
798 impl<T> Copy for FifoDescriptor<T> {}
799
800 /// # Asynchronous usercalls
801 ///
802 /// *Due to `rustdoc`, this section may appear at the top of the
803 /// `Usercalls` documentation. You might want to read the other sections
804 /// first and then come back to this one.*
805 ///
806 /// See also the [`async` module](async/index.html) documentation.
807 impl Usercalls {
808 /// Request FIFO queues for asynchronous usercalls. `usercall_queue`
809 /// and `return_queue` must point to valid user memory with the correct
f2b60f7d
FG
810 /// size and alignment for their types. `cancel_queue` is optional, but
811 /// if specified (not null) it must point to valid user memory with
812 /// correct size and alignment.
813 /// On return, userspace will have filled these structures with
814 /// information about the queues. A single set of queues will be
815 /// allocated per enclave. Once this usercall has returned successfully,
816 /// calling this usercall again is equivalent to calling `exit(true)`.
0731742a
XL
817 ///
818 /// May fail if the platform does not support asynchronous usercalls.
819 ///
820 /// The enclave must ensure that the data pointed to in the fields of
821 /// [`FifoDescriptor`] is outside the enclave.
822 ///
823 /// [`FifoDescriptor`]: async/struct.FifoDescriptor.html
f2b60f7d
FG
824 pub fn async_queues(
825 usercall_queue: *mut FifoDescriptor<Usercall>,
826 return_queue: *mut FifoDescriptor<Return>,
827 cancel_queue: *mut FifoDescriptor<Cancel>
828 ) -> Result { unimplemented!() }
0731742a
XL
829 }
830}
831
832]; ] ];
833
834// docs: Just render the docs verbatim
835macro_rules! docs {
836 ($($tt:tt)*) => ($($tt)*)
837}
838
839#[cfg(feature = "docs")]
840invoke_with_abi_spec!(docs);
841
842// types: flatten the module structure and ignore any items that are not types.
843macro_rules! types {
844 // flatten modules
845 ($(#[$meta:meta])* pub mod $modname:ident { $($contents:tt)* } $($remainder:tt)*) =>
846 { types!($($contents)*); types!($($remainder)*); };
847 // ignore impls
848 ($(#[$meta:meta])* impl Usercalls { $($contents:tt)* } $($remainder:tt)* ) =>
849 { types!($($remainder)*); };
850 // ignore `struct Usercalls`
851 ($(#[$meta:meta])* pub struct Usercalls; $($remainder:tt)* ) =>
852 { types!($($remainder)*); };
853 // ignore free functions
854 ($(#[$meta:meta])* pub fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)* { unimplemented!() } $($remainder:tt)* ) =>
855 { types!($($remainder)*); };
856 // ignore use statements
857 (use $($tt:tt)::*; $($remainder:tt)* ) =>
858 { types!($($remainder)*); };
859 // copy all other items verbatim
860 ($item:item $($remainder:tt)*) =>
861 { $item types!($($remainder)*); };
862 () => {};
863}
864
865#[cfg(not(feature = "docs"))]
866invoke_with_abi_spec!(types);
867
868// Define a macro that will call a second macro providing the list of all
869// function declarations inside all `impl Usercalls` blocks.
870macro_rules! define_invoke_with_usercalls {
871 // collect all usercall function declarations in a list
872 (@ [$($accumulated:tt)*] $(#[$meta1:meta])* impl Usercalls { $($(#[$meta2:meta])* pub fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)* { unimplemented!() } )* } $($remainder:tt)* ) =>
873 { define_invoke_with_usercalls!(@ [$($accumulated)* $(fn $f($($n: $t),*) $(-> $r)*;)*] $($remainder)*); };
874 // visit modules
875 (@ $accumulated:tt $(#[$meta:meta])* pub mod $modname:ident { $($contents:tt)* } $($remainder:tt)*) =>
876 { define_invoke_with_usercalls!(@ $accumulated $($contents)* $($remainder)*); };
877 // ignore all other items
878 (@ $accumulated:tt $item:item $($remainder:tt)*) =>
879 { define_invoke_with_usercalls!(@ $accumulated $($remainder)*); };
880 // Define the macro
881 (@ $accumulated:tt) => {
882 /// Call the macro `$m`, passing a semicolon-separated list of usercall
883 /// function declarations.
884 ///
885 /// The passed in macro could for example use the following pattern:
886 ///
887 /// ```text
888 /// ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*)
889 /// ```
890 #[macro_export]
891 #[cfg_attr(feature = "rustc-dep-of-std", unstable(feature = "sgx_platform", issue = "56975"))]
892 macro_rules! invoke_with_usercalls {
893 ($m:ident) => { $m! $accumulated; }
894 }
895 };
896 // start collection with an empty list
897 ($($tt:tt)*) => {
898 define_invoke_with_usercalls!(@ [] $($tt)*);
899 }
900}
901
902#[cfg(not(feature = "docs"))]
903invoke_with_abi_spec!(define_invoke_with_usercalls);