about summary refs log tree commit diff
path: root/src/libstd/sys/sgx
diff options
context:
space:
mode:
authorStein Somers <git@steinsomers.be>2019-01-09 15:15:18 +0100
committerStein Somers <git@steinsomers.be>2019-01-09 15:15:18 +0100
commitccba43df81d5bda37c9e4d231ad4443e6f3a7e44 (patch)
treeefe674e2d5ae721f38fa8558385e0a2f12997227 /src/libstd/sys/sgx
parentf9f71cc32497ee4e3cbc7d9795bcf358a9268c13 (diff)
parent664c7797f6bfddf9f5e67474c2fd8017f91d7110 (diff)
downloadrust-ccba43df81d5bda37c9e4d231ad4443e6f3a7e44.tar.gz
rust-ccba43df81d5bda37c9e4d231ad4443e6f3a7e44.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src/libstd/sys/sgx')
-rw-r--r--src/libstd/sys/sgx/abi/entry.S18
-rw-r--r--src/libstd/sys/sgx/abi/mem.rs25
-rw-r--r--src/libstd/sys/sgx/abi/mod.rs12
-rw-r--r--src/libstd/sys/sgx/abi/panic.rs10
-rw-r--r--src/libstd/sys/sgx/abi/reloc.rs10
-rw-r--r--src/libstd/sys/sgx/abi/thread.rs10
-rw-r--r--src/libstd/sys/sgx/abi/tls.rs10
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/alloc.rs221
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs67
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/raw.rs39
-rw-r--r--src/libstd/sys/sgx/alloc.rs10
-rw-r--r--src/libstd/sys/sgx/args.rs14
-rw-r--r--src/libstd/sys/sgx/backtrace.rs10
-rw-r--r--src/libstd/sys/sgx/cmath.rs10
-rw-r--r--src/libstd/sys/sgx/condvar.rs10
-rw-r--r--src/libstd/sys/sgx/env.rs10
-rw-r--r--src/libstd/sys/sgx/ext/arch.rs74
-rw-r--r--src/libstd/sys/sgx/ext/io.rs109
-rw-r--r--src/libstd/sys/sgx/ext/mod.rs4
-rw-r--r--src/libstd/sys/sgx/fd.rs26
-rw-r--r--src/libstd/sys/sgx/fs.rs10
-rw-r--r--src/libstd/sys/sgx/memchr.rs10
-rw-r--r--src/libstd/sys/sgx/mod.rs17
-rw-r--r--src/libstd/sys/sgx/mutex.rs10
-rw-r--r--src/libstd/sys/sgx/net.rs85
-rw-r--r--src/libstd/sys/sgx/os.rs10
-rw-r--r--src/libstd/sys/sgx/os_str.rs10
-rw-r--r--src/libstd/sys/sgx/path.rs10
-rw-r--r--src/libstd/sys/sgx/pipe.rs10
-rw-r--r--src/libstd/sys/sgx/process.rs10
-rw-r--r--src/libstd/sys/sgx/rwlock.rs147
-rw-r--r--src/libstd/sys/sgx/stack_overflow.rs10
-rw-r--r--src/libstd/sys/sgx/stdio.rs10
-rw-r--r--src/libstd/sys/sgx/thread.rs12
-rw-r--r--src/libstd/sys/sgx/thread_local.rs10
-rw-r--r--src/libstd/sys/sgx/time.rs10
-rw-r--r--src/libstd/sys/sgx/waitqueue.rs10
37 files changed, 681 insertions, 409 deletions
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index 4d5cc02e11e..8dad6ee976f 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -1,13 +1,3 @@
-/* Copyright 2018 The Rust Project Developers. See the COPYRIGHT     */
-/* file at the top-level directory of this distribution and at       */
-/* http://rust-lang.org/COPYRIGHT.                                   */
-/*                                                                   */
-/* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or */
-/* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license    */
-/* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your      */
-/* option. This file may not be copied, modified, or distributed     */
-/* except according to those terms.                                  */
-
 /*  This symbol is used at runtime to figure out the virtual address that the */
 /*  enclave is loaded at. */
 .section absolute
