1 use crate::Result; 2 #[cfg(not(target_os = "android"))] 3 use crate::NixPath; 4 use crate::errno::Errno; 5 #[cfg(not(target_os = "android"))] 6 use crate::fcntl::OFlag; 7 use libc::{self, c_int, c_void, size_t, off_t}; 8 #[cfg(not(target_os = "android"))] 9 use crate::sys::stat::Mode; 10 use std::os::unix::io::RawFd; 11 12 libc_bitflags!{ memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd>13 /// Desired memory protection of a memory mapping. 14 pub struct ProtFlags: c_int { 15 /// Pages cannot be accessed. 16 PROT_NONE; 17 /// Pages can be read. 18 PROT_READ; 19 /// Pages can be written. 20 PROT_WRITE; 21 /// Pages can be executed 22 PROT_EXEC; 23 /// Apply protection up to the end of a mapping that grows upwards. 24 #[cfg(any(target_os = "android", target_os = "linux"))] 25 PROT_GROWSDOWN; 26 /// Apply protection down to the beginning of a mapping that grows downwards. 27 #[cfg(any(target_os = "android", target_os = "linux"))] 28 PROT_GROWSUP; 29 } 30 } 31 32 libc_bitflags!{ 33 /// Additional parameters for `mmap()`. 34 pub struct MapFlags: c_int { 35 /// Compatibility flag. Ignored. 36 MAP_FILE; 37 /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`. 38 MAP_SHARED; 39 /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`. 40 MAP_PRIVATE; 41 /// Place the mapping at exactly the address specified in `addr`. 42 MAP_FIXED; 43 /// To be used with `MAP_FIXED`, to forbid the system 44 /// to select a different address than the one specified. 45 #[cfg(target_os = "freebsd")] 46 MAP_EXCL; 47 /// Synonym for `MAP_ANONYMOUS`. 48 MAP_ANON; 49 /// The mapping is not backed by any file. 50 MAP_ANONYMOUS; 51 /// Put the mapping into the first 2GB of the process address space. 52 #[cfg(any(all(any(target_os = "android", target_os = "linux"), 53 any(target_arch = "x86", target_arch = "x86_64")), 54 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), 55 all(target_os = "freebsd", target_pointer_width = "64")))] 56 MAP_32BIT; 57 /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. 58 #[cfg(any(target_os = "android", target_os = "linux"))] 59 MAP_GROWSDOWN; 60 /// Compatibility flag. Ignored. 61 #[cfg(any(target_os = "android", target_os = "linux"))] 62 MAP_DENYWRITE; 63 /// Compatibility flag. Ignored. 64 #[cfg(any(target_os = "android", target_os = "linux"))] 65 MAP_EXECUTABLE; 66 /// Mark the mmaped region to be locked in the same way as `mlock(2)`. 67 #[cfg(any(target_os = "android", target_os = "linux"))] 68 MAP_LOCKED; 69 /// Do not reserve swap space for this mapping. 70 /// 71 /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. 72 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] 73 MAP_NORESERVE; 74 /// Populate page tables for a mapping. 75 #[cfg(any(target_os = "android", target_os = "linux"))] 76 MAP_POPULATE; 77 /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. 78 #[cfg(any(target_os = "android", target_os = "linux"))] 79 MAP_NONBLOCK; 80 /// Allocate the mapping using "huge pages." 81 #[cfg(any(target_os = "android", target_os = "linux"))] 82 MAP_HUGETLB; 83 /// Make use of 64KB huge page (must be supported by the system) 84 #[cfg(target_os = "linux")] 85 MAP_HUGE_64KB; 86 /// Make use of 512KB huge page (must be supported by the system) 87 #[cfg(target_os = "linux")] 88 MAP_HUGE_512KB; 89 /// Make use of 1MB huge page (must be supported by the system) 90 #[cfg(target_os = "linux")] 91 MAP_HUGE_1MB; 92 /// Make use of 2MB huge page (must be supported by the system) 93 #[cfg(target_os = "linux")] 94 MAP_HUGE_2MB; 95 /// Make use of 8MB huge page (must be supported by the system) 96 #[cfg(target_os = "linux")] 97 MAP_HUGE_8MB; 98 /// Make use of 16MB huge page (must be supported by the system) 99 #[cfg(target_os = "linux")] 100 MAP_HUGE_16MB; 101 /// Make use of 32MB huge page (must be supported by the system) 102 #[cfg(target_os = "linux")] 103 MAP_HUGE_32MB; 104 /// Make use of 256MB huge page (must be supported by the system) 105 #[cfg(target_os = "linux")] 106 MAP_HUGE_256MB; 107 /// Make use of 512MB huge page (must be supported by the system) 108 #[cfg(target_os = "linux")] 109 MAP_HUGE_512MB; 110 /// Make use of 1GB huge page (must be supported by the system) 111 #[cfg(target_os = "linux")] 112 MAP_HUGE_1GB; 113 /// Make use of 2GB huge page (must be supported by the system) 114 #[cfg(target_os = "linux")] 115 MAP_HUGE_2GB; 116 /// Make use of 16GB huge page (must be supported by the system) 117 #[cfg(target_os = "linux")] 118 MAP_HUGE_16GB; 119 120 /// Lock the mapped region into memory as with `mlock(2)`. 121 #[cfg(target_os = "netbsd")] 122 MAP_WIRED; 123 /// Causes dirtied data in the specified range to be flushed to disk only when necessary. 124 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 125 MAP_NOSYNC; 126 /// Rename private pages to a file. 127 /// 128 /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. 129 #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] 130 MAP_RENAME; 131 /// Region may contain semaphores. 132 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] 133 MAP_HASSEMAPHORE; 134 /// Region grows down, like a stack. 135 #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] 136 MAP_STACK; 137 /// Pages in this mapping are not retained in the kernel's memory cache. 138 #[cfg(any(target_os = "ios", target_os = "macos"))] 139 MAP_NOCACHE; 140 /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. 141 #[cfg(any(target_os = "ios", target_os = "macos"))] 142 MAP_JIT; 143 /// Allows to use large pages, underlying alignment based on size. 144 #[cfg(target_os = "freesd")] 145 MAP_ALIGNED_SUPER; 146 /// Pages will be discarded in the core dumps. 147 #[cfg(target_os = "openbsd")] 148 MAP_CONCEAL; 149 } 150 } 151 152 #[cfg(any(target_os = "linux", target_os = "netbsd"))] 153 libc_bitflags!{ 154 /// Options for `mremap()`. 155 pub struct MRemapFlags: c_int { 156 /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. 157 #[cfg(target_os = "linux")] 158 MREMAP_MAYMOVE; 159 /// Place the mapping at exactly the address specified in `new_address`. 160 #[cfg(target_os = "linux")] 161 MREMAP_FIXED; 162 /// Permits to use the old and new address as hints to relocate the mapping. 163 #[cfg(target_os = "netbsd")] 164 MAP_FIXED; 165 /// Allows to duplicate the mapping to be able to apply different flags on the copy. 166 #[cfg(target_os = "netbsd")] 167 MAP_REMAPDUP; 168 } 169 } 170 171 libc_enum!{ 172 /// Usage information for a range of memory to allow for performance optimizations by the kernel. 173 /// 174 /// Used by [`madvise`](./fn.madvise.html). 175 #[repr(i32)] 176 #[non_exhaustive] 177 pub enum MmapAdvise { 178 /// No further special treatment. This is the default. 179 MADV_NORMAL, 180 /// Expect random page references. 181 MADV_RANDOM, 182 /// Expect sequential page references. 183 MADV_SEQUENTIAL, 184 /// Expect access in the near future. 185 MADV_WILLNEED, 186 /// Do not expect access in the near future. 187 MADV_DONTNEED, 188 /// Free up a given range of pages and its associated backing store. 189 #[cfg(any(target_os = "android", target_os = "linux"))] 190 MADV_REMOVE, 191 /// Do not make pages in this range available to the child after a `fork(2)`. 192 #[cfg(any(target_os = "android", target_os = "linux"))] 193 MADV_DONTFORK, 194 /// Undo the effect of `MADV_DONTFORK`. 195 #[cfg(any(target_os = "android", target_os = "linux"))] 196 MADV_DOFORK, 197 /// Poison the given pages. 198 /// 199 /// Subsequent references to those pages are treated like hardware memory corruption. 200 #[cfg(any(target_os = "android", target_os = "linux"))] 201 MADV_HWPOISON, 202 /// Enable Kernel Samepage Merging (KSM) for the given pages. 203 #[cfg(any(target_os = "android", target_os = "linux"))] 204 MADV_MERGEABLE, 205 /// Undo the effect of `MADV_MERGEABLE` 206 #[cfg(any(target_os = "android", target_os = "linux"))] 207 MADV_UNMERGEABLE, 208 /// Preserve the memory of each page but offline the original page. 209 #[cfg(any(target_os = "android", 210 all(target_os = "linux", any( 211 target_arch = "aarch64", 212 target_arch = "arm", 213 target_arch = "ppc", 214 target_arch = "s390x", 215 target_arch = "x86", 216 target_arch = "x86_64", 217 target_arch = "sparc64"))))] 218 MADV_SOFT_OFFLINE, 219 /// Enable Transparent Huge Pages (THP) for pages in the given range. 220 #[cfg(any(target_os = "android", target_os = "linux"))] 221 MADV_HUGEPAGE, 222 /// Undo the effect of `MADV_HUGEPAGE`. 223 #[cfg(any(target_os = "android", target_os = "linux"))] 224 MADV_NOHUGEPAGE, 225 /// Exclude the given range from a core dump. 226 #[cfg(any(target_os = "android", target_os = "linux"))] 227 MADV_DONTDUMP, 228 /// Undo the effect of an earlier `MADV_DONTDUMP`. 229 #[cfg(any(target_os = "android", target_os = "linux"))] 230 MADV_DODUMP, 231 /// Specify that the application no longer needs the pages in the given range. 232 MADV_FREE, 233 /// Request that the system not flush the current range to disk unless it needs to. 234 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 235 MADV_NOSYNC, 236 /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. 237 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 238 MADV_AUTOSYNC, 239 /// Region is not included in a core file. 240 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 241 MADV_NOCORE, 242 /// Include region in a core file 243 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 244 MADV_CORE, 245 #[cfg(any(target_os = "freebsd"))] 246 MADV_PROTECT, 247 /// Invalidate the hardware page table for the given region. 248 #[cfg(target_os = "dragonfly")] 249 MADV_INVAL, 250 /// Set the offset of the page directory page to `value` for the virtual page table. 251 #[cfg(target_os = "dragonfly")] 252 MADV_SETMAP, 253 /// Indicates that the application will not need the data in the given range. 254 #[cfg(any(target_os = "ios", target_os = "macos"))] 255 MADV_ZERO_WIRED_PAGES, 256 #[cfg(any(target_os = "ios", target_os = "macos"))] 257 MADV_FREE_REUSABLE, 258 #[cfg(any(target_os = "ios", target_os = "macos"))] 259 MADV_FREE_REUSE, 260 #[cfg(any(target_os = "ios", target_os = "macos"))] 261 MADV_CAN_REUSE, 262 } 263 } 264 265 libc_bitflags!{ 266 /// Configuration flags for `msync`. 267 pub struct MsFlags: c_int { 268 /// Schedule an update but return immediately. 269 MS_ASYNC; 270 /// Invalidate all cached data. 271 MS_INVALIDATE; 272 /// Invalidate pages, but leave them mapped. 273 #[cfg(any(target_os = "ios", target_os = "macos"))] 274 MS_KILLPAGES; 275 /// Deactivate pages, but leave them mapped. 276 #[cfg(any(target_os = "ios", target_os = "macos"))] 277 MS_DEACTIVATE; 278 /// Perform an update and wait for it to complete. 279 MS_SYNC; 280 } 281 } 282 283 libc_bitflags!{ 284 /// Flags for `mlockall`. 285 pub struct MlockAllFlags: c_int { 286 /// Lock pages that are currently mapped into the address space of the process. 287 MCL_CURRENT; 288 /// Lock pages which will become mapped into the address space of the process in the future. 289 MCL_FUTURE; 290 } 291 } 292 293 /// Locks all memory pages that contain part of the address range with `length` 294 /// bytes starting at `addr`. 295 /// 296 /// Locked pages never move to the swap area. 297 /// 298 /// # Safety 299 /// 300 /// `addr` must meet all the requirements described in the `mlock(2)` man page. 301 pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { 302 Errno::result(libc::mlock(addr, length)).map(drop) 303 } 304 305 /// Unlocks all memory pages that contain part of the address range with 306 /// `length` bytes starting at `addr`. 307 /// 308 /// # Safety 309 /// 310 /// `addr` must meet all the requirements described in the `munlock(2)` man 311 /// page. 312 pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { 313 Errno::result(libc::munlock(addr, length)).map(drop) 314 } 315 316 /// Locks all memory pages mapped into this process' address space. 317 /// 318 /// Locked pages never move to the swap area. 319 /// 320 /// # Safety 321 /// 322 /// `addr` must meet all the requirements described in the `mlockall(2)` man 323 /// page. 324 pub fn mlockall(flags: MlockAllFlags) -> Result<()> { 325 unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) 326 } 327 328 /// Unlocks all memory pages mapped into this process' address space. 329 pub fn munlockall() -> Result<()> { 330 unsafe { Errno::result(libc::munlockall()) }.map(drop) 331 } 332 333 /// allocate memory, or map files or devices into memory 334 /// 335 /// # Safety 336 /// 337 /// See the `mmap(2)` man page for detailed requirements. 338 pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> { 339 let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset); 340 341 if ret == libc::MAP_FAILED { 342 Err(Errno::last()) 343 } else { 344 Ok(ret) 345 } 346 } 347 348 /// Expands (or shrinks) an existing memory mapping, potentially moving it at 349 /// the same time. 350 /// 351 /// # Safety 352 /// 353 /// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for 354 /// detailed requirements. 355 #[cfg(any(target_os = "linux", target_os = "netbsd"))] 356 pub unsafe fn mremap( 357 addr: *mut c_void, 358 old_size: size_t, 359 new_size: size_t, 360 flags: MRemapFlags, 361 new_address: Option<* mut c_void>, 362 ) -> Result<*mut c_void> { 363 #[cfg(target_os = "linux")] 364 let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut())); 365 #[cfg(target_os = "netbsd")] 366 let ret = libc::mremap( 367 addr, 368 old_size, 369 new_address.unwrap_or(std::ptr::null_mut()), 370 new_size, 371 flags.bits(), 372 ); 373 374 if ret == libc::MAP_FAILED { 375 Err(Errno::last()) 376 } else { 377 Ok(ret) 378 } 379 } 380 381 /// remove a mapping 382 /// 383 /// # Safety 384 /// 385 /// `addr` must meet all the requirements described in the `munmap(2)` man 386 /// page. 387 pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { 388 Errno::result(libc::munmap(addr, len)).map(drop) 389 } 390 391 /// give advice about use of memory 392 /// 393 /// # Safety 394 /// 395 /// See the `madvise(2)` man page. Take special care when using 396 /// `MmapAdvise::MADV_FREE`. 397 pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> { 398 Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) 399 } 400 401 /// Set protection of memory mapping. 402 /// 403 /// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for 404 /// details. 405 /// 406 /// # Safety 407 /// 408 /// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to 409 /// SIGSEGVs. 410 /// 411 /// ``` 412 /// # use nix::libc::size_t; 413 /// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; 414 /// # use std::ptr; 415 /// const ONE_K: size_t = 1024; 416 /// let mut slice: &mut [u8] = unsafe { 417 /// let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE, 418 /// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); 419 /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); 420 /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) 421 /// }; 422 /// assert_eq!(slice[0], 0x00); 423 /// slice[0] = 0xFF; 424 /// assert_eq!(slice[0], 0xFF); 425 /// ``` 426 pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> { 427 Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) 428 } 429 430 /// synchronize a mapped region 431 /// 432 /// # Safety 433 /// 434 /// `addr` must meet all the requirements described in the `msync(2)` man 435 /// page. 436 pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> { 437 Errno::result(libc::msync(addr, length, flags.bits())).map(drop) 438 } 439 440 #[cfg(not(target_os = "android"))] 441 pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> { 442 let ret = name.with_nix_path(|cstr| { 443 #[cfg(any(target_os = "macos", target_os = "ios"))] 444 unsafe { 445 libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) 446 } 447 #[cfg(not(any(target_os = "macos", target_os = "ios")))] 448 unsafe { 449 libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) 450 } 451 })?; 452 453 Errno::result(ret) 454 } 455 456 #[cfg(not(target_os = "android"))] 457 pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> { 458 let ret = name.with_nix_path(|cstr| { 459 unsafe { libc::shm_unlink(cstr.as_ptr()) } 460 })?; 461 462 Errno::result(ret).map(drop) 463 } 464