| //! linux_raw syscalls supporting `rustix::io`. |
| //! |
| //! # Safety |
| //! |
| //! See the `rustix::backend` module documentation for details. |
| #![allow(unsafe_code)] |
| #![allow(clippy::undocumented_unsafe_blocks)] |
| |
| #[cfg(any(linux_kernel, freebsdlike, netbsdlike))] |
| use super::types::MlockAllFlags; |
| use super::types::{ |
| Advice, MapFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags, |
| UserfaultfdFlags, |
| }; |
| use crate::backend::c; |
| #[cfg(target_pointer_width = "64")] |
| use crate::backend::conv::loff_t_from_u64; |
| use crate::backend::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star}; |
| use crate::fd::{BorrowedFd, OwnedFd}; |
| use crate::io; |
| use linux_raw_sys::general::MAP_ANONYMOUS; |
| |
| #[inline] |
| pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { |
| unsafe { |
| ret(syscall!( |
| __NR_madvise, |
| addr, |
| pass_usize(len), |
| c_uint(advice as c::c_uint) |
| )) |
| } |
| } |
| |
| #[inline] |
| pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { |
| ret(syscall!(__NR_msync, addr, pass_usize(len), flags)) |
| } |
| |
| /// # Safety |
| /// |
| /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working |
| /// with memory pointed to by raw pointers is unsafe. |
| #[inline] |
| pub(crate) unsafe fn mmap( |
| addr: *mut c::c_void, |
| length: usize, |
| prot: ProtFlags, |
| flags: MapFlags, |
| fd: BorrowedFd<'_>, |
| offset: u64, |
| ) -> io::Result<*mut c::c_void> { |
| #[cfg(target_pointer_width = "32")] |
| { |
| ret_void_star(syscall!( |
| __NR_mmap2, |
| addr, |
| pass_usize(length), |
| prot, |
| flags, |
| fd, |
| (offset / 4096) |
| .try_into() |
| .map(pass_usize) |
| .map_err(|_| io::Errno::INVAL)? |
| )) |
| } |
| #[cfg(target_pointer_width = "64")] |
| { |
| ret_void_star(syscall!( |
| __NR_mmap, |
| addr, |
| pass_usize(length), |
| prot, |
| flags, |
| fd, |
| loff_t_from_u64(offset) |
| )) |
| } |
| } |
| |
| /// # Safety |
| /// |
| /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working |
| /// with memory pointed to by raw pointers is unsafe. |
| #[inline] |
| pub(crate) unsafe fn mmap_anonymous( |
| addr: *mut c::c_void, |
| length: usize, |
| prot: ProtFlags, |
| flags: MapFlags, |
| ) -> io::Result<*mut c::c_void> { |
| #[cfg(target_pointer_width = "32")] |
| { |
| ret_void_star(syscall!( |
| __NR_mmap2, |
| addr, |
| pass_usize(length), |
| prot, |
| c_uint(flags.bits() | MAP_ANONYMOUS), |
| no_fd(), |
| pass_usize(0) |
| )) |
| } |
| #[cfg(target_pointer_width = "64")] |
| { |
| ret_void_star(syscall!( |
| __NR_mmap, |
| addr, |
| pass_usize(length), |
| prot, |
| c_uint(flags.bits() | MAP_ANONYMOUS), |
| no_fd(), |
| loff_t_from_u64(0) |
| )) |
| } |
| } |
| |
| #[inline] |
| pub(crate) unsafe fn mprotect( |
| ptr: *mut c::c_void, |
| len: usize, |
| flags: MprotectFlags, |
| ) -> io::Result<()> { |
| ret(syscall!(__NR_mprotect, ptr, pass_usize(len), flags)) |
| } |
| |
| /// # Safety |
| /// |
| /// `munmap` is primarily unsafe due to the `addr` parameter, as anything |
| /// working with memory pointed to by raw pointers is unsafe. |
| #[inline] |
| pub(crate) unsafe fn munmap(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
| ret(syscall!(__NR_munmap, addr, pass_usize(length))) |
| } |
| |
| /// # Safety |
| /// |
| /// `mremap` is primarily unsafe due to the `old_address` parameter, as |
| /// anything working with memory pointed to by raw pointers is unsafe. |
| #[inline] |
| pub(crate) unsafe fn mremap( |
| old_address: *mut c::c_void, |
| old_size: usize, |
| new_size: usize, |
| flags: MremapFlags, |
| ) -> io::Result<*mut c::c_void> { |
| ret_void_star(syscall!( |
| __NR_mremap, |
| old_address, |
| pass_usize(old_size), |
| pass_usize(new_size), |
| flags |
| )) |
| } |
| |
| /// # Safety |
| /// |
| /// `mremap_fixed` is primarily unsafe due to the `old_address` and |
| /// `new_address` parameters, as anything working with memory pointed to by raw |
| /// pointers is unsafe. |
| #[inline] |
| pub(crate) unsafe fn mremap_fixed( |
| old_address: *mut c::c_void, |
| old_size: usize, |
| new_size: usize, |
| flags: MremapFlags, |
| new_address: *mut c::c_void, |
| ) -> io::Result<*mut c::c_void> { |
| ret_void_star(syscall!( |
| __NR_mremap, |
| old_address, |
| pass_usize(old_size), |
| pass_usize(new_size), |
| flags, |
| new_address |
| )) |
| } |
| |
| /// # Safety |
| /// |
| /// `mlock` operates on raw pointers and may round out to the nearest page |
| /// boundaries. |
| #[inline] |
| pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
| ret(syscall!(__NR_mlock, addr, pass_usize(length))) |
| } |
| |
| /// # Safety |
| /// |
| /// `mlock_with` operates on raw pointers and may round out to the nearest page |
| /// boundaries. |
| #[inline] |
| pub(crate) unsafe fn mlock_with( |
| addr: *mut c::c_void, |
| length: usize, |
| flags: MlockFlags, |
| ) -> io::Result<()> { |
| ret(syscall!(__NR_mlock2, addr, pass_usize(length), flags)) |
| } |
| |
| /// # Safety |
| /// |
| /// `munlock` operates on raw pointers and may round out to the nearest page |
| /// boundaries. |
| #[inline] |
| pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
| ret(syscall!(__NR_munlock, addr, pass_usize(length))) |
| } |
| |
| #[inline] |
| pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { |
| ret_owned_fd(syscall_readonly!(__NR_userfaultfd, flags)) |
| } |
| |
| /// Locks all pages mapped into the address space of the calling process. |
| /// |
| /// This includes the pages of the code, data and stack segment, as well as shared libraries, |
| /// user space kernel data, shared memory, and memory-mapped files. All mapped pages are |
| /// guaranteed to be resident in RAM when the call returns successfully; |
| /// the pages are guaranteed to stay in RAM until later unlocked. |
| #[inline] |
| #[cfg(any(linux_kernel, freebsdlike, netbsdlike))] |
| pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> { |
| // When `mlockall` is used with `MCL_ONFAULT | MCL_FUTURE`, the ordering |
| // of `mlockall` with respect to arbitrary loads may be significant, |
| // because if a load happens and evokes a fault before the `mlockall`, |
| // the memory doesn't get locked, but if the load and therefore |
| // the fault happens after, then the memory does get locked. |
| // So to be conservative in this regard, we use `syscall` instead |
| // of `syscall_readonly` |
| unsafe { ret(syscall!(__NR_mlockall, flags)) } |
| } |
| |
| /// Unlocks all pages mapped into the address space of the calling process. |
| #[inline] |
| #[cfg(any(linux_kernel, freebsdlike, netbsdlike))] |
| pub(crate) fn munlockall() -> io::Result<()> { |
| unsafe { ret(syscall_readonly!(__NR_munlockall)) } |
| } |