@@ -56,6 +46,14 @@ IMAGE_BASE:
     globvar CFGDATA_BASE 8
     /*  Non-zero if debugging is enabled, zero otherwise */
     globvar DEBUG 1
+    /*  The base address (relative to enclave start) of the enclave text section */
+    globvar TEXT_BASE 8
+    /*  The size in bytes of enclacve text section */
+    globvar TEXT_SIZE 8
+    /*  The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
+    globvar EH_FRM_HDR_BASE 8
+    /*  The size in bytes of enclacve EH_FRM_HDR section */
+    globvar EH_FRM_HDR_SIZE 8
 
 .Lreentry_panic_msg:
     .asciz "Re-entered panicked enclave!"
diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs
index bf32c712216..09552d5b4af 100644
--- a/src/libstd/sys/sgx/abi/mem.rs
+++ b/src/libstd/sys/sgx/abi/mem.rs
@@ -1,22 +1,12 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 // Do not remove inline: will result in relocation failure
 #[inline(always)]
-pub unsafe fn rel_ptr<T>(offset: u64) -> *const T {
+pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
     (image_base() + offset) as *const T
 }
 
 // Do not remove inline: will result in relocation failure
 #[inline(always)]
-pub unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
+pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
     (image_base() + offset) as *mut T
 }
 
@@ -34,6 +24,17 @@ fn image_base() -> u64 {
     base
 }
 
+/// Returns `true` if the specified memory range is in the enclave.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
+    let start=p as u64;
+    let end=start + (len as u64);
+    start >= image_base() &&
+        end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
+}
+
+/// Returns `true` if the specified memory range is in userspace.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn is_user_range(p: *const u8, len: usize) -> bool {
     let start=p as u64;
     let end=start + (len as u64);
diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs
index 069cca3b98e..5ef069aa81c 100644
--- a/src/libstd/sys/sgx/abi/mod.rs
+++ b/src/libstd/sys/sgx/abi/mod.rs
@@ -1,22 +1,12 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use core::sync::atomic::{AtomicUsize, Ordering};
 use io::Write;
 
 // runtime features
 mod reloc;
-mod mem;
 pub(super) mod panic;
 
 // library features
+pub mod mem;
 pub mod thread;
 pub mod tls;
 #[macro_use]
diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs
index dd9159b9fe2..5ace7fb3368 100644
--- a/src/libstd/sys/sgx/abi/panic.rs
+++ b/src/libstd/sys/sgx/abi/panic.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use io::{self, Write};
 use slice::from_raw_parts_mut;
 
diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs
index 2d5e14d6ad1..4dd41d70bd7 100644
--- a/src/libstd/sys/sgx/abi/reloc.rs
+++ b/src/libstd/sys/sgx/abi/reloc.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use slice::from_raw_parts;
 use super::mem;
 
diff --git a/src/libstd/sys/sgx/abi/thread.rs b/src/libstd/sys/sgx/abi/thread.rs
index 4640b812fea..588fbcd9d43 100644
--- a/src/libstd/sys/sgx/abi/thread.rs
+++ b/src/libstd/sys/sgx/abi/thread.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fortanix_sgx_abi::Tcs;
 
 /// Get the ID for the current thread. The ID is guaranteed to be unique among
diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs
index ab7822182a5..aba93db915f 100644
--- a/src/libstd/sys/sgx/abi/tls.rs
+++ b/src/libstd/sys/sgx/abi/tls.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
 use ptr;
 use mem;
diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
index 64968a9970c..8d0013a235a 100644
--- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
@@ -1,16 +1,6 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![allow(unused)]
 
-use ptr;
+use ptr::{self, NonNull};
 use mem;
 use cell::UnsafeCell;
 use slice;
@@ -39,39 +29,78 @@ use super::super::mem::is_user_range;
 ///   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)
@@ -83,27 +112,29 @@ pub unsafe trait UserSafe {
     }
 }
 
