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