rustix/backend/linux_raw/mm/
syscalls.rs

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, MREMAP_FIXED};
20
21#[inline]
22pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> {
23    unsafe {
24        ret(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(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(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(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(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(syscall!(
169        __NR_mremap,
170        old_address,
171        pass_usize(old_size),
172        pass_usize(new_size),
173        c_uint(flags.bits() | MREMAP_FIXED),
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(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(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(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(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(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(syscall_readonly!(__NR_munlockall)) }
237}