+#[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)
     }
 }
 
@@ -111,14 +142,40 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
 /// 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
@@ -127,24 +184,28 @@ impl<T: ?Sized> User<T> where T: UserSafe {
     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:
@@ -154,7 +215,7 @@ impl<T: ?Sized> User<T> where T: UserSafe {
     /// * 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
@@ -162,24 +223,31 @@ impl<T: ?Sized> User<T> where T: UserSafe {
     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:
@@ -188,13 +256,17 @@ impl<T> User<[T]> where [T]: UserSafe {
     /// * 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:
     ///
@@ -206,7 +278,11 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
         &*(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:
@@ -219,6 +295,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
         &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.
@@ -233,6 +311,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
         }
     }
 
+    /// 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.
@@ -247,24 +327,32 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
         }
     }
 
+    /// 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:
     ///
@@ -272,10 +360,15 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
     /// * 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:
@@ -284,21 +377,30 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
     /// * 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()) {
@@ -309,12 +411,14 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
         }
     }
 
+    /// 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?
     {
@@ -323,6 +427,7 @@ impl<T> UserRef<[T]> where [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?
     {
@@ -332,8 +437,13 @@ impl<T> UserRef<[T]> where [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>;
 
@@ -345,8 +455,13 @@ impl<'a, T: UserSafe> Iterator for Iter<'a, 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>;
 
@@ -358,31 +473,36 @@ impl<'a, T: UserSafe> Iterator for IterMut<'a, 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>;
 
@@ -394,6 +514,7 @@ impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Ou
     }
 }
 
+#[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> {
@@ -402,3 +523,21 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I:
         }
     }
 }
+
+#[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()
+        }
+    }
+}
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
index d1d180e4825..58903761ebe 100644
--- a/src/libstd/sys/sgx/abi/usercalls/mod.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -1,29 +1,14 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// 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());
@@ -33,6 +18,18 @@ pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
     }
 }
 
+/// 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(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);
@@ -40,19 +37,25 @@ pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
     }
 }
 
+/// 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());
@@ -67,6 +70,8 @@ pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
     }
 }
 
+/// 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();
@@ -84,6 +89,8 @@ pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
     }
 }
 
+/// 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());
@@ -103,31 +110,45 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
     }
 }
 
-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 {
diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs
index a28d41c1b74..27aca7c0903 100644
--- a/src/libstd/sys/sgx/abi/usercalls/raw.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs
@@ -1,16 +1,7 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![allow(unused)]
 
-use fortanix_sgx_abi::*;
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use fortanix_sgx_abi::*;
 
 use ptr::NonNull;
 
@@ -21,7 +12,16 @@ extern "C" {
     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)
@@ -169,6 +169,9 @@ impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
 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(
@@ -181,6 +184,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         }
     );
     (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(
@@ -193,6 +199,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         }
     );
     (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(
@@ -204,6 +213,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         }
     );
     (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(
@@ -214,6 +226,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         }
     );
     (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(
diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs
index 83c20ace89b..95284190bdd 100644
--- a/src/libstd/sys/sgx/alloc.rs
+++ b/src/libstd/sys/sgx/alloc.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 extern crate dlmalloc;
 
 use alloc::{GlobalAlloc, Layout, System};
diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs
index 8fb35d7ef98..bc138a64019 100644
--- a/src/libstd/sys/sgx/args.rs
+++ b/src/libstd/sys/sgx/args.rs
@@ -1,15 +1,5 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use ffi::OsString;
-use super::abi::usercalls::{copy_user_buffer, alloc, ByteBuffer};
+use super::abi::usercalls::{alloc, raw::ByteBuffer};
 use sync::atomic::{AtomicUsize, Ordering};
 use sys::os_str::Buf;
 use sys_common::FromInner;
@@ -22,7 +12,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
     if argc != 0 {
         let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _);
         let args = args.iter()
-            .map( |a| OsString::from_inner(Buf { inner: copy_user_buffer(a) }) )
+            .map( |a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }) )
             .collect::<ArgsStore>();
         ARGS.store(Box::into_raw(Box::new(args)) as _, Ordering::Relaxed);
     }
diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs
index ca4a7c9561c..52d4a63bb63 100644
--- a/src/libstd/sys/sgx/backtrace.rs
+++ b/src/libstd/sys/sgx/backtrace.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use io;
 use sys::unsupported;
 use sys_common::backtrace::Frame;
diff --git a/src/libstd/sys/sgx/cmath.rs b/src/libstd/sys/sgx/cmath.rs
index 0c1300f61f8..5aabdc1c8d3 100644
--- a/src/libstd/sys/sgx/cmath.rs
+++ b/src/libstd/sys/sgx/cmath.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![cfg(not(test))]
 
 // These symbols are all defined in `compiler-builtins`
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
index 940f50f25b8..b42e5490c72 100644
--- a/src/libstd/sys/sgx/condvar.rs
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use sys::mutex::Mutex;
 use time::Duration;
 
diff --git a/src/libstd/sys/sgx/env.rs b/src/libstd/sys/sgx/env.rs
index 146ce02754b..6fa0ed7bcf4 100644
--- a/src/libstd/sys/sgx/env.rs
+++ b/src/libstd/sys/sgx/env.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 pub mod os {
     pub const FAMILY: &'static str = "";
     pub const OS: &'static str = "";
diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs
new file mode 100644
index 00000000000..ba6f9e622ad
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/arch.rs
@@ -0,0 +1,74 @@
+//! SGX-specific access to architectural features.
+//!
+//! The functionality in this module is further documented in the Intel
+//! Software Developer's Manual, Volume 3, Chapter 40.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use mem::MaybeUninit;
+
+/// Wrapper struct to force 16-byte alignment.
+#[repr(align(16))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align16<T>(pub T);
+
+/// Wrapper struct to force 128-byte alignment.
+#[repr(align(128))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align128<T>(pub T);
+
+/// Wrapper struct to force 512-byte alignment.
+#[repr(align(512))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align512<T>(pub T);
+
+const ENCLU_EREPORT: u32 = 0;
+const ENCLU_EGETKEY: u32 = 1;
+
+/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
+    unsafe {
+        let mut out = MaybeUninit::uninitialized();
+        let error;
+
+        asm!(
+            "enclu"
+            : "={eax}"(error)
+            : "{eax}"(ENCLU_EGETKEY),
+              "{rbx}"(request),
+              "{rcx}"(out.get_mut())
+            : "flags"
+        );
+
+        match error {
+            0 => Ok(out.into_inner()),
+            err => Err(err),
+        }
+    }
+}
+
+/// Call the `EREPORT` instruction.
+///
+/// This creates a cryptographic report describing the contents of the current
+/// enclave. The report may be verified by the enclave described in
+/// `targetinfo`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn ereport(
+    targetinfo: &Align512<[u8; 512]>,
+    reportdata: &Align128<[u8; 64]>,
+) -> Align512<[u8; 432]> {
+    unsafe {
+        let mut report = MaybeUninit::uninitialized();
+
+        asm!(
+            "enclu"
+            : /* no output registers */
+            : "{eax}"(ENCLU_EREPORT),
+              "{rbx}"(targetinfo),
+              "{rcx}"(reportdata),
+              "{rdx}"(report.get_mut())
+        );
+
+        report.into_inner()
+    }
+}
diff --git a/src/libstd/sys/sgx/ext/io.rs b/src/libstd/sys/sgx/ext/io.rs
new file mode 100644
index 00000000000..1eb269783c5
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/io.rs
@@ -0,0 +1,109 @@
+//! SGX-specific extensions to general I/O primitives
+//!
+//! SGX file descriptors behave differently from Unix file descriptors. See the
+//! description of [`TryIntoRawFd`](trait.TryIntoRawFd.html) for more details.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+pub use sys::abi::usercalls::raw::Fd as RawFd;
+use net;
+use sys::{self, AsInner, FromInner, IntoInner, TryIntoInner};
+
+/// A trait to extract the raw SGX file descriptor from an underlying
+/// object.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait FromRawFd {
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait TryIntoRawFd: Sized {
+    /// Consumes this object, returning the raw underlying file descriptor, if
+    /// this object is not cloned.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    ///
+    /// Unlike other platforms, on SGX, the file descriptor is shared between
+    /// all clones of an object. To avoid race conditions, this function will
+    /// only return `Ok` when called on the final clone.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn try_into_raw_fd(self) -> Result<RawFd, Self>;
+}
+
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() }
+}
+
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() }
+}
+
+impl FromRawFd for net::TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        let fd = sys::fd::FileDesc::from_inner(fd);
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None)))
+    }
+}
+
+impl FromRawFd for net::TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        let fd = sys::fd::FileDesc::from_inner(fd);
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
+    }
+}
+
+impl TryIntoRawFd for net::TcpStream {
+    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+        let (socket, peer_addr) = self.into_inner().into_inner();
+        match socket.try_into_inner() {
+            Ok(fd) => Ok(fd.into_inner()),
+            Err(socket) => {
+                let sys = sys::net::TcpStream::from_inner((socket, peer_addr));
+                Err(net::TcpStream::from_inner(sys))
+            }
+        }
+    }
+}
+
+impl TryIntoRawFd for net::TcpListener {
+    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+        match self.into_inner().into_inner().try_into_inner() {
+            Ok(fd) => Ok(fd.into_inner()),
+            Err(socket) => {
+                let sys = sys::net::TcpListener::from_inner(socket);
+                Err(net::TcpListener::from_inner(sys))
+            }
+        }
+    }
+}
diff --git a/src/libstd/sys/sgx/ext/mod.rs b/src/libstd/sys/sgx/ext/mod.rs
new file mode 100644
index 00000000000..5489f6f5694
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/mod.rs
@@ -0,0 +1,4 @@
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+pub mod arch;
+pub mod io;
diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs
index 31c4199c6cd..69077728b1a 100644
--- a/src/libstd/sys/sgx/fd.rs
+++ b/src/libstd/sys/sgx/fd.rs
@@ -1,18 +1,8 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fortanix_sgx_abi::Fd;
 
 use io;
 use mem;
