]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | #![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test |
2 | ||
532ac7d7 | 3 | use crate::io::Write; |
60c5eb7d | 4 | use core::sync::atomic::{AtomicUsize, Ordering}; |
0731742a XL |
5 | |
6 | // runtime features | |
0731742a | 7 | pub(super) mod panic; |
60c5eb7d | 8 | mod reloc; |
0731742a XL |
9 | |
10 | // library features | |
11 | pub mod mem; | |
12 | pub mod thread; | |
13 | pub mod tls; | |
14 | #[macro_use] | |
15 | pub mod usercalls; | |
16 | ||
532ac7d7 | 17 | #[cfg(not(test))] |
9fa01778 | 18 | global_asm!(include_str!("entry.S")); |
0731742a | 19 | |
3dfed10e XL |
20 | #[repr(C)] |
21 | struct EntryReturn(u64, u64); | |
22 | ||
532ac7d7 | 23 | #[cfg(not(test))] |
0731742a XL |
24 | #[no_mangle] |
25 | unsafe extern "C" fn tcs_init(secondary: bool) { | |
26 | // Be very careful when changing this code: it runs before the binary has been | |
27 | // relocated. Any indirect accesses to symbols will likely fail. | |
28 | const UNINIT: usize = 0; | |
29 | const BUSY: usize = 1; | |
30 | const DONE: usize = 2; | |
31 | // Three-state spin-lock | |
32 | static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT); | |
33 | ||
34 | if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE { | |
48663c56 | 35 | rtabort!("Entered secondary TCS before main TCS!") |
0731742a XL |
36 | } |
37 | ||
38 | // Try to atomically swap UNINIT with BUSY. The returned state can be: | |
39 | match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) { | |
40 | // This thread just obtained the lock and other threads will observe BUSY | |
41 | UNINIT => { | |
42 | reloc::relocate_elf_rela(); | |
43 | RELOC_STATE.store(DONE, Ordering::Release); | |
60c5eb7d | 44 | } |
0731742a | 45 | // We need to wait until the initialization is done. |
60c5eb7d XL |
46 | BUSY => { |
47 | while RELOC_STATE.load(Ordering::Acquire) == BUSY { | |
29967ef6 | 48 | core::hint::spin_loop(); |
60c5eb7d XL |
49 | } |
50 | } | |
0731742a | 51 | // Initialization is done. |
60c5eb7d XL |
52 | DONE => {} |
53 | _ => unreachable!(), | |
0731742a XL |
54 | } |
55 | } | |
56 | ||
57 | // FIXME: this item should only exist if this is linked into an executable | |
58 | // (main function exists). If this is a library, the crate author should be | |
59 | // able to specify this | |
532ac7d7 | 60 | #[cfg(not(test))] |
0731742a | 61 | #[no_mangle] |
3dfed10e | 62 | extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn { |
0731742a XL |
63 | // FIXME: how to support TLS in library mode? |
64 | let tls = Box::new(tls::Tls::new()); | |
65 | let _tls_guard = unsafe { tls.activate() }; | |
66 | ||
67 | if secondary { | |
68 | super::thread::Thread::entry(); | |
69 | ||
3dfed10e | 70 | EntryReturn(0, 0) |
0731742a XL |
71 | } else { |
72 | extern "C" { | |
73 | fn main(argc: isize, argv: *const *const u8) -> isize; | |
74 | } | |
75 | ||
76 | // check entry is being called according to ABI | |
532ac7d7 XL |
77 | rtassert!(p3 == 0); |
78 | rtassert!(p4 == 0); | |
79 | rtassert!(p5 == 0); | |
0731742a XL |
80 | |
81 | unsafe { | |
82 | // The actual types of these arguments are `p1: *const Arg, p2: | |
83 | // usize`. We can't currently customize the argument list of Rust's | |
84 | // main function, so we pass these in as the standard pointer-sized | |
85 | // values in `argc` and `argv`. | |
86 | let ret = main(p2 as _, p1 as _); | |
87 | exit_with_code(ret) | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
92 | pub(super) fn exit_with_code(code: isize) -> ! { | |
93 | if code != 0 { | |
94 | if let Some(mut out) = panic::SgxPanicOutput::new() { | |
95 | let _ = write!(out, "Exited with status code {}", code); | |
96 | } | |
97 | } | |
98 | usercalls::exit(code != 0); | |
99 | } | |
48663c56 XL |
100 | |
101 | #[cfg(not(test))] | |
102 | #[no_mangle] | |
103 | extern "C" fn abort_reentry() -> ! { | |
104 | usercalls::exit(false) | |
105 | } |