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}