|
1 | 1 | //! Access the page tables through a recursively mapped level 4 table.
|
2 | 2 |
|
| 3 | +use core::fmt; |
| 4 | + |
3 | 5 | use super::*;
|
4 | 6 | use crate::registers::control::Cr3;
|
5 | 7 | use crate::structures::paging::PageTableIndex;
|
6 | 8 | use crate::structures::paging::{
|
7 | 9 | frame_alloc::FrameAllocator,
|
8 |
| - page::NotGiantPageSize, |
| 10 | + page::{AddressNotAligned, NotGiantPageSize}, |
9 | 11 | page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags},
|
10 | 12 | Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB,
|
11 | 13 | };
|
@@ -46,18 +48,18 @@ impl<'a> RecursivePageTable<'a> {
|
46 | 48 | ///
|
47 | 49 | /// Otherwise `Err(())` is returned.
|
48 | 50 | #[inline]
|
49 |
| - pub fn new(table: &'a mut PageTable) -> Result<Self, ()> { |
| 51 | + pub fn new(table: &'a mut PageTable) -> Result<Self, InvalidPageTable> { |
50 | 52 | let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));
|
51 | 53 | let recursive_index = page.p4_index();
|
52 | 54 |
|
53 | 55 | if page.p3_index() != recursive_index
|
54 | 56 | || page.p2_index() != recursive_index
|
55 | 57 | || page.p1_index() != recursive_index
|
56 | 58 | {
|
57 |
| - return Err(()); |
| 59 | + return Err(InvalidPageTable::NotRecursive); |
58 | 60 | }
|
59 | 61 | if Ok(Cr3::read().0) != table[recursive_index].frame() {
|
60 |
| - return Err(()); |
| 62 | + return Err(InvalidPageTable::NotActive); |
61 | 63 | }
|
62 | 64 |
|
63 | 65 | Ok(RecursivePageTable {
|
@@ -326,7 +328,7 @@ impl<'a> Mapper<Size1GiB> for RecursivePageTable<'a> {
|
326 | 328 | }
|
327 | 329 |
|
328 | 330 | let frame = PhysFrame::from_start_address(p3_entry.addr())
|
329 |
| - .map_err(|()| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; |
| 331 | + .map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; |
330 | 332 |
|
331 | 333 | p3_entry.set_unused();
|
332 | 334 | Ok((frame, MapperFlush::new(page)))
|
@@ -404,7 +406,7 @@ impl<'a> Mapper<Size1GiB> for RecursivePageTable<'a> {
|
404 | 406 | }
|
405 | 407 |
|
406 | 408 | PhysFrame::from_start_address(p3_entry.addr())
|
407 |
| - .map_err(|()| TranslateError::InvalidFrameAddress(p3_entry.addr())) |
| 409 | + .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p3_entry.addr())) |
408 | 410 | }
|
409 | 411 | }
|
410 | 412 |
|
@@ -454,7 +456,7 @@ impl<'a> Mapper<Size2MiB> for RecursivePageTable<'a> {
|
454 | 456 | }
|
455 | 457 |
|
456 | 458 | let frame = PhysFrame::from_start_address(p2_entry.addr())
|
457 |
| - .map_err(|()| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; |
| 459 | + .map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; |
458 | 460 |
|
459 | 461 | p2_entry.set_unused();
|
460 | 462 | Ok((frame, MapperFlush::new(page)))
|
@@ -561,7 +563,7 @@ impl<'a> Mapper<Size2MiB> for RecursivePageTable<'a> {
|
561 | 563 | }
|
562 | 564 |
|
563 | 565 | PhysFrame::from_start_address(p2_entry.addr())
|
564 |
| - .map_err(|()| TranslateError::InvalidFrameAddress(p2_entry.addr())) |
| 566 | + .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p2_entry.addr())) |
565 | 567 | }
|
566 | 568 | }
|
567 | 569 |
|
@@ -752,7 +754,7 @@ impl<'a> Mapper<Size4KiB> for RecursivePageTable<'a> {
|
752 | 754 | }
|
753 | 755 |
|
754 | 756 | PhysFrame::from_start_address(p1_entry.addr())
|
755 |
| - .map_err(|()| TranslateError::InvalidFrameAddress(p1_entry.addr())) |
| 757 | + .map_err(|AddressNotAligned| TranslateError::InvalidFrameAddress(p1_entry.addr())) |
756 | 758 | }
|
757 | 759 | }
|
758 | 760 |
|
@@ -803,13 +805,40 @@ impl<'a> MapperAllSizes for RecursivePageTable<'a> {
|
803 | 805 |
|
804 | 806 | let frame = match PhysFrame::from_start_address(p1_entry.addr()) {
|
805 | 807 | Ok(frame) => frame,
|
806 |
| - Err(()) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), |
| 808 | + Err(AddressNotAligned) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), |
807 | 809 | };
|
808 | 810 | let offset = u64::from(addr.page_offset());
|
809 | 811 | TranslateResult::Frame4KiB { frame, offset }
|
810 | 812 | }
|
811 | 813 | }
|
812 | 814 |
|
| 815 | +/// The given page table was not suitable to create a `RecursivePageTable`. |
| 816 | +#[derive(Debug)] |
| 817 | +pub enum InvalidPageTable { |
| 818 | + /// The given page table was not at an recursive address. |
| 819 | + /// |
| 820 | + /// The page table address must be of the form `0o_xxx_xxx_xxx_xxx_0000` where `xxx` |
| 821 | + /// is the recursive entry. |
| 822 | + NotRecursive, |
| 823 | + /// The given page table was not active on the CPU. |
| 824 | + /// |
| 825 | + /// The recursive page table design requires that the given level 4 table is active |
| 826 | + /// on the CPU because otherwise it's not possible to access the other page tables |
| 827 | + /// through recursive memory addresses. |
| 828 | + NotActive, |
| 829 | +} |
| 830 | + |
| 831 | +impl fmt::Display for InvalidPageTable { |
| 832 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 833 | + match self { |
| 834 | + InvalidPageTable::NotRecursive => { |
| 835 | + write!(f, "given page table address is not recursive") |
| 836 | + } |
| 837 | + InvalidPageTable::NotActive => write!(f, "given page table is not active on the CPU"), |
| 838 | + } |
| 839 | + } |
| 840 | +} |
| 841 | + |
813 | 842 | #[inline]
|
814 | 843 | fn p3_ptr<S: PageSize>(page: Page<S>, recursive_index: PageTableIndex) -> *mut PageTable {
|
815 | 844 | p3_page(page, recursive_index).start_address().as_mut_ptr()
|
|
0 commit comments