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