diff --git a/.gitmodules b/.gitmodules index 4a136cff1cd..3fc6e45db3e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -61,10 +61,12 @@ path = src/tools/clang url = https://github.com/rust-lang-nursery/clang.git branch = rust-release-80-v2 - [submodule "src/doc/rustc-guide"] path = src/doc/rustc-guide url = https://github.com/rust-lang/rustc-guide.git [submodule "src/doc/edition-guide"] path = src/doc/edition-guide url = https://github.com/rust-lang-nursery/edition-guide +[submodule "src/rust-sgx"] + path = src/rust-sgx + url = https://github.com/fortanix/rust-sgx diff --git a/Cargo.lock b/Cargo.lock index 02c63200a28..316724ca651 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,14 @@ name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fortanix-sgx-abi" +version = "0.0.0" +dependencies = [ + "compiler_builtins 0.0.0", + "core 0.0.0", +] + [[package]] name = "fs2" version = "0.4.3" @@ -2773,6 +2781,7 @@ dependencies = [ "compiler_builtins 0.0.0", "core 0.0.0", "dlmalloc 0.0.0", + "fortanix-sgx-abi 0.0.0", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cd8d5642b25..6108692e43c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -874,6 +874,7 @@ impl Step for Src { "src/rustc/compiler_builtins_shim", "src/rustc/libc_shim", "src/rustc/dlmalloc_shim", + "src/rustc/fortanix-sgx-abi_shim", "src/libtest", "src/libterm", "src/libprofiler_builtins", diff --git a/src/dlmalloc b/src/dlmalloc index c99638dc2ec..de99f4b0c88 160000 --- a/src/dlmalloc +++ b/src/dlmalloc @@ -1 +1 @@ -Subproject commit c99638dc2ecfc750cc1656f6edb2bd062c1e0981 +Subproject commit de99f4b0c886f5916cd1a146464276d65bef61b8 diff --git a/src/liblibc b/src/liblibc index c75ca6465a1..5b403753da9 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit c75ca6465a139704e00295be355b1f067af2f535 +Subproject commit 5b403753da9ec8ff501adf34cb6d63b319b4a3ae diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 9235f8e7660..95c3514185e 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -66,6 +66,12 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { unsafe fn abort() -> ! { core::intrinsics::abort(); } + + #[cfg(target_env="sgx")] + unsafe fn abort() -> ! { + extern "C" { pub fn panic_exit() -> !; } + panic_exit(); + } } // This... is a bit of an oddity. The tl;dr; is that this is required to link diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index cfe671c626b..49f8a429126 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -62,7 +62,7 @@ cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] mod imp; - } else if #[cfg(target_arch = "wasm32")] { + } else if #[cfg(any(target_arch = "wasm32", target_env = "sgx"))] { #[path = "dummy.rs"] mod imp; } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index cae2f405318..274d5bec662 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -35,9 +35,12 @@ rustc_lsan = { path = "../librustc_lsan" } rustc_msan = { path = "../librustc_msan" } rustc_tsan = { path = "../librustc_tsan" } -[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] +[target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx"))'.dependencies] dlmalloc = { path = '../rustc/dlmalloc_shim' } +[target.x86_64-fortanix-unknown-sgx.dependencies] +fortanix-sgx-abi = { path = "../rustc/fortanix-sgx-abi_shim" } + [build-dependencies] cc = "1.0" build_helper = { path = "../build_helper" } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 386de080b85..32e29962760 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -184,7 +184,7 @@ pub enum ErrorKind { } impl ErrorKind { - fn as_str(&self) -> &'static str { + pub(crate) fn as_str(&self) -> &'static str { match *self { ErrorKind::NotFound => "entity not found", ErrorKind::PermissionDenied => "permission denied", diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 78109a1a690..bf1e64efd37 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -312,6 +312,7 @@ #![feature(non_exhaustive)] #![feature(alloc_layout_extra)] #![feature(maybe_uninit)] +#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains))] #![default_lib_allocator] @@ -354,6 +355,12 @@ extern crate unwind; // testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; +#[cfg(target_env = "sgx")] +#[macro_use] +#[allow(unused_imports)] // FIXME: without `#[macro_use]`, get error: “cannot + // determine resolution for the macro `usercalls_asm`” +extern crate fortanix_sgx_abi; + // The standard macros that are not built-in to the compiler. #[macro_use] mod macros; diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 61e4ce66eec..04c47aeb827 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -48,6 +48,9 @@ cfg_if! { } else if #[cfg(target_arch = "wasm32")] { mod wasm; pub use self::wasm::*; + } else if #[cfg(target_env = "sgx")] { + mod sgx; + pub use self::sgx::*; } else { compile_error!("libstd doesn't compile for this platform yet"); } diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S new file mode 100644 index 00000000000..4d5cc02e11e --- /dev/null +++ b/src/libstd/sys/sgx/abi/entry.S @@ -0,0 +1,327 @@ +/* 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 or the MIT license */ +/* , 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 +.global IMAGE_BASE +IMAGE_BASE: + +.section .rodata +/* The XSAVE area needs to be a large chunk of readable memory, but since we are */ +/* going to restore everything to its initial state (XSTATE_BV=0), only certain */ +/* parts need to have a defined value. In particular: */ +/* */ +/* * MXCSR in the legacy area. This register is always restored if RFBM[1] or */ +/* RFBM[2] is set, regardless of the value of XSTATE_BV */ +/* * XSAVE header */ +.align 64 +.Lxsave_clear: +.org .+24 +.Lxsave_mxcsr: + .int 0 + +/* We can store a bunch of data in the gap between MXCSR and the XSAVE header */ + +/* The following symbols point at read-only data that will be filled in by the */ +/* post-linker. */ + +/* When using this macro, don't forget to adjust the linker version script! */ +.macro globvar name:req size:req + .global \name + .protected \name + .align \size + .size \name , \size + \name : + .org .+\size +.endm + /* The base address (relative to enclave start) of the heap area */ + globvar HEAP_BASE 8 + /* The heap size in bytes */ + globvar HEAP_SIZE 8 + /* Value of the RELA entry in the dynamic table */ + globvar RELA 8 + /* Value of the RELACOUNT entry in the dynamic table */ + globvar RELACOUNT 8 + /* The enclave size in bytes */ + globvar ENCLAVE_SIZE 8 + /* The base address (relative to enclave start) of the enclave configuration area */ + globvar CFGDATA_BASE 8 + /* Non-zero if debugging is enabled, zero otherwise */ + globvar DEBUG 1 + +.Lreentry_panic_msg: + .asciz "Re-entered panicked enclave!" +.Lreentry_panic_msg_end: + +.Lusercall_panic_msg: + .asciz "Invalid usercall#!" +.Lusercall_panic_msg_end: + +.org .Lxsave_clear+512 +.Lxsave_header: + .int 0, 0 /* XSTATE_BV */ + .int 0, 0 /* XCOMP_BV */ + .org .+48 /* reserved bits */ + +.data +.Lpanicked: + .byte 0 + +/* TCS local storage section */ +.equ tcsls_tos, 0x00 /* initialized by loader to *offset* from image base to TOS */ +.equ tcsls_flags, 0x08 /* initialized by loader */ +.equ tcsls_flag_secondary, 0 /* initialized by loader; 0 = standard TCS, 1 = secondary TCS */ +.equ tcsls_flag_init_once, 1 /* initialized by loader to 0 */ +/* 14 unused bits */ +.equ tcsls_user_fcw, 0x0a +.equ tcsls_user_mxcsr, 0x0c +.equ tcsls_last_rsp, 0x10 /* initialized by loader to 0 */ +.equ tcsls_panic_last_rsp, 0x18 /* initialized by loader to 0 */ +.equ tcsls_debug_panic_buf_ptr, 0x20 /* initialized by loader to 0 */ +.equ tcsls_user_rsp, 0x28 +.equ tcsls_user_retip, 0x30 +.equ tcsls_user_rbp, 0x38 +.equ tcsls_user_r12, 0x40 +.equ tcsls_user_r13, 0x48 +.equ tcsls_user_r14, 0x50 +.equ tcsls_user_r15, 0x58 +.equ tcsls_tls_ptr, 0x60 +.equ tcsls_tcs_addr, 0x68 + +.macro load_tcsls_flag_secondary_bool reg:req comments:vararg + .ifne tcsls_flag_secondary /* to convert to a bool, must be the first bit */ + .abort + .endif + mov $(1< ! { + panic!(msg) +} + +// Called once when a TCS is first entered +extern "C" fn tcs_init(secondary: bool); + +// Standard TCS entrypoint +extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64); +``` +*/ + +.global get_tcs_addr +get_tcs_addr: + mov %gs:tcsls_tcs_addr,%rax + ret + +.global get_tls_ptr +get_tls_ptr: + mov %gs:tcsls_tls_ptr,%rax + ret + +.global set_tls_ptr +set_tls_ptr: + mov %rdi,%gs:tcsls_tls_ptr + ret + +.global take_debug_panic_buf_ptr +take_debug_panic_buf_ptr: + xor %rax,%rax + xchg %gs:tcsls_debug_panic_buf_ptr,%rax + ret diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs new file mode 100644 index 00000000000..aedf6ec7acb --- /dev/null +++ b/src/libstd/sys/sgx/abi/mem.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , 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(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(offset: u64) -> *mut T { + (image_base()+offset) as *mut T +} + +// Do not remove inline: will result in relocation failure +// For the same reason we use inline ASM here instead of an extern static to +// locate the base +#[inline(always)] +fn image_base() -> u64 { + let base; + unsafe{asm!("lea IMAGE_BASE(%rip),$0":"=r"(base))}; + base +} diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs new file mode 100644 index 00000000000..cade96e3f52 --- /dev/null +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -0,0 +1,94 @@ +// 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 or the MIT license +// , 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 +#[macro_use] +mod usercalls; + +global_asm!(concat!(usercalls_asm!(), include_str!("entry.S"))); + +#[no_mangle] +unsafe extern "C" fn tcs_init(secondary: bool) { + // Be very careful when changing this code: it runs before the binary has been + // relocated. Any indirect accesses to symbols will likely fail. + const UNINIT: usize = 0; + const BUSY: usize = 1; + const DONE: usize = 2; + // Three-state spin-lock + static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT); + + if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE { + panic::panic_msg("Entered secondary TCS before main TCS!") + } + + // Try to atomically swap UNINIT with BUSY. The returned state can be: + match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) { + // This thread just obtained the lock and other threads will observe BUSY + UNINIT => { + reloc::relocate_elf_rela(); + RELOC_STATE.store(DONE, Ordering::Release); + }, + // We need to wait until the initialization is done. + BUSY => while RELOC_STATE.load(Ordering::Acquire) == BUSY { + ::core::arch::x86_64::_mm_pause() + }, + // Initialization is done. + DONE => {}, + _ => unreachable!() + } +} + +// FIXME: this item should only exist if this is linked into an executable +// (main function exists). If this is a library, the crate author should be +// able to specify this +#[no_mangle] +#[allow(unreachable_code)] +extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) { + if secondary { + unimplemented!("thread entrypoint"); + + (0, 0) + } else { + extern "C" { + fn main(argc: isize, argv: *const *const u8) -> isize; + } + + // check entry is being called according to ABI + assert_eq!(p3, 0); + assert_eq!(p4, 0); + assert_eq!(p5, 0); + + unsafe { + // The actual types of these arguments are `p1: *const Arg, p2: + // usize`. We can't currently customize the argument list of Rust's + // main function, so we pass these in as the standard pointer-sized + // values in `argc` and `argv`. + let ret = main(p2 as _, p1 as _); + exit_with_code(ret) + } + } +} + +pub(super) fn exit_with_code(code: isize) -> ! { + if code != 0 { + if let Some(mut out) = panic::SgxPanicOutput::new() { + let _ = write!(out, "Exited with status code {}", code); + } + } + unsafe { usercalls::raw::exit(code != 0) }; +} diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs new file mode 100644 index 00000000000..dd9159b9fe2 --- /dev/null +++ b/src/libstd/sys/sgx/abi/panic.rs @@ -0,0 +1,58 @@ +// 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 or the MIT license +// , 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; + +extern "C" { + fn take_debug_panic_buf_ptr() -> *mut u8; + static DEBUG: u8; +} + +pub(crate) struct SgxPanicOutput(Option<&'static mut [u8]>); + +impl SgxPanicOutput { + pub(crate) fn new() -> Option { + if unsafe { DEBUG == 0 } { + None + } else { + Some(SgxPanicOutput(None)) + } + } + + fn init(&mut self) -> &mut &'static mut [u8] { + self.0.get_or_insert_with(|| unsafe { + let ptr = take_debug_panic_buf_ptr(); + if ptr.is_null() { + &mut [] + } else { + from_raw_parts_mut(ptr, 1024) + } + }) + } +} + +impl Write for SgxPanicOutput { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.init().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.init().flush() + } +} + +#[no_mangle] +pub extern "C" fn panic_msg(msg: &str) -> ! { + let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes())); + unsafe { panic_exit(); } +} + +extern "C" { pub fn panic_exit() -> !; } diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs new file mode 100644 index 00000000000..2d5e14d6ad1 --- /dev/null +++ b/src/libstd/sys/sgx/abi/reloc.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , 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; + +const R_X86_64_RELATIVE: u32 = 8; + +#[repr(packed)] +struct Rela { + offset: T, + info: T, + addend: T, +} + +pub fn relocate_elf_rela() { + extern { + static RELA: u64; + static RELACOUNT: usize; + } + + if unsafe { RELACOUNT } == 0 { return } // unsafe ok: link-time constant + + let relas = unsafe { + from_raw_parts::>(mem::rel_ptr(RELA), RELACOUNT) // unsafe ok: link-time constant + }; + for rela in relas { + if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) { + panic!("Invalid relocation"); + } + unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) }; + } +} diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs new file mode 100644 index 00000000000..370e058badf --- /dev/null +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -0,0 +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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_use] +pub mod raw; diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs new file mode 100644 index 00000000000..a28d41c1b74 --- /dev/null +++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs @@ -0,0 +1,231 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use fortanix_sgx_abi::*; + +use ptr::NonNull; + +#[repr(C)] +struct UsercallReturn(u64, u64); + +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) { + if nr==0 { panic!("Invalid usercall number {}",nr) } + let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4); + (a, b) +} + +type Register = u64; + +trait RegisterArgument { + fn from_register(Register) -> Self; + fn into_register(self) -> Register; +} + +trait ReturnValue { + fn from_registers(call: &'static str, regs: (Register, Register)) -> Self; +} + +macro_rules! define_usercalls { + // Using `$r:tt` because `$r:ty` doesn't match ! in `clobber_diverging` + ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => { + #[repr(C)] + #[allow(non_camel_case_types)] + enum Usercalls { + __enclave_usercalls_invalid, + $($f,)* + } + + $(enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) $(-> $r)*);)* + }; +} + +macro_rules! define_usercalls_asm { + ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => { + macro_rules! usercalls_asm { + () => { + concat!( + ".equ usercall_nr_LAST, 0\n", + $( + ".equ usercall_nr_", stringify!($f), ", usercall_nr_LAST+1\n", + ".equ usercall_nr_LAST, usercall_nr_", stringify!($f), "\n" + ),* + ) + } + } + }; +} + +macro_rules! define_ra { + (< $i:ident > $t:ty) => { + impl<$i> RegisterArgument for $t { + fn from_register(a: Register) -> Self { + a as _ + } + fn into_register(self) -> Register { + self as _ + } + } + }; + ($i:ty as $t:ty) => { + impl RegisterArgument for $t { + fn from_register(a: Register) -> Self { + a as $i as _ + } + fn into_register(self) -> Register { + self as $i as _ + } + } + }; + ($t:ty) => { + impl RegisterArgument for $t { + fn from_register(a: Register) -> Self { + a as _ + } + fn into_register(self) -> Register { + self as _ + } + } + }; +} + +define_ra!(Register); +define_ra!(i64); +define_ra!(u32); +define_ra!(u32 as i32); +define_ra!(u16); +define_ra!(u16 as i16); +define_ra!(u8); +define_ra!(u8 as i8); +define_ra!(usize); +define_ra!(usize as isize); +define_ra!( *const T); +define_ra!( *mut T); + +impl RegisterArgument for bool { + fn from_register(a: Register) -> bool { + if a != 0 { + true + } else { + false + } + } + fn into_register(self) -> Register { + self as _ + } +} + +impl RegisterArgument for Option> { + fn from_register(a: Register) -> Option> { + NonNull::new(a as _) + } + fn into_register(self) -> Register { + self.map_or(0 as _, NonNull::as_ptr) as _ + } +} + +impl ReturnValue for ! { + fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { + panic!("Usercall {}: did not expect to be re-entered", call); + } +} + +impl ReturnValue for () { + fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { + assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st"); + assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); + () + } +} + +impl ReturnValue for T { + fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { + assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); + T::from_register(regs.0) + } +} + +impl ReturnValue for (T, U) { + fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self { + ( + T::from_register(regs.0), + U::from_register(regs.1) + ) + } +} + +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) => ( + #[inline(always)] + pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { + ReturnValue::from_registers(stringify!($f), do_usercall( + Usercalls::$f as Register, + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + RegisterArgument::into_register($n3), + RegisterArgument::into_register($n4), + )) + } + ); + (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => ( + #[inline(always)] + pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { + ReturnValue::from_registers(stringify!($f), do_usercall( + Usercalls::$f as Register, + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + RegisterArgument::into_register($n3), + 0 + )) + } + ); + (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => ( + #[inline(always)] + pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { + ReturnValue::from_registers(stringify!($f), do_usercall( + Usercalls::$f as Register, + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + 0,0 + )) + } + ); + (def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => ( + #[inline(always)] + pub unsafe fn $f($n1: $t1) -> $r { + ReturnValue::from_registers(stringify!($f), do_usercall( + Usercalls::$f as Register, + RegisterArgument::into_register($n1), + 0,0,0 + )) + } + ); + (def fn $f:ident() -> $r:ty) => ( + #[inline(always)] + pub unsafe fn $f() -> $r { + ReturnValue::from_registers(stringify!($f), do_usercall( + Usercalls::$f as Register, + 0,0,0,0 + )) + } + ); + (def fn $f:ident($($n:ident: $t:ty),*)) => ( + enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) -> ()); + ); +} + +invoke_with_usercalls!(define_usercalls); +invoke_with_usercalls!(define_usercalls_asm); diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs new file mode 100644 index 00000000000..a31f93ae493 --- /dev/null +++ b/src/libstd/sys/sgx/alloc.rs @@ -0,0 +1,39 @@ +// 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 or the MIT license +// , 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}; + +// FIXME: protect this value for concurrent access +static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + DLMALLOC.malloc(layout.size(), layout.align()) + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + DLMALLOC.calloc(layout.size(), layout.align()) + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + DLMALLOC.free(ptr, layout.size(), layout.align()) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) + } +} diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs new file mode 100644 index 00000000000..64cb83b462a --- /dev/null +++ b/src/libstd/sys/sgx/args.rs @@ -0,0 +1,57 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi::OsString; +use fortanix_sgx_abi::ByteBuffer; + +pub unsafe fn init(argc: isize, argv: *const *const u8) { + // See ABI + let _len: usize = argc as _; + let _args: *const ByteBuffer = argv as _; + + // TODO +} + +pub unsafe fn cleanup() { +} + +pub fn args() -> Args { + Args +} + +pub struct Args; + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + &[] + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + None + } + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + 0 + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + None + } +} diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs new file mode 100644 index 00000000000..ca4a7c9561c --- /dev/null +++ b/src/libstd/sys/sgx/backtrace.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , 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; + +pub struct BacktraceContext; + +pub fn unwind_backtrace(_frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + unsupported() +} + +pub fn resolve_symname(_frame: Frame, + _callback: F, + _: &BacktraceContext) -> io::Result<()> + where F: FnOnce(Option<&str>) -> io::Result<()> +{ + unsupported() +} + +pub fn foreach_symbol_fileline(_: Frame, + _: F, + _: &BacktraceContext) -> io::Result + where F: FnMut(&[u8], u32) -> io::Result<()> +{ + unsupported() +} diff --git a/src/libstd/sys/sgx/cmath.rs b/src/libstd/sys/sgx/cmath.rs new file mode 100644 index 00000000000..0c1300f61f8 --- /dev/null +++ b/src/libstd/sys/sgx/cmath.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , 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` +extern { + pub fn acos(n: f64) -> f64; + pub fn acosf(n: f32) -> f32; + pub fn asin(n: f64) -> f64; + pub fn asinf(n: f32) -> f32; + pub fn atan(n: f64) -> f64; + pub fn atan2(a: f64, b: f64) -> f64; + pub fn atan2f(a: f32, b: f32) -> f32; + pub fn atanf(n: f32) -> f32; + pub fn cbrt(n: f64) -> f64; + pub fn cbrtf(n: f32) -> f32; + pub fn cosh(n: f64) -> f64; + pub fn coshf(n: f32) -> f32; + pub fn expm1(n: f64) -> f64; + pub fn expm1f(n: f32) -> f32; + pub fn fdim(a: f64, b: f64) -> f64; + pub fn fdimf(a: f32, b: f32) -> f32; + pub fn hypot(x: f64, y: f64) -> f64; + pub fn hypotf(x: f32, y: f32) -> f32; + pub fn log1p(n: f64) -> f64; + pub fn log1pf(n: f32) -> f32; + pub fn sinh(n: f64) -> f64; + pub fn sinhf(n: f32) -> f32; + pub fn tan(n: f64) -> f64; + pub fn tanf(n: f32) -> f32; + pub fn tanh(n: f64) -> f64; + pub fn tanhf(n: f32) -> f32; +} diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs new file mode 100644 index 00000000000..2097280a064 --- /dev/null +++ b/src/libstd/sys/sgx/condvar.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::mutex::Mutex; +use time::Duration; + +pub struct Condvar { } + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn notify_one(&self) { + } + + #[inline] + pub unsafe fn notify_all(&self) { + } + + pub unsafe fn wait(&self, _mutex: &Mutex) { + panic!("can't block with web assembly") + } + + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + panic!("can't block with web assembly"); + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/sgx/env.rs b/src/libstd/sys/sgx/env.rs new file mode 100644 index 00000000000..146ce02754b --- /dev/null +++ b/src/libstd/sys/sgx/env.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , 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 = ""; + pub const DLL_PREFIX: &'static str = ""; + pub const DLL_SUFFIX: &'static str = ".sgxs"; + pub const DLL_EXTENSION: &'static str = "sgxs"; + pub const EXE_SUFFIX: &'static str = ".sgxs"; + pub const EXE_EXTENSION: &'static str = "sgxs"; +} diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs new file mode 100644 index 00000000000..1dcea3e8eac --- /dev/null +++ b/src/libstd/sys/sgx/fs.rs @@ -0,0 +1,304 @@ +// 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 or the MIT license +// , 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}; +use io::{self, SeekFrom}; +use path::{Path, PathBuf}; +use sys::time::SystemTime; +use sys::{unsupported, Void}; + +pub struct File(Void); + +pub struct FileAttr(Void); + +pub struct ReadDir(Void); + +pub struct DirEntry(Void); + +#[derive(Clone, Debug)] +pub struct OpenOptions { } + +pub struct FilePermissions(Void); + +pub struct FileType(Void); + +#[derive(Debug)] +pub struct DirBuilder { } + +impl FileAttr { + pub fn size(&self) -> u64 { + match self.0 {} + } + + pub fn perm(&self) -> FilePermissions { + match self.0 {} + } + + pub fn file_type(&self) -> FileType { + match self.0 {} + } + + pub fn modified(&self) -> io::Result { + match self.0 {} + } + + pub fn accessed(&self) -> io::Result { + match self.0 {} + } + + pub fn created(&self) -> io::Result { + match self.0 {} + } +} + +impl Clone for FileAttr { + fn clone(&self) -> FileAttr { + match self.0 {} + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + match self.0 {} + } + + pub fn set_readonly(&mut self, _readonly: bool) { + match self.0 {} + } +} + +impl Clone for FilePermissions { + fn clone(&self) -> FilePermissions { + match self.0 {} + } +} + +impl PartialEq for FilePermissions { + fn eq(&self, _other: &FilePermissions) -> bool { + match self.0 {} + } +} + +impl Eq for FilePermissions { +} + +impl fmt::Debug for FilePermissions { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + match self.0 {} + } + + pub fn is_file(&self) -> bool { + match self.0 {} + } + + pub fn is_symlink(&self) -> bool { + match self.0 {} + } +} + +impl Clone for FileType { + fn clone(&self) -> FileType { + match self.0 {} + } +} + +impl Copy for FileType {} + +impl PartialEq for FileType { + fn eq(&self, _other: &FileType) -> bool { + match self.0 {} + } +} + +impl Eq for FileType { +} + +impl Hash for FileType { + fn hash(&self, _h: &mut H) { + match self.0 {} + } +} + +impl fmt::Debug for FileType { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + match self.0 {} + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + match self.0 {} + } + + pub fn file_name(&self) -> OsString { + match self.0 {} + } + + pub fn metadata(&self) -> io::Result { + match self.0 {} + } + + pub fn file_type(&self) -> io::Result { + match self.0 {} + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { } + } + + pub fn read(&mut self, _read: bool) { } + pub fn write(&mut self, _write: bool) { } + pub fn append(&mut self, _append: bool) { } + pub fn truncate(&mut self, _truncate: bool) { } + pub fn create(&mut self, _create: bool) { } + pub fn create_new(&mut self, _create_new: bool) { } +} + +impl File { + pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { + unsupported() + } + + pub fn file_attr(&self) -> io::Result { + match self.0 {} + } + + pub fn fsync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn datasync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + match self.0 {} + } + + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn flush(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { } + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub fn readdir(_p: &Path) -> io::Result { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + unsupported() +} + +pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { + match perm.0 {} +} + +pub fn rmdir(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn readlink(_p: &Path) -> io::Result { + unsupported() +} + +pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result { + unsupported() +} diff --git a/src/libstd/sys/sgx/memchr.rs b/src/libstd/sys/sgx/memchr.rs new file mode 100644 index 00000000000..0998bc5db4c --- /dev/null +++ b/src/libstd/sys/sgx/memchr.rs @@ -0,0 +1,11 @@ +// 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 or the MIT license +// , 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 new file mode 100644 index 00000000000..f38c69e90c7 --- /dev/null +++ b/src/libstd/sys/sgx/mod.rs @@ -0,0 +1,151 @@ +// 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 or the MIT license +// , 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 +//! OS level functionality for Fortanix SGX. + +use io; +use os::raw::c_char; +use sync::atomic::{AtomicBool, Ordering}; + +pub mod abi; + +pub mod alloc; +pub mod args; +#[cfg(feature = "backtrace")] +pub mod backtrace; +pub mod cmath; +pub mod condvar; +pub mod env; +pub mod fs; +pub mod memchr; +pub mod mutex; +pub mod net; +pub mod os; +pub mod os_str; +pub mod path; +pub mod pipe; +pub mod process; +pub mod rwlock; +pub mod stack_overflow; +pub mod thread; +pub mod thread_local; +pub mod time; +pub mod stdio; + +#[cfg(not(test))] +pub fn init() { +} + +/// This function is used to implement functionality that simply doesn't exist. +/// Programs relying on this functionality will need to deal with the error. +pub fn unsupported() -> io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> io::Error { + io::Error::new(io::ErrorKind::Other, + "operation not supported on SGX yet") +} + +/// This function is used to implement various functions that doesn't exist, +/// but the lack of which might not be reason for error. If no error is +/// returned, the program might very well be able to function normally. This is +/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is +/// `false`, the behavior is the same as `unsupported`. +pub fn sgx_ineffective(v: T) -> io::Result { + static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false); + if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { + Err(io::Error::new(io::ErrorKind::Other, + "operation can't be trusted to have any effect on SGX")) + } else { + Ok(v) + } +} + +pub fn decode_error_kind(code: i32) -> io::ErrorKind { + use fortanix_sgx_abi::Error; + + // FIXME: not sure how to make sure all variants of Error are covered + if code == Error::NotFound as _ { + io::ErrorKind::NotFound + } else if code == Error::PermissionDenied as _ { + io::ErrorKind::PermissionDenied + } else if code == Error::ConnectionRefused as _ { + io::ErrorKind::ConnectionRefused + } else if code == Error::ConnectionReset as _ { + io::ErrorKind::ConnectionReset + } else if code == Error::ConnectionAborted as _ { + io::ErrorKind::ConnectionAborted + } else if code == Error::NotConnected as _ { + io::ErrorKind::NotConnected + } else if code == Error::AddrInUse as _ { + io::ErrorKind::AddrInUse + } else if code == Error::AddrNotAvailable as _ { + io::ErrorKind::AddrNotAvailable + } else if code == Error::BrokenPipe as _ { + io::ErrorKind::BrokenPipe + } else if code == Error::AlreadyExists as _ { + io::ErrorKind::AlreadyExists + } else if code == Error::WouldBlock as _ { + io::ErrorKind::WouldBlock + } else if code == Error::InvalidInput as _ { + io::ErrorKind::InvalidInput + } else if code == Error::InvalidData as _ { + io::ErrorKind::InvalidData + } else if code == Error::TimedOut as _ { + io::ErrorKind::TimedOut + } else if code == Error::WriteZero as _ { + io::ErrorKind::WriteZero + } else if code == Error::Interrupted as _ { + io::ErrorKind::Interrupted + } else if code == Error::Other as _ { + io::ErrorKind::Other + } else if code == Error::UnexpectedEof as _ { + io::ErrorKind::UnexpectedEof + } else { + io::ErrorKind::Other + } +} + +// This enum is used as the storage for a bunch of types which can't actually +// exist. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Void {} + +pub unsafe fn strlen(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n +} + +pub unsafe fn abort_internal() -> ! { + abi::panic::panic_exit() +} + +pub fn hashmap_random_keys() -> (u64, u64) { + fn rdrand64() -> u64 { + unsafe { + let mut ret: u64 = ::mem::uninitialized(); + for _ in 0..10 { + if ::arch::x86_64::_rdrand64_step(&mut ret) == 1 { + return ret; + } + } + panic!("Failed to obtain random data"); + } + } + (rdrand64(), rdrand64()) +} diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs new file mode 100644 index 00000000000..ffaa4014e14 --- /dev/null +++ b/src/libstd/sys/sgx/mutex.rs @@ -0,0 +1,78 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; + +pub struct Mutex { + locked: UnsafeCell, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} // FIXME + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { locked: UnsafeCell::new(false) } + } + + #[inline] + pub unsafe fn init(&mut self) { + } + + #[inline] + pub unsafe fn lock(&self) { + let locked = self.locked.get(); + assert!(!*locked, "cannot recursively acquire mutex"); + *locked = true; + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.locked.get() = false; + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let locked = self.locked.get(); + if *locked { + false + } else { + *locked = true; + true + } + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} + +// FIXME +pub struct ReentrantMutex { +} + +impl ReentrantMutex { + pub unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn lock(&self) {} + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + true + } + + pub unsafe fn unlock(&self) {} + + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs new file mode 100644 index 00000000000..094683e28b8 --- /dev/null +++ b/src/libstd/sys/sgx/net.rs @@ -0,0 +1,356 @@ +// 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 or the MIT license +// , 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}; +use time::Duration; +use sys::{unsupported, Void}; +use convert::TryFrom; + +pub struct TcpStream(Void); + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn read(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn peer_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn nodelay(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct TcpListener(Void); + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn only_v6(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct UdpSocket(Void); + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result { + match self.0 {} + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result { + match self.0 {} + } + + pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn broadcast(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_ttl_v4(&self) -> io::Result { + match self.0 {} + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v6(&self) -> io::Result { + match self.0 {} + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn send(&self, _: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct LookupHost(Void); + +impl LookupHost { + pub fn port(&self) -> u16 { + match self.0 {} + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + match self.0 {} + } +} + +impl<'a> TryFrom<&'a str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &'a str) -> io::Result { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result { + unsupported() + } +} + +#[allow(bad_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr { + } + + pub type socklen_t = usize; +} diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs new file mode 100644 index 00000000000..38d82efaf17 --- /dev/null +++ b/src/libstd/sys/sgx/os.rs @@ -0,0 +1,120 @@ +// 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 or the MIT license +// , 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; +use ffi::{OsString, OsStr}; +use fmt; +use io; +use path::{self, PathBuf}; +use str; +use sys::{unsupported, Void, sgx_ineffective, decode_error_kind}; + +pub fn errno() -> i32 { + RESULT_SUCCESS +} + +pub fn error_string(errno: i32) -> String { + if errno == RESULT_SUCCESS { + "operation succesful".into() + } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { + format!("user-specified error {:08x}", errno) + } else { + decode_error_kind(errno).as_str().into() + } +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + sgx_ineffective(()) +} + +pub struct SplitPaths<'a>(&'a Void); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + match *self.0 {} + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result + where I: Iterator, T: AsRef +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "not supported in SGX yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + fn description(&self) -> &str { + "not supported in SGX yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +pub struct Env; + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + None + } +} + +pub fn env() -> Env { + Env +} + +pub fn getenv(_k: &OsStr) -> io::Result> { + unsupported() +} + +pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { + sgx_ineffective(()) // FIXME: this could trigger a panic higher up the stack +} + +pub fn unsetenv(_k: &OsStr) -> io::Result<()> { + sgx_ineffective(()) // FIXME: this could trigger a panic higher up the stack +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem in SGX") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(code: i32) -> ! { + super::abi::exit_with_code(code as _) +} + +pub fn getpid() -> u32 { + panic!("no pids in SGX") +} diff --git a/src/libstd/sys/sgx/os_str.rs b/src/libstd/sys/sgx/os_str.rs new file mode 100644 index 00000000000..9bfb84db209 --- /dev/null +++ b/src/libstd/sys/sgx/os_str.rs @@ -0,0 +1,189 @@ +// 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 or the MIT license +// , 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]`. + +use borrow::Cow; +use fmt; +use str; +use mem; +use rc::Rc; +use sync::Arc; +use sys_common::{AsInner, IntoInner}; +use sys_common::bytestring::debug_fmt_bytestring; +use core::str::lossy::Utf8Lossy; + +#[derive(Clone, Hash)] +pub struct Buf { + pub inner: Vec +} + +pub struct Slice { + pub inner: [u8] +} + +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + debug_fmt_bytestring(&self.inner, formatter) + } +} + +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) + } +} + +impl IntoInner> for Buf { + fn into_inner(self) -> Vec { + self.inner + } +} + +impl AsInner<[u8]> for Buf { + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + + +impl Buf { + pub fn from_string(s: String) -> Buf { + Buf { inner: s.into_bytes() } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { + inner: Vec::with_capacity(capacity) + } + } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + + pub fn as_slice(&self) -> &Slice { + unsafe { mem::transmute(&*self.inner) } + } + + pub fn into_string(self) -> Result { + String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } ) + } + + pub fn push_slice(&mut self, s: &Slice) { + self.inner.extend_from_slice(&s.inner) + } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + self.as_slice().into_arc() + } + + #[inline] + pub fn into_rc(&self) -> Rc { + self.as_slice().into_rc() + } +} + +impl Slice { + fn from_u8_slice(s: &[u8]) -> &Slice { + unsafe { mem::transmute(s) } + } + + pub fn from_str(s: &str) -> &Slice { + Slice::from_u8_slice(s.as_bytes()) + } + + pub fn to_str(&self) -> Option<&str> { + str::from_utf8(&self.inner).ok() + } + + pub fn to_string_lossy(&self) -> Cow { + String::from_utf8_lossy(&self.inner) + } + + pub fn to_owned(&self) -> Buf { + Buf { inner: self.inner.to_vec() } + } + + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.inner.into(); + unsafe { mem::transmute(boxed) } + } + + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + let arc: Arc<[u8]> = Arc::from(&self.inner); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc { + let rc: Rc<[u8]> = Rc::from(&self.inner); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } +} diff --git a/src/libstd/sys/sgx/path.rs b/src/libstd/sys/sgx/path.rs new file mode 100644 index 00000000000..afe0c490426 --- /dev/null +++ b/src/libstd/sys/sgx/path.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use path::Prefix; +use ffi::OsStr; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' +} + +pub fn parse_prefix(_: &OsStr) -> Option { + None +} + +pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs new file mode 100644 index 00000000000..6c6cbc14a8a --- /dev/null +++ b/src/libstd/sys/sgx/pipe.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::Void; + +pub struct AnonPipe(Void); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec, + _p2: AnonPipe, + _v2: &mut Vec) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs new file mode 100644 index 00000000000..01a12fba043 --- /dev/null +++ b/src/libstd/sys/sgx/process.rs @@ -0,0 +1,162 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi::OsStr; +use fmt; +use io; +use sys::fs::File; +use sys::pipe::AnonPipe; +use sys::{unsupported, Void}; +use sys_common::process::{CommandEnv, DefaultEnvKey}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { + env: CommandEnv +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +impl Command { + pub fn new(_program: &OsStr) -> Command { + Command { + env: Default::default() + } + } + + pub fn arg(&mut self, _arg: &OsStr) { + } + + pub fn env_mut(&mut self) -> &mut CommandEnv { + &mut self.env + } + + pub fn cwd(&mut self, _dir: &OsStr) { + } + + pub fn stdin(&mut self, _stdin: Stdio) { + } + + pub fn stdout(&mut self, _stdout: Stdio) { + } + + pub fn stderr(&mut self, _stderr: Stdio) { + } + + pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + unsupported() + } +} + +impl From for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From for Stdio { + fn from(file: File) -> Stdio { + file.diverge() + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +pub struct ExitStatus(Void); + +impl ExitStatus { + pub fn success(&self) -> bool { + match self.0 {} + } + + pub fn code(&self) -> Option { + match self.0 {} + } +} + +impl Clone for ExitStatus { + fn clone(&self) -> ExitStatus { + match self.0 {} + } +} + +impl Copy for ExitStatus {} + +impl PartialEq for ExitStatus { + fn eq(&self, _other: &ExitStatus) -> bool { + match self.0 {} + } +} + +impl Eq for ExitStatus { +} + +impl fmt::Debug for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result> { + match self.0 {} + } +} diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs new file mode 100644 index 00000000000..2c0b1a45206 --- /dev/null +++ b/src/libstd/sys/sgx/rwlock.rs @@ -0,0 +1,82 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cell::UnsafeCell; + +pub struct RWLock { + mode: UnsafeCell, +} + +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} // FIXME + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { + mode: UnsafeCell::new(0), + } + } + + #[inline] + pub unsafe fn read(&self) { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + } else { + rtabort!("rwlock locked for writing"); + } + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn write(&self) { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + } else { + rtabort!("rwlock locked for reading") + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + *self.mode.get() -= 1; + } + + #[inline] + pub unsafe fn write_unlock(&self) { + *self.mode.get() += 1; + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs new file mode 100644 index 00000000000..0176b748a87 --- /dev/null +++ b/src/libstd/sys/sgx/stack_overflow.rs @@ -0,0 +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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Handler; + +impl Handler { + pub unsafe fn new() -> Handler { + Handler + } +} + +pub unsafe fn init() { +} + +pub unsafe fn cleanup() { +} diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs new file mode 100644 index 00000000000..540599a3596 --- /dev/null +++ b/src/libstd/sys/sgx/stdio.rs @@ -0,0 +1,73 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::unsupported; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result { + Ok(Stdin) + } + + pub fn read(&self, _data: &mut [u8]) -> io::Result { + unsupported() + } +} + +impl Stdout { + pub fn new() -> io::Result { + Ok(Stdout) + } + + pub fn write(&self, _data: &[u8]) -> io::Result { + unsupported() + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result { + Ok(Stderr) + } + + pub fn write(&self, _data: &[u8]) -> io::Result { + unsupported() + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result { + (&*self).write(data) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + super::abi::panic::SgxPanicOutput::new() +} diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs new file mode 100644 index 00000000000..ff8df12302c --- /dev/null +++ b/src/libstd/sys/sgx/thread.rs @@ -0,0 +1,51 @@ +// 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 or the MIT license +// , 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; +use sys::{unsupported, Void}; +use time::Duration; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new(_stack: usize, _p: Box) + -> io::Result + { + unsupported() + } + + pub fn yield_now() { + // do nothing + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(_dur: Duration) { + panic!("can't sleep"); + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} +} diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local.rs new file mode 100644 index 00000000000..2126e0a853e --- /dev/null +++ b/src/libstd/sys/sgx/thread_local.rs @@ -0,0 +1,50 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use boxed::Box; +use ptr; + +pub type Key = usize; + +struct Allocated { + value: *mut u8, + dtor: Option, +} + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { + Box::into_raw(Box::new(Allocated { + value: ptr::null_mut(), + dtor, + })) as usize +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + (*(key as *mut Allocated)).value = value; +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + (*(key as *mut Allocated)).value +} + +#[inline] +pub unsafe fn destroy(key: Key) { + let key = Box::from_raw(key as *mut Allocated); + if let Some(f) = key.dtor { + f(key.value); + } +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs new file mode 100644 index 00000000000..894680b0b65 --- /dev/null +++ b/src/libstd/sys/sgx/time.rs @@ -0,0 +1,61 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use time::Duration; +use sys::unsupported_err; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +impl Instant { + pub fn now() -> Instant { + panic!("{}", unsupported_err()); + } + + pub fn sub_instant(&self, other: &Instant) -> Duration { + self.0 - other.0 + } + + pub fn add_duration(&self, other: &Duration) -> Instant { + Instant(self.0 + *other) + } + + pub fn sub_duration(&self, other: &Duration) -> Instant { + Instant(self.0 - *other) + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + panic!("{}", unsupported_err()); + } + + pub fn sub_time(&self, other: &SystemTime) + -> Result { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + } + + pub fn add_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 + *other) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.0.checked_add(*other).map(|d| SystemTime(d)) + } + + pub fn sub_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 - *other) + } +} diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 4b8cde3d1f4..881794d9f16 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -57,9 +57,11 @@ pub mod bytestring; pub mod process; cfg_if! { - if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] { - pub use sys::net; - } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + if #[cfg(any(target_os = "cloudabi", + target_os = "l4re", + target_os = "redox", + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_env = "sgx"))] { pub use sys::net; } else { pub mod net; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 7c26d042a7c..b8711a69147 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1018,10 +1018,12 @@ fn use_color(opts: &TestOpts) -> bool { } } -#[cfg(any(target_os = "cloudabi", target_os = "redox", - all(target_arch = "wasm32", not(target_os = "emscripten"))))] +#[cfg(any(target_os = "cloudabi", + target_os = "redox", + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_env = "sgx"))] fn stdout_isatty() -> bool { - // FIXME: Implement isatty on Redox + // FIXME: Implement isatty on Redox and SGX false } #[cfg(unix)] @@ -1246,7 +1248,7 @@ fn get_concurrency() -> usize { 1 } - #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + #[cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx"))] fn num_cpus() -> usize { 1 } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 954eb9d6d03..eb53332ab33 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -26,7 +26,10 @@ mod macros; cfg_if! { if #[cfg(target_env = "msvc")] { // no extra unwinder support needed - } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + } else if #[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_env = "sgx" + ))] { // no unwinder on the system! } else { extern crate libc; diff --git a/src/rust-sgx b/src/rust-sgx new file mode 160000 index 00000000000..96562608880 --- /dev/null +++ b/src/rust-sgx @@ -0,0 +1 @@ +Subproject commit 9656260888095f44830641ca7bb3da609a793451 diff --git a/src/rustc/fortanix-sgx-abi_shim/Cargo.toml b/src/rustc/fortanix-sgx-abi_shim/Cargo.toml new file mode 100644 index 00000000000..fd81d3db3a7 --- /dev/null +++ b/src/rustc/fortanix-sgx-abi_shim/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "fortanix-sgx-abi" +version = "0.0.0" +authors = ["The Rust Project Developers"] + +[lib] +path = "../../rust-sgx/fortanix-sgx-abi/src/lib.rs" +test = false +bench = false +doc = false + +[dependencies] +core = { path = "../../libcore" } +compiler_builtins = { path = "../../rustc/compiler_builtins_shim" } diff --git a/src/stdsimd b/src/stdsimd index 0309be1ade6..5e628c5120c 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 0309be1ade6bf61066f2c69f77ac3567b7dc31b5 +Subproject commit 5e628c5120c619a22799187371f057ec41e06f87 diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 700103d35d8..53db589beaf 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -76,6 +76,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/lldb", "src/target", "src/stdsimd", + "src/rust-sgx", "target", "vendor", ];