1b8a62b91Sopenharmony_ci//! Encapsulation for system call arguments and return values.
2b8a62b91Sopenharmony_ci//!
3b8a62b91Sopenharmony_ci//! The inline-asm and outline-asm code paths do some amount of reordering
4b8a62b91Sopenharmony_ci//! of arguments; to ensure that we don't accidentally misroute an argument
5b8a62b91Sopenharmony_ci//! or return value, we use distinct types for each argument index and
6b8a62b91Sopenharmony_ci//! return value.
7b8a62b91Sopenharmony_ci//!
8b8a62b91Sopenharmony_ci//! # Safety
9b8a62b91Sopenharmony_ci//!
10b8a62b91Sopenharmony_ci//! The `ToAsm` and `FromAsm` traits are unsafe to use; they should only be
11b8a62b91Sopenharmony_ci//! used by the syscall code which executes actual syscall machine
12b8a62b91Sopenharmony_ci//! instructions.
13b8a62b91Sopenharmony_ci
14b8a62b91Sopenharmony_ci#![allow(unsafe_code)]
15b8a62b91Sopenharmony_ci
16b8a62b91Sopenharmony_ciuse super::c;
17b8a62b91Sopenharmony_ciuse super::fd::RawFd;
18b8a62b91Sopenharmony_ciuse core::marker::PhantomData;
19b8a62b91Sopenharmony_ci
20b8a62b91Sopenharmony_cipub(super) trait ToAsm: private::Sealed {
21b8a62b91Sopenharmony_ci    /// Convert `self` to a `usize` ready to be passed to a syscall
22b8a62b91Sopenharmony_ci    /// machine instruction.
23b8a62b91Sopenharmony_ci    ///
24b8a62b91Sopenharmony_ci    /// # Safety
25b8a62b91Sopenharmony_ci    ///
26b8a62b91Sopenharmony_ci    /// This should be used immediately before the syscall instruction, and
27b8a62b91Sopenharmony_ci    /// the returned value shouldn't be used for any other purpose.
28b8a62b91Sopenharmony_ci    #[must_use]
29b8a62b91Sopenharmony_ci    unsafe fn to_asm(self) -> *mut Opaque;
30b8a62b91Sopenharmony_ci}
31b8a62b91Sopenharmony_ci
32b8a62b91Sopenharmony_cipub(super) trait FromAsm: private::Sealed {
33b8a62b91Sopenharmony_ci    /// Convert `raw` from a value produced by a syscall machine instruction
34b8a62b91Sopenharmony_ci    /// into a `Self`.
35b8a62b91Sopenharmony_ci    ///
36b8a62b91Sopenharmony_ci    /// # Safety
37b8a62b91Sopenharmony_ci    ///
38b8a62b91Sopenharmony_ci    /// This should be used immediately after the syscall instruction, and
39b8a62b91Sopenharmony_ci    /// the operand value shouldn't be used for any other purpose.
40b8a62b91Sopenharmony_ci    #[must_use]
41b8a62b91Sopenharmony_ci    unsafe fn from_asm(raw: *mut Opaque) -> Self;
42b8a62b91Sopenharmony_ci}
43b8a62b91Sopenharmony_ci
44b8a62b91Sopenharmony_ci/// To preserve provenance, syscall arguments and return values are passed as
45b8a62b91Sopenharmony_ci/// pointer types. They need a type to point to, so we define a custom private
46b8a62b91Sopenharmony_ci/// type, to prevent it from being used for anything else.
47b8a62b91Sopenharmony_ci#[repr(transparent)]
48b8a62b91Sopenharmony_cipub(super) struct Opaque(c::c_void);
49b8a62b91Sopenharmony_ci
50b8a62b91Sopenharmony_ci// Argument numbers.
51b8a62b91Sopenharmony_cipub(super) struct A0(());
52b8a62b91Sopenharmony_cipub(super) struct A1(());
53b8a62b91Sopenharmony_cipub(super) struct A2(());
54b8a62b91Sopenharmony_cipub(super) struct A3(());
55b8a62b91Sopenharmony_cipub(super) struct A4(());
56b8a62b91Sopenharmony_cipub(super) struct A5(());
57b8a62b91Sopenharmony_ci#[cfg(target_arch = "mips")]
58b8a62b91Sopenharmony_cipub(super) struct A6(());
59b8a62b91Sopenharmony_ci#[cfg(target_arch = "x86")]
60b8a62b91Sopenharmony_cipub(super) struct SocketArg;
61b8a62b91Sopenharmony_ci
62b8a62b91Sopenharmony_cipub(super) trait ArgNumber: private::Sealed {}
63b8a62b91Sopenharmony_ciimpl ArgNumber for A0 {}
64b8a62b91Sopenharmony_ciimpl ArgNumber for A1 {}
65b8a62b91Sopenharmony_ciimpl ArgNumber for A2 {}
66b8a62b91Sopenharmony_ciimpl ArgNumber for A3 {}
67b8a62b91Sopenharmony_ciimpl ArgNumber for A4 {}
68b8a62b91Sopenharmony_ciimpl ArgNumber for A5 {}
69b8a62b91Sopenharmony_ci#[cfg(target_arch = "mips")]
70b8a62b91Sopenharmony_ciimpl ArgNumber for A6 {}
71b8a62b91Sopenharmony_ci#[cfg(target_arch = "x86")]
72b8a62b91Sopenharmony_ciimpl ArgNumber for SocketArg {}
73b8a62b91Sopenharmony_ci
74b8a62b91Sopenharmony_ci// Return value numbers.
75b8a62b91Sopenharmony_cipub(super) struct R0(());
76b8a62b91Sopenharmony_ci
77b8a62b91Sopenharmony_cipub(super) trait RetNumber: private::Sealed {}
78b8a62b91Sopenharmony_ciimpl RetNumber for R0 {}
79b8a62b91Sopenharmony_ci
80b8a62b91Sopenharmony_ci/// Syscall arguments use register-sized types. We use a newtype to
81b8a62b91Sopenharmony_ci/// discourage accidental misuse of the raw integer values.
82b8a62b91Sopenharmony_ci///
83b8a62b91Sopenharmony_ci/// This type doesn't implement `Clone` or `Copy`; it should be used exactly
84b8a62b91Sopenharmony_ci/// once. And it has a lifetime to ensure that it doesn't outlive any resources
85b8a62b91Sopenharmony_ci/// it might be pointing to.
86b8a62b91Sopenharmony_ci#[repr(transparent)]
87b8a62b91Sopenharmony_ci#[must_use]
88b8a62b91Sopenharmony_cipub(super) struct ArgReg<'a, Num: ArgNumber> {
89b8a62b91Sopenharmony_ci    raw: *mut Opaque,
90b8a62b91Sopenharmony_ci    _phantom: PhantomData<(&'a (), Num)>,
91b8a62b91Sopenharmony_ci}
92b8a62b91Sopenharmony_ci
93b8a62b91Sopenharmony_ciimpl<'a, Num: ArgNumber> ToAsm for ArgReg<'a, Num> {
94b8a62b91Sopenharmony_ci    #[inline]
95b8a62b91Sopenharmony_ci    unsafe fn to_asm(self) -> *mut Opaque {
96b8a62b91Sopenharmony_ci        self.raw
97b8a62b91Sopenharmony_ci    }
98b8a62b91Sopenharmony_ci}
99b8a62b91Sopenharmony_ci
100b8a62b91Sopenharmony_ci/// Syscall return values use register-sized types. We use a newtype to
101b8a62b91Sopenharmony_ci/// discourage accidental misuse of the raw integer values.
102b8a62b91Sopenharmony_ci///
103b8a62b91Sopenharmony_ci/// This type doesn't implement `Clone` or `Copy`; it should be used exactly
104b8a62b91Sopenharmony_ci/// once.
105b8a62b91Sopenharmony_ci#[repr(transparent)]
106b8a62b91Sopenharmony_ci#[must_use]
107b8a62b91Sopenharmony_cipub(super) struct RetReg<Num: RetNumber> {
108b8a62b91Sopenharmony_ci    raw: *mut Opaque,
109b8a62b91Sopenharmony_ci    _phantom: PhantomData<Num>,
110b8a62b91Sopenharmony_ci}
111b8a62b91Sopenharmony_ci
112b8a62b91Sopenharmony_ciimpl<Num: RetNumber> RetReg<Num> {
113b8a62b91Sopenharmony_ci    #[inline]
114b8a62b91Sopenharmony_ci    pub(super) fn decode_usize(self) -> usize {
115b8a62b91Sopenharmony_ci        debug_assert!(!(-4095..0).contains(&(self.raw as isize)));
116b8a62b91Sopenharmony_ci        self.raw as usize
117b8a62b91Sopenharmony_ci    }
118b8a62b91Sopenharmony_ci
119b8a62b91Sopenharmony_ci    #[inline]
120b8a62b91Sopenharmony_ci    pub(super) fn decode_raw_fd(self) -> RawFd {
121b8a62b91Sopenharmony_ci        let bits = self.decode_usize();
122b8a62b91Sopenharmony_ci        let raw_fd = bits as RawFd;
123b8a62b91Sopenharmony_ci
124b8a62b91Sopenharmony_ci        // Converting `raw` to `RawFd` should be lossless.
125b8a62b91Sopenharmony_ci        debug_assert_eq!(raw_fd as usize, bits);
126b8a62b91Sopenharmony_ci
127b8a62b91Sopenharmony_ci        raw_fd
128b8a62b91Sopenharmony_ci    }
129b8a62b91Sopenharmony_ci
130b8a62b91Sopenharmony_ci    #[inline]
131b8a62b91Sopenharmony_ci    pub(super) fn decode_c_int(self) -> c::c_int {
132b8a62b91Sopenharmony_ci        let bits = self.decode_usize();
133b8a62b91Sopenharmony_ci        let c_int_ = bits as c::c_int;
134b8a62b91Sopenharmony_ci
135b8a62b91Sopenharmony_ci        // Converting `raw` to `c_int` should be lossless.
136b8a62b91Sopenharmony_ci        debug_assert_eq!(c_int_ as usize, bits);
137b8a62b91Sopenharmony_ci
138b8a62b91Sopenharmony_ci        c_int_
139b8a62b91Sopenharmony_ci    }
140b8a62b91Sopenharmony_ci
141b8a62b91Sopenharmony_ci    #[inline]
142b8a62b91Sopenharmony_ci    pub(super) fn decode_c_uint(self) -> c::c_uint {
143b8a62b91Sopenharmony_ci        let bits = self.decode_usize();
144b8a62b91Sopenharmony_ci        let c_uint_ = bits as c::c_uint;
145b8a62b91Sopenharmony_ci
146b8a62b91Sopenharmony_ci        // Converting `raw` to `c_uint` should be lossless.
147b8a62b91Sopenharmony_ci        debug_assert_eq!(c_uint_ as usize, bits);
148b8a62b91Sopenharmony_ci
149b8a62b91Sopenharmony_ci        c_uint_
150b8a62b91Sopenharmony_ci    }
151b8a62b91Sopenharmony_ci
152b8a62b91Sopenharmony_ci    #[inline]
153b8a62b91Sopenharmony_ci    pub(super) fn decode_void_star(self) -> *mut c::c_void {
154b8a62b91Sopenharmony_ci        self.raw.cast()
155b8a62b91Sopenharmony_ci    }
156b8a62b91Sopenharmony_ci
157b8a62b91Sopenharmony_ci    #[cfg(target_pointer_width = "64")]
158b8a62b91Sopenharmony_ci    #[inline]
159b8a62b91Sopenharmony_ci    pub(super) fn decode_u64(self) -> u64 {
160b8a62b91Sopenharmony_ci        self.decode_usize() as u64
161b8a62b91Sopenharmony_ci    }
162b8a62b91Sopenharmony_ci
163b8a62b91Sopenharmony_ci    #[inline]
164b8a62b91Sopenharmony_ci    pub(super) fn decode_void(self) {
165b8a62b91Sopenharmony_ci        let ignore = self.decode_usize();
166b8a62b91Sopenharmony_ci        debug_assert_eq!(ignore, 0);
167b8a62b91Sopenharmony_ci    }
168b8a62b91Sopenharmony_ci
169b8a62b91Sopenharmony_ci    #[inline]
170b8a62b91Sopenharmony_ci    pub(super) fn decode_error_code(self) -> u16 {
171b8a62b91Sopenharmony_ci        let bits = self.raw as usize;
172b8a62b91Sopenharmony_ci
173b8a62b91Sopenharmony_ci        // `raw` must be in `-4095..0`. Linux always returns errors in
174b8a62b91Sopenharmony_ci        // `-4095..0`, and we double-check it here.
175b8a62b91Sopenharmony_ci        debug_assert!((-4095..0).contains(&(bits as isize)));
176b8a62b91Sopenharmony_ci
177b8a62b91Sopenharmony_ci        bits as u16
178b8a62b91Sopenharmony_ci    }
179b8a62b91Sopenharmony_ci
180b8a62b91Sopenharmony_ci    #[inline]
181b8a62b91Sopenharmony_ci    pub(super) fn is_nonzero(&self) -> bool {
182b8a62b91Sopenharmony_ci        !self.raw.is_null()
183b8a62b91Sopenharmony_ci    }
184b8a62b91Sopenharmony_ci
185b8a62b91Sopenharmony_ci    #[inline]
186b8a62b91Sopenharmony_ci    pub(super) fn is_negative(&self) -> bool {
187b8a62b91Sopenharmony_ci        (self.raw as isize) < 0
188b8a62b91Sopenharmony_ci    }
189b8a62b91Sopenharmony_ci
190b8a62b91Sopenharmony_ci    #[inline]
191b8a62b91Sopenharmony_ci    pub(super) fn is_in_range(&self, range: core::ops::Range<isize>) -> bool {
192b8a62b91Sopenharmony_ci        range.contains(&(self.raw as isize))
193b8a62b91Sopenharmony_ci    }
194b8a62b91Sopenharmony_ci}
195b8a62b91Sopenharmony_ci
196b8a62b91Sopenharmony_ciimpl<Num: RetNumber> FromAsm for RetReg<Num> {
197b8a62b91Sopenharmony_ci    #[inline]
198b8a62b91Sopenharmony_ci    unsafe fn from_asm(raw: *mut Opaque) -> Self {
199b8a62b91Sopenharmony_ci        Self {
200b8a62b91Sopenharmony_ci            raw,
201b8a62b91Sopenharmony_ci            _phantom: PhantomData,
202b8a62b91Sopenharmony_ci        }
203b8a62b91Sopenharmony_ci    }
204b8a62b91Sopenharmony_ci}
205b8a62b91Sopenharmony_ci
206b8a62b91Sopenharmony_ci#[repr(transparent)]
207b8a62b91Sopenharmony_cipub(super) struct SyscallNumber<'a> {
208b8a62b91Sopenharmony_ci    nr: usize,
209b8a62b91Sopenharmony_ci    _phantom: PhantomData<&'a ()>,
210b8a62b91Sopenharmony_ci}
211b8a62b91Sopenharmony_ci
212b8a62b91Sopenharmony_ciimpl<'a> ToAsm for SyscallNumber<'a> {
213b8a62b91Sopenharmony_ci    #[inline]
214b8a62b91Sopenharmony_ci    unsafe fn to_asm(self) -> *mut Opaque {
215b8a62b91Sopenharmony_ci        self.nr as usize as *mut Opaque
216b8a62b91Sopenharmony_ci    }
217b8a62b91Sopenharmony_ci}
218b8a62b91Sopenharmony_ci
219b8a62b91Sopenharmony_ci/// Encode a system call argument as an `ArgReg`.
220b8a62b91Sopenharmony_ci#[inline]
221b8a62b91Sopenharmony_cipub(super) fn raw_arg<'a, Num: ArgNumber>(raw: *mut Opaque) -> ArgReg<'a, Num> {
222b8a62b91Sopenharmony_ci    ArgReg {
223b8a62b91Sopenharmony_ci        raw,
224b8a62b91Sopenharmony_ci        _phantom: PhantomData,
225b8a62b91Sopenharmony_ci    }
226b8a62b91Sopenharmony_ci}
227b8a62b91Sopenharmony_ci
228b8a62b91Sopenharmony_ci/// Encode a system call number (a `__NR_*` constant) as a `SyscallNumber`.
229b8a62b91Sopenharmony_ci#[inline]
230b8a62b91Sopenharmony_cipub(super) const fn nr<'a>(nr: u32) -> SyscallNumber<'a> {
231b8a62b91Sopenharmony_ci    SyscallNumber {
232b8a62b91Sopenharmony_ci        nr: nr as usize,
233b8a62b91Sopenharmony_ci        _phantom: PhantomData,
234b8a62b91Sopenharmony_ci    }
235b8a62b91Sopenharmony_ci}
236b8a62b91Sopenharmony_ci
237b8a62b91Sopenharmony_ci/// Seal our various traits using the technique documented [here].
238b8a62b91Sopenharmony_ci///
239b8a62b91Sopenharmony_ci/// [here]: https://rust-lang.github.io/api-guidelines/future-proofing.html
240b8a62b91Sopenharmony_cimod private {
241b8a62b91Sopenharmony_ci    pub trait Sealed {}
242b8a62b91Sopenharmony_ci
243b8a62b91Sopenharmony_ci    // Implement for those same types, but no others.
244b8a62b91Sopenharmony_ci    impl<'a, Num: super::ArgNumber> Sealed for super::ArgReg<'a, Num> {}
245b8a62b91Sopenharmony_ci    impl<Num: super::RetNumber> Sealed for super::RetReg<Num> {}
246b8a62b91Sopenharmony_ci    impl<'a> Sealed for super::SyscallNumber<'a> {}
247b8a62b91Sopenharmony_ci    impl Sealed for super::A0 {}
248b8a62b91Sopenharmony_ci    impl Sealed for super::A1 {}
249b8a62b91Sopenharmony_ci    impl Sealed for super::A2 {}
250b8a62b91Sopenharmony_ci    impl Sealed for super::A3 {}
251b8a62b91Sopenharmony_ci    impl Sealed for super::A4 {}
252b8a62b91Sopenharmony_ci    impl Sealed for super::A5 {}
253b8a62b91Sopenharmony_ci    #[cfg(target_arch = "mips")]
254b8a62b91Sopenharmony_ci    impl Sealed for super::A6 {}
255b8a62b91Sopenharmony_ci    #[cfg(target_arch = "x86")]
256b8a62b91Sopenharmony_ci    impl Sealed for super::SocketArg {}
257b8a62b91Sopenharmony_ci    impl Sealed for super::R0 {}
258b8a62b91Sopenharmony_ci}
259