range_action_map/lib.rs
1//! # RangeAction Map
2//!
3//! 一个区间树结构,用于提供 mmap / munmap / mprotect 时对区间的操作。
4//!
5//! ## 使用
6//!
7//! 本项目有 `std` 环境和 `no_std` 两个选项。
8//!
9//! 如需在 `std` 环境使用,直接在 `Cargo.toml` 引入即可;
10//! 如需在内核中使用,则需要选择:
11//! ```ignore
12//! range-action-map = { default-features = false }
13//! ```
14//!
15//! ## 测试
16//!
17//! 本项目来自 `https://github.com/scPointer/maturin`。
18//!
19//! 其中 crate 源码在 `https://github.com/scPointer/maturin/tree/memory-area-mod/range-action-map`,
20//! 对这个 crate 本身的单元测试在 `https://github.com/scPointer/maturin/tree/memory-area-mod/range-action-map-test`。
21//!
22//! 单元测试本身只包含对数据结构本身的测试,不涉及页表和内存分配。实际在内存中的应用见下
23//!
24//! ## 应用
25//!
26//! 主要在 `https://github.com/scPointer/maturin/kernel` 模块中,
27//! **下面的路径都以这个模块为当前路径做描述**
28//!
29//! - 在 `src/memory/areas/mod.rs` 中,描述了内核里的 `VmArea` 如何实现这个模块的 `trait Segment`
30//! - 在 `src/memory/vmm.rs` 中,描述了内核里的 `MemorySet` 如何使用这个模块的 `RangeActionMap`
31//! - - 以及如何使用 `VmArea`
32//! - 在 `Cargo.toml` 中,描述了如何引入本模块
33//!
34//! ## 对外提供接口
35//!
36//! RangeActionMap 主要提供以下操作:
37//! - `unmap(start, end)`:拆分/缩短/删除部分现有区间,空出`[start, end)` 这一段。
38//! - `mprotect(start, end)`:修改所有区间与 `[start,end)` 相交的部分的属性。没有被 `[start, end)` 覆盖的区间会被拆分。
39//! - `mmap_fixed(start, end)`:`unmap(start, end)`,并插入一个(用户给定的)新区间在`[start, end)`。
40//! - `mmap_anywhere(hint, len)`:不修改任何区间,寻找一个长为 len 且左端点不小于 `hint` 的空位,并插入一个(用户给定的)新区间,返回插入位置的左端点。
41//!
42//! 还提供以下接口:
43//! - `find(pos: usize)`:查询一个点是否在某个区间在,如果在,返回它的引用。
44//! - `.iter()` `.iter_mut()`:迭代器支持。
45//! - `impl Debug`:可以用 Debug 属性输出所有区间信息(需要用户提供的底层 `SegmentType` 实现 `Debug`)。
46//!
47//! 创建:
48//! - `new(args: ArgsType)`
49//!
50//!
51//! ## 需要用户提供的接口和约定
52//!
53//! `RangeActionMap` 需要一个实现 `trait Segment` 的类型,至少实现删除、拆分、修改三个操作:
54//! - `remove()`:删除这段区间
55//! - `split(pos)`:从`pos`位置把当前区间拆成两段区间(pos 参数为全局的绝对位置而非区间内位置)
56//! - `modify(new_flags)`:修改区间的属性
57//!
58//! 一些约定:
59//! - 删除区间时需要用户底层结构完成返还页帧、修改页表等操作,但不需要 `Drop` 结构本身
60//! - 其中每个区间有一个 usize 大小的可修改的属性,在用于内存管理时,它一般是 PTEFlags
61//! - - (尽管这个结构只需要u8,但我们希望这个属性至少可以放下一个 raw_pointer 以便扩展其他用途)。
62//! - **此外,`RangeActionMap`创建时要求传入一个 `ArgsType`,它实际上是一个 usize。这个值会在每次操作时传递给底层区间**
63//!
64
65#![cfg_attr(not(feature = "std"), no_std)]
66#![feature(btree_extract_if)]
67
68#[cfg(feature = "std")]
69mod external {
70 pub use std::collections::btree_map::{Iter, IterMut};
71 pub use std::{collections::BTreeMap, fmt::Debug, iter::Iterator, vec::Vec};
72}
73#[cfg(not(feature = "std"))]
74mod external {
75 extern crate alloc;
76 pub use alloc::collections::btree_map::{Iter, IterMut};
77 pub use alloc::collections::BTreeMap;
78 pub use alloc::vec::Vec;
79 pub use core::fmt::Debug;
80 pub use core::iter::Iterator;
81}
82
83use external::*;
84
85mod segment;
86pub use segment::Segment;
87mod set;
88pub use set::{CutSet, DiffSet};
89mod range_area;
90pub use range_area::RangeArea;
91mod defs;
92pub use defs::{ArgsType, IdentType, LOWER_LIMIT, UPPER_LIMIT};
93
94/// 一个数据结构,维护互不相交的左闭右开区间。
95/// 其中每个区间有一个 usize 大小的可修改的属性,在用于内存管理时,它一般是 PTEFlags
96/// (尽管这个结构只需要u8,但我们希望这个属性至少可以放下一个 raw_pointer 以便扩展其他用途)。
97///
98/// RangeActionMap 主要提供以下操作:
99/// - `unmap(start, end)`:拆分/缩短/删除部分现有区间,空出`[start, end)` 这一段。
100/// - `mprotect(start, end)`:修改所有区间与 `[start,end)` 相交的部分的属性。没有被 `[start, end)` 覆盖的区间会被拆分。
101/// - `mmap_fixed(start, end)`:`unmap(start, end)`,并插入一个(用户给定的)新区间在`[start, end)`。
102/// - `mmap_anywhere(hint, len)`:不修改任何区间,寻找一个长为 len 且左端点不小于 `hint` 的空位,并插入一个(用户给定的)新区间,返回插入位置的左端点。
103///
104/// 还提供以下接口:
105/// - `find(pos: usize)`:查询一个点是否在某个区间在,如果在,返回它的引用。
106/// - `.iter()` `.iter_mut()`:迭代器支持。
107/// - `impl Debug`:可以用 Debug 属性输出所有区间信息(需要用户提供的底层 `SegmentType` 实现 `Debug`)。
108///
109/// `RangeActionMap` 需要一个实现 `trait Segment` 的类型,至少实现删除、拆分、修改三个操作:
110/// - `remove()`:删除这段区间
111/// - `split(pos)`:从`pos`位置把当前区间拆成两段区间(pos 参数为全局的绝对位置而非区间内位置)
112/// - `modify(new_flags)`:修改区间的属性
113///
114/// **此外,`RangeActionMap`创建时要求传入一个 `ArgsType`,它实际上是一个 usize。这个值会在每次操作时传递给底层区间**
115///
116/// # Example
117///
118/// ```
119/// # use range_action_map::{RangeActionMap, Segment, IdentType, ArgsType};
120/// /// 定义一个区间结构,内部只保存左右端点
121/// struct Seg(usize, usize);
122/// let mut ram = RangeActionMap::<Seg>::new(ArgsType::default());
123/// /// 分配一段区间,注意区间是**左闭右开**的
124/// ram.mmap_fixed(0x3000, 0x7000, || { Seg(0x3000, 0x7000) });
125/// assert!(ram.find(0x2111).is_none());
126/// assert!(ram.find(0x3000).is_some());
127/// assert!(ram.find(0x5678).is_some());
128/// assert!(ram.find(0x7000).is_none());
129///
130/// /// 实现 Segment
131/// impl Segment for Seg {
132/// fn remove(&mut self, args: ArgsType) {}
133/// fn modify(&mut self, new_flag: IdentType, args: ArgsType) {}
134/// fn split(&mut self, pos: usize, args: ArgsType) -> Self {
135/// let right_end = self.1;
136/// self.1 = pos;
137/// Self(pos, right_end)
138/// }
139/// }
140/// ```
141///
142pub struct RangeActionMap<SegmentType: Segment> {
143 pub segments: BTreeMap<usize, RangeArea<SegmentType>>,
144 args: ArgsType,
145}
146
147impl<SegmentType: Segment> RangeActionMap<SegmentType> {
148 /// 创建一个空的区间树。
149 ///
150 /// 传入的 `args` 会在每次操作时传递给底层的区间。
151 /// (如果用于内存管理,推荐传入页表位置)
152 ///
153 /// 此外,也可在 `./defs.rs` 修改 `ArgsType` 的定义,以传递不同的参数
154 pub fn new(args: ArgsType) -> Self {
155 Self {
156 segments: BTreeMap::new(),
157 args,
158 }
159 }
160 /// 插入一段区间,不检查
161 fn insert_raw(&mut self, start: usize, end: usize, segment: SegmentType) {
162 self.segments.insert(
163 start,
164 RangeArea {
165 start,
166 end,
167 segment,
168 },
169 );
170 }
171 /// 查询某个地址是否在一个区间内,如是则返回区间引用,否则返回 None
172 pub fn find<'a>(&'a self, pos: usize) -> Option<&'a SegmentType> {
173 if let Some((_, area)) = self.segments.range(..=pos).last() {
174 if area.contains(pos) {
175 return Some(&area.segment);
176 }
177 }
178 None
179 }
180 /// 通过迭代器访问每个区间的引用
181 pub fn iter<'a>(&'a self) -> RangeActionMapIter<'a, SegmentType> {
182 RangeActionMapIter {
183 map_iter: self.segments.iter(),
184 }
185 }
186 /// 通过迭代器访问每个区间的可变引用
187 pub fn iter_mut<'a>(&'a mut self) -> RangeActionMapIterMut<'a, SegmentType> {
188 RangeActionMapIterMut {
189 map_iter: self.segments.iter_mut(),
190 }
191 }
192 /// 插入一段长度为 len 的区间,且区间左端点位置不小于 hint。
193 ///
194 /// - 如找到这样的区间,则会执行 `f(start: usize)` 获取区间实例,
195 /// 然后返回 Some(start) 表示区间左端点;
196 /// - 否则,**不会执行 `f` **,并返回 None
197 ///
198 /// # Example
199 ///
200 /// ```
201 /// # use range_action_map::{RangeActionMap, Segment, IdentType, ArgsType};
202 /// /// 定义一个区间结构,内部只保存左右端点
203 /// struct Seg(usize, usize);
204 /// /// 实现 Segment
205 /// impl Segment for Seg {
206 /// fn remove(&mut self, args: ArgsType) {}
207 /// fn modify(&mut self, new_flag: IdentType, args: ArgsType) {}
208 /// fn split(&mut self, pos: usize, args: ArgsType) -> Self {
209 /// let right_end = self.1;
210 /// self.1 = pos;
211 /// Self(pos, right_end)
212 /// }
213 /// }
214 /// let mut map: RangeActionMap<Seg> = RangeActionMap::new(0);
215 /// /// 申请一个长为 10 的区间,要求左端点不小于 10123,获得[10123,10133)
216 /// assert_eq!(Some(10123), map.mmap_anywhere(10123, 10, |start| Seg(start, start+10)));
217 /// /// 申请一个长为 10 的区间,要求左端点不小于 140,获得[10140,10150)
218 /// assert_eq!(Some(10140), map.mmap_anywhere(10140, 10, |start| Seg(start, start+10)));
219 /// /// 申请一个长为 10 的区间,要求左端点不小于 120,获得[10150, 10160)。
220 /// /// 这是因为[10123,10133)和[10140,10150)已有区间,第一个满足要求的空区间只能从 10150 开始
221 /// assert_eq!(Some(10150), map.mmap_anywhere(10120, 10, |start| Seg(start, start+10)));
222 /// ```
223 pub fn mmap_anywhere(
224 &mut self,
225 hint: usize,
226 len: usize,
227 f: impl FnOnce(usize) -> SegmentType,
228 ) -> Option<usize> {
229 self.find_free_area(hint, len).map(|start| {
230 self.insert_raw(start, start + len, f(start));
231 start
232 })
233 }
234
235 /// 尝试插入一个区间。如插入成功,返回插入后的起始地址
236 ///
237 /// - 如区间在 `[LOWER_LIMIT, UPPER_LIMIT]` 范围内,则会:
238 /// - - unmap(start, end),
239 /// - - 然后执行 `f(start: usize)` ,
240 /// - - 然后返回 Some(start) 表示区间左端点;
241 /// - 否则,**不会执行 `f` **,并返回 None
242 pub fn mmap_fixed(
243 &mut self,
244 start: usize,
245 end: usize,
246 f: impl FnOnce() -> SegmentType,
247 ) -> Option<usize> {
248 if start < LOWER_LIMIT || end > UPPER_LIMIT {
249 return None;
250 }
251 // 需要 unmap 掉原本相交的区间
252 self.unmap(start, end);
253 self.insert_raw(start, end, f());
254 Some(start)
255 }
256 /// 删除映射,空出 [start, end) 这段区间。
257 ///
258 /// 这可能导致一些区间被缩短或拆分
259 pub fn unmap(&mut self, start: usize, end: usize) {
260 // 注意,这里把相交的区间直接从 self.areas 里取出来了
261 // 所以如果仅相交而不需要删除,就需要放回 self.areas
262 let areas_to_be_modified: Vec<RangeArea<SegmentType>> = self
263 .segments
264 .extract_if(|_, area| area.is_overlap_with(start, end))
265 .map(|(_, v)| v)
266 .collect();
267 for mut area in areas_to_be_modified {
268 match area.shrink_or_split_if_overlap(start, end, self.args) {
269 DiffSet::Shrinked => {
270 self.segments.insert(area.start, area);
271 }
272 DiffSet::Splitted(right) => {
273 self.segments.insert(area.start, area);
274 self.segments.insert(right.start, right);
275 }
276 _ => {} // 被删除或者未相交时,就不需要再管了
277 }
278 }
279 }
280 /// 调整所有和已知区间相交的区间,修改 [start, end) 段的权限。
281 /// 它可以直接当作 mprotect 使用
282 pub fn mprotect(&mut self, start: usize, end: usize, new_flags: IdentType) {
283 // 注意,这里把相交的区间直接从 self.areas 里取出来了
284 // 所以如果仅相交而不需要删除,就需要放回 self.areas
285 let areas_to_be_modified: Vec<RangeArea<SegmentType>> = self
286 .segments
287 .extract_if(|_, area| area.is_overlap_with(start, end))
288 .map(|(_, v)| v)
289 .collect();
290 for mut area in areas_to_be_modified {
291 match area.split_and_modify_if_overlap(start, end, new_flags, self.args) {
292 CutSet::WholeModified => {
293 self.segments.insert(area.start, area);
294 }
295 CutSet::ModifiedLeft(right) | CutSet::ModifiedRight(right) => {
296 // 在 split_and_modify_if_overlap 内部已经处理过了修改 flags 的部分
297 // 所以如果有半边相交,可以直接把切出的区间塞回 self.areas
298 self.segments.insert(area.start, area);
299 self.segments.insert(right.start, right);
300 }
301 CutSet::ModifiedMiddle(mid, right) => {
302 self.segments.insert(area.start, area);
303 self.segments.insert(mid.start, mid);
304 self.segments.insert(right.start, right);
305 }
306 _ => {} // 未相交时,就不需要再管了
307 }
308 }
309 }
310 pub fn find_free_area(&self, hint: usize, len: usize) -> Option<usize> {
311 // 上一段区间的末尾
312 let mut last_seg_end = hint.max(LOWER_LIMIT);
313 for (start, seg) in self.segments.iter() {
314 // 现在检查从上一段末尾到这一段开头能不能塞下一个长为 len 的段
315 if last_seg_end + len <= *start {
316 return Some(last_seg_end);
317 }
318 last_seg_end = last_seg_end.max(seg.end);
319 }
320 if last_seg_end + len <= UPPER_LIMIT {
321 Some(last_seg_end)
322 } else {
323 None
324 }
325 }
326}
327
328impl<SegmentType: Segment + Debug> Debug for RangeActionMap<SegmentType> {
329 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
330 f.debug_struct("RangeActionMap")
331 .field("segments", &self.segments.values())
332 .finish()
333 }
334}
335
336pub struct RangeActionMapIter<'a, SegmentType: Segment> {
337 map_iter: Iter<'a, usize, RangeArea<SegmentType>>,
338}
339
340impl<'a, SegmentType: Segment> Iterator for RangeActionMapIter<'a, SegmentType> {
341 type Item = &'a SegmentType;
342 fn next(&mut self) -> Option<Self::Item> {
343 self.map_iter.next().map(|(_, area)| &area.segment)
344 }
345}
346
347pub struct RangeActionMapIterMut<'a, SegmentType: Segment> {
348 map_iter: IterMut<'a, usize, RangeArea<SegmentType>>,
349}
350
351impl<'a, SegmentType: Segment> Iterator for RangeActionMapIterMut<'a, SegmentType> {
352 type Item = &'a mut SegmentType;
353 fn next(&mut self) -> Option<Self::Item> {
354 self.map_iter.next().map(|(_, area)| &mut area.segment)
355 }
356}