-use sys_common::AsInner;
+use sys::{AsInner, FromInner, IntoInner};
 use super::abi::usercalls;
 
 #[derive(Debug)]
@@ -51,6 +41,20 @@ impl AsInner<Fd> for FileDesc {
     fn as_inner(&self) -> &Fd { &self.fd }
 }
 
+impl IntoInner<Fd> for FileDesc {
+    fn into_inner(self) -> Fd {
+        let fd = self.fd;
+        mem::forget(self);
+        fd
+    }
+}
+
+impl FromInner<Fd> for FileDesc {
+    fn from_inner(fd: Fd) -> FileDesc {
+        FileDesc { fd }
+    }
+}
+
 impl Drop for FileDesc {
     fn drop(&mut self) {
         usercalls::close(self.fd)
diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs
index 1dcea3e8eac..8b1c4476bc4 100644
--- a/src/libstd/sys/sgx/fs.rs
+++ b/src/libstd/sys/sgx/fs.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use ffi::OsString;
 use fmt;
 use hash::{Hash, Hasher};
diff --git a/src/libstd/sys/sgx/memchr.rs b/src/libstd/sys/sgx/memchr.rs
index 0998bc5db4c..9967482197e 100644
--- a/src/libstd/sys/sgx/memchr.rs
+++ b/src/libstd/sys/sgx/memchr.rs
@@ -1,11 +1 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index dd6862e908e..7f8550490a1 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 //! System bindings for the Fortanix SGX platform
 //!
 //! This module contains the facade (aka platform-specific) implementations of
@@ -27,6 +17,7 @@ pub mod backtrace;
 pub mod cmath;
 pub mod condvar;
 pub mod env;
+pub mod ext;
 pub mod fd;
 pub mod fs;
 pub mod memchr;
@@ -151,3 +142,9 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     }
     (rdrand64(), rdrand64())
 }
