1b8a62b91Sopenharmony_ci//! Bindings for the Linux `prctl` system call.
2b8a62b91Sopenharmony_ci//!
3b8a62b91Sopenharmony_ci//! There are similarities (but also differences) with FreeBSD's `procctl` system call, whose
4b8a62b91Sopenharmony_ci//! interface is located in the `procctl.rs` file.
5b8a62b91Sopenharmony_ci
6b8a62b91Sopenharmony_ci#![allow(unsafe_code)]
7b8a62b91Sopenharmony_ci
8b8a62b91Sopenharmony_ciuse core::convert::{TryFrom, TryInto};
9b8a62b91Sopenharmony_ciuse core::mem::MaybeUninit;
10b8a62b91Sopenharmony_ciuse core::ptr::NonNull;
11b8a62b91Sopenharmony_ciuse core::{mem, ptr};
12b8a62b91Sopenharmony_ci
13b8a62b91Sopenharmony_ciuse bitflags::bitflags;
14b8a62b91Sopenharmony_ci
15b8a62b91Sopenharmony_ciuse crate::backend::c::{c_int, c_uint, c_void};
16b8a62b91Sopenharmony_ciuse crate::backend::process::syscalls;
17b8a62b91Sopenharmony_ciuse crate::backend::process::types::Signal;
18b8a62b91Sopenharmony_ciuse crate::fd::{AsRawFd, BorrowedFd};
19b8a62b91Sopenharmony_ciuse crate::ffi::CStr;
20b8a62b91Sopenharmony_ciuse crate::io;
21b8a62b91Sopenharmony_ciuse crate::process::{Pid, RawPid};
22b8a62b91Sopenharmony_ci
23b8a62b91Sopenharmony_ci//
24b8a62b91Sopenharmony_ci// Helper functions.
25b8a62b91Sopenharmony_ci//
26b8a62b91Sopenharmony_ci
27b8a62b91Sopenharmony_ci#[inline]
28b8a62b91Sopenharmony_cipub(crate) unsafe fn prctl_1arg(option: c_int) -> io::Result<c_int> {
29b8a62b91Sopenharmony_ci    const NULL: *mut c_void = ptr::null_mut();
30b8a62b91Sopenharmony_ci    syscalls::prctl(option, NULL, NULL, NULL, NULL)
31b8a62b91Sopenharmony_ci}
32b8a62b91Sopenharmony_ci
33b8a62b91Sopenharmony_ci#[inline]
34b8a62b91Sopenharmony_cipub(crate) unsafe fn prctl_2args(option: c_int, arg2: *mut c_void) -> io::Result<c_int> {
35b8a62b91Sopenharmony_ci    const NULL: *mut c_void = ptr::null_mut();
36b8a62b91Sopenharmony_ci    syscalls::prctl(option, arg2, NULL, NULL, NULL)
37b8a62b91Sopenharmony_ci}
38b8a62b91Sopenharmony_ci
39b8a62b91Sopenharmony_ci#[inline]
40b8a62b91Sopenharmony_cipub(crate) unsafe fn prctl_3args(
41b8a62b91Sopenharmony_ci    option: c_int,
42b8a62b91Sopenharmony_ci    arg2: *mut c_void,
43b8a62b91Sopenharmony_ci    arg3: *mut c_void,
44b8a62b91Sopenharmony_ci) -> io::Result<c_int> {
45b8a62b91Sopenharmony_ci    syscalls::prctl(option, arg2, arg3, ptr::null_mut(), ptr::null_mut())
46b8a62b91Sopenharmony_ci}
47b8a62b91Sopenharmony_ci
48b8a62b91Sopenharmony_ci#[inline]
49b8a62b91Sopenharmony_cipub(crate) unsafe fn prctl_get_at_arg2_optional<P>(option: i32) -> io::Result<P> {
50b8a62b91Sopenharmony_ci    let mut value: MaybeUninit<P> = MaybeUninit::uninit();
51b8a62b91Sopenharmony_ci    prctl_2args(option, value.as_mut_ptr().cast())?;
52b8a62b91Sopenharmony_ci    Ok(value.assume_init())
53b8a62b91Sopenharmony_ci}
54b8a62b91Sopenharmony_ci
55b8a62b91Sopenharmony_ci#[inline]
56b8a62b91Sopenharmony_cipub(crate) unsafe fn prctl_get_at_arg2<P, T>(option: i32) -> io::Result<T>
57b8a62b91Sopenharmony_ciwhere
58b8a62b91Sopenharmony_ci    P: Default,
59b8a62b91Sopenharmony_ci    T: TryFrom<P, Error = io::Errno>,
60b8a62b91Sopenharmony_ci{
61b8a62b91Sopenharmony_ci    let mut value: P = Default::default();
62b8a62b91Sopenharmony_ci    prctl_2args(option, ((&mut value) as *mut P).cast())?;
63b8a62b91Sopenharmony_ci    TryFrom::try_from(value)
64b8a62b91Sopenharmony_ci}
65b8a62b91Sopenharmony_ci
66b8a62b91Sopenharmony_ci//
67b8a62b91Sopenharmony_ci// PR_GET_PDEATHSIG/PR_SET_PDEATHSIG
68b8a62b91Sopenharmony_ci//
69b8a62b91Sopenharmony_ci
70b8a62b91Sopenharmony_ciconst PR_GET_PDEATHSIG: c_int = 2;
71b8a62b91Sopenharmony_ci
72b8a62b91Sopenharmony_ci/// Get the current value of the parent process death signal.
73b8a62b91Sopenharmony_ci///
74b8a62b91Sopenharmony_ci/// # References
75b8a62b91Sopenharmony_ci/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`]
76b8a62b91Sopenharmony_ci/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]
77b8a62b91Sopenharmony_ci///
78b8a62b91Sopenharmony_ci/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
79b8a62b91Sopenharmony_ci/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
80b8a62b91Sopenharmony_ci#[inline]
81b8a62b91Sopenharmony_cipub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
82b8a62b91Sopenharmony_ci    unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG) }.map(Signal::from_raw)
83b8a62b91Sopenharmony_ci}
84b8a62b91Sopenharmony_ci
85b8a62b91Sopenharmony_ciconst PR_SET_PDEATHSIG: c_int = 1;
86b8a62b91Sopenharmony_ci
87b8a62b91Sopenharmony_ci/// Set the parent-death signal of the calling process.
88b8a62b91Sopenharmony_ci///
89b8a62b91Sopenharmony_ci/// # References
90b8a62b91Sopenharmony_ci/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`]
91b8a62b91Sopenharmony_ci/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]
92b8a62b91Sopenharmony_ci///
93b8a62b91Sopenharmony_ci/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
94b8a62b91Sopenharmony_ci/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
95b8a62b91Sopenharmony_ci#[inline]
96b8a62b91Sopenharmony_cipub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
97b8a62b91Sopenharmony_ci    let signal = signal.map_or(0_usize, |signal| signal as usize);
98b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ())
99b8a62b91Sopenharmony_ci}
100b8a62b91Sopenharmony_ci
101b8a62b91Sopenharmony_ci//
102b8a62b91Sopenharmony_ci// PR_GET_DUMPABLE/PR_SET_DUMPABLE
103b8a62b91Sopenharmony_ci//
104b8a62b91Sopenharmony_ci
105b8a62b91Sopenharmony_ciconst PR_GET_DUMPABLE: c_int = 3;
106b8a62b91Sopenharmony_ci
107b8a62b91Sopenharmony_ciconst SUID_DUMP_DISABLE: i32 = 0;
108b8a62b91Sopenharmony_ciconst SUID_DUMP_USER: i32 = 1;
109b8a62b91Sopenharmony_ciconst SUID_DUMP_ROOT: i32 = 2;
110b8a62b91Sopenharmony_ci
111b8a62b91Sopenharmony_ci/// `SUID_DUMP_*`.
112b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113b8a62b91Sopenharmony_ci#[repr(i32)]
114b8a62b91Sopenharmony_cipub enum DumpableBehavior {
115b8a62b91Sopenharmony_ci    /// Not dumpable.
116b8a62b91Sopenharmony_ci    NotDumpable = SUID_DUMP_DISABLE,
117b8a62b91Sopenharmony_ci    /// Dumpable.
118b8a62b91Sopenharmony_ci    Dumpable = SUID_DUMP_USER,
119b8a62b91Sopenharmony_ci    /// Dumpable but only readable by root.
120b8a62b91Sopenharmony_ci    DumpableReadableOnlyByRoot = SUID_DUMP_ROOT,
121b8a62b91Sopenharmony_ci}
122b8a62b91Sopenharmony_ci
123b8a62b91Sopenharmony_ciimpl TryFrom<i32> for DumpableBehavior {
124b8a62b91Sopenharmony_ci    type Error = io::Errno;
125b8a62b91Sopenharmony_ci
126b8a62b91Sopenharmony_ci    fn try_from(value: i32) -> Result<Self, Self::Error> {
127b8a62b91Sopenharmony_ci        match value {
128b8a62b91Sopenharmony_ci            SUID_DUMP_DISABLE => Ok(Self::NotDumpable),
129b8a62b91Sopenharmony_ci            SUID_DUMP_USER => Ok(Self::Dumpable),
130b8a62b91Sopenharmony_ci            SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot),
131b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
132b8a62b91Sopenharmony_ci        }
133b8a62b91Sopenharmony_ci    }
134b8a62b91Sopenharmony_ci}
135b8a62b91Sopenharmony_ci
136b8a62b91Sopenharmony_ci/// Get the current state of the calling process's `dumpable` attribute.
137b8a62b91Sopenharmony_ci///
138b8a62b91Sopenharmony_ci/// # References
139b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_DUMPABLE,...)`]
140b8a62b91Sopenharmony_ci///
141b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
142b8a62b91Sopenharmony_ci#[inline]
143b8a62b91Sopenharmony_cipub fn dumpable_behavior() -> io::Result<DumpableBehavior> {
144b8a62b91Sopenharmony_ci    unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into)
145b8a62b91Sopenharmony_ci}
146b8a62b91Sopenharmony_ci
147b8a62b91Sopenharmony_ciconst PR_SET_DUMPABLE: c_int = 4;
148b8a62b91Sopenharmony_ci
149b8a62b91Sopenharmony_ci/// Set the state of the `dumpable` attribute, which determines whether the process can be traced
150b8a62b91Sopenharmony_ci/// and whether core dumps are produced for the calling process upon delivery of a signal whose
151b8a62b91Sopenharmony_ci/// default behavior is to produce a core dump.
152b8a62b91Sopenharmony_ci///
153b8a62b91Sopenharmony_ci/// A similar function with the same name is available on FreeBSD (as part of the `procctl`
154b8a62b91Sopenharmony_ci/// interface), but it has an extra argument which allows to select a process other then the
155b8a62b91Sopenharmony_ci/// current process.
156b8a62b91Sopenharmony_ci///
157b8a62b91Sopenharmony_ci/// # References
158b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_DUMPABLE,...)`]
159b8a62b91Sopenharmony_ci///
160b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
161b8a62b91Sopenharmony_ci#[inline]
162b8a62b91Sopenharmony_cipub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> {
163b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ())
164b8a62b91Sopenharmony_ci}
165b8a62b91Sopenharmony_ci
166b8a62b91Sopenharmony_ci//
167b8a62b91Sopenharmony_ci// PR_GET_UNALIGN/PR_SET_UNALIGN
168b8a62b91Sopenharmony_ci//
169b8a62b91Sopenharmony_ci
170b8a62b91Sopenharmony_ciconst PR_GET_UNALIGN: c_int = 5;
171b8a62b91Sopenharmony_ci
172b8a62b91Sopenharmony_cibitflags! {
173b8a62b91Sopenharmony_ci    /// `PR_UNALIGN_*`.
174b8a62b91Sopenharmony_ci    pub struct UnalignedAccessControl: u32 {
175b8a62b91Sopenharmony_ci        /// Silently fix up unaligned user accesses.
176b8a62b91Sopenharmony_ci        const NO_PRINT = 1;
177b8a62b91Sopenharmony_ci        /// Generate `SIGBUS` on unaligned user access.
178b8a62b91Sopenharmony_ci        const SIGBUS = 2;
179b8a62b91Sopenharmony_ci    }
180b8a62b91Sopenharmony_ci}
181b8a62b91Sopenharmony_ci
182b8a62b91Sopenharmony_ci/// Get unaligned access control bits.
183b8a62b91Sopenharmony_ci///
184b8a62b91Sopenharmony_ci/// # References
185b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_UNALIGN,...)`]
186b8a62b91Sopenharmony_ci///
187b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
188b8a62b91Sopenharmony_ci#[inline]
189b8a62b91Sopenharmony_cipub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> {
190b8a62b91Sopenharmony_ci    let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? };
191b8a62b91Sopenharmony_ci    UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE)
192b8a62b91Sopenharmony_ci}
193b8a62b91Sopenharmony_ci
194b8a62b91Sopenharmony_ciconst PR_SET_UNALIGN: c_int = 6;
195b8a62b91Sopenharmony_ci
196b8a62b91Sopenharmony_ci/// Set unaligned access control bits.
197b8a62b91Sopenharmony_ci///
198b8a62b91Sopenharmony_ci/// # References
199b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_UNALIGN,...)`]
200b8a62b91Sopenharmony_ci///
201b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
202b8a62b91Sopenharmony_ci#[inline]
203b8a62b91Sopenharmony_cipub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> {
204b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ())
205b8a62b91Sopenharmony_ci}
206b8a62b91Sopenharmony_ci
207b8a62b91Sopenharmony_ci//
208b8a62b91Sopenharmony_ci// PR_GET_FPEMU/PR_SET_FPEMU
209b8a62b91Sopenharmony_ci//
210b8a62b91Sopenharmony_ci
211b8a62b91Sopenharmony_ciconst PR_GET_FPEMU: c_int = 9;
212b8a62b91Sopenharmony_ci
213b8a62b91Sopenharmony_cibitflags! {
214b8a62b91Sopenharmony_ci    /// `PR_FPEMU_*`.
215b8a62b91Sopenharmony_ci    pub struct FloatingPointEmulationControl: u32 {
216b8a62b91Sopenharmony_ci        /// Silently emulate floating point operations accesses.
217b8a62b91Sopenharmony_ci        const NO_PRINT = 1;
218b8a62b91Sopenharmony_ci        /// Don't emulate floating point operations, send `SIGFPE` instead.
219b8a62b91Sopenharmony_ci        const SIGFPE = 2;
220b8a62b91Sopenharmony_ci    }
221b8a62b91Sopenharmony_ci}
222b8a62b91Sopenharmony_ci
223b8a62b91Sopenharmony_ci/// Get floating point emulation control bits.
224b8a62b91Sopenharmony_ci///
225b8a62b91Sopenharmony_ci/// # References
226b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_FPEMU,...)`]
227b8a62b91Sopenharmony_ci///
228b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
229b8a62b91Sopenharmony_ci#[inline]
230b8a62b91Sopenharmony_cipub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> {
231b8a62b91Sopenharmony_ci    let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? };
232b8a62b91Sopenharmony_ci    FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE)
233b8a62b91Sopenharmony_ci}
234b8a62b91Sopenharmony_ci
235b8a62b91Sopenharmony_ciconst PR_SET_FPEMU: c_int = 10;
236b8a62b91Sopenharmony_ci
237b8a62b91Sopenharmony_ci/// Set floating point emulation control bits.
238b8a62b91Sopenharmony_ci///
239b8a62b91Sopenharmony_ci/// # References
240b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_FPEMU,...)`]
241b8a62b91Sopenharmony_ci///
242b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
243b8a62b91Sopenharmony_ci#[inline]
244b8a62b91Sopenharmony_cipub fn set_floating_point_emulation_control(
245b8a62b91Sopenharmony_ci    config: FloatingPointEmulationControl,
246b8a62b91Sopenharmony_ci) -> io::Result<()> {
247b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ())
248b8a62b91Sopenharmony_ci}
249b8a62b91Sopenharmony_ci
250b8a62b91Sopenharmony_ci//
251b8a62b91Sopenharmony_ci// PR_GET_FPEXC/PR_SET_FPEXC
252b8a62b91Sopenharmony_ci//
253b8a62b91Sopenharmony_ci
254b8a62b91Sopenharmony_ciconst PR_GET_FPEXC: c_int = 11;
255b8a62b91Sopenharmony_ci
256b8a62b91Sopenharmony_cibitflags! {
257b8a62b91Sopenharmony_ci    /// Zero means floating point exceptions are disabled.
258b8a62b91Sopenharmony_ci    pub struct FloatingPointExceptionMode: u32 {
259b8a62b91Sopenharmony_ci        /// Async non-recoverable exception mode.
260b8a62b91Sopenharmony_ci        const NONRECOV = 1;
261b8a62b91Sopenharmony_ci        /// Async recoverable exception mode.
262b8a62b91Sopenharmony_ci        const ASYNC = 2;
263b8a62b91Sopenharmony_ci        /// Precise exception mode.
264b8a62b91Sopenharmony_ci        const PRECISE = 3;
265b8a62b91Sopenharmony_ci
266b8a62b91Sopenharmony_ci        /// Use FPEXC for floating point exception enables.
267b8a62b91Sopenharmony_ci        const SW_ENABLE = 0x80;
268b8a62b91Sopenharmony_ci        /// Floating point divide by zero.
269b8a62b91Sopenharmony_ci        const DIV = 0x01_0000;
270b8a62b91Sopenharmony_ci        /// Floating point overflow.
271b8a62b91Sopenharmony_ci        const OVF = 0x02_0000;
272b8a62b91Sopenharmony_ci        /// Floating point underflow.
273b8a62b91Sopenharmony_ci        const UND = 0x04_0000;
274b8a62b91Sopenharmony_ci        /// Floating point inexact result.
275b8a62b91Sopenharmony_ci        const RES = 0x08_0000;
276b8a62b91Sopenharmony_ci        /// Floating point invalid operation.
277b8a62b91Sopenharmony_ci        const INV = 0x10_0000;
278b8a62b91Sopenharmony_ci    }
279b8a62b91Sopenharmony_ci}
280b8a62b91Sopenharmony_ci
281b8a62b91Sopenharmony_ci/// Get floating point exception mode.
282b8a62b91Sopenharmony_ci///
283b8a62b91Sopenharmony_ci/// # References
284b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_FPEXC,...)`]
285b8a62b91Sopenharmony_ci///
286b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
287b8a62b91Sopenharmony_ci#[inline]
288b8a62b91Sopenharmony_cipub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> {
289b8a62b91Sopenharmony_ci    unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) }
290b8a62b91Sopenharmony_ci        .map(FloatingPointExceptionMode::from_bits)
291b8a62b91Sopenharmony_ci}
292b8a62b91Sopenharmony_ci
293b8a62b91Sopenharmony_ciconst PR_SET_FPEXC: c_int = 12;
294b8a62b91Sopenharmony_ci
295b8a62b91Sopenharmony_ci/// Set floating point exception mode.
296b8a62b91Sopenharmony_ci///
297b8a62b91Sopenharmony_ci/// # References
298b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_FPEXC,...)`]
299b8a62b91Sopenharmony_ci///
300b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
301b8a62b91Sopenharmony_ci#[inline]
302b8a62b91Sopenharmony_cipub fn set_floating_point_exception_mode(
303b8a62b91Sopenharmony_ci    config: Option<FloatingPointExceptionMode>,
304b8a62b91Sopenharmony_ci) -> io::Result<()> {
305b8a62b91Sopenharmony_ci    let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits);
306b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ())
307b8a62b91Sopenharmony_ci}
308b8a62b91Sopenharmony_ci
309b8a62b91Sopenharmony_ci//
310b8a62b91Sopenharmony_ci// PR_GET_TIMING/PR_SET_TIMING
311b8a62b91Sopenharmony_ci//
312b8a62b91Sopenharmony_ci
313b8a62b91Sopenharmony_ciconst PR_GET_TIMING: c_int = 13;
314b8a62b91Sopenharmony_ci
315b8a62b91Sopenharmony_ciconst PR_TIMING_STATISTICAL: i32 = 0;
316b8a62b91Sopenharmony_ciconst PR_TIMING_TIMESTAMP: i32 = 1;
317b8a62b91Sopenharmony_ci
318b8a62b91Sopenharmony_ci/// `PR_TIMING_*`.
319b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
320b8a62b91Sopenharmony_ci#[repr(i32)]
321b8a62b91Sopenharmony_cipub enum TimingMethod {
322b8a62b91Sopenharmony_ci    /// Normal, traditional, statistical process timing.
323b8a62b91Sopenharmony_ci    Statistical = PR_TIMING_STATISTICAL,
324b8a62b91Sopenharmony_ci    /// Accurate timestamp based process timing.
325b8a62b91Sopenharmony_ci    TimeStamp = PR_TIMING_TIMESTAMP,
326b8a62b91Sopenharmony_ci}
327b8a62b91Sopenharmony_ci
328b8a62b91Sopenharmony_ciimpl TryFrom<i32> for TimingMethod {
329b8a62b91Sopenharmony_ci    type Error = io::Errno;
330b8a62b91Sopenharmony_ci
331b8a62b91Sopenharmony_ci    fn try_from(value: i32) -> Result<Self, Self::Error> {
332b8a62b91Sopenharmony_ci        match value {
333b8a62b91Sopenharmony_ci            PR_TIMING_STATISTICAL => Ok(Self::Statistical),
334b8a62b91Sopenharmony_ci            PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp),
335b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
336b8a62b91Sopenharmony_ci        }
337b8a62b91Sopenharmony_ci    }
338b8a62b91Sopenharmony_ci}
339b8a62b91Sopenharmony_ci
340b8a62b91Sopenharmony_ci/// Get which process timing method is currently in use.
341b8a62b91Sopenharmony_ci///
342b8a62b91Sopenharmony_ci/// # References
343b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_TIMING,...)`]
344b8a62b91Sopenharmony_ci///
345b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
346b8a62b91Sopenharmony_ci#[inline]
347b8a62b91Sopenharmony_cipub fn timing_method() -> io::Result<TimingMethod> {
348b8a62b91Sopenharmony_ci    unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into)
349b8a62b91Sopenharmony_ci}
350b8a62b91Sopenharmony_ci
351b8a62b91Sopenharmony_ciconst PR_SET_TIMING: c_int = 14;
352b8a62b91Sopenharmony_ci
353b8a62b91Sopenharmony_ci/// Set whether to use (normal, traditional) statistical process timing or accurate
354b8a62b91Sopenharmony_ci/// timestamp-based process timing.
355b8a62b91Sopenharmony_ci///
356b8a62b91Sopenharmony_ci/// # References
357b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_TIMING,...)`]
358b8a62b91Sopenharmony_ci///
359b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
360b8a62b91Sopenharmony_ci#[inline]
361b8a62b91Sopenharmony_cipub fn set_timing_method(method: TimingMethod) -> io::Result<()> {
362b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ())
363b8a62b91Sopenharmony_ci}
364b8a62b91Sopenharmony_ci
365b8a62b91Sopenharmony_ci//
366b8a62b91Sopenharmony_ci// PR_GET_ENDIAN/PR_SET_ENDIAN
367b8a62b91Sopenharmony_ci//
368b8a62b91Sopenharmony_ci
369b8a62b91Sopenharmony_ciconst PR_GET_ENDIAN: c_int = 19;
370b8a62b91Sopenharmony_ci
371b8a62b91Sopenharmony_ciconst PR_ENDIAN_BIG: u32 = 0;
372b8a62b91Sopenharmony_ciconst PR_ENDIAN_LITTLE: u32 = 1;
373b8a62b91Sopenharmony_ciconst PR_ENDIAN_PPC_LITTLE: u32 = 2;
374b8a62b91Sopenharmony_ci
375b8a62b91Sopenharmony_ci/// `PR_ENDIAN_*`.
376b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
377b8a62b91Sopenharmony_ci#[repr(u32)]
378b8a62b91Sopenharmony_cipub enum EndianMode {
379b8a62b91Sopenharmony_ci    /// Big endian mode.
380b8a62b91Sopenharmony_ci    Big = PR_ENDIAN_BIG,
381b8a62b91Sopenharmony_ci    /// True little endian mode.
382b8a62b91Sopenharmony_ci    Little = PR_ENDIAN_LITTLE,
383b8a62b91Sopenharmony_ci    /// `PowerPC` pseudo little endian.
384b8a62b91Sopenharmony_ci    PowerPCLittle = PR_ENDIAN_PPC_LITTLE,
385b8a62b91Sopenharmony_ci}
386b8a62b91Sopenharmony_ci
387b8a62b91Sopenharmony_ciimpl TryFrom<u32> for EndianMode {
388b8a62b91Sopenharmony_ci    type Error = io::Errno;
389b8a62b91Sopenharmony_ci
390b8a62b91Sopenharmony_ci    fn try_from(value: u32) -> Result<Self, Self::Error> {
391b8a62b91Sopenharmony_ci        match value {
392b8a62b91Sopenharmony_ci            PR_ENDIAN_BIG => Ok(Self::Big),
393b8a62b91Sopenharmony_ci            PR_ENDIAN_LITTLE => Ok(Self::Little),
394b8a62b91Sopenharmony_ci            PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle),
395b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
396b8a62b91Sopenharmony_ci        }
397b8a62b91Sopenharmony_ci    }
398b8a62b91Sopenharmony_ci}
399b8a62b91Sopenharmony_ci
400b8a62b91Sopenharmony_ci/// Get the endianness of the calling process.
401b8a62b91Sopenharmony_ci///
402b8a62b91Sopenharmony_ci/// # References
403b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_ENDIAN,...)`]
404b8a62b91Sopenharmony_ci///
405b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
406b8a62b91Sopenharmony_ci#[inline]
407b8a62b91Sopenharmony_cipub fn endian_mode() -> io::Result<EndianMode> {
408b8a62b91Sopenharmony_ci    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) }
409b8a62b91Sopenharmony_ci}
410b8a62b91Sopenharmony_ci
411b8a62b91Sopenharmony_ciconst PR_SET_ENDIAN: c_int = 20;
412b8a62b91Sopenharmony_ci
413b8a62b91Sopenharmony_ci/// Set the endianness of the calling process.
414b8a62b91Sopenharmony_ci///
415b8a62b91Sopenharmony_ci/// # References
416b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_ENDIAN,...)`]
417b8a62b91Sopenharmony_ci///
418b8a62b91Sopenharmony_ci/// # Safety
419b8a62b91Sopenharmony_ci///
420b8a62b91Sopenharmony_ci/// Please ensure the conditions necessary to safely call this function,
421b8a62b91Sopenharmony_ci/// as detailed in the references above.
422b8a62b91Sopenharmony_ci///
423b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
424b8a62b91Sopenharmony_ci#[inline]
425b8a62b91Sopenharmony_cipub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> {
426b8a62b91Sopenharmony_ci    prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ())
427b8a62b91Sopenharmony_ci}
428b8a62b91Sopenharmony_ci
429b8a62b91Sopenharmony_ci//
430b8a62b91Sopenharmony_ci// PR_GET_TSC/PR_SET_TSC
431b8a62b91Sopenharmony_ci//
432b8a62b91Sopenharmony_ci
433b8a62b91Sopenharmony_ciconst PR_GET_TSC: c_int = 25;
434b8a62b91Sopenharmony_ci
435b8a62b91Sopenharmony_ciconst PR_TSC_ENABLE: u32 = 1;
436b8a62b91Sopenharmony_ciconst PR_TSC_SIGSEGV: u32 = 2;
437b8a62b91Sopenharmony_ci
438b8a62b91Sopenharmony_ci/// `PR_TSC_*`.
439b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
440b8a62b91Sopenharmony_ci#[repr(u32)]
441b8a62b91Sopenharmony_cipub enum TimeStampCounterReadability {
442b8a62b91Sopenharmony_ci    /// Allow the use of the timestamp counter.
443b8a62b91Sopenharmony_ci    Readable = PR_TSC_ENABLE,
444b8a62b91Sopenharmony_ci    /// Throw a `SIGSEGV` instead of reading the TSC.
445b8a62b91Sopenharmony_ci    RaiseSIGSEGV = PR_TSC_SIGSEGV,
446b8a62b91Sopenharmony_ci}
447b8a62b91Sopenharmony_ci
448b8a62b91Sopenharmony_ciimpl TryFrom<u32> for TimeStampCounterReadability {
449b8a62b91Sopenharmony_ci    type Error = io::Errno;
450b8a62b91Sopenharmony_ci
451b8a62b91Sopenharmony_ci    fn try_from(value: u32) -> Result<Self, Self::Error> {
452b8a62b91Sopenharmony_ci        match value {
453b8a62b91Sopenharmony_ci            PR_TSC_ENABLE => Ok(Self::Readable),
454b8a62b91Sopenharmony_ci            PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV),
455b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
456b8a62b91Sopenharmony_ci        }
457b8a62b91Sopenharmony_ci    }
458b8a62b91Sopenharmony_ci}
459b8a62b91Sopenharmony_ci
460b8a62b91Sopenharmony_ci/// Get the state of the flag determining if the timestamp counter can be read.
461b8a62b91Sopenharmony_ci///
462b8a62b91Sopenharmony_ci/// # References
463b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_TSC,...)`]
464b8a62b91Sopenharmony_ci///
465b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
466b8a62b91Sopenharmony_ci#[inline]
467b8a62b91Sopenharmony_cipub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> {
468b8a62b91Sopenharmony_ci    unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) }
469b8a62b91Sopenharmony_ci}
470b8a62b91Sopenharmony_ci
471b8a62b91Sopenharmony_ciconst PR_SET_TSC: c_int = 26;
472b8a62b91Sopenharmony_ci
473b8a62b91Sopenharmony_ci/// Set the state of the flag determining if the timestamp counter can be read by the process.
474b8a62b91Sopenharmony_ci///
475b8a62b91Sopenharmony_ci/// # References
476b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_TSC,...)`]
477b8a62b91Sopenharmony_ci///
478b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
479b8a62b91Sopenharmony_ci#[inline]
480b8a62b91Sopenharmony_cipub fn set_time_stamp_counter_readability(
481b8a62b91Sopenharmony_ci    readability: TimeStampCounterReadability,
482b8a62b91Sopenharmony_ci) -> io::Result<()> {
483b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ())
484b8a62b91Sopenharmony_ci}
485b8a62b91Sopenharmony_ci
486b8a62b91Sopenharmony_ci//
487b8a62b91Sopenharmony_ci// PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE
488b8a62b91Sopenharmony_ci//
489b8a62b91Sopenharmony_ci
490b8a62b91Sopenharmony_ciconst PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
491b8a62b91Sopenharmony_ciconst PR_TASK_PERF_EVENTS_ENABLE: c_int = 32;
492b8a62b91Sopenharmony_ci
493b8a62b91Sopenharmony_ci/// Enable or disable all performance counters attached to the calling process.
494b8a62b91Sopenharmony_ci///
495b8a62b91Sopenharmony_ci/// # References
496b8a62b91Sopenharmony_ci/// - [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]
497b8a62b91Sopenharmony_ci/// - [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]
498b8a62b91Sopenharmony_ci///
499b8a62b91Sopenharmony_ci/// [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
500b8a62b91Sopenharmony_ci/// [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
501b8a62b91Sopenharmony_ci#[inline]
502b8a62b91Sopenharmony_cipub fn configure_performance_counters(enable: bool) -> io::Result<()> {
503b8a62b91Sopenharmony_ci    let option = if enable {
504b8a62b91Sopenharmony_ci        PR_TASK_PERF_EVENTS_ENABLE
505b8a62b91Sopenharmony_ci    } else {
506b8a62b91Sopenharmony_ci        PR_TASK_PERF_EVENTS_DISABLE
507b8a62b91Sopenharmony_ci    };
508b8a62b91Sopenharmony_ci
509b8a62b91Sopenharmony_ci    unsafe { prctl_1arg(option) }.map(|_r| ())
510b8a62b91Sopenharmony_ci}
511b8a62b91Sopenharmony_ci
512b8a62b91Sopenharmony_ci//
513b8a62b91Sopenharmony_ci// PR_MCE_KILL_GET/PR_MCE_KILL
514b8a62b91Sopenharmony_ci//
515b8a62b91Sopenharmony_ci
516b8a62b91Sopenharmony_ciconst PR_MCE_KILL_GET: c_int = 34;
517b8a62b91Sopenharmony_ci
518b8a62b91Sopenharmony_ciconst PR_MCE_KILL_LATE: u32 = 0;
519b8a62b91Sopenharmony_ciconst PR_MCE_KILL_EARLY: u32 = 1;
520b8a62b91Sopenharmony_ciconst PR_MCE_KILL_DEFAULT: u32 = 2;
521b8a62b91Sopenharmony_ci
522b8a62b91Sopenharmony_ci/// `PR_MCE_KILL_*`.
523b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
524b8a62b91Sopenharmony_ci#[repr(u32)]
525b8a62b91Sopenharmony_cipub enum MachineCheckMemoryCorruptionKillPolicy {
526b8a62b91Sopenharmony_ci    /// Late kill policy.
527b8a62b91Sopenharmony_ci    Late = PR_MCE_KILL_LATE,
528b8a62b91Sopenharmony_ci    /// Early kill policy.
529b8a62b91Sopenharmony_ci    Early = PR_MCE_KILL_EARLY,
530b8a62b91Sopenharmony_ci    /// System-wide default policy.
531b8a62b91Sopenharmony_ci    Default = PR_MCE_KILL_DEFAULT,
532b8a62b91Sopenharmony_ci}
533b8a62b91Sopenharmony_ci
534b8a62b91Sopenharmony_ciimpl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy {
535b8a62b91Sopenharmony_ci    type Error = io::Errno;
536b8a62b91Sopenharmony_ci
537b8a62b91Sopenharmony_ci    fn try_from(value: u32) -> Result<Self, Self::Error> {
538b8a62b91Sopenharmony_ci        match value {
539b8a62b91Sopenharmony_ci            PR_MCE_KILL_LATE => Ok(Self::Late),
540b8a62b91Sopenharmony_ci            PR_MCE_KILL_EARLY => Ok(Self::Early),
541b8a62b91Sopenharmony_ci            PR_MCE_KILL_DEFAULT => Ok(Self::Default),
542b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
543b8a62b91Sopenharmony_ci        }
544b8a62b91Sopenharmony_ci    }
545b8a62b91Sopenharmony_ci}
546b8a62b91Sopenharmony_ci
547b8a62b91Sopenharmony_ci/// Get the current per-process machine check kill policy.
548b8a62b91Sopenharmony_ci///
549b8a62b91Sopenharmony_ci/// # References
550b8a62b91Sopenharmony_ci/// - [`prctl(PR_MCE_KILL_GET,...)`]
551b8a62b91Sopenharmony_ci///
552b8a62b91Sopenharmony_ci/// [`prctl(PR_MCE_KILL_GET,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
553b8a62b91Sopenharmony_ci#[inline]
554b8a62b91Sopenharmony_cipub fn machine_check_memory_corruption_kill_policy(
555b8a62b91Sopenharmony_ci) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> {
556b8a62b91Sopenharmony_ci    let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint;
557b8a62b91Sopenharmony_ci    MachineCheckMemoryCorruptionKillPolicy::try_from(r)
558b8a62b91Sopenharmony_ci}
559b8a62b91Sopenharmony_ci
560b8a62b91Sopenharmony_ciconst PR_MCE_KILL: c_int = 33;
561b8a62b91Sopenharmony_ci
562b8a62b91Sopenharmony_ciconst PR_MCE_KILL_CLEAR: usize = 0;
563b8a62b91Sopenharmony_ciconst PR_MCE_KILL_SET: usize = 1;
564b8a62b91Sopenharmony_ci
565b8a62b91Sopenharmony_ci/// Set the machine check memory corruption kill policy for the calling thread.
566b8a62b91Sopenharmony_ci///
567b8a62b91Sopenharmony_ci/// # References
568b8a62b91Sopenharmony_ci/// - [`prctl(PR_MCE_KILL,...)`]
569b8a62b91Sopenharmony_ci///
570b8a62b91Sopenharmony_ci/// [`prctl(PR_MCE_KILL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
571b8a62b91Sopenharmony_ci#[inline]
572b8a62b91Sopenharmony_cipub fn set_machine_check_memory_corruption_kill_policy(
573b8a62b91Sopenharmony_ci    policy: Option<MachineCheckMemoryCorruptionKillPolicy>,
574b8a62b91Sopenharmony_ci) -> io::Result<()> {
575b8a62b91Sopenharmony_ci    let (sub_operation, policy) = if let Some(policy) = policy {
576b8a62b91Sopenharmony_ci        (PR_MCE_KILL_SET, policy as usize as *mut _)
577b8a62b91Sopenharmony_ci    } else {
578b8a62b91Sopenharmony_ci        (PR_MCE_KILL_CLEAR, ptr::null_mut())
579b8a62b91Sopenharmony_ci    };
580b8a62b91Sopenharmony_ci
581b8a62b91Sopenharmony_ci    unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ())
582b8a62b91Sopenharmony_ci}
583b8a62b91Sopenharmony_ci
584b8a62b91Sopenharmony_ci//
585b8a62b91Sopenharmony_ci// PR_SET_MM
586b8a62b91Sopenharmony_ci//
587b8a62b91Sopenharmony_ci
588b8a62b91Sopenharmony_ciconst PR_SET_MM: c_int = 35;
589b8a62b91Sopenharmony_ci
590b8a62b91Sopenharmony_ciconst PR_SET_MM_START_CODE: u32 = 1;
591b8a62b91Sopenharmony_ciconst PR_SET_MM_END_CODE: u32 = 2;
592b8a62b91Sopenharmony_ciconst PR_SET_MM_START_DATA: u32 = 3;
593b8a62b91Sopenharmony_ciconst PR_SET_MM_END_DATA: u32 = 4;
594b8a62b91Sopenharmony_ciconst PR_SET_MM_START_STACK: u32 = 5;
595b8a62b91Sopenharmony_ciconst PR_SET_MM_START_BRK: u32 = 6;
596b8a62b91Sopenharmony_ciconst PR_SET_MM_BRK: u32 = 7;
597b8a62b91Sopenharmony_ciconst PR_SET_MM_ARG_START: u32 = 8;
598b8a62b91Sopenharmony_ciconst PR_SET_MM_ARG_END: u32 = 9;
599b8a62b91Sopenharmony_ciconst PR_SET_MM_ENV_START: u32 = 10;
600b8a62b91Sopenharmony_ciconst PR_SET_MM_ENV_END: u32 = 11;
601b8a62b91Sopenharmony_ciconst PR_SET_MM_AUXV: usize = 12;
602b8a62b91Sopenharmony_ciconst PR_SET_MM_EXE_FILE: usize = 13;
603b8a62b91Sopenharmony_ciconst PR_SET_MM_MAP: usize = 14;
604b8a62b91Sopenharmony_ciconst PR_SET_MM_MAP_SIZE: usize = 15;
605b8a62b91Sopenharmony_ci
606b8a62b91Sopenharmony_ci/// `PR_SET_MM_*`.
607b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
608b8a62b91Sopenharmony_ci#[repr(u32)]
609b8a62b91Sopenharmony_cipub enum VirtualMemoryMapAddress {
610b8a62b91Sopenharmony_ci    /// Set the address above which the program text can run.
611b8a62b91Sopenharmony_ci    CodeStart = PR_SET_MM_START_CODE,
612b8a62b91Sopenharmony_ci    /// Set the address below which the program text can run.
613b8a62b91Sopenharmony_ci    CodeEnd = PR_SET_MM_END_CODE,
614b8a62b91Sopenharmony_ci    /// Set the address above which initialized and uninitialized (bss) data are placed.
615b8a62b91Sopenharmony_ci    DataStart = PR_SET_MM_START_DATA,
616b8a62b91Sopenharmony_ci    /// Set the address below which initialized and uninitialized (bss) data are placed.
617b8a62b91Sopenharmony_ci    DataEnd = PR_SET_MM_END_DATA,
618b8a62b91Sopenharmony_ci    /// Set the start address of the stack.
619b8a62b91Sopenharmony_ci    StackStart = PR_SET_MM_START_STACK,
620b8a62b91Sopenharmony_ci    /// Set the address above which the program heap can be expanded with `brk` call.
621b8a62b91Sopenharmony_ci    BrkStart = PR_SET_MM_START_BRK,
622b8a62b91Sopenharmony_ci    /// Set the current `brk` value.
623b8a62b91Sopenharmony_ci    BrkCurrent = PR_SET_MM_BRK,
624b8a62b91Sopenharmony_ci    /// Set the address above which the program command line is placed.
625b8a62b91Sopenharmony_ci    ArgStart = PR_SET_MM_ARG_START,
626b8a62b91Sopenharmony_ci    /// Set the address below which the program command line is placed.
627b8a62b91Sopenharmony_ci    ArgEnd = PR_SET_MM_ARG_END,
628b8a62b91Sopenharmony_ci    /// Set the address above which the program environment is placed.
629b8a62b91Sopenharmony_ci    EnvironmentStart = PR_SET_MM_ENV_START,
630b8a62b91Sopenharmony_ci    /// Set the address below which the program environment is placed.
631b8a62b91Sopenharmony_ci    EnvironmentEnd = PR_SET_MM_ENV_END,
632b8a62b91Sopenharmony_ci}
633b8a62b91Sopenharmony_ci
634b8a62b91Sopenharmony_ci/// Modify certain kernel memory map descriptor addresses of the calling process.
635b8a62b91Sopenharmony_ci///
636b8a62b91Sopenharmony_ci/// # References
637b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_MM,...)`]
638b8a62b91Sopenharmony_ci///
639b8a62b91Sopenharmony_ci/// # Safety
640b8a62b91Sopenharmony_ci///
641b8a62b91Sopenharmony_ci/// Please ensure the conditions necessary to safely call this function,
642b8a62b91Sopenharmony_ci/// as detailed in the references above.
643b8a62b91Sopenharmony_ci///
644b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_MM,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
645b8a62b91Sopenharmony_ci#[inline]
646b8a62b91Sopenharmony_cipub unsafe fn set_virtual_memory_map_address(
647b8a62b91Sopenharmony_ci    option: VirtualMemoryMapAddress,
648b8a62b91Sopenharmony_ci    address: Option<NonNull<c_void>>,
649b8a62b91Sopenharmony_ci) -> io::Result<()> {
650b8a62b91Sopenharmony_ci    let address = address.map_or_else(ptr::null_mut, NonNull::as_ptr);
651b8a62b91Sopenharmony_ci    prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ())
652b8a62b91Sopenharmony_ci}
653b8a62b91Sopenharmony_ci
654b8a62b91Sopenharmony_ci/// Supersede the `/proc/pid/exe` symbolic link with a new one pointing to a new executable file.
655b8a62b91Sopenharmony_ci///
656b8a62b91Sopenharmony_ci/// # References
657b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]
658b8a62b91Sopenharmony_ci///
659b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
660b8a62b91Sopenharmony_ci#[inline]
661b8a62b91Sopenharmony_cipub fn set_executable_file(fd: BorrowedFd) -> io::Result<()> {
662b8a62b91Sopenharmony_ci    let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?;
663b8a62b91Sopenharmony_ci    unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ())
664b8a62b91Sopenharmony_ci}
665b8a62b91Sopenharmony_ci
666b8a62b91Sopenharmony_ci/// Set a new auxiliary vector.
667b8a62b91Sopenharmony_ci///
668b8a62b91Sopenharmony_ci/// # References
669b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]
670b8a62b91Sopenharmony_ci///
671b8a62b91Sopenharmony_ci/// # Safety
672b8a62b91Sopenharmony_ci///
673b8a62b91Sopenharmony_ci/// Please ensure the conditions necessary to safely call this function,
674b8a62b91Sopenharmony_ci/// as detailed in the references above.
675b8a62b91Sopenharmony_ci///
676b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
677b8a62b91Sopenharmony_ci#[inline]
678b8a62b91Sopenharmony_cipub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> {
679b8a62b91Sopenharmony_ci    syscalls::prctl(
680b8a62b91Sopenharmony_ci        PR_SET_MM,
681b8a62b91Sopenharmony_ci        PR_SET_MM_AUXV as *mut _,
682b8a62b91Sopenharmony_ci        auxv.as_ptr() as *mut _,
683b8a62b91Sopenharmony_ci        auxv.len() as *mut _,
684b8a62b91Sopenharmony_ci        ptr::null_mut(),
685b8a62b91Sopenharmony_ci    )
686b8a62b91Sopenharmony_ci    .map(|_r| ())
687b8a62b91Sopenharmony_ci}
688b8a62b91Sopenharmony_ci
689b8a62b91Sopenharmony_ci/// Get the size of the [`PrctlMmMap`] the kernel expects.
690b8a62b91Sopenharmony_ci///
691b8a62b91Sopenharmony_ci/// # References
692b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]
693b8a62b91Sopenharmony_ci///
694b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
695b8a62b91Sopenharmony_ci#[inline]
696b8a62b91Sopenharmony_cipub fn virtual_memory_map_config_struct_size() -> io::Result<usize> {
697b8a62b91Sopenharmony_ci    let mut value: c_uint = 0;
698b8a62b91Sopenharmony_ci    let value_ptr = (&mut value) as *mut c_uint;
699b8a62b91Sopenharmony_ci    unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? };
700b8a62b91Sopenharmony_ci    Ok(value as usize)
701b8a62b91Sopenharmony_ci}
702b8a62b91Sopenharmony_ci
703b8a62b91Sopenharmony_ci/// This structure provides new memory descriptor map which mostly modifies `/proc/pid/stat[m]`
704b8a62b91Sopenharmony_ci/// output for a task.
705b8a62b91Sopenharmony_ci/// This mostly done in a sake of checkpoint/restore functionality.
706b8a62b91Sopenharmony_ci#[repr(C)]
707b8a62b91Sopenharmony_ci#[derive(Debug, Clone)]
708b8a62b91Sopenharmony_cipub struct PrctlMmMap {
709b8a62b91Sopenharmony_ci    /// Code section start address.
710b8a62b91Sopenharmony_ci    pub start_code: u64,
711b8a62b91Sopenharmony_ci    /// Code section end address.
712b8a62b91Sopenharmony_ci    pub end_code: u64,
713b8a62b91Sopenharmony_ci    /// Data section start address.
714b8a62b91Sopenharmony_ci    pub start_data: u64,
715b8a62b91Sopenharmony_ci    /// Data section end address.
716b8a62b91Sopenharmony_ci    pub end_data: u64,
717b8a62b91Sopenharmony_ci    /// brk() start address.
718b8a62b91Sopenharmony_ci    pub start_brk: u64,
719b8a62b91Sopenharmony_ci    /// brk() current address.
720b8a62b91Sopenharmony_ci    pub brk: u64,
721b8a62b91Sopenharmony_ci    /// Stack start address.
722b8a62b91Sopenharmony_ci    pub start_stack: u64,
723b8a62b91Sopenharmony_ci    /// Program command line start address.
724b8a62b91Sopenharmony_ci    pub arg_start: u64,
725b8a62b91Sopenharmony_ci    /// Program command line end address.
726b8a62b91Sopenharmony_ci    pub arg_end: u64,
727b8a62b91Sopenharmony_ci    /// Program environment start address.
728b8a62b91Sopenharmony_ci    pub env_start: u64,
729b8a62b91Sopenharmony_ci    /// Program environment end address.
730b8a62b91Sopenharmony_ci    pub env_end: u64,
731b8a62b91Sopenharmony_ci    /// Auxiliary vector start address.
732b8a62b91Sopenharmony_ci    pub auxv: *mut u64,
733b8a62b91Sopenharmony_ci    /// Auxiliary vector size.
734b8a62b91Sopenharmony_ci    pub auxv_size: u32,
735b8a62b91Sopenharmony_ci    /// File descriptor of executable file that was used to create this process.
736b8a62b91Sopenharmony_ci    pub exe_fd: u32,
737b8a62b91Sopenharmony_ci}
738b8a62b91Sopenharmony_ci
739b8a62b91Sopenharmony_ci/// Provides one-shot access to all the addresses by passing in a [`PrctlMmMap`].
740b8a62b91Sopenharmony_ci///
741b8a62b91Sopenharmony_ci/// # References
742b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]
743b8a62b91Sopenharmony_ci///
744b8a62b91Sopenharmony_ci/// # Safety
745b8a62b91Sopenharmony_ci///
746b8a62b91Sopenharmony_ci/// Please ensure the conditions necessary to safely call this function,
747b8a62b91Sopenharmony_ci/// as detailed in the references above.
748b8a62b91Sopenharmony_ci///
749b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
750b8a62b91Sopenharmony_ci#[inline]
751b8a62b91Sopenharmony_cipub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> {
752b8a62b91Sopenharmony_ci    syscalls::prctl(
753b8a62b91Sopenharmony_ci        PR_SET_MM,
754b8a62b91Sopenharmony_ci        PR_SET_MM_MAP as *mut _,
755b8a62b91Sopenharmony_ci        config as *const PrctlMmMap as *mut _,
756b8a62b91Sopenharmony_ci        mem::size_of::<PrctlMmMap>() as *mut _,
757b8a62b91Sopenharmony_ci        ptr::null_mut(),
758b8a62b91Sopenharmony_ci    )
759b8a62b91Sopenharmony_ci    .map(|_r| ())
760b8a62b91Sopenharmony_ci}
761b8a62b91Sopenharmony_ci
762b8a62b91Sopenharmony_ci//
763b8a62b91Sopenharmony_ci// PR_SET_PTRACER
764b8a62b91Sopenharmony_ci//
765b8a62b91Sopenharmony_ci
766b8a62b91Sopenharmony_ciconst PR_SET_PTRACER: c_int = 0x59_61_6d_61;
767b8a62b91Sopenharmony_ci
768b8a62b91Sopenharmony_ciconst PR_SET_PTRACER_ANY: usize = usize::MAX;
769b8a62b91Sopenharmony_ci
770b8a62b91Sopenharmony_ci/// Process ptracer.
771b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
772b8a62b91Sopenharmony_cipub enum PTracer {
773b8a62b91Sopenharmony_ci    /// None.
774b8a62b91Sopenharmony_ci    None,
775b8a62b91Sopenharmony_ci    /// Disable `ptrace` restrictions for the calling process.
776b8a62b91Sopenharmony_ci    Any,
777b8a62b91Sopenharmony_ci    /// Specific process.
778b8a62b91Sopenharmony_ci    ProcessID(Pid),
779b8a62b91Sopenharmony_ci}
780b8a62b91Sopenharmony_ci
781b8a62b91Sopenharmony_ci/// Declare that the ptracer process can `ptrace` the calling process as if it were a direct
782b8a62b91Sopenharmony_ci/// process ancestor.
783b8a62b91Sopenharmony_ci///
784b8a62b91Sopenharmony_ci/// # References
785b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_PTRACER,...)`]
786b8a62b91Sopenharmony_ci///
787b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_PTRACER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
788b8a62b91Sopenharmony_ci#[inline]
789b8a62b91Sopenharmony_cipub fn set_ptracer(tracer: PTracer) -> io::Result<()> {
790b8a62b91Sopenharmony_ci    let pid = match tracer {
791b8a62b91Sopenharmony_ci        PTracer::None => ptr::null_mut(),
792b8a62b91Sopenharmony_ci        PTracer::Any => PR_SET_PTRACER_ANY as *mut _,
793b8a62b91Sopenharmony_ci        PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _,
794b8a62b91Sopenharmony_ci    };
795b8a62b91Sopenharmony_ci
796b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ())
797b8a62b91Sopenharmony_ci}
798b8a62b91Sopenharmony_ci
799b8a62b91Sopenharmony_ci//
800b8a62b91Sopenharmony_ci// PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER
801b8a62b91Sopenharmony_ci//
802b8a62b91Sopenharmony_ci
803b8a62b91Sopenharmony_ciconst PR_GET_CHILD_SUBREAPER: c_int = 37;
804b8a62b91Sopenharmony_ci
805b8a62b91Sopenharmony_ci/// Get the `child subreaper` setting of the calling process.
806b8a62b91Sopenharmony_ci///
807b8a62b91Sopenharmony_ci/// # References
808b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_CHILD_SUBREAPER,...)`]
809b8a62b91Sopenharmony_ci///
810b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
811b8a62b91Sopenharmony_ci#[inline]
812b8a62b91Sopenharmony_cipub fn child_subreaper() -> io::Result<Option<Pid>> {
813b8a62b91Sopenharmony_ci    unsafe {
814b8a62b91Sopenharmony_ci        let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?;
815b8a62b91Sopenharmony_ci        Ok(Pid::from_raw(r as RawPid))
816b8a62b91Sopenharmony_ci    }
817b8a62b91Sopenharmony_ci}
818b8a62b91Sopenharmony_ci
819b8a62b91Sopenharmony_ciconst PR_SET_CHILD_SUBREAPER: c_int = 36;
820b8a62b91Sopenharmony_ci
821b8a62b91Sopenharmony_ci/// Set the `child subreaper` attribute of the calling process.
822b8a62b91Sopenharmony_ci///
823b8a62b91Sopenharmony_ci/// # References
824b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_CHILD_SUBREAPER,...)`]
825b8a62b91Sopenharmony_ci///
826b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
827b8a62b91Sopenharmony_ci#[inline]
828b8a62b91Sopenharmony_cipub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> {
829b8a62b91Sopenharmony_ci    let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize);
830b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ())
831b8a62b91Sopenharmony_ci}
832b8a62b91Sopenharmony_ci
833b8a62b91Sopenharmony_ci//
834b8a62b91Sopenharmony_ci// PR_GET_FP_MODE/PR_SET_FP_MODE
835b8a62b91Sopenharmony_ci//
836b8a62b91Sopenharmony_ci
837b8a62b91Sopenharmony_ciconst PR_GET_FP_MODE: c_int = 46;
838b8a62b91Sopenharmony_ci
839b8a62b91Sopenharmony_ciconst PR_FP_MODE_FR: u32 = 1_u32 << 0;
840b8a62b91Sopenharmony_ciconst PR_FP_MODE_FRE: u32 = 1_u32 << 1;
841b8a62b91Sopenharmony_ci
842b8a62b91Sopenharmony_ci/// `PR_FP_MODE_*`.
843b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
844b8a62b91Sopenharmony_ci#[repr(u32)]
845b8a62b91Sopenharmony_cipub enum FloatingPointMode {
846b8a62b91Sopenharmony_ci    /// 64-bit floating point registers.
847b8a62b91Sopenharmony_ci    FloatingPointRegisters = PR_FP_MODE_FR,
848b8a62b91Sopenharmony_ci    /// Enable emulation of 32-bit floating-point mode.
849b8a62b91Sopenharmony_ci    FloatingPointEmulation = PR_FP_MODE_FRE,
850b8a62b91Sopenharmony_ci}
851b8a62b91Sopenharmony_ci
852b8a62b91Sopenharmony_ciimpl TryFrom<u32> for FloatingPointMode {
853b8a62b91Sopenharmony_ci    type Error = io::Errno;
854b8a62b91Sopenharmony_ci
855b8a62b91Sopenharmony_ci    fn try_from(value: u32) -> Result<Self, Self::Error> {
856b8a62b91Sopenharmony_ci        match value {
857b8a62b91Sopenharmony_ci            PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters),
858b8a62b91Sopenharmony_ci            PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation),
859b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
860b8a62b91Sopenharmony_ci        }
861b8a62b91Sopenharmony_ci    }
862b8a62b91Sopenharmony_ci}
863b8a62b91Sopenharmony_ci
864b8a62b91Sopenharmony_ci/// Get the current floating point mode.
865b8a62b91Sopenharmony_ci///
866b8a62b91Sopenharmony_ci/// # References
867b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_FP_MODE,...)`]
868b8a62b91Sopenharmony_ci///
869b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
870b8a62b91Sopenharmony_ci#[inline]
871b8a62b91Sopenharmony_cipub fn floating_point_mode() -> io::Result<FloatingPointMode> {
872b8a62b91Sopenharmony_ci    let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint;
873b8a62b91Sopenharmony_ci    FloatingPointMode::try_from(r)
874b8a62b91Sopenharmony_ci}
875b8a62b91Sopenharmony_ci
876b8a62b91Sopenharmony_ciconst PR_SET_FP_MODE: c_int = 45;
877b8a62b91Sopenharmony_ci
878b8a62b91Sopenharmony_ci/// Allow control of the floating point mode from user space.
879b8a62b91Sopenharmony_ci///
880b8a62b91Sopenharmony_ci/// # References
881b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_FP_MODE,...)`]
882b8a62b91Sopenharmony_ci///
883b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
884b8a62b91Sopenharmony_ci#[inline]
885b8a62b91Sopenharmony_cipub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> {
886b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ())
887b8a62b91Sopenharmony_ci}
888b8a62b91Sopenharmony_ci
889b8a62b91Sopenharmony_ci//
890b8a62b91Sopenharmony_ci// PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL
891b8a62b91Sopenharmony_ci//
892b8a62b91Sopenharmony_ci
893b8a62b91Sopenharmony_ciconst PR_GET_SPECULATION_CTRL: c_int = 52;
894b8a62b91Sopenharmony_ci
895b8a62b91Sopenharmony_ciconst PR_SPEC_STORE_BYPASS: u32 = 0;
896b8a62b91Sopenharmony_ciconst PR_SPEC_INDIRECT_BRANCH: u32 = 1;
897b8a62b91Sopenharmony_ciconst PR_SPEC_L1D_FLUSH: u32 = 2;
898b8a62b91Sopenharmony_ci
899b8a62b91Sopenharmony_ci/// `PR_SPEC_*`.
900b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
901b8a62b91Sopenharmony_ci#[repr(u32)]
902b8a62b91Sopenharmony_cipub enum SpeculationFeature {
903b8a62b91Sopenharmony_ci    /// Set the state of the speculative store bypass misfeature.
904b8a62b91Sopenharmony_ci    SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS,
905b8a62b91Sopenharmony_ci    /// Set the state of the indirect branch speculation misfeature.
906b8a62b91Sopenharmony_ci    IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH,
907b8a62b91Sopenharmony_ci    /// Flush L1D Cache on context switch out of the task.
908b8a62b91Sopenharmony_ci    FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH,
909b8a62b91Sopenharmony_ci}
910b8a62b91Sopenharmony_ci
911b8a62b91Sopenharmony_ciimpl TryFrom<u32> for SpeculationFeature {
912b8a62b91Sopenharmony_ci    type Error = io::Errno;
913b8a62b91Sopenharmony_ci
914b8a62b91Sopenharmony_ci    fn try_from(value: u32) -> Result<Self, Self::Error> {
915b8a62b91Sopenharmony_ci        match value {
916b8a62b91Sopenharmony_ci            PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass),
917b8a62b91Sopenharmony_ci            PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation),
918b8a62b91Sopenharmony_ci            PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask),
919b8a62b91Sopenharmony_ci            _ => Err(io::Errno::RANGE),
920b8a62b91Sopenharmony_ci        }
921b8a62b91Sopenharmony_ci    }
922b8a62b91Sopenharmony_ci}
923b8a62b91Sopenharmony_ci
924b8a62b91Sopenharmony_cibitflags! {
925b8a62b91Sopenharmony_ci    /// `PR_SPEC_*`.
926b8a62b91Sopenharmony_ci    pub struct SpeculationFeatureControl: u32 {
927b8a62b91Sopenharmony_ci        /// The speculation feature is enabled, mitigation is disabled.
928b8a62b91Sopenharmony_ci        const ENABLE = 1_u32 << 1;
929b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled.
930b8a62b91Sopenharmony_ci        const DISABLE = 1_u32 << 2;
931b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone.
932b8a62b91Sopenharmony_ci        const FORCE_DISABLE = 1_u32 << 3;
933b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`.
934b8a62b91Sopenharmony_ci        const DISABLE_NOEXEC = 1_u32 << 4;
935b8a62b91Sopenharmony_ci    }
936b8a62b91Sopenharmony_ci}
937b8a62b91Sopenharmony_ci
938b8a62b91Sopenharmony_cibitflags! {
939b8a62b91Sopenharmony_ci    /// Zero means the processors are not vulnerable.
940b8a62b91Sopenharmony_ci    pub struct SpeculationFeatureState: u32 {
941b8a62b91Sopenharmony_ci        /// Mitigation can be controlled per thread by `PR_SET_SPECULATION_CTRL`.
942b8a62b91Sopenharmony_ci        const PRCTL = 1_u32 << 0;
943b8a62b91Sopenharmony_ci        /// The speculation feature is enabled, mitigation is disabled.
944b8a62b91Sopenharmony_ci        const ENABLE = 1_u32 << 1;
945b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled.
946b8a62b91Sopenharmony_ci        const DISABLE = 1_u32 << 2;
947b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone.
948b8a62b91Sopenharmony_ci        const FORCE_DISABLE = 1_u32 << 3;
949b8a62b91Sopenharmony_ci        /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`.
950b8a62b91Sopenharmony_ci        const DISABLE_NOEXEC = 1_u32 << 4;
951b8a62b91Sopenharmony_ci    }
952b8a62b91Sopenharmony_ci}
953b8a62b91Sopenharmony_ci
954b8a62b91Sopenharmony_ci/// Get the state of the speculation misfeature.
955b8a62b91Sopenharmony_ci///
956b8a62b91Sopenharmony_ci/// # References
957b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_SPECULATION_CTRL,...)`]
958b8a62b91Sopenharmony_ci///
959b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html
960b8a62b91Sopenharmony_ci#[inline]
961b8a62b91Sopenharmony_cipub fn speculative_feature_state(
962b8a62b91Sopenharmony_ci    feature: SpeculationFeature,
963b8a62b91Sopenharmony_ci) -> io::Result<Option<SpeculationFeatureState>> {
964b8a62b91Sopenharmony_ci    let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint;
965b8a62b91Sopenharmony_ci    Ok(SpeculationFeatureState::from_bits(r))
966b8a62b91Sopenharmony_ci}
967b8a62b91Sopenharmony_ci
968b8a62b91Sopenharmony_ciconst PR_SET_SPECULATION_CTRL: c_int = 53;
969b8a62b91Sopenharmony_ci
970b8a62b91Sopenharmony_ci/// Sets the state of the speculation misfeature.
971b8a62b91Sopenharmony_ci///
972b8a62b91Sopenharmony_ci/// # References
973b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_SPECULATION_CTRL,...)`]
974b8a62b91Sopenharmony_ci///
975b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html
976b8a62b91Sopenharmony_ci#[inline]
977b8a62b91Sopenharmony_cipub fn control_speculative_feature(
978b8a62b91Sopenharmony_ci    feature: SpeculationFeature,
979b8a62b91Sopenharmony_ci    config: SpeculationFeatureControl,
980b8a62b91Sopenharmony_ci) -> io::Result<()> {
981b8a62b91Sopenharmony_ci    let feature = feature as usize as *mut _;
982b8a62b91Sopenharmony_ci    let config = config.bits() as usize as *mut _;
983b8a62b91Sopenharmony_ci    unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ())
984b8a62b91Sopenharmony_ci}
985b8a62b91Sopenharmony_ci
986b8a62b91Sopenharmony_ci//
987b8a62b91Sopenharmony_ci// PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER
988b8a62b91Sopenharmony_ci//
989b8a62b91Sopenharmony_ci
990b8a62b91Sopenharmony_ciconst PR_GET_IO_FLUSHER: c_int = 58;
991b8a62b91Sopenharmony_ci
992b8a62b91Sopenharmony_ci/// Get the `IO_FLUSHER` state of the caller.
993b8a62b91Sopenharmony_ci///
994b8a62b91Sopenharmony_ci/// # References
995b8a62b91Sopenharmony_ci/// - [`prctl(PR_GET_IO_FLUSHER,...)`]
996b8a62b91Sopenharmony_ci///
997b8a62b91Sopenharmony_ci/// [`prctl(PR_GET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
998b8a62b91Sopenharmony_ci#[inline]
999b8a62b91Sopenharmony_cipub fn is_io_flusher() -> io::Result<bool> {
1000b8a62b91Sopenharmony_ci    unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0)
1001b8a62b91Sopenharmony_ci}
1002b8a62b91Sopenharmony_ci
1003b8a62b91Sopenharmony_ciconst PR_SET_IO_FLUSHER: c_int = 57;
1004b8a62b91Sopenharmony_ci
1005b8a62b91Sopenharmony_ci/// Put the process in the `IO_FLUSHER` state, allowing it to make progress when
1006b8a62b91Sopenharmony_ci/// allocating memory.
1007b8a62b91Sopenharmony_ci///
1008b8a62b91Sopenharmony_ci/// # References
1009b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_IO_FLUSHER,...)`]
1010b8a62b91Sopenharmony_ci///
1011b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
1012b8a62b91Sopenharmony_ci#[inline]
1013b8a62b91Sopenharmony_cipub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> {
1014b8a62b91Sopenharmony_ci    unsafe { prctl_2args(PR_SET_IO_FLUSHER, enable as usize as *mut _) }.map(|_r| ())
1015b8a62b91Sopenharmony_ci}
1016b8a62b91Sopenharmony_ci
1017b8a62b91Sopenharmony_ci//
1018b8a62b91Sopenharmony_ci// PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS
1019b8a62b91Sopenharmony_ci//
1020b8a62b91Sopenharmony_ci
1021b8a62b91Sopenharmony_ciconst PR_PAC_GET_ENABLED_KEYS: c_int = 61;
1022b8a62b91Sopenharmony_ci
1023b8a62b91Sopenharmony_cibitflags! {
1024b8a62b91Sopenharmony_ci    /// `PR_PAC_AP*`.
1025b8a62b91Sopenharmony_ci    pub struct PointerAuthenticationKeys: u32 {
1026b8a62b91Sopenharmony_ci        /// Instruction authentication key `A`.
1027b8a62b91Sopenharmony_ci        const INSTRUCTION_AUTHENTICATION_KEY_A = 1_u32 << 0;
1028b8a62b91Sopenharmony_ci        /// Instruction authentication key `B`.
1029b8a62b91Sopenharmony_ci        const INSTRUCTION_AUTHENTICATION_KEY_B = 1_u32 << 1;
1030b8a62b91Sopenharmony_ci        /// Data authentication key `A`.
1031b8a62b91Sopenharmony_ci        const DATA_AUTHENTICATION_KEY_A = 1_u32 << 2;
1032b8a62b91Sopenharmony_ci        /// Data authentication key `B`.
1033b8a62b91Sopenharmony_ci        const DATA_AUTHENTICATION_KEY_B = 1_u32 << 3;
1034b8a62b91Sopenharmony_ci        /// Generic authentication `A` key.
1035b8a62b91Sopenharmony_ci        const GENERIC_AUTHENTICATION_KEY_A = 1_u32 << 4;
1036b8a62b91Sopenharmony_ci    }
1037b8a62b91Sopenharmony_ci}
1038b8a62b91Sopenharmony_ci
1039b8a62b91Sopenharmony_ci/// Get enabled pointer authentication keys.
1040b8a62b91Sopenharmony_ci///
1041b8a62b91Sopenharmony_ci/// # References
1042b8a62b91Sopenharmony_ci/// - [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]
1043b8a62b91Sopenharmony_ci///
1044b8a62b91Sopenharmony_ci/// [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html
1045b8a62b91Sopenharmony_ci#[inline]
1046b8a62b91Sopenharmony_cipub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> {
1047b8a62b91Sopenharmony_ci    let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint;
1048b8a62b91Sopenharmony_ci    PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE)
1049b8a62b91Sopenharmony_ci}
1050b8a62b91Sopenharmony_ci
1051b8a62b91Sopenharmony_ciconst PR_PAC_SET_ENABLED_KEYS: c_int = 60;
1052b8a62b91Sopenharmony_ci
1053b8a62b91Sopenharmony_ci/// Set enabled pointer authentication keys.
1054b8a62b91Sopenharmony_ci///
1055b8a62b91Sopenharmony_ci/// # References
1056b8a62b91Sopenharmony_ci/// - [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]
1057b8a62b91Sopenharmony_ci///
1058b8a62b91Sopenharmony_ci/// # Safety
1059b8a62b91Sopenharmony_ci///
1060b8a62b91Sopenharmony_ci/// Please ensure the conditions necessary to safely call this function,
1061b8a62b91Sopenharmony_ci/// as detailed in the references above.
1062b8a62b91Sopenharmony_ci///
1063b8a62b91Sopenharmony_ci/// [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html
1064b8a62b91Sopenharmony_ci#[inline]
1065b8a62b91Sopenharmony_cipub unsafe fn configure_pointer_authentication_keys(
1066b8a62b91Sopenharmony_ci    config: impl Iterator<Item = (PointerAuthenticationKeys, bool)>,
1067b8a62b91Sopenharmony_ci) -> io::Result<()> {
1068b8a62b91Sopenharmony_ci    let mut affected_keys: u32 = 0;
1069b8a62b91Sopenharmony_ci    let mut enabled_keys: u32 = 0;
1070b8a62b91Sopenharmony_ci
1071b8a62b91Sopenharmony_ci    for (key, enable) in config {
1072b8a62b91Sopenharmony_ci        let key = key.bits();
1073b8a62b91Sopenharmony_ci        affected_keys |= key;
1074b8a62b91Sopenharmony_ci
1075b8a62b91Sopenharmony_ci        if enable {
1076b8a62b91Sopenharmony_ci            enabled_keys |= key;
1077b8a62b91Sopenharmony_ci        } else {
1078b8a62b91Sopenharmony_ci            enabled_keys &= !key;
1079b8a62b91Sopenharmony_ci        }
1080b8a62b91Sopenharmony_ci    }
1081b8a62b91Sopenharmony_ci
1082b8a62b91Sopenharmony_ci    if affected_keys == 0 {
1083b8a62b91Sopenharmony_ci        return Ok(()); // Nothing to do.
1084b8a62b91Sopenharmony_ci    }
1085b8a62b91Sopenharmony_ci
1086b8a62b91Sopenharmony_ci    prctl_3args(
1087b8a62b91Sopenharmony_ci        PR_PAC_SET_ENABLED_KEYS,
1088b8a62b91Sopenharmony_ci        affected_keys as usize as *mut _,
1089b8a62b91Sopenharmony_ci        enabled_keys as usize as *mut _,
1090b8a62b91Sopenharmony_ci    )
1091b8a62b91Sopenharmony_ci    .map(|_r| ())
1092b8a62b91Sopenharmony_ci}
1093b8a62b91Sopenharmony_ci
1094b8a62b91Sopenharmony_ci//
1095b8a62b91Sopenharmony_ci// PR_SET_VMA
1096b8a62b91Sopenharmony_ci//
1097b8a62b91Sopenharmony_ci
1098b8a62b91Sopenharmony_ciconst PR_SET_VMA: c_int = 0x53_56_4d_41;
1099b8a62b91Sopenharmony_ci
1100b8a62b91Sopenharmony_ciconst PR_SET_VMA_ANON_NAME: usize = 0;
1101b8a62b91Sopenharmony_ci
1102b8a62b91Sopenharmony_ci/// Set the name for a virtual memory region.
1103b8a62b91Sopenharmony_ci///
1104b8a62b91Sopenharmony_ci/// # References
1105b8a62b91Sopenharmony_ci/// - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]
1106b8a62b91Sopenharmony_ci///
1107b8a62b91Sopenharmony_ci/// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]: https://lwn.net/Articles/867818/
1108b8a62b91Sopenharmony_ci#[inline]
1109b8a62b91Sopenharmony_cipub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> {
1110b8a62b91Sopenharmony_ci    unsafe {
1111b8a62b91Sopenharmony_ci        syscalls::prctl(
1112b8a62b91Sopenharmony_ci            PR_SET_VMA,
1113b8a62b91Sopenharmony_ci            PR_SET_VMA_ANON_NAME as *mut _,
1114b8a62b91Sopenharmony_ci            region.as_ptr() as *mut _,
1115b8a62b91Sopenharmony_ci            region.len() as *mut _,
1116b8a62b91Sopenharmony_ci            name.map_or_else(ptr::null, CStr::as_ptr) as *mut _,
1117b8a62b91Sopenharmony_ci        )
1118b8a62b91Sopenharmony_ci        .map(|_r| ())
1119b8a62b91Sopenharmony_ci    }
1120b8a62b91Sopenharmony_ci}
1121