1 | //! The `mmap` API. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! `mmap` and related functions manipulate raw pointers and have special |
6 | //! semantics and are wildly unsafe. |
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 | /// Raw pointers and lots of special semantics. |
56 | /// |
57 | /// # References |
58 | /// - [POSIX] |
59 | /// - [Linux] |
60 | /// - [Apple] |
61 | /// - [FreeBSD] |
62 | /// - [NetBSD] |
63 | /// - [OpenBSD] |
64 | /// - [DragonFly BSD] |
65 | /// - [illumos] |
66 | /// - [glibc] |
67 | /// |
68 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html |
69 | /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html |
70 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html |
71 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 |
72 | /// [NetBSD]: https://man.netbsd.org/mmap.2 |
73 | /// [OpenBSD]: https://man.openbsd.org/mmap.2 |
74 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 |
75 | /// [illumos]: https://illumos.org/man/2/mmap |
76 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap |
77 | #[inline ] |
78 | pub unsafe fn mmap<Fd: AsFd>( |
79 | ptr: *mut c_void, |
80 | len: usize, |
81 | prot: ProtFlags, |
82 | flags: MapFlags, |
83 | fd: Fd, |
84 | offset: u64, |
85 | ) -> io::Result<*mut c_void> { |
86 | backend::mm::syscalls::mmap(addr:ptr, length:len, prot, flags, fd.as_fd(), offset) |
87 | } |
88 | |
89 | /// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`—Create an anonymous |
90 | /// memory mapping. |
91 | /// |
92 | /// For file-backed mappings, see [`mmap`]. |
93 | /// |
94 | /// # Safety |
95 | /// |
96 | /// Raw pointers and lots of special semantics. |
97 | /// |
98 | /// # References |
99 | /// - [POSIX] |
100 | /// - [Linux] |
101 | /// - [Apple] |
102 | /// - [FreeBSD] |
103 | /// - [NetBSD] |
104 | /// - [OpenBSD] |
105 | /// - [DragonFly BSD] |
106 | /// - [illumos] |
107 | /// - [glibc] |
108 | /// |
109 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html |
110 | /// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html |
111 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html |
112 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2 |
113 | /// [NetBSD]: https://man.netbsd.org/mmap.2 |
114 | /// [OpenBSD]: https://man.openbsd.org/mmap.2 |
115 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap§ion=2 |
116 | /// [illumos]: https://illumos.org/man/2/mmap |
117 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-mmap |
118 | #[inline ] |
119 | #[doc (alias = "mmap" )] |
120 | pub unsafe fn mmap_anonymous( |
121 | ptr: *mut c_void, |
122 | len: usize, |
123 | prot: ProtFlags, |
124 | flags: MapFlags, |
125 | ) -> io::Result<*mut c_void> { |
126 | backend::mm::syscalls::mmap_anonymous(addr:ptr, length:len, prot, flags) |
127 | } |
128 | |
129 | /// `munmap(ptr, len)`—Remove a memory mapping. |
130 | /// |
131 | /// # Safety |
132 | /// |
133 | /// Raw pointers and lots of special semantics. |
134 | /// |
135 | /// # References |
136 | /// - [POSIX] |
137 | /// - [Linux] |
138 | /// - [Apple] |
139 | /// - [FreeBSD] |
140 | /// - [NetBSD] |
141 | /// - [OpenBSD] |
142 | /// - [DragonFly BSD] |
143 | /// - [illumos] |
144 | /// - [glibc] |
145 | /// |
146 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html |
147 | /// [Linux]: https://man7.org/linux/man-pages/man2/munmap.2.html |
148 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munmap.2.html |
149 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munmap&sektion=2 |
150 | /// [NetBSD]: https://man.netbsd.org/munmap.2 |
151 | /// [OpenBSD]: https://man.openbsd.org/munmap.2 |
152 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munmap§ion=2 |
153 | /// [illumos]: https://illumos.org/man/2/munmap |
154 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Memory_002dmapped-I_002fO.html#index-munmap |
155 | #[inline ] |
156 | pub unsafe fn munmap(ptr: *mut c_void, len: usize) -> io::Result<()> { |
157 | backend::mm::syscalls::munmap(addr:ptr, length:len) |
158 | } |
159 | |
160 | /// `mremap(old_address, old_size, new_size, flags)`—Resize, modify, and/or |
161 | /// move a memory mapping. |
162 | /// |
163 | /// For moving a mapping to a fixed address (`MREMAP_FIXED`), see |
164 | /// [`mremap_fixed`]. |
165 | /// |
166 | /// # Safety |
167 | /// |
168 | /// Raw pointers and lots of special semantics. |
169 | /// |
170 | /// # References |
171 | /// - [Linux] |
172 | /// |
173 | /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html |
174 | #[cfg (any(target_os = "emscripten" , target_os = "linux" ))] |
175 | #[inline ] |
176 | pub unsafe fn mremap( |
177 | old_address: *mut c_void, |
178 | old_size: usize, |
179 | new_size: usize, |
180 | flags: MremapFlags, |
181 | ) -> io::Result<*mut c_void> { |
182 | backend::mm::syscalls::mremap(old_address, old_size, new_size, flags) |
183 | } |
184 | |
185 | /// `mremap(old_address, old_size, new_size, MREMAP_FIXED | flags)`—Resize, |
186 | /// modify, and/or move a memory mapping to a specific address. |
187 | /// |
188 | /// For `mremap` without moving to a specific address, see [`mremap`]. |
189 | /// [`mremap_fixed`]. |
190 | /// |
191 | /// # Safety |
192 | /// |
193 | /// Raw pointers and lots of special semantics. |
194 | /// |
195 | /// # References |
196 | /// - [Linux] |
197 | /// |
198 | /// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html |
199 | #[cfg (any(target_os = "emscripten" , target_os = "linux" ))] |
200 | #[inline ] |
201 | #[doc (alias = "mremap" )] |
202 | pub unsafe fn mremap_fixed( |
203 | old_address: *mut c_void, |
204 | old_size: usize, |
205 | new_size: usize, |
206 | flags: MremapFlags, |
207 | new_address: *mut c_void, |
208 | ) -> io::Result<*mut c_void> { |
209 | backend::mm::syscalls::mremap_fixed(old_address, old_size, new_size, flags, new_address) |
210 | } |
211 | |
212 | /// `mprotect(ptr, len, flags)`—Change the protection flags of a region of |
213 | /// memory. |
214 | /// |
215 | /// # Safety |
216 | /// |
217 | /// Raw pointers and lots of special semantics. |
218 | /// |
219 | /// # References |
220 | /// - [POSIX] |
221 | /// - [Linux] |
222 | /// - [Apple] |
223 | /// - [FreeBSD] |
224 | /// - [NetBSD] |
225 | /// - [OpenBSD] |
226 | /// - [DragonFly BSD] |
227 | /// - [illumos] |
228 | /// |
229 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html |
230 | /// [Linux]: https://man7.org/linux/man-pages/man2/mprotect.2.html |
231 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html |
232 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mprotect&sektion=2 |
233 | /// [NetBSD]: https://man.netbsd.org/mprotect.2 |
234 | /// [OpenBSD]: https://man.openbsd.org/mprotect.2 |
235 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mprotect§ion=2 |
236 | /// [illumos]: https://illumos.org/man/2/mprotect |
237 | #[inline ] |
238 | pub unsafe fn mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()> { |
239 | backend::mm::syscalls::mprotect(ptr, len, flags) |
240 | } |
241 | |
242 | /// `mlock(ptr, len)`—Lock memory into RAM. |
243 | /// |
244 | /// # Safety |
245 | /// |
246 | /// This function operates on raw pointers, but it should only be used on |
247 | /// memory which the caller owns. Technically, locking memory shouldn't violate |
248 | /// any invariants, but since unlocking it can violate invariants, this |
249 | /// function is also unsafe for symmetry. |
250 | /// |
251 | /// Some implementations implicitly round the memory region out to the nearest |
252 | /// page boundaries, so this function may lock more memory than explicitly |
253 | /// requested if the memory isn't page-aligned. Other implementations fail if |
254 | /// the memory isn't page-aligned. |
255 | /// |
256 | /// # References |
257 | /// - [POSIX] |
258 | /// - [Linux] |
259 | /// - [Apple] |
260 | /// - [FreeBSD] |
261 | /// - [NetBSD] |
262 | /// - [OpenBSD] |
263 | /// - [DragonFly BSD] |
264 | /// - [illumos] |
265 | /// - [glibc] |
266 | /// |
267 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html |
268 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlock.2.html |
269 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mlock.2.html |
270 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlock&sektion=2 |
271 | /// [NetBSD]: https://man.netbsd.org/mlock.2 |
272 | /// [OpenBSD]: https://man.openbsd.org/mlock.2 |
273 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlock§ion=2 |
274 | /// [illumos]: https://illumos.org/man/3C/mlock |
275 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock |
276 | #[inline ] |
277 | pub unsafe fn mlock(ptr: *mut c_void, len: usize) -> io::Result<()> { |
278 | backend::mm::syscalls::mlock(addr:ptr, length:len) |
279 | } |
280 | |
281 | /// `mlock2(ptr, len, flags)`—Lock memory into RAM, with flags. |
282 | /// |
283 | /// `mlock_with` is the same as [`mlock`] but adds an additional flags operand. |
284 | /// |
285 | /// # Safety |
286 | /// |
287 | /// This function operates on raw pointers, but it should only be used on |
288 | /// memory which the caller owns. Technically, locking memory shouldn't violate |
289 | /// any invariants, but since unlocking it can violate invariants, this |
290 | /// function is also unsafe for symmetry. |
291 | /// |
292 | /// Some implementations implicitly round the memory region out to the nearest |
293 | /// page boundaries, so this function may lock more memory than explicitly |
294 | /// requested if the memory isn't page-aligned. |
295 | /// |
296 | /// # References |
297 | /// - [Linux] |
298 | /// - [glibc] |
299 | /// |
300 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlock2.2.html |
301 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlock2 |
302 | #[cfg (linux_kernel)] |
303 | #[inline ] |
304 | #[doc (alias = "mlock2" )] |
305 | pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()> { |
306 | backend::mm::syscalls::mlock_with(addr:ptr, length:len, flags) |
307 | } |
308 | |
309 | /// `munlock(ptr, len)`—Unlock memory. |
310 | /// |
311 | /// # Safety |
312 | /// |
313 | /// This function operates on raw pointers, but it should only be used on |
314 | /// memory which the caller owns, to avoid compromising the `mlock` invariants |
315 | /// of other unrelated code in the process. |
316 | /// |
317 | /// Some implementations implicitly round the memory region out to the nearest |
318 | /// page boundaries, so this function may unlock more memory than explicitly |
319 | /// requested if the memory isn't page-aligned. |
320 | /// |
321 | /// # References |
322 | /// - [POSIX] |
323 | /// - [Linux] |
324 | /// - [Apple] |
325 | /// - [FreeBSD] |
326 | /// - [NetBSD] |
327 | /// - [OpenBSD] |
328 | /// - [DragonFly BSD] |
329 | /// - [illumos] |
330 | /// - [glibc] |
331 | /// |
332 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlock.html |
333 | /// [Linux]: https://man7.org/linux/man-pages/man2/munlock.2.html |
334 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munlock.2.html |
335 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlock&sektion=2 |
336 | /// [NetBSD]: https://man.netbsd.org/munlock.2 |
337 | /// [OpenBSD]: https://man.openbsd.org/munlock.2 |
338 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlock§ion=2 |
339 | /// [illumos]: https://illumos.org/man/3C/munlock |
340 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlock |
341 | #[inline ] |
342 | pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> { |
343 | backend::mm::syscalls::munlock(addr:ptr, length:len) |
344 | } |
345 | |
346 | /// Locks all pages mapped into the address space of the calling process. |
347 | /// |
348 | /// This includes the pages of the code, data, and stack segment, as well as |
349 | /// shared libraries, user space kernel data, shared memory, and memory-mapped |
350 | /// files. All mapped pages are guaranteed to be resident in RAM when the call |
351 | /// returns successfully; the pages are guaranteed to stay in RAM until later |
352 | /// unlocked. |
353 | /// |
354 | /// # References |
355 | /// - [POSIX] |
356 | /// - [Linux] |
357 | /// - [FreeBSD] |
358 | /// - [NetBSD] |
359 | /// - [OpenBSD] |
360 | /// - [DragonFly BSD] |
361 | /// - [illumos] |
362 | /// - [glibc] |
363 | /// |
364 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html |
365 | /// [Linux]: https://man7.org/linux/man-pages/man2/mlockall.2.html |
366 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlockall&sektion=2 |
367 | /// [NetBSD]: https://man.netbsd.org/mlockall.2 |
368 | /// [OpenBSD]: https://man.openbsd.org/mlockall.2 |
369 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlockall§ion=2 |
370 | /// [illumos]: https://illumos.org/man/3C/mlockall |
371 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-mlockall |
372 | #[cfg (any(linux_kernel, freebsdlike, netbsdlike))] |
373 | #[inline ] |
374 | pub fn mlockall(flags: MlockAllFlags) -> io::Result<()> { |
375 | backend::mm::syscalls::mlockall(flags) |
376 | } |
377 | |
378 | /// Unlocks all pages mapped into the address space of the calling process. |
379 | /// |
380 | /// # Warnings |
381 | /// |
382 | /// This function is aware of all the memory pages in the process, as if it |
383 | /// were a debugger. It unlocks all the pages, which could potentially |
384 | /// compromise security assumptions made by code about memory it has |
385 | /// encapsulated. |
386 | /// |
387 | /// # References |
388 | /// - [POSIX] |
389 | /// - [Linux] |
390 | /// - [FreeBSD] |
391 | /// - [NetBSD] |
392 | /// - [OpenBSD] |
393 | /// - [DragonFly BSD] |
394 | /// - [illumos] |
395 | /// - [glibc] |
396 | /// |
397 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/munlockall.html |
398 | /// [Linux]: https://man7.org/linux/man-pages/man2/munlockall.2.html |
399 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlockall&sektion=2 |
400 | /// [NetBSD]: https://man.netbsd.org/munlockall.2 |
401 | /// [OpenBSD]: https://man.openbsd.org/munlockall.2 |
402 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlockall§ion=2 |
403 | /// [illumos]: https://illumos.org/man/3C/munlockall |
404 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Page-Lock-Functions.html#index-munlockall |
405 | #[cfg (any(linux_kernel, freebsdlike, netbsdlike))] |
406 | #[inline ] |
407 | pub fn munlockall() -> io::Result<()> { |
408 | backend::mm::syscalls::munlockall() |
409 | } |
410 | |