+
+pub use sys_common::{AsInner, FromInner, IntoInner};
+
+pub trait TryIntoInner<Inner>: Sized {
+    fn try_into_inner(self) -> Result<Inner, Self>;
+}
diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs
index 994cf91eea0..f325fb1dd58 100644
--- a/src/libstd/sys/sgx/mutex.rs
+++ b/src/libstd/sys/sgx/mutex.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fortanix_sgx_abi::Tcs;
 
 use super::abi::thread;
diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs
index 176d230846d..6e86b06b286 100644
--- a/src/libstd/sys/sgx/net.rs
+++ b/src/libstd/sys/sgx/net.rs
@@ -1,18 +1,8 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fmt;
 use io;
 use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
 use time::Duration;
-use sys::{unsupported, Void, sgx_ineffective};
+use sys::{unsupported, Void, sgx_ineffective, AsInner, FromInner, IntoInner, TryIntoInner};
 use sys::fd::FileDesc;
 use convert::TryFrom;
 use error;
@@ -23,21 +13,38 @@ use super::abi::usercalls;
 const DEFAULT_FAKE_TTL: u32 = 64;
 
 #[derive(Debug, Clone)]
-struct Socket {
+pub struct Socket {
     inner: Arc<FileDesc>,
-    local_addr: String,
+    local_addr: Option<String>,
 }
 
 impl Socket {
-    fn new(fd: usercalls::Fd, local_addr: String) -> Socket {
-        Socket { inner: Arc::new(FileDesc::new(fd)), local_addr }
+    fn new(fd: usercalls::raw::Fd, local_addr: String) -> Socket {
+        Socket { inner: Arc::new(FileDesc::new(fd)), local_addr: Some(local_addr) }
+    }
+}
+
+impl AsInner<FileDesc> for Socket {
+    fn as_inner(&self) -> &FileDesc { &self.inner }
+}
+
+impl TryIntoInner<FileDesc> for Socket {
+    fn try_into_inner(self) -> Result<FileDesc, Socket> {
+        let Socket { inner, local_addr } = self;
+        Arc::try_unwrap(inner).map_err(|inner| Socket { inner, local_addr } )
+    }
+}
+
+impl FromInner<FileDesc> for Socket {
+    fn from_inner(inner: FileDesc) -> Socket {
+        Socket { inner: Arc::new(inner), local_addr: None }
     }
 }
 
 #[derive(Debug, Clone)]
 pub struct TcpStream {
     inner: Socket,
-    peer_addr: String,
+    peer_addr: Option<String>,
 }
 
 fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
@@ -53,16 +60,19 @@ fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
     }
 }
 
-fn addr_to_sockaddr(addr: &str) -> io::Result<SocketAddr> {
-    // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
-    addr.to_socket_addrs().map(|mut it| it.next().unwrap())
+fn addr_to_sockaddr(addr: &Option<String>) -> io::Result<SocketAddr> {
+    addr.as_ref()
+        .ok_or(io::ErrorKind::AddrNotAvailable)?
+        .to_socket_addrs()
+        // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
+        .map(|mut it| it.next().unwrap())
 }
 
 impl TcpStream {
     pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
         let addr = io_err_to_addr(addr)?;
         let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
-        Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr })
+        Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
     }
 
     pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
@@ -138,6 +148,24 @@ impl TcpStream {
     }
 }
 
+impl AsInner<Socket> for TcpStream {
+    fn as_inner(&self) -> &Socket { &self.inner }
+}
+
+// `Inner` includes `peer_addr` so that a `TcpStream` maybe correctly
+// reconstructed if `Socket::try_into_inner` fails.
+impl IntoInner<(Socket, Option<String>)> for TcpStream {
+    fn into_inner(self) -> (Socket, Option<String>) {
+        (self.inner, self.peer_addr)
+    }
+}
+
+impl FromInner<(Socket, Option<String>)> for TcpStream {
+    fn from_inner((inner, peer_addr): (Socket, Option<String>)) -> TcpStream {
+        TcpStream { inner, peer_addr }
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct TcpListener {
     inner: Socket,
@@ -156,6 +184,7 @@ impl TcpListener {
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?;
+        let peer_addr = Some(peer_addr);
         let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into());
         Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer))
     }
