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