1use core::{
2 ptr,
3 sync::atomic::{AtomicU32, Ordering},
4};
5
6use crate::{syscall, Errno, Sysno};
7
8const FUTEX_WAIT_BITSET: i32 = 9;
9const FUTEX_WAKE: i32 = 1;
10const FUTEX_PRIVATE_FLAG: i32 = 128;
11
12const INITIAL: u32 = 0x0;
13const RUNNING: u32 = 0x1;
14const COMPLETE: u32 = 0x2;
15const PANICKED: u32 = 0xffff_ffff;
16
17static mut LOCK: AtomicU32 = AtomicU32::new(INITIAL);
18
19unsafe fn real_init(env: *const ()) {
20 crate::env::aux::init(env);
21 #[cfg(target_arch = "powerpc64")]
22 crate::arch::init();
23 crate::env::kernel::init();
24 crate::env::vdso::init();
25 #[cfg(not(target_arch = "powerpc64"))]
26 crate::arch::init();
27}
28
29unsafe fn aux_from_environ(env: *const *const u8) -> *const () {
30 let mut p = env;
31 while !(*p).is_null() {
32 p = p.add(1);
33 }
34 p.add(1) as *mut ()
35}
36
37#[cfg(any(doc, not(feature = "bare")))]
38unsafe fn aux_ptr() -> *const () {
39 extern "C" {
40 #[cfg(any(target_env = "gnu", target_env = "musl"))]
41 static __environ: *const *const u8;
42 #[cfg(not(any(target_env = "gnu", target_env = "musl")))]
43 static environ: *const *const u8;
44 }
45 #[cfg(not(any(target_env = "gnu", target_env = "musl")))]
46 let env = environ;
47 #[cfg(any(target_env = "gnu", target_env = "musl"))]
48 let env = __environ;
49 aux_from_environ(env)
50}
51
52#[cfg(any(doc, not(feature = "bare")))]
55#[cfg_attr(docs_rs, doc(cfg(not(feature = "bare"))))]
56pub fn init() {
57 unsafe { inner_init(aux_ptr()) }
58}
59
60#[cfg(any(doc, feature = "bare"))]
61#[cfg_attr(docs_rs, doc(cfg(feature = "bare")))]
68#[allow(clippy::not_unsafe_ptr_arg_deref)]
69pub unsafe fn init_from_environ(env: *const *const u8) {
70 inner_init(aux_from_environ(env))
71}
72
73#[cfg(any(doc, feature = "bare"))]
74#[allow(clippy::not_unsafe_ptr_arg_deref)]
81#[cfg_attr(docs_rs, doc(cfg(feature = "bare")))]
82pub unsafe fn init_from_args(argc: usize, argv: *const *const u8) {
83 inner_init(aux_from_environ(argv.add(argc)))
84}
85
86#[cfg(any(doc, feature = "bare"))]
87#[cfg_attr(docs_rs, doc(cfg(feature = "bare")))]
94pub unsafe fn init_from_auxv(auxv: *const core::ffi::c_void) {
95 inner_init(auxv.cast())
96}
97
98unsafe fn inner_init(auxv: *const ()) {
99 loop {
100 match LOCK.compare_exchange_weak(INITIAL, RUNNING, Ordering::Acquire, Ordering::Relaxed) {
101 Ok(_) => {
102 let _guard = Guard;
103 real_init(auxv);
104 LOCK.store(COMPLETE, Ordering::Release);
105 syscall!(
106 Sysno::futex,
107 ptr::addr_of!(LOCK),
108 FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
109 0x7fffffff,
110 )
111 .unwrap();
112 break;
113 }
114 Err(x) if x == RUNNING => loop {
115 let res = syscall!(
116 Sysno::futex,
117 ptr::addr_of!(LOCK),
118 FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG,
119 x,
120 core::ptr::null::<u8>(),
121 core::ptr::null::<u32>(),
122 !0u32,
123 );
124 if res != Err(Errno::EINTR) {
125 break;
126 }
127 },
128 Err(x) if x == PANICKED => panic!("syscall locker has been poisoned"),
129 Err(_) => break,
130 }
131 }
132}
133
134struct Guard;
135
136impl Drop for Guard {
137 fn drop(&mut self) {
138 unsafe {
139 if LOCK.load(Ordering::Relaxed) == RUNNING {
140 LOCK.store(PANICKED, Ordering::Relaxed);
141 }
142 }
143 }
144}