@@ -189,6 +218,22 @@ impl TcpListener {
     }
 }
 
+impl AsInner<Socket> for TcpListener {
+    fn as_inner(&self) -> &Socket { &self.inner }
+}
+
+impl IntoInner<Socket> for TcpListener {
+    fn into_inner(self) -> Socket {
+        self.inner
+    }
+}
+
+impl FromInner<Socket> for TcpListener {
+    fn from_inner(inner: Socket) -> TcpListener {
+        TcpListener { inner }
+    }
+}
+
 pub struct UdpSocket(Void);
 
 impl UdpSocket {
diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs
index 79ebafe73f9..b1e4d371a67 100644
--- a/src/libstd/sys/sgx/os.rs
+++ b/src/libstd/sys/sgx/os.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fortanix_sgx_abi::{Error, RESULT_SUCCESS};
 
 use error::Error as StdError;
diff --git a/src/libstd/sys/sgx/os_str.rs b/src/libstd/sys/sgx/os_str.rs
index 9bfb84db209..9d5e084feb2 100644
--- a/src/libstd/sys/sgx/os_str.rs
+++ b/src/libstd/sys/sgx/os_str.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 /// The underlying OsString/OsStr implementation on Unix systems: just
 /// a `Vec<u8>`/`[u8]`.
 
diff --git a/src/libstd/sys/sgx/path.rs b/src/libstd/sys/sgx/path.rs
index afe0c490426..90b1fa7c97b 100644
--- a/src/libstd/sys/sgx/path.rs
+++ b/src/libstd/sys/sgx/path.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use path::Prefix;
 use ffi::OsStr;
 
diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs
index 6c6cbc14a8a..ac48a6dc033 100644
--- a/src/libstd/sys/sgx/pipe.rs
+++ b/src/libstd/sys/sgx/pipe.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use io;
 use sys::Void;
 
diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs
index 01a12fba043..5357d931c73 100644
--- a/src/libstd/sys/sgx/process.rs
+++ b/src/libstd/sys/sgx/process.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use ffi::OsStr;
 use fmt;
 use io;
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index a1551dbb53b..47874158ed9 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -1,22 +1,23 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use num::NonZeroUsize;
+use slice;
+use str;
 
-use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false};
+use super::waitqueue::{
+    try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
+};
+use mem;
 
 pub struct RWLock {
     readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
     writer: SpinMutex<WaitVariable<bool>>,
 }
 
+// Below is to check at compile time, that RWLock has size of 128 bytes.
+#[allow(dead_code)]
+unsafe fn rw_lock_size_assert(r: RWLock) {
+    mem::transmute::<RWLock, [u8; 128]>(r);
+}
+
 //unsafe impl Send for RWLock {}
 //unsafe impl Sync for RWLock {} // FIXME
 
