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