linux_syscalls/
init.rs

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/// Initialize the environment for the library.
53/// It's recommended to call it before anything else in the main function.
54#[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/// Initialize library from the environment list pointer (`char **envp`).
62/// It's recommended to call it before anything else in the main function.
63///
64/// # Safety
65///
66/// Dealing with pointers is unsafe by definition.
67#[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/// Initialize library from arguments count and arguments list (`int argc, char **argv`).
75/// It's recommended to call it before anything else in the main function.
76///
77/// # Safety
78///
79/// Dealing with pointers is unsafe by definition.
80#[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/// Initialize library from auxv pointer.
88/// It's recommended to call it before anything else in the main function.
89///
90/// # Safety
91///
92/// Dealing with pointers is unsafe by definition.
93#[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}