@@ -24,7 +25,7 @@ impl RWLock {
     pub const fn new() -> RWLock {
         RWLock {
             readers: SpinMutex::new(WaitVariable::new(None)),
-            writer: SpinMutex::new(WaitVariable::new(false))
+            writer: SpinMutex::new(WaitVariable::new(false)),
         }
     }
 
@@ -89,9 +90,11 @@ impl RWLock {
     }
 
     #[inline]
-    pub unsafe fn read_unlock(&self) {
-        let mut rguard = self.readers.lock();
-        let wguard = self.writer.lock();
+    unsafe fn __read_unlock(
+        &self,
+        mut rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
+        wguard: SpinMutexGuard<WaitVariable<bool>>,
+    ) {
         *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
         if rguard.lock_var().is_some() {
             // There are other active readers
@@ -107,9 +110,18 @@ impl RWLock {
     }
 
     #[inline]
-    pub unsafe fn write_unlock(&self) {
+    pub unsafe fn read_unlock(&self) {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
+        self.__read_unlock(rguard, wguard);
+    }
+
+    #[inline]
+    unsafe fn __write_unlock(
+        &self,
+        rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>,
+        wguard: SpinMutexGuard<WaitVariable<bool>>,
+    ) {
         if let Err(mut wguard) = WaitQueue::notify_one(wguard) {
             // No writers waiting, release the write lock
             *wguard.lock_var_mut() = false;
@@ -129,5 +141,108 @@ impl RWLock {
     }
 
     #[inline]
+    pub unsafe fn write_unlock(&self) {
+        let rguard = self.readers.lock();
+        let wguard = self.writer.lock();
+        self.__write_unlock(rguard, wguard);
+    }
+
+    #[inline]
+    unsafe fn unlock(&self) {
+        let rguard = self.readers.lock();
+        let wguard = self.writer.lock();
+        if *wguard.lock_var() == true {
+            self.__write_unlock(rguard, wguard);
+        } else {
+            self.__read_unlock(rguard, wguard);
+        }
+    }
+
+    #[inline]
     pub unsafe fn destroy(&self) {}
 }
+
+const EINVAL: i32 = 22;
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+    (*p).read();
+    return 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+    (*p).write();
+    return 0;
+}
+#[no_mangle]
+pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
+    if p.is_null() {
+        return EINVAL;
+    }
+    (*p).unlock();
+    return 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
+    if s < 0 {
+        return;
+    }
+    let buf = slice::from_raw_parts(m as *const u8, s as _);
+    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
+        eprint!("{}", s);
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_abort() {
+    ::sys::abort_internal();
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use core::array::FixedSizeArray;
+    use mem::MaybeUninit;
+    use {mem, ptr};
+
+    // The below test verifies that the bytes of initialized RWLock are the ones
+    // we use in libunwind.
+    // If they change we need to update src/UnwindRustSgx.h in libunwind.
+    #[test]
+    fn test_c_rwlock_initializer() {
+        const RWLOCK_INIT: &[u8] = &[
+            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        ];
+
+        let mut init = MaybeUninit::<RWLock>::zeroed();
+        init.set(RWLock::new());
+        assert_eq!(
+            mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(),
+            RWLOCK_INIT
+        );
+    }
+}
diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs
index 0176b748a87..c0e7c824615 100644
--- a/src/libstd/sys/sgx/stack_overflow.rs
+++ b/src/libstd/sys/sgx/stack_overflow.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 pub struct Handler;
 
 impl Handler {
diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs
index 13c91195569..6f206cd9a51 100644
--- a/src/libstd/sys/sgx/stdio.rs
+++ b/src/libstd/sys/sgx/stdio.rs
@@ -1,13 +1,3 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use fortanix_sgx_abi as abi;
 
 use io;
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
index 9f3c4536cb5..b4bdb03e61a 100644
--- a/src/libstd/sys/sgx/thread.rs
+++ b/src/libstd/sys/sgx/thread.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use boxed::FnBox;
 use ffi::CStr;
 use io;
@@ -75,7 +65,7 @@ impl Thread {
 
     pub fn yield_now() {
         assert_eq!(
-            usercalls::wait(0, usercalls::WAIT_NO).unwrap_err().kind(),
+            usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
             io::ErrorKind::WouldBlock
         );
     }
diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local.rs
index 3b628bae4fb..e0d0fe76957 100644
--- a/src/libstd/sys/sgx/thread_local.rs
+++ b/src/libstd/sys/sgx/thread_local.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use super::abi::tls::{Tls, Key as AbiKey};
 
 pub type Key = usize;
diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs
index 196e1a97fc4..10fe72d5f68 100644
--- a/src/libstd/sys/sgx/time.rs
+++ b/src/libstd/sys/sgx/time.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use time::Duration;
 use super::abi::usercalls;
 
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index ef0def13eee..a4738208778 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 /// A simple queue implementation for synchronization primitives.
 ///
 /// This queue is used to implement condition variable and mutexes.