summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/linux_raw/param/init.rs
blob: 46aae009a097308953ecd5fd60aad26caaf6d62f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Linux auxv `init` function, for "use-explicitly-provided-auxv" mode.
//!
//! # Safety
//!
//! This uses raw pointers to locate and read the kernel-provided auxv array.
#![allow(unsafe_code)]

use crate::backend::c;
#[cfg(feature = "param")]
use crate::ffi::CStr;
use core::ffi::c_void;
use core::ptr::{null_mut, read, NonNull};
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use linux_raw_sys::elf::*;
use linux_raw_sys::general::{
    AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
};
#[cfg(feature = "runtime")]
use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM};

#[cfg(feature = "param")]
#[inline]
pub(crate) fn page_size() -> usize {
    unsafe { PAGE_SIZE.load(Ordering::Relaxed) }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn clock_ticks_per_second() -> u64 {
    unsafe { CLOCK_TICKS_PER_SECOND.load(Ordering::Relaxed) as u64 }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn linux_hwcap() -> (usize, usize) {
    unsafe {
        (
            HWCAP.load(Ordering::Relaxed),
            HWCAP2.load(Ordering::Relaxed),
        )
    }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn linux_execfn() -> &'static CStr {
    let execfn = unsafe { EXECFN.load(Ordering::Relaxed) };

    // SAFETY: We initialize `EXECFN` to a valid `CStr` pointer, and we assume
    // the `AT_EXECFN` value provided by the kernel points to a valid C string.
    unsafe { CStr::from_ptr(execfn.cast()) }
}

#[cfg(feature = "runtime")]
#[inline]
pub(crate) fn exe_phdrs() -> (*const c_void, usize, usize) {
    unsafe {
        (
            PHDR.load(Ordering::Relaxed).cast(),
            PHENT.load(Ordering::Relaxed),
            PHNUM.load(Ordering::Relaxed),
        )
    }
}

/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, so
/// if we don't see it, this function returns a null pointer.
#[inline]
pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
    unsafe { SYSINFO_EHDR.load(Ordering::Relaxed) }
}

#[cfg(feature = "runtime")]
#[inline]
pub(crate) fn entry() -> usize {
    unsafe { ENTRY.load(Ordering::Relaxed) }
}

static mut PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
static mut CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
static mut HWCAP: AtomicUsize = AtomicUsize::new(0);
static mut HWCAP2: AtomicUsize = AtomicUsize::new(0);
static mut SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
// Initialize `EXECFN` to a valid `CStr` pointer so that we don't need to check
// for null on every `execfn` call.
static mut EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(b"\0".as_ptr() as _);
// Use `dangling` so that we can always treat it like an empty slice.
#[cfg(feature = "runtime")]
static mut PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(NonNull::dangling().as_ptr());
#[cfg(feature = "runtime")]
static mut PHENT: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "runtime")]
static mut PHNUM: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "runtime")]
static mut ENTRY: AtomicUsize = AtomicUsize::new(0);

/// When "use-explicitly-provided-auxv" is enabled, we export a function to be
/// called during initialization, and passed a pointer to the original
/// environment variable block set up by the OS.
pub(crate) unsafe fn init(envp: *mut *mut u8) {
    init_from_envp(envp);
}

/// # Safety
///
/// This must be passed a pointer to the environment variable buffer
/// provided by the kernel, which is followed in memory by the auxv array.
unsafe fn init_from_envp(mut envp: *mut *mut u8) {
    while !(*envp).is_null() {
        envp = envp.add(1);
    }
    init_from_auxp(envp.add(1).cast())
}

/// Process auxv entries from the auxv array pointed to by `auxp`.
///
/// # Safety
///
/// This must be passed a pointer to an auxv array.
///
/// The buffer contains `Elf_aux_t` elements, though it need not be aligned;
/// function uses `read_unaligned` to read from it.
unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
    loop {
        let Elf_auxv_t { a_type, a_val } = read(auxp);

        match a_type as _ {
            AT_PAGESZ => PAGE_SIZE.store(a_val as usize, Ordering::Relaxed),
            AT_CLKTCK => CLOCK_TICKS_PER_SECOND.store(a_val as usize, Ordering::Relaxed),
            AT_HWCAP => HWCAP.store(a_val as usize, Ordering::Relaxed),
            AT_HWCAP2 => HWCAP2.store(a_val as usize, Ordering::Relaxed),
            AT_EXECFN => EXECFN.store(a_val.cast::<c::c_char>(), Ordering::Relaxed),
            AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::<Elf_Ehdr>(), Ordering::Relaxed),

            #[cfg(feature = "runtime")]
            AT_PHDR => PHDR.store(a_val.cast::<Elf_Phdr>(), Ordering::Relaxed),
            #[cfg(feature = "runtime")]
            AT_PHNUM => PHNUM.store(a_val as usize, Ordering::Relaxed),
            #[cfg(feature = "runtime")]
            AT_PHENT => PHENT.store(a_val as usize, Ordering::Relaxed),
            #[cfg(feature = "runtime")]
            AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed),

            AT_NULL => break,
            _ => (),
        }
        auxp = auxp.add(1);
    }
}