summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs
blob: f45a25fafa608867ae2aa03194e1d52aa3cb1b67 (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
150
151
152
153
154
155
156
157
158
159
//! Linux auxv support, for Mustang.
//!
//! # Safety
//!
//! This uses raw pointers to locate and read the kernel-provided auxv array.
#![allow(unsafe_code)]

use crate::backend::c;
use crate::backend::elf::*;
#[cfg(feature = "param")]
use crate::ffi::CStr;
use core::ffi::c_void;
use core::mem::size_of;
use core::ptr::{null, read};
#[cfg(feature = "runtime")]
use core::slice;
use linux_raw_sys::general::{
    AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM,
    AT_SYSINFO_EHDR,
};

#[cfg(feature = "param")]
#[inline]
pub(crate) fn page_size() -> usize {
    // SAFETY: This is initialized during program startup.
    unsafe { PAGE_SIZE }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn clock_ticks_per_second() -> u64 {
    // SAFETY: This is initialized during program startup.
    unsafe { CLOCK_TICKS_PER_SECOND as u64 }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn linux_hwcap() -> (usize, usize) {
    // SAFETY: This is initialized during program startup.
    unsafe { (HWCAP, HWCAP2) }
}

#[cfg(feature = "param")]
#[inline]
pub(crate) fn linux_execfn() -> &'static CStr {
    // SAFETY: This is initialized during program startup. And we
    // assume it's a valid pointer to a NUL-terminated string.
    unsafe { CStr::from_ptr(EXECFN.0.cast()) }
}

#[cfg(feature = "runtime")]
#[inline]
pub(crate) fn exe_phdrs() -> (*const c_void, usize) {
    // SAFETY: This is initialized during program startup.
    unsafe { (PHDR.0.cast(), PHNUM) }
}

#[cfg(feature = "runtime")]
#[inline]
pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] {
    let (phdr, phnum) = exe_phdrs();

    // SAFETY: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the
    // kernel form a valid slice.
    unsafe { slice::from_raw_parts(phdr.cast(), phnum) }
}

/// `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 {
    // SAFETY: This is initialized during program startup.
    unsafe { SYSINFO_EHDR.0 }
}

/// A const pointer to `T` that implements [`Sync`].
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SyncConstPtr<T>(*const T);
unsafe impl<T> Sync for SyncConstPtr<T> {}

impl<T> SyncConstPtr<T> {
    /// Creates a `SyncConstPointer` from a raw pointer.
    ///
    /// Behavior is undefined if `ptr` is actually not
    /// safe to share across threads.
    pub const unsafe fn new(ptr: *const T) -> Self {
        Self(ptr)
    }
}

static mut PAGE_SIZE: usize = 0;
static mut CLOCK_TICKS_PER_SECOND: usize = 0;
static mut HWCAP: usize = 0;
static mut HWCAP2: usize = 0;
static mut SYSINFO_EHDR: SyncConstPtr<Elf_Ehdr> = unsafe { SyncConstPtr::new(null()) };
static mut PHDR: SyncConstPtr<Elf_Phdr> = unsafe { SyncConstPtr::new(null()) };
static mut PHNUM: usize = 0;
static mut EXECFN: SyncConstPtr<c::c_char> = unsafe { SyncConstPtr::new(null()) };

/// On mustang, 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 = a_val as usize,
            AT_CLKTCK => CLOCK_TICKS_PER_SECOND = a_val as usize,
            AT_HWCAP => HWCAP = a_val as usize,
            AT_HWCAP2 => HWCAP2 = a_val as usize,
            AT_PHDR => PHDR = SyncConstPtr::new(a_val.cast::<Elf_Phdr>()),
            AT_PHNUM => PHNUM = a_val as usize,
            AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()),
            AT_EXECFN => EXECFN = SyncConstPtr::new(a_val.cast::<c::c_char>()),
            AT_SYSINFO_EHDR => SYSINFO_EHDR = SyncConstPtr::new(a_val.cast::<Elf_Ehdr>()),
            AT_NULL => break,
            _ => (),
        }
        auxp = auxp.add(1);
    }
}

// ELF ABI

#[repr(C)]
#[derive(Copy, Clone)]
struct Elf_auxv_t {
    a_type: usize,

    // Some of the values in the auxv array are pointers, so we make `a_val` a
    // pointer, in order to preserve their provenance. For the values which are
    // integers, we cast this to `usize`.
    a_val: *const c_void,
}