1 | //! linux_raw syscalls supporting `rustix::io`. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! See the `rustix::backend` module documentation for details. |
6 | #![allow (unsafe_code)] |
7 | #![allow (clippy::undocumented_unsafe_blocks)] |
8 | |
9 | use super::types::{ |
10 | Advice, MapFlags, MlockAllFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags, |
11 | UserfaultfdFlags, |
12 | }; |
13 | use crate::backend::c; |
14 | #[cfg (target_pointer_width = "64" )] |
15 | use crate::backend::conv::loff_t_from_u64; |
16 | use crate::backend::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star}; |
17 | use crate::fd::{BorrowedFd, OwnedFd}; |
18 | use crate::io; |
19 | use linux_raw_sys::general::MAP_ANONYMOUS; |
20 | |
21 | #[inline ] |
22 | pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { |
23 | unsafe { |
24 | ret(raw:syscall!( |
25 | __NR_madvise, |
26 | addr, |
27 | pass_usize(len), |
28 | c_uint(advice as c::c_uint) |
29 | )) |
30 | } |
31 | } |
32 | |
33 | #[inline ] |
34 | pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { |
35 | ret(raw:syscall!(__NR_msync, addr, pass_usize(len), flags)) |
36 | } |
37 | |
38 | /// # Safety |
39 | /// |
40 | /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working |
41 | /// with memory pointed to by raw pointers is unsafe. |
42 | #[inline ] |
43 | pub(crate) unsafe fn mmap( |
44 | addr: *mut c::c_void, |
45 | length: usize, |
46 | prot: ProtFlags, |
47 | flags: MapFlags, |
48 | fd: BorrowedFd<'_>, |
49 | offset: u64, |
50 | ) -> io::Result<*mut c::c_void> { |
51 | #[cfg (target_pointer_width = "32" )] |
52 | { |
53 | ret_void_star(syscall!( |
54 | __NR_mmap2, |
55 | addr, |
56 | pass_usize(length), |
57 | prot, |
58 | flags, |
59 | fd, |
60 | (offset / 4096) |
61 | .try_into() |
62 | .map(pass_usize) |
63 | .map_err(|_| io::Errno::INVAL)? |
64 | )) |
65 | } |
66 | #[cfg (target_pointer_width = "64" )] |
67 | { |
68 | ret_void_star(syscall!( |
69 | __NR_mmap, |
70 | addr, |
71 | pass_usize(length), |
72 | prot, |
73 | flags, |
74 | fd, |
75 | loff_t_from_u64(offset) |
76 | )) |
77 | } |
78 | } |
79 | |
80 | /// # Safety |
81 | /// |
82 | /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working |
83 | /// with memory pointed to by raw pointers is unsafe. |
84 | #[inline ] |
85 | pub(crate) unsafe fn mmap_anonymous( |
86 | addr: *mut c::c_void, |
87 | length: usize, |
88 | prot: ProtFlags, |
89 | flags: MapFlags, |
90 | ) -> io::Result<*mut c::c_void> { |
91 | #[cfg (target_pointer_width = "32" )] |
92 | { |
93 | ret_void_star(syscall!( |
94 | __NR_mmap2, |
95 | addr, |
96 | pass_usize(length), |
97 | prot, |
98 | c_uint(flags.bits() | MAP_ANONYMOUS), |
99 | no_fd(), |
100 | pass_usize(0) |
101 | )) |
102 | } |
103 | #[cfg (target_pointer_width = "64" )] |
104 | { |
105 | ret_void_star(syscall!( |
106 | __NR_mmap, |
107 | addr, |
108 | pass_usize(length), |
109 | prot, |
110 | c_uint(flags.bits() | MAP_ANONYMOUS), |
111 | no_fd(), |
112 | loff_t_from_u64(0) |
113 | )) |
114 | } |
115 | } |
116 | |
117 | #[inline ] |
118 | pub(crate) unsafe fn mprotect( |
119 | ptr: *mut c::c_void, |
120 | len: usize, |
121 | flags: MprotectFlags, |
122 | ) -> io::Result<()> { |
123 | ret(raw:syscall!(__NR_mprotect, ptr, pass_usize(len), flags)) |
124 | } |
125 | |
126 | /// # Safety |
127 | /// |
128 | /// `munmap` is primarily unsafe due to the `addr` parameter, as anything |
129 | /// working with memory pointed to by raw pointers is unsafe. |
130 | #[inline ] |
131 | pub(crate) unsafe fn munmap(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
132 | ret(raw:syscall!(__NR_munmap, addr, pass_usize(length))) |
133 | } |
134 | |
135 | /// # Safety |
136 | /// |
137 | /// `mremap` is primarily unsafe due to the `old_address` parameter, as |
138 | /// anything working with memory pointed to by raw pointers is unsafe. |
139 | #[inline ] |
140 | pub(crate) unsafe fn mremap( |
141 | old_address: *mut c::c_void, |
142 | old_size: usize, |
143 | new_size: usize, |
144 | flags: MremapFlags, |
145 | ) -> io::Result<*mut c::c_void> { |
146 | ret_void_star(raw:syscall!( |
147 | __NR_mremap, |
148 | old_address, |
149 | pass_usize(old_size), |
150 | pass_usize(new_size), |
151 | flags |
152 | )) |
153 | } |
154 | |
155 | /// # Safety |
156 | /// |
157 | /// `mremap_fixed` is primarily unsafe due to the `old_address` and |
158 | /// `new_address` parameters, as anything working with memory pointed to by raw |
159 | /// pointers is unsafe. |
160 | #[inline ] |
161 | pub(crate) unsafe fn mremap_fixed( |
162 | old_address: *mut c::c_void, |
163 | old_size: usize, |
164 | new_size: usize, |
165 | flags: MremapFlags, |
166 | new_address: *mut c::c_void, |
167 | ) -> io::Result<*mut c::c_void> { |
168 | ret_void_star(raw:syscall!( |
169 | __NR_mremap, |
170 | old_address, |
171 | pass_usize(old_size), |
172 | pass_usize(new_size), |
173 | flags, |
174 | new_address |
175 | )) |
176 | } |
177 | |
178 | /// # Safety |
179 | /// |
180 | /// `mlock` operates on raw pointers and may round out to the nearest page |
181 | /// boundaries. |
182 | #[inline ] |
183 | pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
184 | ret(raw:syscall!(__NR_mlock, addr, pass_usize(length))) |
185 | } |
186 | |
187 | /// # Safety |
188 | /// |
189 | /// `mlock_with` operates on raw pointers and may round out to the nearest page |
190 | /// boundaries. |
191 | #[inline ] |
192 | pub(crate) unsafe fn mlock_with( |
193 | addr: *mut c::c_void, |
194 | length: usize, |
195 | flags: MlockFlags, |
196 | ) -> io::Result<()> { |
197 | ret(raw:syscall!(__NR_mlock2, addr, pass_usize(length), flags)) |
198 | } |
199 | |
200 | /// # Safety |
201 | /// |
202 | /// `munlock` operates on raw pointers and may round out to the nearest page |
203 | /// boundaries. |
204 | #[inline ] |
205 | pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { |
206 | ret(raw:syscall!(__NR_munlock, addr, pass_usize(length))) |
207 | } |
208 | |
209 | #[inline ] |
210 | pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { |
211 | ret_owned_fd(raw:syscall_readonly!(__NR_userfaultfd, flags)) |
212 | } |
213 | |
214 | /// Locks all pages mapped into the address space of the calling process. |
215 | /// |
216 | /// This includes the pages of the code, data, and stack segment, as well as |
217 | /// shared libraries, user space kernel data, shared memory, and memory-mapped |
218 | /// files. All mapped pages are guaranteed to be resident in RAM when the call |
219 | /// returns successfully; the pages are guaranteed to stay in RAM until later |
220 | /// unlocked. |
221 | #[inline ] |
222 | pub(crate) fn mlockall(flags: MlockAllFlags) -> io::Result<()> { |
223 | // When `mlockall` is used with `MCL_ONFAULT | MCL_FUTURE`, the ordering |
224 | // of `mlockall` with respect to arbitrary loads may be significant, |
225 | // because if a load happens and evokes a fault before the `mlockall`, |
226 | // the memory doesn't get locked, but if the load and therefore |
227 | // the fault happens after, then the memory does get locked. |
228 | // So to be conservative in this regard, we use `syscall` instead |
229 | // of `syscall_readonly` |
230 | unsafe { ret(raw:syscall!(__NR_mlockall, flags)) } |
231 | } |
232 | |
233 | /// Unlocks all pages mapped into the address space of the calling process. |
234 | #[inline ] |
235 | pub(crate) fn munlockall() -> io::Result<()> { |
236 | unsafe { ret(raw:syscall_readonly!(__NR_munlockall)) } |
237 | } |
238 | |