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