Skip to main content

page_table_generic/
map.rs

1use crate::{
2    FrameAllocator, PageTableEntry, PagingError, PagingResult, PhysAddr, PteConfigOf, TableMeta,
3    VirtAddr, frame::Frame,
4};
5
6/// 页表映射配置
7#[repr(C)]
8#[derive(Clone, Copy)]
9pub struct MapConfig<C> {
10    pub vaddr: VirtAddr,
11    pub paddr: PhysAddr,
12    pub size: usize,
13    /// Page Table Entry 配置模板
14    ///
15    /// 所有页表项将使用此配置创建(除了物理地址位)
16    pub pte: C,
17    pub allow_huge: bool,
18    pub flush: bool,
19}
20
21/// 内部映射递归配置
22#[derive(Clone, Copy)]
23pub struct MapRecursiveConfig<C> {
24    pub start_vaddr: VirtAddr,
25    pub start_paddr: PhysAddr,
26    pub end_vaddr: VirtAddr,
27    pub level: usize,
28    pub allow_huge: bool,
29    pub flush: bool,
30    pub pte_template: C,
31}
32
33/// 取消映射配置
34#[derive(Clone, Copy)]
35pub struct UnmapConfig {
36    pub start_vaddr: VirtAddr,
37    pub size: usize,
38    pub flush: bool,
39}
40
41/// 内部取消映射递归配置
42#[derive(Clone, Copy)]
43pub struct UnmapRecursiveConfig {
44    pub start_vaddr: VirtAddr,
45    pub end_vaddr: VirtAddr,
46    pub level: usize,
47    pub flush: bool,
48    pub(crate) retained_root_entries: Option<(usize, usize)>,
49}
50
51impl<C> core::fmt::Debug for MapConfig<C> {
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        f.debug_struct("MapConfig")
54            .field("vaddr", &format_args!("{:#x}", self.vaddr.as_usize()))
55            .field("paddr", &format_args!("{:#x}", self.paddr.as_usize()))
56            .field("size", &format_args!("{:#x}", self.size))
57            .field("allow_huge", &self.allow_huge)
58            .field("flush", &self.flush)
59            .finish()
60    }
61}
62
63impl<T, A> Frame<T, A>
64where
65    T: TableMeta,
66    A: FrameAllocator,
67{
68    /// 递归映射的核心实现
69    pub fn map_range_recursive(
70        &mut self,
71        config: MapRecursiveConfig<PteConfigOf<T>>,
72    ) -> PagingResult<()> {
73        let mut vaddr = config.start_vaddr;
74        let mut paddr = config.start_paddr;
75
76        while vaddr < config.end_vaddr {
77            let index = Self::virt_to_index(vaddr, config.level);
78            let level_size = Self::level_size(config.level);
79            let remaining_size = config.end_vaddr - vaddr;
80
81            // 检查是否可以使用大页映射
82            if config.allow_huge
83                && config.level > 1
84                && config.level <= T::MAX_BLOCK_LEVEL
85                && level_size <= remaining_size
86                && vaddr.as_usize().is_multiple_of(level_size)
87                && paddr.as_usize().is_multiple_of(level_size)
88            {
89                // 创建大页映射
90                let entries = self.as_slice_mut();
91                let pte_ref = &mut entries[index];
92                if !pte_ref.unused() {
93                    return Err(PagingError::mapping_conflict(vaddr, paddr));
94                }
95                *pte_ref = T::P::new_page(paddr, config.pte_template, true);
96
97                // 如果需要刷新TLB,立即执行
98                if config.flush {
99                    T::flush(Some(vaddr));
100                }
101
102                vaddr = VirtAddr::from_usize(vaddr.as_usize().checked_add(level_size).ok_or_else(
103                    || {
104                        PagingError::address_overflow(
105                            "Virtual address overflow in map_range_recursive",
106                        )
107                    },
108                )?);
109                paddr = PhysAddr::from_usize(paddr.as_usize().checked_add(level_size).ok_or_else(
110                    || {
111                        PagingError::address_overflow(
112                            "Physical address overflow in map_range_recursive",
113                        )
114                    },
115                )?);
116                continue;
117            }
118
119            // 如果到达页表级别,进行普通页映射
120            if config.level == 1 {
121                // 创建普通页面映射
122                let entries = self.as_slice_mut();
123                let pte_ref = &mut entries[index];
124                if !pte_ref.unused() {
125                    return Err(PagingError::mapping_conflict(vaddr, paddr));
126                }
127
128                *pte_ref = T::P::new_page(paddr, config.pte_template, false);
129
130                // 如果需要刷新TLB,立即执行
131                if config.flush {
132                    T::flush(Some(vaddr));
133                }
134
135                vaddr = VirtAddr::from_usize(
136                    vaddr.as_usize().checked_add(T::PAGE_SIZE).ok_or_else(|| {
137                        PagingError::address_overflow(
138                            "Virtual address overflow in map_range_recursive",
139                        )
140                    })?,
141                );
142                paddr = PhysAddr::from_usize(
143                    paddr.as_usize().checked_add(T::PAGE_SIZE).ok_or_else(|| {
144                        PagingError::address_overflow(
145                            "Physical address overflow in map_range_recursive",
146                        )
147                    })?,
148                );
149                continue;
150            }
151
152            // 检查当前页表项状态并决定如何处理
153            let allocator = self.allocator.clone();
154            let current_pte = self.as_slice()[index];
155
156            let child_frame = if !current_pte.unused() {
157                if current_pte.huge(true) {
158                    return Err(PagingError::mapping_conflict(
159                        vaddr,
160                        current_pte.paddr(true),
161                    ));
162                }
163                if !current_pte.present() {
164                    return Err(PagingError::hierarchy_error(
165                        "Non-present intermediate entry is not a leaf",
166                    ));
167                }
168
169                // 子页表已存在,获取它
170                Frame::from_paddr(current_pte.paddr(true), allocator)
171            } else {
172                // 需要创建新的子页表
173                let new_frame = Frame::<T, A>::new(allocator)?;
174                let new_frame_paddr = new_frame.paddr;
175
176                // 链接子页表 - 子页表指针必须是 NON_BLOCK(不是大页)
177                let entries = self.as_slice_mut();
178                let pte_ref = &mut entries[index];
179                *pte_ref = T::P::new_table(new_frame_paddr);
180
181                new_frame
182            };
183
184            // 计算当前页表条目对应的范围结束地址。  All arithmetic is
185            // checked: a wrapped boundary could make the recursive walker
186            // revisit a low address and install aliases outside the request.
187            let entry_base = (vaddr.as_usize() / level_size)
188                .checked_mul(level_size)
189                .ok_or_else(|| {
190                    PagingError::address_overflow(
191                        "Page-table entry base overflow in map_range_recursive",
192                    )
193                })?;
194            // A sign-extended canonical address can legitimately occupy the
195            // final page-table entry.  Its mathematical entry end is 2^N,
196            // which is represented by the request's exclusive end only (and
197            // cannot be stored in a `usize` address).  Clamp that one boundary
198            // to the request end; every other overflow remains an error.
199            let current_entry_end = match entry_base.checked_add(level_size) {
200                Some(end) => end,
201                None if config.end_vaddr.as_usize() > entry_base => config.end_vaddr.as_usize(),
202                None => {
203                    return Err(PagingError::address_overflow(
204                        "Page-table entry end overflow in map_range_recursive",
205                    ));
206                }
207            };
208            let next_level_vaddr =
209                VirtAddr::from_usize(current_entry_end.min(config.end_vaddr.as_usize()));
210            let mut child_frame = child_frame;
211            let child_config = MapRecursiveConfig {
212                start_vaddr: vaddr,
213                start_paddr: paddr,
214                end_vaddr: next_level_vaddr,
215                level: config.level - 1,
216                allow_huge: config.allow_huge,
217                flush: config.flush,
218                pte_template: config.pte_template,
219            };
220            child_frame.map_range_recursive(child_config)?;
221
222            // 计算本轮映射的虚拟地址范围
223            let mapped_size = next_level_vaddr - vaddr;
224            vaddr = next_level_vaddr;
225            paddr = PhysAddr::from_usize(paddr.as_usize().checked_add(mapped_size).ok_or_else(
226                || {
227                    PagingError::address_overflow(
228                        "Physical address overflow in map_range_recursive",
229                    )
230                },
231            )?);
232        }
233
234        Ok(())
235    }
236
237    /// Recursively clears leaf mappings.
238    ///
239    /// Returns whether this frame is empty and can be reclaimed by its caller.
240    /// This is the existing generic page-table contract used by stage-2 and
241    /// single-owner domains. Stage-1 owners that require remote shootdown
242    /// confirmation use `PageTableRef::unmap_page_deferred` instead.
243    pub fn unmap_range_recursive(&mut self, config: UnmapRecursiveConfig) -> PagingResult<bool> {
244        let mut vaddr = config.start_vaddr;
245        let mut can_reclaim = true;
246        let allocator = self.allocator.clone();
247
248        while vaddr < config.end_vaddr {
249            let index = Self::virt_to_index(vaddr, config.level);
250            let level_size = Self::level_size(config.level);
251            let remaining_size = config.end_vaddr - vaddr;
252
253            let entries = self.as_slice_mut();
254            let pte_ref = &mut entries[index];
255
256            // An invalid leaf can still retain its physical address. Treat it
257            // as occupied state and clear it instead of skipping it.
258            if pte_ref.unused() {
259                vaddr = checked_advance(vaddr, level_size.min(remaining_size))?;
260                continue;
261            }
262
263            if !pte_ref.present() {
264                pte_ref.clear();
265                if config.flush {
266                    T::flush(Some(vaddr));
267                }
268                vaddr = checked_advance(vaddr, level_size.min(remaining_size))?;
269                continue;
270            }
271
272            // 如果是叶子级别或者是大页,直接清除
273            let is_huge = pte_ref.huge(config.level > 1);
274            if config.level == 1 || is_huge {
275                // 清除页表项
276                pte_ref.clear();
277
278                // 刷新TLB
279                if config.flush {
280                    T::flush(Some(vaddr));
281                }
282
283                vaddr = checked_advance(vaddr, if is_huge { level_size } else { T::PAGE_SIZE })?;
284                continue;
285            }
286
287            // 中间级别:递归处理子页表
288            // 需要在修改pte_ref之前获取所需信息
289            let child_paddr = pte_ref.paddr(true);
290
291            // 计算当前页表条目对应的范围结束地址
292            let entry_base = (vaddr.as_usize() / level_size)
293                .checked_mul(level_size)
294                .ok_or_else(|| {
295                    PagingError::address_overflow(
296                        "Page-table entry base overflow in unmap_range_recursive",
297                    )
298                })?;
299            let current_entry_end = match entry_base.checked_add(level_size) {
300                Some(end) => end,
301                None if config.end_vaddr.as_usize() > entry_base => config.end_vaddr.as_usize(),
302                None => {
303                    return Err(PagingError::address_overflow(
304                        "Page-table entry end overflow in unmap_range_recursive",
305                    ));
306                }
307            };
308            let next_level_vaddr =
309                VirtAddr::from_usize(current_entry_end.min(config.end_vaddr.as_usize()));
310
311            {
312                let mut child_frame: Frame<T, A> =
313                    Frame::from_paddr(child_paddr, allocator.clone());
314                let child_config = UnmapRecursiveConfig {
315                    start_vaddr: vaddr,
316                    end_vaddr: next_level_vaddr,
317                    level: config.level - 1,
318                    flush: config.flush,
319                    retained_root_entries: None,
320                };
321
322                let child_can_reclaim = child_frame.unmap_range_recursive(child_config)?;
323
324                if child_can_reclaim
325                    && config
326                        .retained_root_entries
327                        .is_some_and(|(start, end)| start <= index && index < end)
328                {
329                    can_reclaim = false;
330                } else if child_can_reclaim {
331                    // 子页表完全为空,可以回收
332                    // 清除指向子页表的PTE
333                    pte_ref.clear();
334                    allocator.dealloc_frame(child_paddr);
335                } else {
336                    can_reclaim = false;
337                }
338            }
339
340            vaddr = next_level_vaddr;
341        }
342
343        if can_reclaim {
344            can_reclaim = self.as_slice().iter().all(PageTableEntry::unused);
345        }
346        Ok(can_reclaim)
347    }
348}
349
350fn checked_advance(address: VirtAddr, amount: usize) -> PagingResult<VirtAddr> {
351    address
352        .as_usize()
353        .checked_add(amount)
354        .map(VirtAddr::from_usize)
355        .ok_or_else(|| PagingError::address_overflow("page-table address advance overflow"))
356}