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
9use super::types::{
10 Advice, MapFlags, MlockAllFlags, MlockFlags, MprotectFlags, MremapFlags, MsyncFlags, ProtFlags,
11 UserfaultfdFlags,
12};
13use crate::backend::c;
14#[cfg(target_pointer_width = "64")]
15use crate::backend::conv::loff_t_from_u64;
16use crate::backend::conv::{c_uint, no_fd, pass_usize, ret, ret_owned_fd, ret_void_star};
17use crate::fd::{BorrowedFd, OwnedFd};
18use crate::io;
19use linux_raw_sys::general::MAP_ANONYMOUS;
20
21#[inline]
22pub(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]
34pub(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]
43pub(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]
85pub(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]
118pub(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]
131pub(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]
140pub(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]
161pub(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]
183pub(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]
192pub(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]
205pub(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]
210pub(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]
222pub(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]
235pub(crate) fn munlockall() -> io::Result<()> {
236 unsafe { ret(raw:syscall_readonly!(__NR_munlockall)) }
237}
238