]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/mod.rs
99ea7a381f37b2c27614ed4d25241611c4eb79a8
[rust.git] / src / libstd / sys / sgx / abi / mod.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use core::sync::atomic::{AtomicUsize, Ordering};
12 use io::Write;
13
14 // runtime features
15 mod reloc;
16 mod mem;
17 pub(super) mod panic;
18
19 // library features
20 pub mod thread;
21 pub mod tls;
22 #[macro_use]
23 mod usercalls;
24
25 global_asm!(concat!(usercalls_asm!(), include_str!("entry.S")));
26
27 #[no_mangle]
28 unsafe extern "C" fn tcs_init(secondary: bool) {
29     // Be very careful when changing this code: it runs before the binary has been
30     // relocated. Any indirect accesses to symbols will likely fail.
31     const UNINIT: usize = 0;
32     const BUSY: usize = 1;
33     const DONE: usize = 2;
34     // Three-state spin-lock
35     static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);
36
37     if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
38         panic::panic_msg("Entered secondary TCS before main TCS!")
39     }
40
41     // Try to atomically swap UNINIT with BUSY. The returned state can be:
42     match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
43         // This thread just obtained the lock and other threads will observe BUSY
44         UNINIT => {
45             reloc::relocate_elf_rela();
46             RELOC_STATE.store(DONE, Ordering::Release);
47         },
48         // We need to wait until the initialization is done.
49         BUSY => while RELOC_STATE.load(Ordering::Acquire) == BUSY  {
50             ::core::arch::x86_64::_mm_pause()
51         },
52         // Initialization is done.
53         DONE => {},
54         _ => unreachable!()
55     }
56 }
57
58 // FIXME: this item should only exist if this is linked into an executable
59 // (main function exists). If this is a library, the crate author should be
60 // able to specify this
61 #[no_mangle]
62 #[allow(unreachable_code)]
63 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
64     // FIXME: how to support TLS in library mode?
65     let tls = Box::new(tls::Tls::new());
66     let _tls_guard = unsafe { tls.activate() };
67
68     if secondary {
69         unimplemented!("thread entrypoint");
70
71         (0, 0)
72     } else {
73         extern "C" {
74             fn main(argc: isize, argv: *const *const u8) -> isize;
75         }
76
77         // check entry is being called according to ABI
78         assert_eq!(p3, 0);
79         assert_eq!(p4, 0);
80         assert_eq!(p5, 0);
81
82         unsafe {
83             // The actual types of these arguments are `p1: *const Arg, p2:
84             // usize`. We can't currently customize the argument list of Rust's
85             // main function, so we pass these in as the standard pointer-sized
86             // values in `argc` and `argv`.
87             let ret = main(p2 as _, p1 as _);
88             exit_with_code(ret)
89         }
90     }
91 }
92
93 pub(super) fn exit_with_code(code: isize) -> ! {
94     if code != 0 {
95         if let Some(mut out) = panic::SgxPanicOutput::new() {
96             let _ = write!(out, "Exited with status code {}", code);
97         }
98     }
99     unsafe { usercalls::raw::exit(code != 0) };
100 }