1 | //! The `mmap` API. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! `mmap` and related functions manipulate raw pointers and have special |
6 | //! semantics. |
7 | #![allow (unsafe_code)] |
8 | |
9 | use crate::{backend, io}; |
10 | use backend::fd::AsFd; |
11 | use core::ffi::c_void; |
12 | |
13 | #[cfg (any(linux_kernel, freebsdlike, netbsdlike))] |
14 | pub use backend::mm::types::MlockAllFlags; |
15 | #[cfg (linux_kernel)] |
16 | pub use backend::mm::types::MlockFlags; |
17 | #[cfg (any(target_os = "emscripten" , target_os = "linux" ))] |
18 | pub use backend::mm::types::MremapFlags; |
19 | pub use backend::mm::types::{MapFlags, MprotectFlags, ProtFlags}; |
20 | |
21 | impl MapFlags { |
22 | /// Create `MAP_HUGETLB` with provided size of huge page. |
23 | /// |
24 | /// Under the hood it computes |
25 | /// `MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT)`. |
26 | /// `huge_page_size_log2` denotes logarithm of huge page size to use and |
27 | /// should be between 16 and 63 (inclusive). |
28 | /// |
29 | /// ``` |
30 | /// use rustix::mm::MapFlags; |
31 | /// |
32 | /// let f = MapFlags::hugetlb_with_size_log2(30).unwrap(); |
33 | /// assert_eq!(f, MapFlags::HUGETLB | MapFlags::HUGE_1GB); |
34 | /// ``` |
35 | #[cfg (linux_kernel)] |
36 | pub const fn hugetlb_with_size_log2(huge_page_size_log2: u32) -> Option<Self> { |
37 | use linux_raw_sys::general::{MAP_HUGETLB, MAP_HUGE_SHIFT}; |
38 | if 16 <= huge_page_size_log2 && huge_page_size_log2 <= 63 { |
39 | let bits = MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT); |
40 | Self::from_bits(bits) |
41 | } else { |
42 | None |
43 | } |
44 | } |
45 | } |
46 | |
47 | /// `mmap(ptr, len, prot, flags, fd, offset)`—Create a file-backed memory |
48 | /// mapping. |
49 | /// |
50 | /// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see |
51 | /// [`mmap_anonymous`]. |
52 | /// |
53 | /// # Safety |
54 | /// |
55 | /// If `ptr` is not null, it must be aligned to the applicable page size, and |
56 | /// the range of memory starting at `ptr` and extending for `len` bytes, |
57 | /// rounded up to the applicable page size, must be valid to mutate using |
58 | /// `ptr`'s provenance. |
59 | /// |
60 | /// If there exist any Rust references referring to the memory region, or if |
61 | /// you subsequently create a Rust reference referring to the resulting region, |
62 | /// it is your responsibility to ensure that the Rust reference invariants are |
63 | /// preserved, including ensuring that the memory is not mutated in a way that |
64 | /// a Rust reference would not expect. |
65 | /// |
66 | /// # References |
67 | /// - [POSIX] |
68 | /// - [Linux] |
69 | /// - [Apple] |
70 | /// - [FreeBSD] |
71 | /// - [NetBSD] |
72 | /// - [OpenBSD] |
73 | /// - [DragonFly BSD] |
74 | /// - [illumos] |
75 | /// - [glibc] |
76 | /// |
77 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html |
78 | /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html |
79 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html |
80 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 |
81 | /// [NetBSD]: https://man.netbsd.org/mmap.2 |
82 | /// [OpenBSD]: https://man.openbsd.org/mmap.2 |
83 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 |
84 | /// [illumos]: https://illumos.org/man/2/mmap |
85 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-mmap |
86 | #[inline ] |
87 | pub unsafe fn mmap<Fd: AsFd>( |
88 | ptr: *mut c_void, |
89 | len: usize, |
90 | prot: ProtFlags, |
91 | flags: MapFlags, |
92 | fd: Fd, |
93 | offset: u64, |
94 | ) -> io::Result<*mut c_void> { |
95 | backend::mm::syscalls::mmap(addr:ptr, length:len, prot, flags, fd.as_fd(), offset) |
96 | } |
97 | |
98 | /// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`—Create an anonymous |
99 | /// memory mapping. |
100 | /// |
101 | /// For file-backed mappings, see [`mmap`]. |
102 | /// |
103 | /// # Safety |
104 | /// |
105 | /// If `ptr` is not null, it must be aligned to the applicable page size, and |
106 | /// the range of memory starting at `ptr` and extending for `len` bytes, |
107 | /// rounded up to the applicable page size, must be valid to mutate with |
108 | /// `ptr`'s provenance. |
109 | /// |
110 | /// # References |
111 | /// - [POSIX] |
112 | /// - [Linux] |
113 | /// - [Apple] |
114 | /// - [FreeBSD] |
115 | /// - [NetBSD] |
116 | /// - [OpenBSD] |
117 | /// - [DragonFly BSD] |
118 | /// - [illumos] |
119 | /// - [glibc] |
120 | /// |
121 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html |
122 | /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html |
123 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html |
124 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 |
125 | /// [NetBSD]: https://man.netbsd.org/mmap.2 |
126 | /// [OpenBSD]: https://man.openbsd.org/mmap.2 |
127 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 |
128 | /// [illumos]: https://illumos.org/man/2/mmap |
129 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-mmap |
130 | #[inline ] |
131 | #[doc (alias = "mmap" )] |
132 | pub unsafe fn mmap_anonymous( |
133 | ptr: *mut c_void, |
134 | len: usize, |
135 | prot: ProtFlags, |
136 | flags: MapFlags, |
137 | ) -> io::Result<*mut c_void> { |
138 | backend::mm::syscalls::mmap_anonymous(addr:ptr, length:len, prot, flags) |
139 | } |
140 | |
141 | /// `munmap(ptr, len)`—Remove a memory mapping. |
142 | /// |
143 | /// # Safety |
144 | /// |
145 | /// `ptr` must be aligned to the applicable page size, and the range of memory |
146 | /// starting at `ptr` and extending for `len` bytes, rounded up to the |
147 | /// applicable page size, must be valid to mutate with `ptr`'s provenance. And |
148 | /// there must be no Rust references referring to that memory. |
149 | /// |
150 | /// # References |
151 | /// - [POSIX] |
152 | /// - [Linux] |
153 | /// - [Apple] |
154 | /// - [FreeBSD] |
155 | /// - [NetBSD] |
156 | /// - [OpenBSD] |
157 | /// - [DragonFly BSD] |
158 | /// - [illumos] |
159 | /// - [glibc] |
160 | /// |
161 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munmap.html |
162 | /// [Linux]: https://man7.org/linux/man-pages/man2/munmap.2.html |
163 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munmap.2.html |
164 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munmap&sektion=2 |
165 | /// [NetBSD]: https://man.netbsd.org/munmap.2 |
166 | /// [OpenBSD]: https://man.openbsd.org/munmap.2 |
167 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munmap§ion=2 |
168 | /// [illumos]: https://illumos.org/man/2/munmap |
169 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-munmap |
170 | #[inline ] |
171 | pub unsafe fn munmap(ptr: *mut c_void, len: usize) -> io::Result<()> { |
172 | backend::mm::syscalls::munmap(addr:ptr, length:len) |
173 | } |
174 | |
175 | /// `mremap(old_address, old_size, new_size, flags)`—Resize, modify, and/or |
176 | /// move a memory mapping. |
177 | /// |
178 | /// For moving a mapping to a fixed address (`MREMAP_FIXED`), see |
179 | /// [`mremap_fixed`]. |
180 | /// |
181 | /// # Safety |
182 | /// |
183 | /// `old_address` must be aligned to the applicable page size, and the range of |
184 | /// memory starting at `old_address` and extending for `old_size` bytes, |
185 | /// rounded up to the applicable page size, must be valid to mutate with |
186 | /// `old_address`'s provenance. If `MremapFlags::MAY_MOVE` is set in `flags`, |
187 | /// there must be no Rust references referring to that the memory. |
188 | /// |
189 | /// If `new_size` is less than `old_size`, than there must be no Rust |
190 | /// references referring to the memory starting at offset `new_size` and ending |
191 | /// at `old_size`. |
192 | /// |
193 | /// # References |
194 | /// - [Linux] |
195 | /// |
196 | /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html |
197 | #[cfg (any(target_os = "emscripten" , target_os = "linux" ))] |
198 | #[inline ] |
199 | pub unsafe fn mremap( |
200 | old_address: *mut c_void, |
201 | old_size: usize, |
202 | new_size: usize, |
203 | flags: MremapFlags, |
204 | ) -> io::Result<*mut c_void> { |
205 | backend::mm::syscalls::mremap(old_address, old_size, new_size, flags) |
206 | } |
207 | |
208 | /// `mremap(old_address, old_size, new_size, MREMAP_FIXED | flags)`—Resize, |
209 | /// modify, and/or move a memory mapping to a specific address. |
210 | /// |
211 | /// For `mremap` without moving to a specific address, see [`mremap`]. |
212 | /// [`mremap_fixed`]. |
213 | /// |
214 | /// # Safety |
215 | /// |
216 | /// `old_address` and `new_address` must be aligned to the applicable page |
217 | /// size, the range of memory starting at `old_address` and extending for |
218 | /// `old_size` bytes, rounded up to the applicable page size, must be valid to |
219 | /// mutate with `old_address`'s provenance, and the range of memory starting at |
220 | /// `new_address` and extending for `new_size` bytes, rounded up to the |
221 | /// applicable page size, must be valid to mutate with `new_address`'s |
222 | /// provenance. |
223 | /// |
224 | /// There must be no Rust references referring to either of those memory |
225 | /// regions. |
226 | /// |
227 | /// # References |
228 | /// - [Linux] |
229 | /// |
230 | /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html |
231 | #[cfg (any(target_os = "emscripten" , target_os = "linux" ))] |
232 | #[inline ] |
233 | #[doc (alias = "mremap" )] |
234 | pub unsafe fn mremap_fixed( |
235 | old_address: *mut c_void, |
236 | old_size: usize, |
237 | new_size: usize, |
238 | flags: MremapFlags, |
239 | new_address: *mut c_void, |
240 | ) -> io::Result<*mut c_void> { |
241 | backend::mm::syscalls::mremap_fixed(old_address, old_size, new_size, flags, new_address) |
242 | } |
243 | |
244 | /// `mprotect(ptr, len, flags)`—Change the protection flags of a region of |
245 | /// memory. |
246 | /// |
247 | /// # Safety |
248 | /// |
249 | /// The range of memory starting at `ptr` and extending for `len` bytes, |
250 | /// rounded up to the applicable page size, must be valid to read with `ptr`'s |
251 | /// provenance. |
252 | /// |
253 | /// # References |
254 | /// - [POSIX] |
255 | /// - [Linux] |
256 | /// - [Apple] |
257 | /// - [FreeBSD] |
258 | /// - [NetBSD] |
259 | /// - [OpenBSD] |
260 | /// - [DragonFly BSD] |
261 | /// - [illumos] |
262 | /// |
263 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mprotect.html |
264 | /// [Linux]: https://man7.org/linux/man-pages/man2/mprotect.2.html |
265 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html |
266 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mprotect&sektion=2 |
267 | /// [NetBSD]: https://man.netbsd.org/mprotect.2 |
268 | /// [OpenBSD]: https://man.openbsd.org/mprotect.2 |
269 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mprotect§ion=2 |
270 | /// [illumos]: https://illumos.org/man/2/mprotect |
271 | #[inline ] |
272 | pub unsafe fn mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()> { |
273 | backend::mm::syscalls::mprotect(ptr, len, flags) |
274 | } |
275 | |
276 | /// `mlock(ptr, len)`—Lock memory into RAM. |
277 | /// |
278 | /// Some implementations implicitly round the memory region out to the nearest |
279 | /// page boundaries, so this function may lock more memory than explicitly |
280 | /// requested if the memory isn't page-aligned. Other implementations fail if |
281 | /// the memory isn't page-aligned. |
282 | /// |
283 | /// # Safety |
284 | /// |
285 | /// The range of memory starting at `ptr`, rounded down to the applicable page |
286 | /// boundary, and extending for `len` bytes, rounded up to the applicable page |
287 | /// size, must be valid to read with `ptr`'s provenance. |
288 | /// |
289 | /// # References |
290 | /// - [POSIX] |
291 | /// - [Linux] |
292 | /// - [Apple] |
293 | /// - [FreeBSD] |
294 | /// - [NetBSD] |
295 | /// - [OpenBSD] |
296 | /// - [DragonFly BSD] |
297 | /// - [illumos] |
298 | /// - [glibc] |
299 | /// |
300 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mlock.html |
301 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlock.2.html |
302 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mlock.2.html |
303 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlock&sektion=2 |
304 | /// [NetBSD]: https://man.netbsd.org/mlock.2 |
305 | /// [OpenBSD]: https://man.openbsd.org/mlock.2 |
306 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlock§ion=2 |
307 | /// [illumos]: https://illumos.org/man/3C/mlock |
308 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlock |
309 | #[inline ] |
310 | pub unsafe fn mlock(ptr: *mut c_void, len: usize) -> io::Result<()> { |
311 | backend::mm::syscalls::mlock(addr:ptr, length:len) |
312 | } |
313 | |
314 | /// `mlock2(ptr, len, flags)`—Lock memory into RAM, with flags. |
315 | /// |
316 | /// `mlock_with` is the same as [`mlock`] but adds an additional flags operand. |
317 | /// |
318 | /// Some implementations implicitly round the memory region out to the nearest |
319 | /// page boundaries, so this function may lock more memory than explicitly |
320 | /// requested if the memory isn't page-aligned. |
321 | /// |
322 | /// # Safety |
323 | /// |
324 | /// The range of memory starting at `ptr`, rounded down to the applicable page |
325 | /// boundary, and extending for `len` bytes, rounded up to the applicable page |
326 | /// size, must be valid to read with `ptr`'s provenance. |
327 | /// |
328 | /// # References |
329 | /// - [Linux] |
330 | /// - [glibc] |
331 | /// |
332 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlock2.2.html |
333 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlock2 |
334 | #[cfg (linux_kernel)] |
335 | #[inline ] |
336 | #[doc (alias = "mlock2" )] |
337 | pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()> { |
338 | backend::mm::syscalls::mlock_with(addr:ptr, length:len, flags) |
339 | } |
340 | |
341 | /// `munlock(ptr, len)`—Unlock memory. |
342 | /// |
343 | /// Some implementations implicitly round the memory region out to the nearest |
344 | /// page boundaries, so this function may unlock more memory than explicitly |
345 | /// requested if the memory isn't page-aligned. |
346 | /// |
347 | /// # Safety |
348 | /// |
349 | /// The range of memory starting at `ptr`, rounded down to the applicable page |
350 | /// boundary, and extending for `len` bytes, rounded up to the applicable page |
351 | /// size, must be valid to read with `ptr`'s provenance. |
352 | /// |
353 | /// # References |
354 | /// - [POSIX] |
355 | /// - [Linux] |
356 | /// - [Apple] |
357 | /// - [FreeBSD] |
358 | /// - [NetBSD] |
359 | /// - [OpenBSD] |
360 | /// - [DragonFly BSD] |
361 | /// - [illumos] |
362 | /// - [glibc] |
363 | /// |
364 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munlock.html |
365 | /// [Linux]: https://man7.org/linux/man-pages/man2/munlock.2.html |
366 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munlock.2.html |
367 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlock&sektion=2 |
368 | /// [NetBSD]: https://man.netbsd.org/munlock.2 |
369 | /// [OpenBSD]: https://man.openbsd.org/munlock.2 |
370 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlock§ion=2 |
371 | /// [illumos]: https://illumos.org/man/3C/munlock |
372 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-munlock |
373 | #[inline ] |
374 | pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> { |
375 | backend::mm::syscalls::munlock(addr:ptr, length:len) |
376 | } |
377 | |
378 | /// Locks all pages mapped into the address space of the calling process. |
379 | /// |
380 | /// This includes the pages of the code, data, and stack segment, as well as |
381 | /// shared libraries, user space kernel data, shared memory, and memory-mapped |
382 | /// files. All mapped pages are guaranteed to be resident in RAM when the call |
383 | /// returns successfully; the pages are guaranteed to stay in RAM until later |
384 | /// unlocked. |
385 | /// |
386 | /// # References |
387 | /// - [POSIX] |
388 | /// - [Linux] |
389 | /// - [FreeBSD] |
390 | /// - [NetBSD] |
391 | /// - [OpenBSD] |
392 | /// - [DragonFly BSD] |
393 | /// - [illumos] |
394 | /// - [glibc] |
395 | /// |
396 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mlockall.html |
397 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlockall.2.html |
398 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlockall&sektion=2 |
399 | /// [NetBSD]: https://man.netbsd.org/mlockall.2 |
400 | /// [OpenBSD]: https://man.openbsd.org/mlockall.2 |
401 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlockall§ion=2 |
402 | /// [illumos]: https://illumos.org/man/3C/mlockall |
403 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlockall |
404 | #[cfg (any(linux_kernel, freebsdlike, netbsdlike))] |
405 | #[inline ] |
406 | pub fn mlockall(flags: MlockAllFlags) -> io::Result<()> { |
407 | backend::mm::syscalls::mlockall(flags) |
408 | } |
409 | |
410 | /// Unlocks all pages mapped into the address space of the calling process. |
411 | /// |
412 | /// # Warnings |
413 | /// |
414 | /// This function is aware of all the memory pages in the process, as if it |
415 | /// were a debugger. It unlocks all the pages, which could potentially |
416 | /// compromise security assumptions made by code about memory it has |
417 | /// encapsulated. |
418 | /// |
419 | /// # References |
420 | /// - [POSIX] |
421 | /// - [Linux] |
422 | /// - [FreeBSD] |
423 | /// - [NetBSD] |
424 | /// - [OpenBSD] |
425 | /// - [DragonFly BSD] |
426 | /// - [illumos] |
427 | /// - [glibc] |
428 | /// |
429 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munlockall.html |
430 | /// [Linux]: https://man7.org/linux/man-pages/man2/munlockall.2.html |
431 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlockall&sektion=2 |
432 | /// [NetBSD]: https://man.netbsd.org/munlockall.2 |
433 | /// [OpenBSD]: https://man.openbsd.org/munlockall.2 |
434 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlockall§ion=2 |
435 | /// [illumos]: https://illumos.org/man/3C/munlockall |
436 | /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-munlockall |
437 | #[cfg (any(linux_kernel, freebsdlike, netbsdlike))] |
438 | #[inline ] |
439 | pub fn munlockall() -> io::Result<()> { |
440 | backend::mm::syscalls::munlockall() |
441 | } |
442 | |