1//! libc syscalls supporting `rustix::mm`. 2 3use super::super::c; 4#[cfg(any(target_os = "android", target_os = "linux"))] 5use super::super::conv::syscall_ret_owned_fd; 6use super::super::conv::{borrowed_fd, no_fd, ret}; 7use super::super::offset::libc_mmap; 8#[cfg(not(target_os = "redox"))] 9use super::types::Advice; 10#[cfg(target_os = "linux")] 11use super::types::MremapFlags; 12use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags}; 13#[cfg(any(target_os = "android", target_os = "linux"))] 14use super::types::{MlockFlags, UserfaultfdFlags}; 15use crate::fd::BorrowedFd; 16#[cfg(any(target_os = "android", target_os = "linux"))] 17use crate::fd::OwnedFd; 18use crate::io; 19 20#[cfg(not(target_os = "redox"))] 21pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { 22 // On Linux platforms, `MADV_DONTNEED` has the same value as 23 // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different 24 // value, and check for it here. 25 #[cfg(target_os = "linux")] 26 if let Advice::LinuxDontNeed = advice { 27 return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) }; 28 } 29 30 #[cfg(not(target_os = "android"))] 31 { 32 let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) }; 33 34 // `posix_madvise` returns its error status rather than using `errno`. 35 if err == 0 { 36 Ok(()) 37 } else { 38 Err(io::Errno(err)) 39 } 40 } 41 42 #[cfg(target_os = "android")] 43 { 44 if let Advice::DontNeed = advice { 45 // Do nothing. Linux's `MADV_DONTNEED` isn't the same as 46 // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`. 47 Ok(()) 48 } else { 49 unsafe { ret(c::madvise(addr, len, advice as c::c_int)) } 50 } 51 } 52} 53 54pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { 55 let err = c::msync(addr, len, flags.bits()); 56 57 // `msync` returns its error status rather than using `errno`. 58 if err == 0 { 59 Ok(()) 60 } else { 61 Err(io::Errno(err)) 62 } 63} 64 65/// # Safety 66/// 67/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working 68/// with memory pointed to by raw pointers is unsafe. 69pub(crate) unsafe fn mmap( 70 ptr: *mut c::c_void, 71 len: usize, 72 prot: ProtFlags, 73 flags: MapFlags, 74 fd: BorrowedFd<'_>, 75 offset: u64, 76) -> io::Result<*mut c::c_void> { 77 let res = libc_mmap( 78 ptr, 79 len, 80 prot.bits(), 81 flags.bits(), 82 borrowed_fd(fd), 83 offset as i64, 84 ); 85 if res == c::MAP_FAILED { 86 Err(io::Errno::last_os_error()) 87 } else { 88 Ok(res) 89 } 90} 91 92/// # Safety 93/// 94/// `mmap` is primarily unsafe due to the `addr` parameter, as anything working 95/// with memory pointed to by raw pointers is unsafe. 96pub(crate) unsafe fn mmap_anonymous( 97 ptr: *mut c::c_void, 98 len: usize, 99 prot: ProtFlags, 100 flags: MapFlags, 101) -> io::Result<*mut c::c_void> { 102 let res = libc_mmap( 103 ptr, 104 len, 105 prot.bits(), 106 flags.bits() | c::MAP_ANONYMOUS, 107 no_fd(), 108 0, 109 ); 110 if res == c::MAP_FAILED { 111 Err(io::Errno::last_os_error()) 112 } else { 113 Ok(res) 114 } 115} 116 117pub(crate) unsafe fn mprotect( 118 ptr: *mut c::c_void, 119 len: usize, 120 flags: MprotectFlags, 121) -> io::Result<()> { 122 ret(c::mprotect(ptr, len, flags.bits())) 123} 124 125pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> { 126 ret(c::munmap(ptr, len)) 127} 128 129/// # Safety 130/// 131/// `mremap` is primarily unsafe due to the `old_address` parameter, as 132/// anything working with memory pointed to by raw pointers is unsafe. 133#[cfg(target_os = "linux")] 134pub(crate) unsafe fn mremap( 135 old_address: *mut c::c_void, 136 old_size: usize, 137 new_size: usize, 138 flags: MremapFlags, 139) -> io::Result<*mut c::c_void> { 140 let res = c::mremap(old_address, old_size, new_size, flags.bits()); 141 if res == c::MAP_FAILED { 142 Err(io::Errno::last_os_error()) 143 } else { 144 Ok(res) 145 } 146} 147 148/// # Safety 149/// 150/// `mremap_fixed` is primarily unsafe due to the `old_address` and 151/// `new_address` parameters, as anything working with memory pointed to by raw 152/// pointers is unsafe. 153#[cfg(target_os = "linux")] 154pub(crate) unsafe fn mremap_fixed( 155 old_address: *mut c::c_void, 156 old_size: usize, 157 new_size: usize, 158 flags: MremapFlags, 159 new_address: *mut c::c_void, 160) -> io::Result<*mut c::c_void> { 161 let res = c::mremap( 162 old_address, 163 old_size, 164 new_size, 165 flags.bits() | c::MAP_FIXED, 166 new_address, 167 ); 168 if res == c::MAP_FAILED { 169 Err(io::Errno::last_os_error()) 170 } else { 171 Ok(res) 172 } 173} 174 175/// # Safety 176/// 177/// `mlock` operates on raw pointers and may round out to the nearest page 178/// boundaries. 179#[inline] 180pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { 181 ret(c::mlock(addr, length)) 182} 183 184/// # Safety 185/// 186/// `mlock_with` operates on raw pointers and may round out to the nearest page 187/// boundaries. 188#[cfg(any(target_os = "android", target_os = "linux"))] 189#[inline] 190pub(crate) unsafe fn mlock_with( 191 addr: *mut c::c_void, 192 length: usize, 193 flags: MlockFlags, 194) -> io::Result<()> { 195 weak_or_syscall! { 196 fn mlock2( 197 addr: *const c::c_void, 198 len: c::size_t, 199 flags: c::c_int 200 ) via SYS_mlock2 -> c::c_int 201 } 202 203 ret(mlock2(addr, length, flags.bits())) 204} 205 206/// # Safety 207/// 208/// `munlock` operates on raw pointers and may round out to the nearest page 209/// boundaries. 210#[inline] 211pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { 212 ret(c::munlock(addr, length)) 213} 214 215#[cfg(any(target_os = "android", target_os = "linux"))] 216pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { 217 syscall_ret_owned_fd(c::syscall(c::SYS_userfaultfd, flags.bits())) 218} 219