1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
use core::{
mem::ManuallyDrop,
ptr,
};
use super::abi::*;
use crate::{
eprintln,
result_from_value,
unit_result_from_value,
AsRawFd,
RawFd,
};
pub const MAP_SHARED: u32 = 0x1;
pub const MAP_PRIVATE: u32 = 0x2;
pub const MAP_SHARED_VALIDATE: u32 = 0x3;
pub const MAP_FIXED: u32 = 0x10;
pub const MAP_ANONYMOUS: u32 = 0x20;
pub const MAP_GROWSDOWN: u32 = 0x100;
pub const MAP_LOCKED: u32 = 0x2000;
pub const MAP_NORESERVE: u32 = 0x4000;
pub const MAP_POPULATE: u32 = 0x8000;
pub const MAP_NONBLOCK: u32 = 0x10000;
pub const MAP_STACK: u32 = 0x20000;
pub const MAP_HUGETLB: u32 = 0x40000;
pub const MAP_SYNC: u32 = 0x80000;
pub const MAP_FIXED_NOREPLACE: u32 = 0x100000;
pub const MREMAP_MAYMOVE: u32 = 0x1;
pub const MREMAP_FIXED: u32 = 0x2;
pub const MREMAP_DONTUNMAP: u32 = 0x4;
pub const PROT_NONE: u32 = 0;
pub const PROT_READ: u32 = 1;
pub const PROT_WRITE: u32 = 2;
pub const PROT_EXEC: u32 = 4;
/// A memory mapping that was mapped application using `mmap`. `munmap` is automatically called
/// when the object is dropped.
///
/// # Invariants
///
/// The address in `mem` must be a multiple of the `PAGE_SIZE` and of the mapping's huge page
/// size if the mapping employs huge pages.
///
/// `mem`'s length must not be zero.
pub struct Mmap {
// `NonNull` and `Unique` cannot be used because they require the pointer to be non-null. A
// mutable pointer.
mem: *mut [u8],
}
unsafe impl Send for Mmap {}
unsafe impl Sync for Mmap {}
impl Mmap {
/// Creates a new `Mmap` object from a slice that was mapped with `mmap`.
///
/// # Safety
///
/// The address in `mem` must be a multiple of the `PAGE_SIZE` and of the mapping's huge page
/// size if the mapping employs huge pages.
///
/// `mem`'s length must not be zero.
pub unsafe fn from_raw(mem: *mut [u8]) -> Self {
Self { mem }
}
/// Splits the memory mapping into two sub-mappings:
/// 1. from zero included to `offset` excluded, and
/// 2. from `offset` included to the end.
///
/// # Safety
///
/// `offset` must be a multiple of the `PAGE_SIZE` and of the mapping's huge page size if the
/// mapping employs huge pages.
///
/// `offset` must not be zero or be larger than or equal to the mapping's size as empty
/// (sub-)mappings are invalid according to `Mmap`'s invariants.
pub unsafe fn split_at(self, offset: usize) -> (Self, Self) {
let mut this = ManuallyDrop::new(self);
let (first, second) = this.as_mut().split_at_mut(offset);
(Mmap::from_raw(first), Mmap::from_raw(second))
}
/// Consumes the `Mmap`, returning a wrapped raw pointer.
///
/// After calling this function, the caller is responsible for the memory mapping.
pub fn into_raw(self) -> *mut [u8] {
let this = ManuallyDrop::new(self);
this.mem
}
}
impl AsRef<[u8]> for Mmap {
fn as_ref(&self) -> &[u8] {
unsafe { &*self.mem }
}
}
impl AsMut<[u8]> for Mmap {
fn as_mut(&mut self) -> &mut [u8] {
unsafe { &mut *self.mem }
}
}
impl Drop for Mmap {
fn drop(&mut self) {
if let Err(e) = unsafe { munmap(self.mem) } {
eprintln!(
"munmap({addr:p}, {len}): {e}",
addr = self.as_ref().as_ptr(),
len = self.as_ref().len(),
);
}
}
}
/// Maps a chunk of memory.
///
/// # Safety
///
/// If the map is a shared file map, then the application must be careful about potential undefined
/// behavior if the underlying file can change, in or out of process.
#[inline]
pub unsafe fn mmap(
addr: *mut u8,
len: usize,
prot: u32,
flags: u32,
fd: RawFd,
off: usize,
) -> crate::Result<Mmap> {
let ret = syscall_6(
9,
addr as usize,
len,
prot as usize,
flags as usize,
fd as isize as usize,
off,
);
let final_addr = result_from_value(ret)?;
let mem = ptr::slice_from_raw_parts_mut(final_addr as *mut u8, len);
Ok(Mmap { mem })
}
/// Creates a file-backed memory mapping.
///
/// # Safety
///
/// If the map is shared, then the application must be careful about potential undefined behavior
/// if the underlying file changes, in or out of process.
#[inline]
pub unsafe fn mmap_file(
addr: *mut u8,
len: usize,
prot: u32,
flags: u32,
fd: &impl AsRawFd,
off: usize,
) -> crate::Result<Mmap> {
mmap(addr, len, prot, flags, fd.as_raw_fd(), off)
}
/// Creates an anonymous memory mapping.
#[inline]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn mmap_anonymous(addr: *mut u8, len: usize, prot: u32, flags: u32) -> crate::Result<Mmap> {
unsafe { mmap(addr, len, prot, flags | MAP_ANONYMOUS, -1, 0) }
}
/// Grows, shrinks or moves a memory mapping.
///
/// # Safety
///
/// The application must ensure that the memory that is unmapped or moved is no longer used.
#[inline]
pub unsafe fn mremap(
mmap: &mut Mmap,
new_len: usize,
flags: u32,
new_addr: *mut u8,
) -> crate::Result<()> {
let ret = syscall_5(
25,
mmap.as_mut().as_mut_ptr() as usize,
mmap.as_mut().len(),
new_len,
flags as usize,
new_addr as usize,
);
let final_addr = result_from_value(ret)?;
let mem = ptr::slice_from_raw_parts_mut(final_addr as *mut u8, new_len);
mmap.mem = mem;
Ok(())
}
/// Modifies a memory mapping's protection flags.
#[inline]
pub fn mprotect(mmap: &Mmap, prot: u32) -> crate::Result<()> {
let ret = unsafe {
syscall_3(
10,
mmap.as_ref().as_ptr() as usize,
mmap.as_ref().len(),
prot as usize,
) as i32
};
unit_result_from_value(ret)
}
/// Unmaps a memory mapping.
///
/// # Safety
///
/// The application must ensure that the memory that is unmapped is no longer used.
#[inline]
pub unsafe fn munmap(mem: *mut [u8]) -> crate::Result<()> {
let mem = &mut *mem;
let ret = syscall_2(11, mem.as_mut_ptr() as usize, mem.len()) as i32;
unit_result_from_value(ret)
}