Skip to main content

x86_64/structures/paging/mapper/
mapped_page_table.rs

1use crate::structures::paging::{
2    mapper::*,
3    page::AddressNotAligned,
4    page_table::{FrameError, PageTable, PageTableEntry, PageTableLevel},
5};
6
7/// A Mapper implementation that relies on a PhysAddr to VirtAddr conversion function.
8///
9/// This type requires that the all physical page table frames are mapped to some virtual
10/// address. Normally, this is done by mapping the complete physical address space into
11/// the virtual address space at some offset. Other mappings between physical and virtual
12/// memory are possible too, as long as they can be calculated as an `PhysAddr` to
13/// `VirtAddr` closure.
14#[derive(Debug)]
15pub struct MappedPageTable<'a, P: PageTableFrameMapping> {
16    page_table_walker: PageTableWalker<P>,
17    level_4_table: &'a mut PageTable,
18}
19
20impl<'a, P: PageTableFrameMapping> MappedPageTable<'a, P> {
21    /// Creates a new `MappedPageTable` that uses the passed `PageTableFrameMapping` for converting virtual
22    /// to physical addresses.
23    ///
24    /// ## Safety
25    ///
26    /// This function is unsafe because the caller must guarantee that the passed `page_table_frame_mapping`
27    /// `PageTableFrameMapping` is correct. Also, the passed `level_4_table` must point to the level 4 page table
28    /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g.
29    /// by writing to an illegal memory location.
30    #[inline]
31    pub unsafe fn new(level_4_table: &'a mut PageTable, page_table_frame_mapping: P) -> Self {
32        Self {
33            level_4_table,
34            page_table_walker: unsafe { PageTableWalker::new(page_table_frame_mapping) },
35        }
36    }
37
38    /// Returns an immutable reference to the wrapped level 4 `PageTable` instance.
39    pub fn level_4_table(&self) -> &PageTable {
40        self.level_4_table
41    }
42
43    /// Returns a mutable reference to the wrapped level 4 `PageTable` instance.
44    pub fn level_4_table_mut(&mut self) -> &mut PageTable {
45        self.level_4_table
46    }
47
48    /// Returns the `PageTableFrameMapping` used for converting virtual to physical addresses.
49    pub fn page_table_frame_mapping(&self) -> &P {
50        &self.page_table_walker.page_table_frame_mapping
51    }
52}
53
54impl<P: PageTableFrameMapping> Mapper<Size1GiB> for MappedPageTable<'_, P> {
55    #[inline]
56    unsafe fn map_to_with_table_flags<A>(
57        &mut self,
58        page: Page<Size1GiB>,
59        frame: PhysFrame<Size1GiB>,
60        flags: PageTableFlags,
61        parent_table_flags: PageTableFlags,
62        allocator: &mut A,
63    ) -> Result<MapperFlush<Size1GiB>, MapToError<Size1GiB>>
64    where
65        A: FrameAllocator<Size4KiB> + ?Sized,
66    {
67        let p4 = &mut self.level_4_table;
68        let p3 = self.page_table_walker.create_next_table(
69            &mut p4[page.p4_index()],
70            parent_table_flags,
71            allocator,
72        )?;
73
74        if !p3[page.p3_index()].is_unused() {
75            return Err(MapToError::PageAlreadyMapped(frame));
76        }
77        p3[page.p3_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE);
78
79        Ok(MapperFlush::new(page))
80    }
81
82    fn unmap(
83        &mut self,
84        page: Page<Size1GiB>,
85    ) -> Result<(PhysFrame<Size1GiB>, MapperFlush<Size1GiB>), UnmapError> {
86        let p4 = &mut self.level_4_table;
87        let p3 = self
88            .page_table_walker
89            .next_table_mut(&mut p4[page.p4_index()])?;
90
91        let p3_entry = &mut p3[page.p3_index()];
92        let flags = p3_entry.flags();
93
94        if !flags.contains(PageTableFlags::PRESENT) {
95            return Err(UnmapError::PageNotMapped);
96        }
97        if !flags.contains(PageTableFlags::HUGE_PAGE) {
98            return Err(UnmapError::ParentEntryHugePage);
99        }
100
101        let frame = PhysFrame::from_start_address(p3_entry.addr())
102            .map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p3_entry.addr()))?;
103
104        p3_entry.set_unused();
105        Ok((frame, MapperFlush::new(page)))
106    }
107
108    unsafe fn update_flags(
109        &mut self,
110        page: Page<Size1GiB>,
111        flags: PageTableFlags,
112    ) -> Result<MapperFlush<Size1GiB>, FlagUpdateError> {
113        let p4 = &mut self.level_4_table;
114        let p3 = self
115            .page_table_walker
116            .next_table_mut(&mut p4[page.p4_index()])?;
117
118        if p3[page.p3_index()].is_unused() {
119            return Err(FlagUpdateError::PageNotMapped);
120        }
121        p3[page.p3_index()].set_flags(flags | PageTableFlags::HUGE_PAGE);
122
123        Ok(MapperFlush::new(page))
124    }
125
126    unsafe fn set_flags_p4_entry(
127        &mut self,
128        page: Page<Size1GiB>,
129        flags: PageTableFlags,
130    ) -> Result<MapperFlushAll, FlagUpdateError> {
131        let p4 = &mut self.level_4_table;
132        let p4_entry = &mut p4[page.p4_index()];
133
134        if p4_entry.is_unused() {
135            return Err(FlagUpdateError::PageNotMapped);
136        }
137
138        p4_entry.set_flags(flags);
139
140        Ok(MapperFlushAll::new())
141    }
142
143    unsafe fn set_flags_p3_entry(
144        &mut self,
145        _page: Page<Size1GiB>,
146        _flags: PageTableFlags,
147    ) -> Result<MapperFlushAll, FlagUpdateError> {
148        Err(FlagUpdateError::ParentEntryHugePage)
149    }
150
151    unsafe fn set_flags_p2_entry(
152        &mut self,
153        _page: Page<Size1GiB>,
154        _flags: PageTableFlags,
155    ) -> Result<MapperFlushAll, FlagUpdateError> {
156        Err(FlagUpdateError::ParentEntryHugePage)
157    }
158
159    fn translate_page(&self, page: Page<Size1GiB>) -> Result<PhysFrame<Size1GiB>, TranslateError> {
160        let p4 = &self.level_4_table;
161        let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?;
162
163        let p3_entry = &p3[page.p3_index()];
164
165        if p3_entry.is_unused() {
166            return Err(TranslateError::PageNotMapped);
167        }
168
169        PhysFrame::from_start_address(p3_entry.addr())
170            .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p3_entry.addr()))
171    }
172}
173
174impl<P: PageTableFrameMapping> Mapper<Size2MiB> for MappedPageTable<'_, P> {
175    #[inline]
176    unsafe fn map_to_with_table_flags<A>(
177        &mut self,
178        page: Page<Size2MiB>,
179        frame: PhysFrame<Size2MiB>,
180        flags: PageTableFlags,
181        parent_table_flags: PageTableFlags,
182        allocator: &mut A,
183    ) -> Result<MapperFlush<Size2MiB>, MapToError<Size2MiB>>
184    where
185        A: FrameAllocator<Size4KiB> + ?Sized,
186    {
187        let p4 = &mut self.level_4_table;
188        let p3 = self.page_table_walker.create_next_table(
189            &mut p4[page.p4_index()],
190            parent_table_flags,
191            allocator,
192        )?;
193        let p2 = self.page_table_walker.create_next_table(
194            &mut p3[page.p3_index()],
195            parent_table_flags,
196            allocator,
197        )?;
198
199        if !p2[page.p2_index()].is_unused() {
200            return Err(MapToError::PageAlreadyMapped(frame));
201        }
202        p2[page.p2_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE);
203
204        Ok(MapperFlush::new(page))
205    }
206
207    fn unmap(
208        &mut self,
209        page: Page<Size2MiB>,
210    ) -> Result<(PhysFrame<Size2MiB>, MapperFlush<Size2MiB>), UnmapError> {
211        let p4 = &mut self.level_4_table;
212        let p3 = self
213            .page_table_walker
214            .next_table_mut(&mut p4[page.p4_index()])?;
215        let p2 = self
216            .page_table_walker
217            .next_table_mut(&mut p3[page.p3_index()])?;
218
219        let p2_entry = &mut p2[page.p2_index()];
220        let flags = p2_entry.flags();
221
222        if !flags.contains(PageTableFlags::PRESENT) {
223            return Err(UnmapError::PageNotMapped);
224        }
225        if !flags.contains(PageTableFlags::HUGE_PAGE) {
226            return Err(UnmapError::ParentEntryHugePage);
227        }
228
229        let frame = PhysFrame::from_start_address(p2_entry.addr())
230            .map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p2_entry.addr()))?;
231
232        p2_entry.set_unused();
233        Ok((frame, MapperFlush::new(page)))
234    }
235
236    unsafe fn update_flags(
237        &mut self,
238        page: Page<Size2MiB>,
239        flags: PageTableFlags,
240    ) -> Result<MapperFlush<Size2MiB>, FlagUpdateError> {
241        let p4 = &mut self.level_4_table;
242        let p3 = self
243            .page_table_walker
244            .next_table_mut(&mut p4[page.p4_index()])?;
245        let p2 = self
246            .page_table_walker
247            .next_table_mut(&mut p3[page.p3_index()])?;
248
249        if p2[page.p2_index()].is_unused() {
250            return Err(FlagUpdateError::PageNotMapped);
251        }
252
253        p2[page.p2_index()].set_flags(flags | PageTableFlags::HUGE_PAGE);
254
255        Ok(MapperFlush::new(page))
256    }
257
258    unsafe fn set_flags_p4_entry(
259        &mut self,
260        page: Page<Size2MiB>,
261        flags: PageTableFlags,
262    ) -> Result<MapperFlushAll, FlagUpdateError> {
263        let p4 = &mut self.level_4_table;
264        let p4_entry = &mut p4[page.p4_index()];
265
266        if p4_entry.is_unused() {
267            return Err(FlagUpdateError::PageNotMapped);
268        }
269
270        p4_entry.set_flags(flags);
271
272        Ok(MapperFlushAll::new())
273    }
274
275    unsafe fn set_flags_p3_entry(
276        &mut self,
277        page: Page<Size2MiB>,
278        flags: PageTableFlags,
279    ) -> Result<MapperFlushAll, FlagUpdateError> {
280        let p4 = &mut self.level_4_table;
281        let p3 = self
282            .page_table_walker
283            .next_table_mut(&mut p4[page.p4_index()])?;
284        let p3_entry = &mut p3[page.p3_index()];
285
286        if p3_entry.is_unused() {
287            return Err(FlagUpdateError::PageNotMapped);
288        }
289
290        p3_entry.set_flags(flags);
291
292        Ok(MapperFlushAll::new())
293    }
294
295    unsafe fn set_flags_p2_entry(
296        &mut self,
297        _page: Page<Size2MiB>,
298        _flags: PageTableFlags,
299    ) -> Result<MapperFlushAll, FlagUpdateError> {
300        Err(FlagUpdateError::ParentEntryHugePage)
301    }
302
303    fn translate_page(&self, page: Page<Size2MiB>) -> Result<PhysFrame<Size2MiB>, TranslateError> {
304        let p4 = &self.level_4_table;
305        let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?;
306        let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?;
307
308        let p2_entry = &p2[page.p2_index()];
309
310        if p2_entry.is_unused() {
311            return Err(TranslateError::PageNotMapped);
312        }
313
314        PhysFrame::from_start_address(p2_entry.addr())
315            .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p2_entry.addr()))
316    }
317}
318
319impl<P: PageTableFrameMapping> Mapper<Size4KiB> for MappedPageTable<'_, P> {
320    #[inline]
321    unsafe fn map_to_with_table_flags<A>(
322        &mut self,
323        page: Page<Size4KiB>,
324        frame: PhysFrame<Size4KiB>,
325        flags: PageTableFlags,
326        parent_table_flags: PageTableFlags,
327        allocator: &mut A,
328    ) -> Result<MapperFlush<Size4KiB>, MapToError<Size4KiB>>
329    where
330        A: FrameAllocator<Size4KiB> + ?Sized,
331    {
332        let p4 = &mut self.level_4_table;
333        let p3 = self.page_table_walker.create_next_table(
334            &mut p4[page.p4_index()],
335            parent_table_flags,
336            allocator,
337        )?;
338        let p2 = self.page_table_walker.create_next_table(
339            &mut p3[page.p3_index()],
340            parent_table_flags,
341            allocator,
342        )?;
343        let p1 = self.page_table_walker.create_next_table(
344            &mut p2[page.p2_index()],
345            parent_table_flags,
346            allocator,
347        )?;
348
349        if !p1[page.p1_index()].is_unused() {
350            return Err(MapToError::PageAlreadyMapped(frame));
351        }
352        p1[page.p1_index()].set_frame(frame, flags);
353
354        Ok(MapperFlush::new(page))
355    }
356
357    fn unmap(
358        &mut self,
359        page: Page<Size4KiB>,
360    ) -> Result<(PhysFrame<Size4KiB>, MapperFlush<Size4KiB>), UnmapError> {
361        let p4 = &mut self.level_4_table;
362        let p3 = self
363            .page_table_walker
364            .next_table_mut(&mut p4[page.p4_index()])?;
365        let p2 = self
366            .page_table_walker
367            .next_table_mut(&mut p3[page.p3_index()])?;
368        let p1 = self
369            .page_table_walker
370            .next_table_mut(&mut p2[page.p2_index()])?;
371
372        let p1_entry = &mut p1[page.p1_index()];
373
374        let frame = p1_entry.frame().map_err(|err| match err {
375            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
376            FrameError::HugeFrame => UnmapError::ParentEntryHugePage,
377        })?;
378
379        p1_entry.set_unused();
380        Ok((frame, MapperFlush::new(page)))
381    }
382
383    unsafe fn update_flags(
384        &mut self,
385        page: Page<Size4KiB>,
386        flags: PageTableFlags,
387    ) -> Result<MapperFlush<Size4KiB>, FlagUpdateError> {
388        let p4 = &mut self.level_4_table;
389        let p3 = self
390            .page_table_walker
391            .next_table_mut(&mut p4[page.p4_index()])?;
392        let p2 = self
393            .page_table_walker
394            .next_table_mut(&mut p3[page.p3_index()])?;
395        let p1 = self
396            .page_table_walker
397            .next_table_mut(&mut p2[page.p2_index()])?;
398
399        if p1[page.p1_index()].is_unused() {
400            return Err(FlagUpdateError::PageNotMapped);
401        }
402
403        p1[page.p1_index()].set_flags(flags);
404
405        Ok(MapperFlush::new(page))
406    }
407
408    unsafe fn set_flags_p4_entry(
409        &mut self,
410        page: Page<Size4KiB>,
411        flags: PageTableFlags,
412    ) -> Result<MapperFlushAll, FlagUpdateError> {
413        let p4 = &mut self.level_4_table;
414        let p4_entry = &mut p4[page.p4_index()];
415
416        if p4_entry.is_unused() {
417            return Err(FlagUpdateError::PageNotMapped);
418        }
419
420        p4_entry.set_flags(flags);
421
422        Ok(MapperFlushAll::new())
423    }
424
425    unsafe fn set_flags_p3_entry(
426        &mut self,
427        page: Page<Size4KiB>,
428        flags: PageTableFlags,
429    ) -> Result<MapperFlushAll, FlagUpdateError> {
430        let p4 = &mut self.level_4_table;
431        let p3 = self
432            .page_table_walker
433            .next_table_mut(&mut p4[page.p4_index()])?;
434        let p3_entry = &mut p3[page.p3_index()];
435
436        if p3_entry.is_unused() {
437            return Err(FlagUpdateError::PageNotMapped);
438        }
439
440        p3_entry.set_flags(flags);
441
442        Ok(MapperFlushAll::new())
443    }
444
445    unsafe fn set_flags_p2_entry(
446        &mut self,
447        page: Page<Size4KiB>,
448        flags: PageTableFlags,
449    ) -> Result<MapperFlushAll, FlagUpdateError> {
450        let p4 = &mut self.level_4_table;
451        let p3 = self
452            .page_table_walker
453            .next_table_mut(&mut p4[page.p4_index()])?;
454        let p2 = self
455            .page_table_walker
456            .next_table_mut(&mut p3[page.p3_index()])?;
457        let p2_entry = &mut p2[page.p2_index()];
458
459        if p2_entry.is_unused() {
460            return Err(FlagUpdateError::PageNotMapped);
461        }
462
463        p2_entry.set_flags(flags);
464
465        Ok(MapperFlushAll::new())
466    }
467
468    fn translate_page(&self, page: Page<Size4KiB>) -> Result<PhysFrame<Size4KiB>, TranslateError> {
469        let p4 = &self.level_4_table;
470        let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?;
471        let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?;
472        let p1 = self.page_table_walker.next_table(&p2[page.p2_index()])?;
473
474        let p1_entry = &p1[page.p1_index()];
475
476        if p1_entry.is_unused() {
477            return Err(TranslateError::PageNotMapped);
478        }
479
480        PhysFrame::from_start_address(p1_entry.addr())
481            .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p1_entry.addr()))
482    }
483}
484
485impl<P: PageTableFrameMapping> Translate for MappedPageTable<'_, P> {
486    #[allow(clippy::inconsistent_digit_grouping)]
487    fn translate(&self, addr: VirtAddr) -> TranslateResult {
488        let p4 = &self.level_4_table;
489        let p3 = match self.page_table_walker.next_table(&p4[addr.p4_index()]) {
490            Ok(page_table) => page_table,
491            Err(PageTableWalkError::NotMapped) => return TranslateResult::NotMapped,
492            Err(PageTableWalkError::MappedToHugePage) => {
493                panic!("level 4 entry has huge page bit set")
494            }
495        };
496        let p2 = match self.page_table_walker.next_table(&p3[addr.p3_index()]) {
497            Ok(page_table) => page_table,
498            Err(PageTableWalkError::NotMapped) => return TranslateResult::NotMapped,
499            Err(PageTableWalkError::MappedToHugePage) => {
500                let entry = &p3[addr.p3_index()];
501                let frame = PhysFrame::containing_address(entry.addr());
502                #[allow(clippy::unusual_byte_groupings)]
503                let offset = addr.as_u64() & 0o_777_777_7777;
504                let flags = entry.flags();
505                return TranslateResult::Mapped {
506                    frame: MappedFrame::Size1GiB(frame),
507                    offset,
508                    flags,
509                };
510            }
511        };
512        let p1 = match self.page_table_walker.next_table(&p2[addr.p2_index()]) {
513            Ok(page_table) => page_table,
514            Err(PageTableWalkError::NotMapped) => return TranslateResult::NotMapped,
515            Err(PageTableWalkError::MappedToHugePage) => {
516                let entry = &p2[addr.p2_index()];
517                let frame = PhysFrame::containing_address(entry.addr());
518                #[allow(clippy::unusual_byte_groupings)]
519                let offset = addr.as_u64() & 0o_777_7777;
520                let flags = entry.flags();
521                return TranslateResult::Mapped {
522                    frame: MappedFrame::Size2MiB(frame),
523                    offset,
524                    flags,
525                };
526            }
527        };
528
529        let p1_entry = &p1[addr.p1_index()];
530
531        if p1_entry.is_unused() {
532            return TranslateResult::NotMapped;
533        }
534
535        let frame = match PhysFrame::from_start_address(p1_entry.addr()) {
536            Ok(frame) => frame,
537            Err(AddressNotAligned) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()),
538        };
539        let offset = u64::from(addr.page_offset());
540        let flags = p1_entry.flags();
541        TranslateResult::Mapped {
542            frame: MappedFrame::Size4KiB(frame),
543            offset,
544            flags,
545        }
546    }
547}
548
549impl<P: PageTableFrameMapping> CleanUp for MappedPageTable<'_, P> {
550    #[inline]
551    unsafe fn clean_up<D>(&mut self, frame_deallocator: &mut D)
552    where
553        D: FrameDeallocator<Size4KiB>,
554    {
555        unsafe {
556            self.clean_up_addr_range(
557                PageRangeInclusive {
558                    start: Page::from_start_address(VirtAddr::new(0)).unwrap(),
559                    end: Page::from_start_address(VirtAddr::new(0xffff_ffff_ffff_f000)).unwrap(),
560                },
561                frame_deallocator,
562            )
563        }
564    }
565
566    unsafe fn clean_up_addr_range<D>(
567        &mut self,
568        range: PageRangeInclusive,
569        frame_deallocator: &mut D,
570    ) where
571        D: FrameDeallocator<Size4KiB>,
572    {
573        unsafe fn clean_up<P: PageTableFrameMapping>(
574            page_table: &mut PageTable,
575            page_table_walker: &PageTableWalker<P>,
576            level: PageTableLevel,
577            range: PageRangeInclusive,
578            frame_deallocator: &mut impl FrameDeallocator<Size4KiB>,
579        ) -> bool {
580            if range.is_empty() {
581                return false;
582            }
583
584            let table_addr = range
585                .start
586                .start_address()
587                .align_down(level.table_address_space_alignment());
588
589            let start = range.start.page_table_index(level);
590            let end = range.end.page_table_index(level);
591
592            if let Some(next_level) = level.next_lower_level() {
593                let offset_per_entry = level.entry_address_space_alignment();
594                for (i, entry) in page_table
595                    .iter_mut()
596                    .enumerate()
597                    .take(usize::from(end) + 1)
598                    .skip(usize::from(start))
599                {
600                    if let Ok(page_table) = page_table_walker.next_table_mut(entry) {
601                        let start = VirtAddr::forward_checked_impl(
602                            table_addr,
603                            (offset_per_entry as usize) * i,
604                        )
605                        .unwrap();
606                        let end = start + (offset_per_entry - 1);
607                        let start = Page::<Size4KiB>::containing_address(start);
608                        let start = start.max(range.start);
609                        let end = Page::<Size4KiB>::containing_address(end);
610                        let end = end.min(range.end);
611                        unsafe {
612                            if clean_up(
613                                page_table,
614                                page_table_walker,
615                                next_level,
616                                Page::range_inclusive(start, end),
617                                frame_deallocator,
618                            ) {
619                                let frame = entry.frame().unwrap();
620                                entry.set_unused();
621                                frame_deallocator.deallocate_frame(frame);
622                            }
623                        }
624                    }
625                }
626            }
627
628            page_table.iter().all(PageTableEntry::is_unused)
629        }
630
631        unsafe {
632            clean_up(
633                self.level_4_table,
634                &self.page_table_walker,
635                PageTableLevel::Four,
636                range,
637                frame_deallocator,
638            );
639        }
640    }
641}
642
643#[derive(Debug)]
644struct PageTableWalker<P: PageTableFrameMapping> {
645    page_table_frame_mapping: P,
646}
647
648impl<P: PageTableFrameMapping> PageTableWalker<P> {
649    #[inline]
650    pub unsafe fn new(page_table_frame_mapping: P) -> Self {
651        Self {
652            page_table_frame_mapping,
653        }
654    }
655
656    /// Internal helper function to get a reference to the page table of the next level.
657    ///
658    /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns
659    /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set
660    /// in the passed entry.
661    #[inline]
662    fn next_table<'b>(
663        &self,
664        entry: &'b PageTableEntry,
665    ) -> Result<&'b PageTable, PageTableWalkError> {
666        let page_table_ptr = self
667            .page_table_frame_mapping
668            .frame_to_pointer(entry.frame()?);
669        let page_table: &PageTable = unsafe { &*page_table_ptr };
670
671        Ok(page_table)
672    }
673
674    /// Internal helper function to get a mutable reference to the page table of the next level.
675    ///
676    /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns
677    /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set
678    /// in the passed entry.
679    #[inline]
680    fn next_table_mut<'b>(
681        &self,
682        entry: &'b mut PageTableEntry,
683    ) -> Result<&'b mut PageTable, PageTableWalkError> {
684        let page_table_ptr = self
685            .page_table_frame_mapping
686            .frame_to_pointer(entry.frame()?);
687        let page_table: &mut PageTable = unsafe { &mut *page_table_ptr };
688
689        Ok(page_table)
690    }
691
692    /// Internal helper function to create the page table of the next level if needed.
693    ///
694    /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed,
695    /// and the entry is updated to that address. If the passed entry is already mapped, the next
696    /// table is returned directly.
697    ///
698    /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator
699    /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set
700    /// in the passed entry.
701    fn create_next_table<'b, A>(
702        &self,
703        entry: &'b mut PageTableEntry,
704        insert_flags: PageTableFlags,
705        allocator: &mut A,
706    ) -> Result<&'b mut PageTable, PageTableCreateError>
707    where
708        A: FrameAllocator<Size4KiB> + ?Sized,
709    {
710        let created;
711
712        if entry.is_unused() {
713            if let Some(frame) = allocator.allocate_frame() {
714                entry.set_frame(frame, insert_flags);
715                created = true;
716            } else {
717                return Err(PageTableCreateError::FrameAllocationFailed);
718            }
719        } else {
720            if !insert_flags.is_empty() && !entry.flags().contains(insert_flags) {
721                entry.set_flags(entry.flags() | insert_flags);
722            }
723            created = false;
724        }
725
726        let page_table = match self.next_table_mut(entry) {
727            Err(PageTableWalkError::MappedToHugePage) => {
728                return Err(PageTableCreateError::MappedToHugePage);
729            }
730            Err(PageTableWalkError::NotMapped) => panic!("entry should be mapped at this point"),
731            Ok(page_table) => page_table,
732        };
733
734        if created {
735            page_table.zero();
736        }
737        Ok(page_table)
738    }
739}
740
741#[derive(Debug)]
742enum PageTableWalkError {
743    NotMapped,
744    MappedToHugePage,
745}
746
747#[derive(Debug)]
748enum PageTableCreateError {
749    MappedToHugePage,
750    FrameAllocationFailed,
751}
752
753impl From<PageTableCreateError> for MapToError<Size4KiB> {
754    #[inline]
755    fn from(err: PageTableCreateError) -> Self {
756        match err {
757            PageTableCreateError::MappedToHugePage => MapToError::ParentEntryHugePage,
758            PageTableCreateError::FrameAllocationFailed => MapToError::FrameAllocationFailed,
759        }
760    }
761}
762
763impl From<PageTableCreateError> for MapToError<Size2MiB> {
764    #[inline]
765    fn from(err: PageTableCreateError) -> Self {
766        match err {
767            PageTableCreateError::MappedToHugePage => MapToError::ParentEntryHugePage,
768            PageTableCreateError::FrameAllocationFailed => MapToError::FrameAllocationFailed,
769        }
770    }
771}
772
773impl From<PageTableCreateError> for MapToError<Size1GiB> {
774    #[inline]
775    fn from(err: PageTableCreateError) -> Self {
776        match err {
777            PageTableCreateError::MappedToHugePage => MapToError::ParentEntryHugePage,
778            PageTableCreateError::FrameAllocationFailed => MapToError::FrameAllocationFailed,
779        }
780    }
781}
782
783impl From<FrameError> for PageTableWalkError {
784    #[inline]
785    fn from(err: FrameError) -> Self {
786        match err {
787            FrameError::HugeFrame => PageTableWalkError::MappedToHugePage,
788            FrameError::FrameNotPresent => PageTableWalkError::NotMapped,
789        }
790    }
791}
792
793impl From<PageTableWalkError> for UnmapError {
794    #[inline]
795    fn from(err: PageTableWalkError) -> Self {
796        match err {
797            PageTableWalkError::MappedToHugePage => UnmapError::ParentEntryHugePage,
798            PageTableWalkError::NotMapped => UnmapError::PageNotMapped,
799        }
800    }
801}
802
803impl From<PageTableWalkError> for FlagUpdateError {
804    #[inline]
805    fn from(err: PageTableWalkError) -> Self {
806        match err {
807            PageTableWalkError::MappedToHugePage => FlagUpdateError::ParentEntryHugePage,
808            PageTableWalkError::NotMapped => FlagUpdateError::PageNotMapped,
809        }
810    }
811}
812
813impl From<PageTableWalkError> for TranslateError {
814    #[inline]
815    fn from(err: PageTableWalkError) -> Self {
816        match err {
817            PageTableWalkError::MappedToHugePage => TranslateError::ParentEntryHugePage,
818            PageTableWalkError::NotMapped => TranslateError::PageNotMapped,
819        }
820    }
821}
822
823/// Provides a virtual address mapping for physical page table frames.
824///
825/// This only works if the physical address space is somehow mapped to the virtual
826/// address space, e.g. at an offset.
827///
828/// ## Safety
829///
830/// This trait is unsafe to implement because the implementer must ensure that
831/// `frame_to_pointer` returns a valid page table pointer for any given physical frame.
832pub unsafe trait PageTableFrameMapping {
833    /// Translate the given physical frame to a virtual page table pointer.
834    fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable;
835}
836
837unsafe impl<P: PageTableFrameMapping + ?Sized> PageTableFrameMapping for &P {
838    #[inline]
839    fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable {
840        (**self).frame_to_pointer(frame)
841    }
842}