#![allow(unused)]
-use ptr;
+use ptr::{self, NonNull};
use mem;
use cell::UnsafeCell;
use slice;
/// as vtable pointers) must not be leaked for confidentiality reasons.
///
/// Non-exhaustive list of specific requirements for reading from userspace:
-/// * Any bit pattern is valid for this type (no `enum`s). There can be no
+/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
/// guarantee that the value correctly adheres to the expectations of the
/// type, so any value must be valid for this type.
///
/// Non-exhaustive list of specific requirements for writing to userspace:
-/// * No pointers to enclave memory. Memory addresses of data in enclave memory
-/// must not be leaked for confidentiality reasons.
-/// * No internal padding. Padding might contain previously-initialized secret
-/// data stored at that memory location and must not be leaked for
+/// * **No pointers to enclave memory.** Memory addresses of data in enclave
+/// memory must not be leaked for confidentiality reasons.
+/// * **No internal padding.** Padding might contain previously-initialized
+/// secret data stored at that memory location and must not be leaked for
/// confidentiality reasons.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafeSized: Copy + Sized {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for u8 {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for ByteBuffer {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for Usercall {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for Return {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
/// A type that can be represented in memory as one or more `UserSafeSized`s.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafe {
- unsafe fn align_of() -> usize;
+ /// Equivalent to `mem::align_of::<Self>`.
+ fn align_of() -> usize;
+ /// Construct a pointer to `Self` given a memory range in user space.
+ ///
/// NB. This takes a size, not a length!
- unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self;
+ ///
+ /// # Safety
+ /// The caller must ensure the memory range is in user memory, is the
+ /// correct size and is correctly aligned and points to the right type.
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
+ /// Construct a pointer to `Self` given a memory range.
+ ///
/// NB. This takes a size, not a length!
- unsafe fn from_raw_sized(ptr: *const u8, size: usize) -> *const Self {
+ ///
+ /// # Safety
+ /// The caller must ensure the memory range points to the correct type.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
+ unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
let ret = Self::from_raw_sized_unchecked(ptr, size);
Self::check_ptr(ret);
- ret
+ NonNull::new_unchecked(ret as _)
}
+ /// Check if a pointer may point to Self in user memory.
+ ///
+ /// # Safety
+ /// The caller must ensure the memory range points to the correct type and
+ /// length (if this is a slice).
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer is not aligned
+ /// * The pointer is null
+ /// * The pointed-to range is not in user memory
unsafe fn check_ptr(ptr: *const Self) {
let is_aligned = |p| -> bool {
0 == (p as usize) & (Self::align_of() - 1)
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafe for T {
- unsafe fn align_of() -> usize {
+ fn align_of() -> usize {
mem::align_of::<T>()
}
- unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
assert_eq!(size, mem::size_of::<T>());
ptr as _
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafe for [T] {
- unsafe fn align_of() -> usize {
+ fn align_of() -> usize {
mem::align_of::<T>()
}
- unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
+ unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
let elem_size = mem::size_of::<T>();
assert_eq!(size % elem_size, 0);
let len = size / elem_size;
- slice::from_raw_parts(ptr as _, len)
+ slice::from_raw_parts_mut(ptr as _, len)
}
}
/// to `&T` in enclave memory. Access to the memory is only allowed by copying
/// to avoid TOCTTOU issues. After copying, code should make sure to completely
/// check the value before use.
+///
+/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
+/// regular mutable references, these are not exclusive. Userspace may always
+/// write to the backing memory at any time, so it can't be assumed that there
+/// the pointed-to memory is uniquely borrowed. The two different refence types
+/// are used solely to indicate intent: a mutable reference is for writing to
+/// user memory, an immutable reference for reading from user memory.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
/// enclave memory. Access to the memory is only allowed by copying to avoid
/// TOCTTOU issues. The user memory will be freed when the value is dropped.
/// After copying, code should make sure to completely check the value before
/// use.
-pub struct User<T: UserSafe + ?Sized>(*mut UserRef<T>);
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
+
+trait NewUserRef<T: ?Sized> {
+ unsafe fn new_userref(v: T) -> Self;
+}
+
+impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
+ unsafe fn new_userref(v: *mut T) -> Self {
+ NonNull::new_unchecked(v as _)
+ }
+}
+impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
+ unsafe fn new_userref(v: NonNull<T>) -> Self {
+ NonNull::new_userref(v.as_ptr())
+ }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> User<T> where T: UserSafe {
// This function returns memory that is practically uninitialized, but is
// not considered "unspecified" or "undefined" for purposes of an
fn new_uninit_bytes(size: usize) -> Self {
unsafe {
let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed");
- User(T::from_raw_sized(ptr as _, size) as _)
+ User(NonNull::new_userref(T::from_raw_sized(ptr as _, size)))
}
}
+ /// Copy `val` into freshly allocated space in user memory.
pub fn new_from_enclave(val: &T) -> Self {
unsafe {
let ret = Self::new_uninit_bytes(mem::size_of_val(val));
ptr::copy(
val as *const T as *const u8,
- ret.0 as *mut T as *mut u8,
+ ret.0.as_ptr() as *mut u8,
mem::size_of_val(val)
);
ret
}
}
- /// Create an owned `User<T>` from a raw pointer. The pointer should be
- /// freeable with the `free` usercall and the alignment of `T`.
+ /// Create an owned `User<T>` from a raw pointer.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`, is freeable with the `free`
+ /// usercall and the alignment of `T`, and is uniquely owned.
///
/// # Panics
/// This function panics if:
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw(ptr: *mut T) -> Self {
T::check_ptr(ptr);
- User(ptr as _)
+ User(NonNull::new_userref(ptr))
}
/// Convert this value into a raw pointer. The value will no longer be
pub fn into_raw(self) -> *mut T {
let ret = self.0;
mem::forget(self);
- ret as _
+ ret.as_ptr() as _
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> User<T> where T: UserSafe {
+ /// Allocate space for `T` in user memory.
pub fn uninitialized() -> Self {
Self::new_uninit_bytes(mem::size_of::<T>())
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> User<[T]> where [T]: UserSafe {
+ /// Allocate space for a `[T]` of `n` elements in user memory.
pub fn uninitialized(n: usize) -> Self {
Self::new_uninit_bytes(n * mem::size_of::<T>())
}
/// Create an owned `User<[T]>` from a raw thin pointer and a slice length.
- /// The pointer should be freeable with the `free` usercall and the
- /// alignment of `T`.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `len` elements of `T`, is
+ /// freeable with the `free` usercall and the alignment of `T`, and is
+ /// uniquely owned.
///
/// # Panics
/// This function panics if:
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
- User(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as _)
+ User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> UserRef<T> where T: UserSafe {
/// Create a `&UserRef<[T]>` from a raw pointer.
///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`.
+ ///
/// # Panics
/// This function panics if:
///
&*(ptr as *const Self)
}
- /// Create a `&mut UserRef<[T]>` from a raw pointer.
+ /// Create a `&mut UserRef<[T]>` from a raw pointer. See the struct
+ /// documentation for the nuances regarding a `&mut UserRef<T>`.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `T`.
///
/// # Panics
/// This function panics if:
&mut*(ptr as *mut Self)
}
+ /// Copy `val` into user memory.
+ ///
/// # Panics
/// This function panics if the destination doesn't have the same size as
/// the source. This can happen for dynamically-sized types such as slices.
}
}
+ /// Copy the value from user memory and place it into `dest`.
+ ///
/// # Panics
/// This function panics if the destination doesn't have the same size as
/// the source. This can happen for dynamically-sized types such as slices.
}
}
+ /// Obtain a raw pointer from this reference.
pub fn as_raw_ptr(&self) -> *const T {
self as *const _ as _
}
+ /// Obtain a raw pointer from this reference.
pub fn as_raw_mut_ptr(&mut self) -> *mut T {
self as *mut _ as _
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> UserRef<T> where T: UserSafe {
+ /// Copy the value from user memory into enclave memory.
pub fn to_enclave(&self) -> T {
unsafe { ptr::read(self.0.get()) }
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> UserRef<[T]> where [T]: UserSafe {
/// Create a `&UserRef<[T]>` from a raw thin pointer and a slice length.
///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `n` elements of `T`.
+ ///
/// # Panics
/// This function panics if:
///
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
- &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *const Self)
+ &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
}
/// Create a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
+ /// See the struct documentation for the nuances regarding a
+ /// `&mut UserRef<T>`.
+ ///
+ /// # Safety
+ /// The caller must ensure `ptr` points to `n` elements of `T`.
///
/// # Panics
/// This function panics if:
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
- &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *mut Self)
+ &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
}
+ /// Obtain a raw pointer to the first element of this user slice.
pub fn as_ptr(&self) -> *const T {
self.0.get() as _
}
+ /// Obtain a raw pointer to the first element of this user slice.
pub fn as_mut_ptr(&mut self) -> *mut T {
self.0.get() as _
}
+ /// Obtain the number of elements in this user slice.
pub fn len(&self) -> usize {
unsafe { (*self.0.get()).len() }
}
+ /// Copy the value from user memory and place it into `dest`. Afterwards,
+ /// `dest` will contain exactly `self.len()` elements.
+ ///
+ /// # Panics
+ /// This function panics if the destination doesn't have the same size as
+ /// the source. This can happen for dynamically-sized types such as slices.
pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
unsafe {
if let Some(missing) = self.len().checked_sub(dest.capacity()) {
}
}
+ /// Copy the value from user memory into a vector in enclave memory.
pub fn to_enclave(&self) -> Vec<T> {
let mut ret = Vec::with_capacity(self.len());
self.copy_to_enclave_vec(&mut ret);
ret
}
+ /// Returns an iterator over the slice.
pub fn iter(&self) -> Iter<T>
where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
{
}
}
+ /// Returns an iterator that allows modifying each value.
pub fn iter_mut(&mut self) -> IterMut<T>
where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
{
}
}
+/// Immutable user slice iterator
+///
+/// This struct is created by the `iter` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
type Item = &'a UserRef<T>;
}
}
+/// Mutable user slice iterator
+///
+/// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
type Item = &'a mut UserRef<T>;
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> Deref for User<T> where T: UserSafe {
type Target = UserRef<T>;
fn deref(&self) -> &Self::Target {
- unsafe { &*self.0 }
+ unsafe { &*self.0.as_ptr() }
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe { &mut*self.0 }
+ unsafe { &mut*self.0.as_ptr() }
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> Drop for User<T> where T: UserSafe {
fn drop(&mut self) {
unsafe {
- let ptr = (*self.0).0.get();
+ let ptr = (*self.0.as_ptr()).0.get();
super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
}
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
type Output = UserRef<I::Output>;
}
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
#[inline]
fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
}
}
}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl UserRef<super::raw::ByteBuffer> {
+ /// Copy the user memory range pointed to by the user `ByteBuffer` to
+ /// enclave memory.
+ ///
+ /// # Panics
+ /// This function panics if:
+ ///
+ /// * The pointer in the user `ByteBuffer` is null
+ /// * The pointed-to range in the user `ByteBuffer` is not in user memory
+ pub fn copy_user_buffer(&self) -> Vec<u8> {
+ unsafe {
+ let buf = self.to_enclave();
+ User::from_raw_parts(buf.data as _, buf.len).to_enclave()
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use fortanix_sgx_abi::*;
-
use io::{Error as IoError, Result as IoResult};
use time::Duration;
-pub mod alloc;
+pub(crate) mod alloc;
#[macro_use]
-mod raw;
+pub(crate) mod raw;
-pub(crate) fn copy_user_buffer(buf: &alloc::UserRef<ByteBuffer>) -> Vec<u8> {
- unsafe {
- let buf = buf.to_enclave();
- alloc::User::from_raw_parts(buf.data as _, buf.len).to_enclave()
- }
-}
+use self::raw::*;
+/// Usercall `read`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
unsafe {
let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len());
}
}
+/// Usercall `read_alloc`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
unsafe {
let mut userbuf = alloc::User::<ByteBuffer>::uninitialized();
raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
- Ok(copy_user_buffer(&userbuf))
+ Ok(userbuf.copy_user_buffer())
}
}
+/// Usercall `write`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
unsafe {
let userbuf = alloc::User::new_from_enclave(buf);
}
}
+/// Usercall `flush`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn flush(fd: Fd) -> IoResult<()> {
unsafe { raw::flush(fd).from_sgx_result() }
}
+/// Usercall `close`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn close(fd: Fd) {
unsafe { raw::close(fd) }
}
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
- String::from_utf8(copy_user_buffer(buf))
+ String::from_utf8(buf.copy_user_buffer())
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
}
+/// Usercall `bind_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
}
}
+/// Usercall `accept_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
unsafe {
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
}
}
+/// Usercall `connect_stream`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
}
}
-pub fn launch_thread() -> IoResult<()> {
- unsafe { raw::launch_thread().from_sgx_result() }
+/// Usercall `launch_thread`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub unsafe fn launch_thread() -> IoResult<()> {
+ raw::launch_thread().from_sgx_result()
}
+/// Usercall `exit`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn exit(panic: bool) -> ! {
unsafe { raw::exit(panic) }
}
+/// Usercall `wait`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
}
+/// Usercall `send`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
unsafe { raw::send(event_set, tcs).from_sgx_result() }
}
+/// Usercall `insecure_time`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn insecure_time() -> Duration {
let t = unsafe { raw::insecure_time() };
Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
}
+/// Usercall `alloc`. See the ABI documentation for more information.
+#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
unsafe { raw::alloc(size, alignment).from_sgx_result() }
}
+#[unstable(feature = "sgx_platform", issue = "56975")]
+#[doc(inline)]
pub use self::raw::free;
fn check_os_error(err: Result) -> i32 {
#![allow(unused)]
-use fortanix_sgx_abi::*;
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use fortanix_sgx_abi::*;
use ptr::NonNull;
fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn;
}
-unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
+/// Perform the raw usercall operation as defined in the ABI calling convention.
+///
+/// # Safety
+/// The caller must ensure to pass parameters appropriate for the usercall `nr`
+/// and to observe all requirements specified in the ABI.
+///
+/// # Panics
+/// Panics if `nr` is 0.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
if nr==0 { panic!("Invalid usercall number {}",nr) }
let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4);
(a, b)
macro_rules! enclave_usercalls_internal_define_usercalls {
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
$n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
}
);
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
}
);
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
}
);
(def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
}
);
(def fn $f:ident() -> $r:ty) => (
+ /// This is the raw function definition, see the ABI documentation for
+ /// more information.
+ #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f() -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(